net.sf.saxon.z.IntHashMap 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
The XSLT and XQuery Processor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2022 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.transpile.CSharpInjectMembers;
import net.sf.saxon.transpile.CSharpReplaceBody;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* A hash table that maps int keys to Object values.
*
* @author Dave Hale, Landmark Graphics
* @author Dominique Devienne
* @author Michael Kay: retrofitted to JDK 1.4, added iterator(), modified to disallow null values
* Reverted to generics July 2008.
*/
@CSharpInjectMembers(code={""
+ "public class IntHashMapValueSet : System.Collections.Generic.IEnumerable {"
+ " internal readonly IntHashMap container;"
+ " public IntHashMapValueSet(IntHashMap container) {this.container = container;}"
+ " public System.Collections.Generic.IEnumerator GetEnumerator() {return container.valueIterator();}"
+ " System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {return GetEnumerator();}"
+ "}"})
public class IntHashMap {
/**
* Initializes a map with a capacity of 8 and a load factor of 0,25.
*/
public IntHashMap() {
this(8, 0.25);
}
/**
* Initializes a map with the given capacity and a load factor of 0,25.
*
* @param capacity the initial capacity.
*/
public IntHashMap(int capacity) {
this(capacity, 0.25);
}
/**
* Constructs a new map with initial capacity, and load factor.
* The capacity is the number of keys that can be mapped without resizing
* the arrays in which keys and values are stored. For efficiency, only
* a fraction of the elements in those arrays are used. That fraction is
* the specified load factor. The initial length of the arrays equals the
* smallest power of two not less than the ratio capacity/factor. The
* capacity of the map is increased, as necessary. The maximum number
* of keys that can be mapped is 2^30.
*
* @param capacity the initial capacity.
* @param factor the load factor.
*/
public IntHashMap(int capacity, double factor) {
_factor = factor;
setCapacity(capacity);
}
/**
* Clears the map.
*/
public void clear() {
_n = 0;
for (int i = 0; i < _nmax; ++i) {
_value[i] = nullValue();
}
}
@CSharpReplaceBody(code="return default(T);")
private T nullValue() {
return null;
}
@CSharpReplaceBody(code = "return object.Equals(value, default(T));")
private boolean isNull(T value) {
return value == null;
}
/**
* Gets the value for this key.
*
* @param key Key
* @return the value, null if not found.
*/
public T get(int key) {
return _value[indexOf(key)];
}
/**
* Gets the size of the map.
*
* @return the size (the number of entries in the map)
*/
public int size() {
return _n;
}
/**
* Removes a key from the map.
*
* @param key Key to remove
* @return true if the value was removed
*/
public boolean remove(int key) {
// Knuth, v. 3, 527, Algorithm R.
int i = indexOf(key);
//if (!_filled[i]) {
if (_value[i] == null) {
return false;
}
--_n;
for (; ; ) {
//_filled[i] = false;
_value[i] = nullValue();
int j = i;
int r;
do {
i = (i - 1) & _mask;
//if (!_filled[i]) {
if (isNull(_value[i])) {
return true;
}
r = hash(_key[i]);
} while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r));
_key[j] = _key[i];
_value[j] = _value[i];
//_filled[j] = _filled[i];
}
}
/**
* Adds a key-value pair to the map.
*
* @param key Key
* @param value Value
* @return the value that was previously associated with the key, or null if there was no previous value
*/
public T put(int key, /*@Nullable*/ T value) {
if (isNull(value)) {
throw new NullPointerException("IntHashMap does not allow null values");
}
int i = indexOf(key);
T old = _value[i];
if (!isNull(old)) {
_value[i] = value;
} else {
_key[i] = key;
_value[i] = value;
grow();
}
return old;
}
///////////////////////////////////////////////////////////////////////////
// private
private static final int NBIT = 30; // NMAX = 2^NBIT
private static final int NMAX = 1 << NBIT; // maximum number of keys mapped
private final double _factor; // 0.0 <= _factor <= 1.0
private int _nmax; // 0 <= _nmax = 2^nbit <= 2^NBIT = NMAX
private int _n; // 0 <= _n <= _nmax <= NMAX
private int _nlo; // _nmax*_factor (_n<=_nlo, if possible)
private int _nhi; // NMAX*_factor (_n< _nhi, if possible)
private int _shift; // _shift = 1 + NBIT - nbit (see function hash() below)
private int _mask; // _mask = _nmax - 1
private int[] _key; // array[_nmax] of keys
//@SuppressWarnings(value = {"unchecked"})
private T[] _value; // array[_nmax] of values
//private boolean[] _filled; // _filled[i]==true iff _key[i] is mapped
private int hash(int key) {
// Knuth, v. 3, 509-510. Randomize the 31 low-order bits of c*key
// and return the highest nbits (where nbits <= 30) bits of these.
// The constant c = 1327217885 approximates 2^31 * (sqrt(5)-1)/2.
return ((1327217885 * key) >> _shift) & _mask;
}
private int indexOf(int key) {
int i = hash(key);
//while (_filled[i]) {
while (!isNull(_value[i])) {
if (_key[i] == key) {
return i;
}
i = (i - 1) & _mask;
}
return i;
}
private void grow() {
++_n;
if (_n > NMAX) {
throw new RuntimeException("number of keys mapped exceeds " + NMAX);
}
if (_nlo < _n && _n <= _nhi) {
setCapacity(_n);
}
}
private void setCapacity(int capacity) {
if (capacity < _n) {
capacity = _n;
}
double factor = (_factor < 0.01) ? 0.01 : (_factor > 0.99) ? 0.99 : _factor;
int nbit, nmax;
for (nbit = 1, nmax = 2; nmax * factor < capacity && nmax < NMAX; ++nbit, nmax *= 2) {
// no-op
}
int nold = _nmax;
if (nmax == nold) {
return;
}
_nmax = nmax;
_nlo = (int) (nmax * factor);
_nhi = (int) (NMAX * factor);
_shift = 1 + NBIT - nbit;
_mask = nmax - 1;
int[] key = _key;
T[] value = _value;
//boolean[] filled = _filled;
_n = 0;
_key = new int[nmax];
// semantically equivalent to _value = new V[nmax]
_value = makeValueArray(nmax);
//_filled = new boolean[nmax];
if (key != null) {
for (int i = 0; i < nold; ++i) {
//if (filled[i]) {
if (!isNull(value[i])) {
put(key[i], value[i]);
}
}
}
}
@CSharpReplaceBody(code="return new T[size];")
private T[] makeValueArray(int size) {
return (T[]) new Object[size];
}
/**
* Get an iterator over the keys
*
* @return an iterator over the integer keys in the map
*/
@CSharpReplaceBody(code="return new Saxon.Hej.z.IntHashMap.IntHashMapKeyIterator(this);")
public IntIterator keyIterator() {
return new IntHashMapKeyIterator(this);
}
/**
* Get an iterator over the values
*
* @return an iterator over the values in the map
*/
@CSharpReplaceBody(code = "return new Saxon.Hej.z.IntHashMap.IntHashMapValueIterator(this);")
public Iterator valueIterator() {
return new IntHashMapValueIterator(this);
}
/**
* Get the collection of values. (Despite the name, this is not a set: it may contain duplicates.)
* @return the set of values as an iterable collection
*/
@CSharpReplaceBody(code = "return new Saxon.Hej.z.IntHashMap.IntHashMapValueSet(this);")
public Iterable valueSet() {
return this::valueIterator;
}
/**
* Create a copy of the IntHashMap
*
* @return a copy of this map
*/
public IntHashMap copy() {
IntHashMap n = new IntHashMap<>(size());
IntIterator it = keyIterator();
while (it.hasNext()) {
int k = it.next();
n.put(k, get(k));
}
return n;
}
// /**
// * Diagnostic display of contents
// */
//
// public void display(PrintStream ps) {
// IntIterator iter = new IntHashMapKeyIterator(this);
// while (iter.hasNext()) {
// int key = iter.next();
// Object value = get(key);
// ps.println(key + " -> " + value.toString());
// }
// }
/**
* Iterator over keys
* @implNote implemented as a static inner class for ease of conversion to C#
*/
private static class IntHashMapKeyIterator implements IntIterator {
private int i = 0;
private final IntHashMap map;
public IntHashMapKeyIterator(IntHashMap map) {
this.map = map;
i = 0;
}
@Override
public boolean hasNext() {
while (i < map._key.length) {
if (!map.isNull(map._value[i])) {
return true;
} else {
i++;
}
}
return false;
}
@Override
public int next() {
return map._key[i++];
}
}
/**
* Iterator over values
* @implNote implemented as a static inner class for ease of conversion to C#
*/
private static class IntHashMapValueIterator implements Iterator {
private int i = 0;
private final IntHashMap map;
public IntHashMapValueIterator(IntHashMap map) {
this.map = map;
i = 0;
}
@Override
public boolean hasNext() {
while (i < map._key.length) {
if (!map.isNull(map._value[i])) {
return true;
} else {
i++;
}
}
return false;
}
@Override
public W next() {
W temp = map._value[i++];
if (map.isNull(temp)) {
throw new NoSuchElementException();
}
return temp;
}
/**
* Removes from the underlying collection the last element returned by the
* iterator (optional operation).
*
* @throws UnsupportedOperationException if the remove
* operation is not supported by this Iterator.
*/
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
}
/**
* Get the set of integer keys present in this IntHashSet
*
* @return the set of integer keys present in this IntHashSet
*/
@CSharpReplaceBody(code="return new Saxon.Hej.z.IntHashMap.IntHashMapKeySet(this);")
public IntSet keySet() {
return new IntHashMapKeySet(this);
}
private static class IntHashMapKeySet extends IntSet {
private final IntHashMap map;
public IntHashMapKeySet(IntHashMap map) {
this.map = map;
}
@Override
public void clear() {
throw new UnsupportedOperationException("Immutable set");
}
@Override
public IntSet copy() {
IntHashSet s = new IntHashSet();
IntIterator ii = iterator();
while (ii.hasNext()) {
s.add(ii.next());
}
return s;
}
@Override
public IntSet mutableCopy() {
return copy();
}
@Override
public boolean isMutable() {
return false;
}
@Override
public int size() {
return map._n;
}
@Override
public boolean isEmpty() {
return map._n == 0;
}
@Override
public boolean contains(int key) {
return map._value[map.indexOf(key)] != null;
}
@Override
public boolean remove(int value) {
throw new UnsupportedOperationException("Immutable set");
}
@Override
public boolean add(int value) {
throw new UnsupportedOperationException("Immutable set");
}
@Override
@CSharpReplaceBody(code="return new Saxon.Hej.z.IntHashMap.IntHashMapKeyIterator(map);")
public IntIterator iterator() {
return new IntHashMapKeyIterator(map);
}
@Override
public IntSet union(IntSet other) {
return copy().union(other);
}
@Override
public IntSet intersect(IntSet other) {
return copy().intersect(other);
}
@Override
public IntSet except(IntSet other) {
return copy().except(other);
}
@Override
public boolean containsAll(IntSet other) {
return copy().containsAll(other);
}
public String toString() {
return IntHashSet.stringify(iterator());
}
}
}