package plume; import java.io.Serializable; import java.util.*; /** * LimitedSizeIntSet stores up to some maximum number of unique * integer values, at which point its rep is nulled, in order to save space. * <p> * The advantage of this class over LimitedSizeSet<Integer> is that * it does not autobox the int values, so it takes less memory. * * @see LimitedSizeSet **/ // Consider adding: // * @deprecated Use LimitedSizeSet instead // @Deprecated public class LimitedSizeIntSet implements Serializable, Cloneable { // We are Serializable, so we specify a version to allow changes to // method signatures without breaking serialization. If you add or // remove fields, you should change this number to the current date. static final long serialVersionUID = 20031021L; // public final int max_values; // If null, then at least num_values distinct values have been seen. // The size is not separately stored, because that would take extra space. protected int /*@Nullable*/ [] values; // The number of active elements (equivalently, the first unused index). int num_values; public LimitedSizeIntSet(int max_values) { assert max_values > 0; // this.max_values = max_values; values = new int[max_values]; num_values = 0; } public void add(int elt) { if (values == null) return; for (int i=0; i < num_values; i++) { if (values[i] == elt) { return; } } if (num_values == values.length) { values = null; num_values++; return; } values[num_values] = elt; num_values++; } public void addAll(LimitedSizeIntSet s) { if (repNulled()) return; if (s.repNulled()) { int values_length = values.length; // We don't know whether the elements of this and the argument were // disjoint. There might be anywhere from max(size(), s.size()) to // (size() + s.size()) elements in the resulting set. if (s.size() > values_length) { num_values = values_length+1; values = null; return; } else { throw new Error("Arg is rep-nulled, so we don't know its values and can't add them to this."); } } for (int i=0; i<s.size(); i++) { assert s.values != null : "@SuppressWarnings(nullness): no relevant side effect: add's side effects do not affect s.values, whether or not this == s"; add(s.values[i]); if (repNulled()) { return; // optimization, not necessary for correctness } } } public boolean contains(int elt) { if (values == null) { throw new UnsupportedOperationException(); } for (int i=0; i < num_values; i++) { if (values[i] == elt) { return true; } } return false; } /** * A lower bound on the number of elements in the set. Returns either * the number of elements that have been inserted in the set, or * max_size(), whichever is less. **/ /*@Pure*/ public int size() { return num_values; } /** * An upper bound how many distinct elements can be individually * represented in the set. * Returns max_values+1 (where max_values is the argument to the constructor). **/ public int max_size() { if (values == null) { return num_values; } else { return values.length + 1; } } /*@AssertNonNullIfFalse("values")*/ /*@Pure*/ public boolean repNulled() { return values == null; } public LimitedSizeIntSet clone() { LimitedSizeIntSet result; try { result = (LimitedSizeIntSet) super.clone(); } catch (CloneNotSupportedException e) { throw new Error(); // can't happen } if (values != null) { result.values = values.clone(); } return result; } /** * Merges a list of LimitedSizeIntSet objects into a single object that * represents the values seen by the entire list. Returns the new * object, whose max_values is the given integer. **/ public static LimitedSizeIntSet merge (int max_values, List<LimitedSizeIntSet> slist) { LimitedSizeIntSet result = new LimitedSizeIntSet(max_values); for (LimitedSizeIntSet s : slist) { result.addAll(s); } return result; } public String toString() { return ("[size=" + size() + "; " + ((values == null) ? "null" : ArraysMDE.toString(values)) + "]"); } }