All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ibm.wala.util.intset.SparseLongSet Maven / Gradle / Ivy

There is a newer version: 1.6.6
Show newest version
/*
 * Copyright (c) 2002 - 2006 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 */
package com.ibm.wala.util.intset;

import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.debug.UnimplementedError;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.TreeSet;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;

/** A sparse ordered, duplicate-free, fully-encapsulated set of longs; not necessary mutable */
public class SparseLongSet implements LongSet {

  private static final int SINGLETON_CACHE_SIZE = 0;

  private static final SparseLongSet[] singletonCache = new SparseLongSet[SINGLETON_CACHE_SIZE];

  static {
    for (int i = 0; i < SINGLETON_CACHE_SIZE; i++) {
      singletonCache[i] = new SparseLongSet(new long[] {i});
    }
  }

  // TODO: I'm not thrilled with exposing these to subclasses, but
  // it seems expedient for now.
  /** The backing store of int arrays */
  @SuppressWarnings("NullAway.Init")
  protected long[] elements;

  /** The number of entries in the backing store that are valid. */
  protected int size = 0;

  /////////////////////////////////////////////////////////////////////////////
  //
  //  Constructors & Factories
  //
  /////////////////////////////////////////////////////////////////////////////

  protected SparseLongSet(int size) {
    elements = new long[size];
    this.size = size;
  }

  /**
   * Subclasses should use this with extreme care. Do not allow the backing array to escape
   * elsewhere.
   */
  protected SparseLongSet(long[] backingArray) {
    if (backingArray == null) {
      throw new IllegalArgumentException("backingArray is null");
    }
    elements = backingArray;
    this.size = backingArray.length;
  }

  /** Subclasses should use this with extreme care. */
  @NullUnmarked
  public SparseLongSet() {
    elements = null;
    this.size = 0;
  }

  protected SparseLongSet(SparseLongSet S) {
    cloneState(S);
  }

  private void cloneState(SparseLongSet S) {
    elements = S.elements.clone();
    this.size = S.size;
  }

  public SparseLongSet(IntSet S) throws IllegalArgumentException {
    if (S == null) {
      throw new IllegalArgumentException("S == null");
    }
    if (S instanceof SparseLongSet) {
      cloneState((SparseLongSet) S);
    } else {
      elements = new long[S.size()];
      size = S.size();
      S.foreach(
          new IntSetAction() {
            private int index = 0;

            @Override
            public void act(int i) {
              elements[index++] = i;
            }
          });
    }
  }

  /**
   * Does this set contain value x?
   *
   * @see com.ibm.wala.util.intset.IntSet#contains(int)
   */
  @Override
  public final boolean contains(long x) {
    if (elements == null) {
      return false;
    }
    return LongSetUtil.binarySearch(elements, x, 0, size - 1) >= 0;
  }

  /**
   * @return index i s.t. elements[i] == x, or -1 if not found.
   */
  public final int getIndex(long x) {
    if (elements == null) {
      return -1;
    }
    return LongSetUtil.binarySearch(elements, x, 0, size - 1);
  }

  @Override
  public final int size() {
    return size;
  }

  @Override
  public final boolean isEmpty() {
    return size == 0;
  }

  public final long elementAt(int idx) throws NoSuchElementException {
    if (idx < 0 || idx >= size) {
      throw new NoSuchElementException();
    }
    return elements[idx];
  }

  private boolean sameValueInternal(SparseLongSet that) {
    if (size != that.size) {
      return false;
    } else {
      for (int i = 0; i < size; i++) {
        if (elements[i] != that.elements[i]) {
          return false;
        }
      }
      return true;
    }
  }

  @Override
  public boolean sameValue(LongSet that) throws IllegalArgumentException, UnimplementedError {
    if (that == null) {
      throw new IllegalArgumentException("that == null");
    }
    if (that instanceof SparseLongSet) {
      return sameValueInternal((SparseLongSet) that);
    } else {
      Assertions.UNREACHABLE(that.getClass().toString());
      return false;
    }
  }

  /**
   * @return true iff {@code this} is a subset of {@code that}.
   *     

Faster than: {@code this.diff(that) == EMPTY}. */ private boolean isSubsetInternal(SparseLongSet that) { if (elements == null) return true; if (that.elements == null) return false; if (this.equals(that)) return true; if (this.sameValue(that)) { return true; } long[] ar = this.elements; int ai = 0; int al = size; long[] br = that.elements; int bi = 0; int bl = that.size; while (ai < al && bi < bl) { long cmp = (ar[ai] - br[bi]); // (fail when element only found in 'a') if (cmp > 0) { // a greater bi++; } else if (cmp < 0) { // b greater return false; } else { ai++; bi++; } } if (bi == bl && ai < al) { // we ran off the end of b without finding an a return false; } return true; } /** * Compute the asymmetric difference of two sets, a \ b. * * @throws IllegalArgumentException if A is null */ public static SparseLongSet diff(SparseLongSet A, SparseLongSet B) { if (A == null) { throw new IllegalArgumentException("A is null"); } if (B == null) { throw new IllegalArgumentException("B is null"); } if (A.isEmpty()) { return new SparseLongSet(0); } else if (B.isEmpty()) { return new SparseLongSet(A); } else if (A.equals(B)) { return new SparseLongSet(0); } else if (A.sameValue(B)) { return new SparseLongSet(0); } long[] ar = A.elements; int ai = 0; int al = A.size; long[] br = B.elements; int bi = 0; int bl = B.size; long[] cr = new long[al]; // allocate enough (i.e. too much) int ci = 0; while (ai < al && bi < bl) { long cmp = (ar[ai] - br[bi]); // (accept element when only found in 'a') if (cmp > 0) { // a greater bi++; } else if (cmp < 0) { // b greater cr[ci++] = ar[ai]; ai++; } else { ai++; bi++; } } // append a's tail if any if (ai < al) { int tail = al - ai; System.arraycopy(ar, ai, cr, ci, tail); ci += tail; } // now compact cr to 'just enough' ar = new long[ci]; System.arraycopy(cr, 0, ar, 0, ci); // ar := cr return new SparseLongSet(ar); } @Override public String toString() { StringBuilder sb = new StringBuilder(6 * size); sb.append("{ "); if (elements != null) { for (int ii = 0; ii < size; ii++) { sb.append(elements[ii]); sb.append(' '); } } sb.append('}'); return sb.toString(); } /** * Reverse of toString(): "{2,3}" -> [2,3] * * @throws IllegalArgumentException if str is null */ public static long[] parseLongArray(String str) throws NumberFormatException, IllegalArgumentException { if (str == null) { throw new IllegalArgumentException("str is null"); } int len = str.length(); if (len < 2) { throw new IllegalArgumentException("malformed input: " + str); } if (str.charAt(0) != '{' || str.charAt(len - 1) != '}') { throw new NumberFormatException(str); } str = str.substring(1, len - 1); StringTokenizer tok = new StringTokenizer(str, " ,"); // XXX not very efficient: TreeSet set = new TreeSet<>(); while (tok.hasMoreTokens()) { set.add(Long.decode(tok.nextToken())); } long[] result = new long[set.size()]; int i = 0; for (Long L : set) { result[i++] = L; } return result; } public static SparseLongSet singleton(int i) { if (i >= 0 && i < SINGLETON_CACHE_SIZE) { return singletonCache[i]; } else { return new SparseLongSet(new long[] {i}); } } public static SparseLongSet pair(long i, long j) { if (j > i) { return new SparseLongSet(new long[] {i, j}); } else { return new SparseLongSet(new long[] {j, i}); } } /** * @see com.ibm.wala.util.intset.IntSet#intersection(com.ibm.wala.util.intset.IntSet) */ @Override public @Nullable LongSet intersection(LongSet that) throws IllegalArgumentException, UnimplementedError { if (that == null) { throw new IllegalArgumentException("that == null"); } if (that instanceof SparseLongSet) { MutableSparseLongSet temp = MutableSparseLongSet.make(this); temp.intersectWith((SparseLongSet) that); return temp; } else { Assertions.UNREACHABLE("Unexpected: " + that.getClass()); return null; } } /** * @see com.ibm.wala.util.intset.IntSet#intIterator() */ @Override public LongIterator longIterator() { return new LongIterator() { int i = 0; @Override public boolean hasNext() { return (i < size); } @Override public long next() throws NoSuchElementException { if (elements == null) { throw new NoSuchElementException(); } return elements[i++]; } }; } @Override public void foreach(LongSetAction action) { if (action == null) { throw new IllegalArgumentException("null action"); } for (int i = 0; i < size; i++) action.act(elements[i]); } @Override public void foreachExcluding(LongSet X, LongSetAction action) { if (X == null) { throw new IllegalArgumentException("null X"); } if (action == null) { throw new IllegalArgumentException("null action"); } for (int i = 0; i < size; i++) { if (!X.contains(elements[i])) { action.act(elements[i]); } } } /** * @return the largest element in the set */ @Override public final long max() throws IllegalStateException { if (elements == null) { throw new IllegalStateException("Illegal to ask max() on an empty int set"); } return (size > 0) ? elements[size - 1] : -1; } /** * @return a new sparse int set which adds j to s */ public static SparseLongSet add(SparseLongSet s, int j) { if (s == null || s.elements == null) { return SparseLongSet.singleton(j); } SparseLongSet result = new SparseLongSet(s.size + 1); int k = 0; int m = 0; while (k < s.elements.length && s.elements[k] < j) { result.elements[k++] = s.elements[m++]; } if (k == s.size) { result.elements[k] = j; } else { if (s.elements[k] == j) { result.size--; } else { result.elements[k++] = j; } while (k < result.size) { result.elements[k++] = s.elements[m++]; } } return result; } /** * @see com.ibm.wala.util.intset.IntSet#isSubset(com.ibm.wala.util.intset.IntSet) */ @Override public boolean isSubset(LongSet that) throws IllegalArgumentException, UnimplementedError { if (that == null) { throw new IllegalArgumentException("that == null"); } if (that instanceof SparseLongSet) { return isSubsetInternal((SparseLongSet) that); } else { Assertions.UNREACHABLE("Unexpected type " + that.getClass()); return false; } } /** * @see com.ibm.wala.util.intset.IntSet#containsAny(com.ibm.wala.util.intset.IntSet) */ @Override public boolean containsAny(LongSet set) { if (set == null) { throw new IllegalArgumentException("set == null"); } if (set instanceof SparseLongSet) { return containsAny((SparseLongSet) set); } else { for (int i = 0; i < size; i++) { if (set.contains(elements[i])) { return true; } } return false; } } public boolean containsAny(SparseLongSet set) throws IllegalArgumentException { if (set == null) { throw new IllegalArgumentException("set == null"); } int i = 0; for (int j = 0; j < set.size; j++) { long x = set.elements[j]; while (i < size && elements[i] < x) { i++; } if (i == size) { return false; } else if (elements[i] == x) { return true; } } return false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy