diff --git a/projects/samskivert/src/java/com/samskivert/util/ArrayIntSet.java b/projects/samskivert/src/java/com/samskivert/util/ArrayIntSet.java
new file mode 100644
index 00000000..9010d6eb
--- /dev/null
+++ b/projects/samskivert/src/java/com/samskivert/util/ArrayIntSet.java
@@ -0,0 +1,274 @@
+//
+// $Id: ArrayIntSet.java,v 1.1 2002/02/03 07:10:16 mdb Exp $
+//
+// samskivert library - useful routines for java programs
+// Copyright (C) 2001 Michael Bayne
+//
+// 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.util.AbstractSet;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Provides an {@link IntSet} implementation using a sorted array of
+ * integers to maintain the contents of the set.
+ */
+public class ArrayIntSet extends AbstractSet
+ implements IntSet
+{
+ // documentation inherited from interface
+ public int size ()
+ {
+ return _size;
+ }
+
+ // documentation inherited from interface
+ public boolean isEmpty ()
+ {
+ return _size == 0;
+ }
+
+ // documentation inherited from interface
+ public boolean contains (Object o)
+ {
+ return contains(((Integer)o).intValue());
+ }
+
+ // documentation inherited from interface
+ public boolean contains (int value)
+ {
+ return (binarySearch(value) >= 0);
+ }
+
+ // documentation inherited from interface
+ public Iterator iterator ()
+ {
+ return new Iterator() {
+ public boolean hasNext () {
+ return (_pos < _size);
+ }
+
+ public Object next () {
+ if (_pos == _size) {
+ throw new NoSuchElementException();
+ } else {
+ return new Integer(_values[_pos++]);
+ }
+ }
+
+ public void remove () {
+ throw new UnsupportedOperationException();
+ }
+
+ protected int _pos;
+ };
+ }
+
+ // documentation inherited from interface
+ public Object[] toArray ()
+ {
+ return toArray(new Integer[_size]);
+ }
+
+ // documentation inherited from interface
+ public Object[] toArray (Object[] a)
+ {
+ for (int i = 0; i < _size; i++) {
+ a[i] = new Integer(_values[i]);
+ }
+ return a;
+ }
+
+ // documentation inherited from interface
+ public int[] toIntArray ()
+ {
+ int[] values = new int[_size];
+ System.arraycopy(_values, 0, values, 0, _size);
+ return values;
+ }
+
+ // documentation inherited from interface
+ public boolean add (Object o)
+ {
+ return add(((Integer)o).intValue());
+ }
+
+ // documentation inherited from interface
+ public boolean add (int value)
+ {
+ int index = binarySearch(value);
+ if (index >= 0) {
+ return false;
+ }
+
+ // 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 valen = _values.length;
+ int[] source = _values;
+ if (valen == _size) {
+ _values = new int[valen*2];
+ System.arraycopy(source, 0, _values, 0, index);
+ }
+
+ // shift and insert
+ if (_size > index) {
+ System.arraycopy(source, index,
+ _values, index+1, _size-index);
+ }
+ _values[index] = value;
+
+ // increment our size
+ _size += 1;
+
+ return true;
+ }
+
+ /**
+ * Add all of the values in the supplied array to the set.
+ *
+ * @param values elements to be added to this set.
+ *
+ * @return true if this set did not already contain all of
+ * the specified elements.
+ */
+ public boolean add (int[] values)
+ {
+ boolean modified = false;
+ int vlength = values.length;
+ for (int i = 0; i < vlength; i++) {
+ modified = (add(values[i]) || modified);
+ }
+ return modified;
+ }
+
+ // documentation inherited from interface
+ public boolean remove (Object o)
+ {
+ return remove(((Integer)o).intValue());
+ }
+
+ // documentation inherited from interface
+ public boolean remove (int value)
+ {
+ int index = binarySearch(value);
+ if (index > 0) {
+ System.arraycopy(_values, index, _values, index+1, --_size-index);
+ _values[_size] = 0;
+ return true;
+ }
+ return false;
+ }
+
+ // documentation inherited from interface
+ public boolean containsAll (Collection c)
+ {
+ Iterator iter = c.iterator();
+ while (iter.hasNext()) {
+ if (!contains(iter.next())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // documentation inherited from interface
+ public boolean addAll (Collection c)
+ {
+ boolean modified = false;
+ Iterator iter = c.iterator();
+ while (iter.hasNext()) {
+ modified = (add(iter.next()) || modified);
+ }
+ return modified;
+ }
+
+ // documentation inherited from interface
+ public boolean retainAll (Collection c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ // documentation inherited from interface
+ public void clear ()
+ {
+ Arrays.fill(_values, 0);
+ _size = 0;
+ }
+
+ // documentation inherited from interface
+ public boolean equals (Object o)
+ {
+ if (o instanceof ArrayIntSet) {
+ ArrayIntSet other = (ArrayIntSet)o;
+ if (other._size == _size) {
+ return Arrays.equals(_values, other._values);
+ }
+ }
+
+ return false;
+ }
+
+ // documentation inherited from interface
+ public int hashCode ()
+ {
+ int hashCode = 0;
+ for (int i = 0; i < _size; i++) {
+ hashCode ^= _values[i];
+ }
+ return hashCode;
+ }
+
+ /**
+ * Performs a binary search on our values array, looking for the
+ * specified value. Swiped from java.util.Arrays 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 = _size-1;
+
+ while (low <= high) {
+ int mid = (low + high) >> 1;
+ int midVal = _values[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[] _values = new int[16];
+
+ /** The number of elements in this set. */
+ protected int _size;
+}
diff --git a/projects/samskivert/src/java/com/samskivert/util/IntSet.java b/projects/samskivert/src/java/com/samskivert/util/IntSet.java
new file mode 100644
index 00000000..10edec39
--- /dev/null
+++ b/projects/samskivert/src/java/com/samskivert/util/IntSet.java
@@ -0,0 +1,84 @@
+//
+// $Id: IntSet.java,v 1.1 2002/02/03 07:10:16 mdb Exp $
+//
+// samskivert library - useful routines for java programs
+// Copyright (C) 2001 Michael Bayne
+//
+// 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.util.Set;
+
+/**
+ * A set that holds integers and provides accessors that eliminate the
+ * need to create and manipulate superfluous Integer
+ * objects. It extends the Set interface and therefore
+ * provides all of the standard methods (in which Integer
+ * objects will be converted to ints).
+ */
+public interface IntSet extends Set
+{
+ /**
+ * Returns true if this set contains the specified element.
+ *
+ * @param value element whose presence in this set is to be tested.
+ *
+ * @return true if this set contains the specified element.
+ */
+ public boolean contains (int value);
+
+ /**
+ * Adds the specified element to this set if it is not already present
+ * (optional operation). If this set already contains the specified
+ * element, the call leaves this set unchanged and returns
+ * false. In combination with the restriction on
+ * constructors, this ensures that sets never contain duplicate
+ * elements.
+ *
+ * @param value element to be added to this set.
+ *
+ * @return true if this set did not already contain the
+ * specified element.
+ *
+ * @throws UnsupportedOperationException if the add method is
+ * not supported by this set.
+ */
+ public boolean add (int value);
+
+ /**
+ * Removes the specified element from this set if it is present
+ * (optional operation). Returns true if the set contained
+ * the specified element (or equivalently, if the set changed as a
+ * result of the call). (The set will not contain the specified
+ * element once the call returns.)
+ *
+ * @param value element to be removed from this set, if present.
+ *
+ * @return true if the set contained the specified element.
+ *
+ * @throws UnsupportedOperationException if the remove method
+ * is not supported by this set.
+ */
+ public boolean remove (int value);
+
+ /**
+ * Returns an array containing all of the elements in this set. Obeys
+ * the general contract of the Collection.toArray method.
+ *
+ * @return an array containing all of the elements in this set.
+ */
+ public int[] toIntArray ();
+}
diff --git a/projects/samskivert/tests/src/java/com/samskivert/util/ArrayIntSetTest.java b/projects/samskivert/tests/src/java/com/samskivert/util/ArrayIntSetTest.java
new file mode 100644
index 00000000..30db2df8
--- /dev/null
+++ b/projects/samskivert/tests/src/java/com/samskivert/util/ArrayIntSetTest.java
@@ -0,0 +1,58 @@
+//
+// $Id: ArrayIntSetTest.java,v 1.1 2002/02/03 07:10:16 mdb Exp $
+//
+// samskivert library - useful routines for java programs
+// Copyright (C) 2001 Michael Bayne
+//
+// 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.util.Arrays;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import com.samskivert.Log;
+
+public class ArrayIntSetTest extends TestCase
+{
+ public ArrayIntSetTest ()
+ {
+ super(ArrayIntSetTest.class.getName());
+ }
+
+ public void runTest ()
+ {
+ ArrayIntSet set = new ArrayIntSet();
+ set.add(3);
+ set.add(5);
+ set.add(5);
+ set.add(9);
+ set.add(5);
+ set.add(7);
+ set.add(1);
+
+ int[] values = { 1, 3, 5, 7, 9 };
+ int[] setvals = set.toIntArray();
+
+ assert("values equal", Arrays.equals(values, setvals));
+ }
+
+ public static Test suite ()
+ {
+ return new ArrayIntSetTest();
+ }
+}