I'm just going to commit these for posterity, but I'll remove them.
Hell, maybe I should remove IntSets.java too. git-svn-id: https://samskivert.googlecode.com/svn/trunk@2702 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package com.samskivert.util;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* A more memory-efficient Set implementation than HashSet.
|
||||
*/
|
||||
public class ArraySet<E> extends AbstractSet<E>
|
||||
{
|
||||
public ArraySet ()
|
||||
{
|
||||
this(DEFAULT_CAPACITY);
|
||||
}
|
||||
|
||||
public ArraySet (int initialCapacity)
|
||||
{
|
||||
_hashCodes = new int[initialCapacity];
|
||||
_elements = new Object[initialCapacity];
|
||||
}
|
||||
|
||||
public ArraySet (Collection<? extends E> c)
|
||||
{
|
||||
this(c.size());
|
||||
addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains (Object o)
|
||||
{
|
||||
o = wrap(o);
|
||||
return (indexFor(o.hashCode(), o) >= 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add (E e)
|
||||
{
|
||||
Object o = wrap(e);
|
||||
int hashCode = o.hashCode();
|
||||
int index = indexFor(hashCode, o);
|
||||
if (index >= 0) {
|
||||
return false; // we've already got one!
|
||||
}
|
||||
// convert the index to the actual insertion point
|
||||
index = -(index + 1);
|
||||
|
||||
// possibly grow the arrays
|
||||
int len = _hashCodes.length;
|
||||
int[] codes = _hashCodes;
|
||||
Object[] elems = _elements;
|
||||
if (len == _size) {
|
||||
int newLen = (len >= Integer.MAX_VALUE/2)
|
||||
? Integer.MAX_VALUE
|
||||
: Math.max(DEFAULT_CAPACITY, len * 2);
|
||||
_hashCodes = new int[newLen];
|
||||
System.arraycopy(codes, 0, _hashCodes, 0, index);
|
||||
_elements = new Object[newLen];
|
||||
System.arraycopy(elems, 0, _elements, 0, index);
|
||||
}
|
||||
|
||||
// shift and insert
|
||||
if (_size > index) {
|
||||
System.arraycopy(codes, index, _hashCodes, index + 1, _size - index);
|
||||
System.arraycopy(elems, index, _elements, index + 1, _size - index);
|
||||
}
|
||||
|
||||
_hashCodes[index] = hashCode;
|
||||
_elements[index] = o;
|
||||
_size++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove (Object o)
|
||||
{
|
||||
o = wrap(o);
|
||||
int hashCode = o.hashCode();
|
||||
int index = indexFor(hashCode, o);
|
||||
if (index < 0) {
|
||||
return false; // not found
|
||||
}
|
||||
removeAtIndex(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size ()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator ()
|
||||
{
|
||||
// TODO: comodification
|
||||
return new Iterator<E>() {
|
||||
public boolean hasNext ()
|
||||
{
|
||||
return (_cursor < _size);
|
||||
}
|
||||
|
||||
public E next ()
|
||||
{
|
||||
if (_cursor >= _size) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
_canRemove = true;
|
||||
return unwrap(_elements[_cursor++]);
|
||||
}
|
||||
|
||||
public void remove ()
|
||||
{
|
||||
if (!_canRemove) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
--_cursor;
|
||||
removeAtIndex(_cursor);
|
||||
_canRemove = false;
|
||||
}
|
||||
|
||||
protected int _cursor;
|
||||
protected boolean _canRemove;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear ()
|
||||
{
|
||||
_hashCodes = new int[DEFAULT_CAPACITY];
|
||||
_elements = new Object[DEFAULT_CAPACITY];
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
protected int indexFor (int hashCode, Object o)
|
||||
{
|
||||
int index = Arrays.binarySearch(_hashCodes, 0, _size, hashCode);
|
||||
if (index < 0) {
|
||||
return index; // not found, so return our insertion point
|
||||
}
|
||||
// see if we landed right on it
|
||||
if (o.equals(_elements[index])) {
|
||||
return index; // found it!
|
||||
}
|
||||
// search forward for it
|
||||
for (int ii = index + 1; (ii < _size) && (_hashCodes[ii] == hashCode); ii++) {
|
||||
if (o.equals(_elements[ii])) {
|
||||
return ii;
|
||||
}
|
||||
}
|
||||
// search backward for it
|
||||
for (int ii = index - 1; (ii >= 0) && (_hashCodes[ii] == hashCode); ii--) {
|
||||
if (o.equals(_elements[ii])) {
|
||||
return ii;
|
||||
}
|
||||
}
|
||||
// else convert our original found index into an insertion point
|
||||
return -(index + 1);
|
||||
}
|
||||
|
||||
protected void removeAtIndex (int index)
|
||||
{
|
||||
_size--;
|
||||
int len = _hashCodes.length;
|
||||
if ((len > DEFAULT_CAPACITY) && (_size < len/8)) {
|
||||
// we're using less than 1/8 of our capacity, shrink by half, omitting the removed elem
|
||||
int[] codes = new int[len / 2];
|
||||
System.arraycopy(_hashCodes, 0, codes, 0, index);
|
||||
System.arraycopy(_hashCodes, index + 1, codes, index, _size - index);
|
||||
_hashCodes = codes;
|
||||
Object[] elems = new Object[len / 2];
|
||||
System.arraycopy(_elements, 0, elems, 0, index);
|
||||
System.arraycopy(_elements, index + 1, elems, index, _size - index);
|
||||
_elements = elems;
|
||||
|
||||
} else {
|
||||
// otherwise, simply shift the elements above it downward
|
||||
System.arraycopy(_hashCodes, index + 1, _hashCodes, index, _size - index);
|
||||
System.arraycopy(_elements, index + 1, _elements, index, _size - index);
|
||||
_elements[_size] = null; // clear loose refs, but no need to clean hashCodes
|
||||
}
|
||||
}
|
||||
|
||||
protected Object wrap (Object o)
|
||||
{
|
||||
return ((o == null) ? NULL : o);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected E unwrap (Object o)
|
||||
{
|
||||
return ((o == NULL) ? null : (E)o);
|
||||
}
|
||||
|
||||
protected int _size;
|
||||
protected int[] _hashCodes;
|
||||
protected Object[] _elements;
|
||||
|
||||
protected static final Object NULL = new Object();
|
||||
|
||||
protected static int DEFAULT_CAPACITY = 8;
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2001-2010 Michael Bayne, et al.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.samskivert.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Efficiently stores ints that are "clumped" together.
|
||||
*/
|
||||
public class ClumpyArrayIntSet extends AbstractIntSet
|
||||
implements Cloneable, Serializable
|
||||
{
|
||||
/**
|
||||
*/
|
||||
public ClumpyArrayIntSet ()
|
||||
{
|
||||
_anchors = new int[DEFAULT_CAPACITY];
|
||||
_masks = new int[DEFAULT_CAPACITY];
|
||||
}
|
||||
|
||||
@Override // from interface IntSet
|
||||
public boolean contains (int value)
|
||||
{
|
||||
int index = binarySearch(value >>> 5);
|
||||
return (index >= 0) && (0 != (_masks[index] & (1 << (value & 31))));
|
||||
}
|
||||
|
||||
@Override // from interface IntSet
|
||||
public boolean add (int value)
|
||||
{
|
||||
int anchor = value >>> 5;
|
||||
int mask = 1 << (value & 31);
|
||||
int index = binarySearch(anchor);
|
||||
if (index >= 0) {
|
||||
if (0 != (_masks[index] & mask)) {
|
||||
return false; // already contained
|
||||
}
|
||||
_masks[index] |= mask;
|
||||
_size++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// convert the return value into the insertion point
|
||||
index += 1;
|
||||
index *= -1;
|
||||
|
||||
// expand the values array if necessary, leaving room for the newly added element
|
||||
int alen = _anchors.length;
|
||||
int[] sourceAnchors = _anchors;
|
||||
int[] sourceMask = _masks;
|
||||
if (alen == _anchorSize) {
|
||||
int newLen = Math.max(DEFAULT_CAPACITY, alen*2);
|
||||
_anchors = new int[newLen];
|
||||
System.arraycopy(sourceAnchors, 0, _anchors, 0, index);
|
||||
_masks = new int[newLen];
|
||||
System.arraycopy(sourceMask, 0, _masks, 0, index);
|
||||
}
|
||||
|
||||
// shift and insert
|
||||
if (_anchorSize > index) {
|
||||
System.arraycopy(sourceAnchors, index, _anchors, index+1, _anchorSize-index);
|
||||
System.arraycopy(sourceMask, index, _masks, index+1, _anchorSize-index);
|
||||
}
|
||||
_anchors[index] = anchor;
|
||||
_masks[index] = mask;
|
||||
|
||||
// increment our size
|
||||
_anchorSize++;
|
||||
_size++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// @Override // from interface IntSet
|
||||
// public boolean remove (int value)
|
||||
// {
|
||||
// int anchor = value >>> 5;
|
||||
// int mask = 1 << (value & 31);
|
||||
// int index = binarySearch(anchor);
|
||||
// if (index < 0) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// // TODO!!!!!!! HERE
|
||||
//
|
||||
//// _size--;
|
||||
//// if ((_values.length > DEFAULT_CAPACITY) && (_size < _values.length/8)) {
|
||||
//// // if we're using less than 1/8 of our capacity, shrink by half
|
||||
//// int[] newVals = new int[_values.length/2];
|
||||
//// System.arraycopy(_values, 0, newVals, 0, index);
|
||||
//// System.arraycopy(_values, index+1, newVals, index, _size-index);
|
||||
//// _values = newVals;
|
||||
////
|
||||
//// } else {
|
||||
//// // shift entries past the removed one downwards
|
||||
//// System.arraycopy(_values, index+1, _values, index, _size-index);
|
||||
//// //_values[_size] = 0;
|
||||
//// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// from interface IntSet
|
||||
public Interator interator ()
|
||||
{
|
||||
// TODO: rewrite, use FindingInterator
|
||||
return new AbstractInterator() {
|
||||
public boolean hasNext () {
|
||||
if (!_hasNext) {
|
||||
_hasNext = findNext();
|
||||
}
|
||||
return _hasNext;
|
||||
}
|
||||
|
||||
public int nextInt () {
|
||||
if (!_hasNext && !hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
int mask = Integer.lowestOneBit(_curMask);
|
||||
int retval = (_anchors[_pos] << 5) + Integer.numberOfTrailingZeros(mask);
|
||||
_curMask &= ~mask;
|
||||
_hasNext = (_curMask != 0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// @Override public void remove () {
|
||||
// if (!_canRemove) {
|
||||
// throw new IllegalStateException();
|
||||
// }
|
||||
// System.arraycopy(_values, _pos, _values, _pos - 1, _size - _pos);
|
||||
// _pos--;
|
||||
// _size--; //_values[--_size] = 0;
|
||||
// _canRemove = false;
|
||||
// }
|
||||
|
||||
protected boolean findNext ()
|
||||
{
|
||||
if (_pos + 1 < _anchorSize) {
|
||||
_curMask = _masks[++_pos];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected int _pos = -1;
|
||||
protected int _curMask;
|
||||
protected boolean _hasNext;
|
||||
};
|
||||
}
|
||||
|
||||
@Override // from AbstractSet<Integer>
|
||||
public int size ()
|
||||
{
|
||||
return (_size > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)_size;
|
||||
}
|
||||
|
||||
@Override // from AbstractSet<Integer>
|
||||
public void clear ()
|
||||
{
|
||||
_anchorSize = 0;
|
||||
_size = 0;
|
||||
Arrays.fill(_masks, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a binary search on our values array, looking for the specified value. Swiped from
|
||||
* <code>java.util.Arrays</code> because those wankers didn't provide a means by which to
|
||||
* perform a binary search on a subset of an array.
|
||||
*/
|
||||
protected int binarySearch (int key)
|
||||
{
|
||||
int low = 0;
|
||||
int high = _anchorSize-1;
|
||||
|
||||
while (low <= high) {
|
||||
int mid = (low + high) >> 1;
|
||||
int midVal = _anchors[mid];
|
||||
|
||||
if (midVal < key) {
|
||||
low = mid + 1;
|
||||
} else if (midVal > key) {
|
||||
high = mid - 1;
|
||||
} else {
|
||||
return mid; // key found
|
||||
}
|
||||
}
|
||||
|
||||
return -(low + 1); // key not found.
|
||||
}
|
||||
|
||||
/** An array containing the values in this set. */
|
||||
protected int[] _anchors;
|
||||
|
||||
protected int[] _masks;
|
||||
|
||||
protected int _anchorSize;
|
||||
|
||||
/** The number of elements in this set. */
|
||||
protected long _size;
|
||||
|
||||
/** The default initial capacity of this set. */
|
||||
protected static final int DEFAULT_CAPACITY = 16;
|
||||
|
||||
/** Change this if the fields or inheritance hierarchy ever changes (extremely unlikely). */
|
||||
private static final long serialVersionUID = 1;
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package com.samskivert.util;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Is able to store every single int, using sub ArrayIntSets.
|
||||
*/
|
||||
public class CompleteIntSet extends AbstractIntSet
|
||||
{
|
||||
public CompleteIntSet ()
|
||||
{
|
||||
for (int ii = 0; ii < 4; ii++) {
|
||||
// start each with 0-length arrays, they'll grow when used
|
||||
_subsets[ii] = new ArrayIntSet(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains (int value)
|
||||
{
|
||||
return getSet(value).contains(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add (int value)
|
||||
{
|
||||
return getSet(value).add(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove (int value)
|
||||
{
|
||||
return getSet(value).remove(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size ()
|
||||
{
|
||||
long size = 0;
|
||||
for (IntSet set : _subsets) {
|
||||
size += set.size();
|
||||
}
|
||||
return (size > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)size;
|
||||
}
|
||||
|
||||
public Interator interator ()
|
||||
{
|
||||
return new AbstractInterator() {
|
||||
public boolean hasNext ()
|
||||
{
|
||||
while (true) {
|
||||
if (_current == null) {
|
||||
if (_index < 4) {
|
||||
_current = _subsets[_index++].interator();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (_current.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
_current = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int nextInt ()
|
||||
{
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
_removeFrom = _current;
|
||||
return _current.nextInt();
|
||||
}
|
||||
|
||||
@Override public void remove ()
|
||||
{
|
||||
if (_removeFrom == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
_removeFrom.remove();
|
||||
_removeFrom = null;
|
||||
}
|
||||
|
||||
protected Interator _current;
|
||||
protected Interator _removeFrom;
|
||||
protected int _index = 0;
|
||||
};
|
||||
}
|
||||
|
||||
protected IntSet getSet (int value)
|
||||
{
|
||||
return _subsets[valueToIndex(value)];
|
||||
}
|
||||
|
||||
protected int valueToIndex (int value)
|
||||
{
|
||||
// the indexes don't matter much, as long as they're distinct..
|
||||
return (value >>> 30);
|
||||
// if (value < 0) {
|
||||
// return (value < Integer.MIN_VALUE/2) ? 0 : 1;
|
||||
// } else {
|
||||
// return (value < Integer.MAX_VALUE/2) ? 2 : 3;
|
||||
// }
|
||||
}
|
||||
|
||||
/** The subsets. 3 would work, but 4 is a nicer split... */
|
||||
protected IntSet[] _subsets = new IntSet[4];
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package com.samskivert.util;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class RangeIntSet extends AbstractIntSet
|
||||
{
|
||||
/**
|
||||
* Construct a set of ints in the range from low to high, <b>inclusive</b>.
|
||||
*/
|
||||
public RangeIntSet (int lowValue, int highValue)
|
||||
{
|
||||
if (lowValue > highValue) {
|
||||
throw new IllegalArgumentException("lowValue is greater than highValue");
|
||||
}
|
||||
_low = lowValue;
|
||||
_high = highValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains (int value)
|
||||
{
|
||||
return (value >= _low) && (value <= _high);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size ()
|
||||
{
|
||||
long size = ((long) _high) - _low + 1;
|
||||
return (size > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)size;
|
||||
}
|
||||
|
||||
public Interator interator ()
|
||||
{
|
||||
return new AbstractInterator() {
|
||||
public boolean hasNext ()
|
||||
{
|
||||
return _curValid;
|
||||
}
|
||||
|
||||
public int nextInt ()
|
||||
{
|
||||
if (!_curValid) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
// check for the end before we increment _cur, in case _high is MAX_VALUE
|
||||
if (_cur == _high) {
|
||||
_curValid = false;
|
||||
}
|
||||
return _cur++;
|
||||
}
|
||||
|
||||
protected int _cur = _low;
|
||||
protected boolean _curValid = true;
|
||||
};
|
||||
}
|
||||
|
||||
protected int _low;
|
||||
protected int _high;
|
||||
}
|
||||
Reference in New Issue
Block a user