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:
ray.j.greenwell
2010-01-15 01:48:57 +00:00
parent e0e2f1cf7d
commit 2a6397ddcb
4 changed files with 608 additions and 0 deletions
+207
View File
@@ -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;
}