net.sf.saxon.z.IntArraySet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of saxon-he Show documentation
Show all versions of saxon-he Show documentation
An OSGi bundle for Saxon-HE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2013 Saxonica Limited.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package net.sf.saxon.z;
import net.sf.saxon.tree.util.FastStringBuffer;
import java.io.Serializable;
import java.util.Arrays;
/**
* Set of int values. This class is modelled on the java.net.Set interface, but it does
* not implement this interface, because the set members are int's rather than Objects.
*
* This implementation of a set of integers is optimized to use very little storage
* and to provide fast comparison of two sets. The equals() method determines whether
* two sets contain the same integers.
*
* This implementation is not efficient at adding new integers to the set. It creates a new
* array each time you do that.
*
* Not thread safe.
*
* @author Michael Kay
*/
public class IntArraySet extends AbstractIntSet implements Serializable, IntSet {
public static final int[] EMPTY_INT_ARRAY = new int[0];
/**
* The array of integers, which will always be sorted
*/
private int[] contents;
/**
* Hashcode, evaluated lazily
*/
private int hashCode = -1;
/**
* Create an empty set
*/
public IntArraySet() {
contents = EMPTY_INT_ARRAY;
}
/**
* Create a set containing integers from the specified IntHashSet
* @param input the set to be copied
*/
public IntArraySet(IntHashSet input) {
// exploits the fact that getValues() constructs a new array
contents = input.getValues();
//System.err.println("new IntArraySet(" + contents.length + ")");
Arrays.sort(contents);
}
/**
* Create one IntArraySet as a copy of another
* @param input the set to be copied
*/
public IntArraySet(IntArraySet input) {
contents = new int[input.contents.length];
System.arraycopy(input.contents, 0, contents, 0, contents.length);
}
public IntSet copy() {
IntArraySet i2 = new IntArraySet();
i2.contents = new int[contents.length];
System.arraycopy(contents, 0, i2.contents, 0, contents.length);
//i2.contents = Arrays.copyOf(contents, contents.length);
return i2;
}
public IntSet mutableCopy() {
return copy();
}
public void clear() {
contents = EMPTY_INT_ARRAY;
hashCode = -1;
}
public int size() {
return contents.length;
}
public boolean isEmpty() {
return contents.length == 0;
}
/**
* Get the set of integer values as an array
* @return a sorted array of integers
*/
public int[] getValues() {
return contents;
}
public boolean contains(int value) {
return Arrays.binarySearch(contents, value) >= 0;
}
public boolean remove(int value) {
hashCode = -1;
int pos = Arrays.binarySearch(contents, value);
if (pos < 0) {
return false;
}
int[] newArray = new int[contents.length - 1];
if (pos > 0) {
// copy the items before the one that's being removed
System.arraycopy(contents, 0, newArray, 0, pos);
}
if (pos < newArray.length) {
// copy the items after the one that's being removed
System.arraycopy(contents, pos+1, newArray, pos, contents.length - pos);
}
contents = newArray;
return true;
}
/**
* Add an integer to the set
* @param value the integer to be added
* @return true if the integer was added, false if it was already present
*/
public boolean add(int value) {
hashCode = -1;
if (contents.length == 0) {
contents = new int[] {value};
return true;
}
int pos = Arrays.binarySearch(contents, value);
if (pos >= 0) {
return false; // value was already present
}
pos = -pos - 1; // new insertion point
int[] newArray = new int[contents.length + 1];
if (pos > 0) {
// copy the items before the insertion point
System.arraycopy(contents, 0, newArray, 0, pos);
}
newArray[pos] = value;
if (pos < contents.length) {
// copy the items after the insertion point
System.arraycopy(contents, pos, newArray, pos+1, newArray.length - pos);
}
contents = newArray;
return true;
}
/**
* Get the first value in the set.
* @return the first value in the set, in sorted order
* @throws ArrayIndexOutOfBoundsException if the set is empty
*/
public int getFirst() {
return contents[0];
}
/**
* Get an iterator over the values
* @return an iterator over the values, which will be delivered in sorted order
*/
public IntIterator iterator() {
return new IntArraySetIterator();
}
/**
* Form a new set that is the union of this set with another set.
* @param other the other set
* @return the union of the two sets
*/
public IntSet union(IntSet other) {
// Look for special cases: one set empty, or both sets equal
if (size() == 0) {
return other.copy();
} else if (other.isEmpty()) {
return copy();
} else if (other == IntUniversalSet.getInstance()) {
return other;
} else if (other instanceof IntComplementSet) {
return other.union(this);
}
if (equals(other)) {
return copy();
}
if (other instanceof IntArraySet) {
// Form the union by a merge of the two sorted arrays
int[] merged = new int[size() + other.size()];
int[] a = contents;
int[] b = ((IntArraySet)other).contents;
int m = a.length, n = b.length;
int o=0, i=0, j=0;
while (true) {
if (a[i] < b[j]) {
merged[o++] = a[i++];
} else if (b[j] < a[i]) {
merged[o++] = b[j++];
} else {
merged[o++] = a[i++];
j++;
}
if (i == m) {
System.arraycopy(b, j, merged, o, n-j);
o += (n-j);
return make(merged, o);
} else if (j == n) {
System.arraycopy(a, i, merged, o, m-i);
o += (m-i);
return make(merged, o);
}
}
} else {
return super.union(other);
}
}
/**
* Factory method to construct a set from an array of integers
* @param in the array of integers, which must be in ascending order
* @param size the number of elements in the array that are significant
* @return the constructed set
*/
public static IntArraySet make(int[] in, int size) {
int[] out;
if (in.length == size) {
out = in;
} else {
out = new int[size];
System.arraycopy(in, 0, out, 0, size);
}
return new IntArraySet(out);
}
private IntArraySet(int[] content) {
contents = content;
}
public String toString() {
FastStringBuffer sb = new FastStringBuffer(contents.length*4);
for (int i=0; i