summaryrefslogtreecommitdiff
path: root/israfil-foundation-collections/src/main/java/net/israfil/foundation
diff options
context:
space:
mode:
Diffstat (limited to 'israfil-foundation-collections/src/main/java/net/israfil/foundation')
-rw-r--r--israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ArraySet.java105
-rw-r--r--israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ArrayUtils.java113
-rw-r--r--israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/IterableResultSet.java132
-rw-r--r--israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/RandomOrderIterable.java72
-rw-r--r--israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/RandomOrderIterator.java94
-rw-r--r--israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ReciprocalHashMap.java202
-rw-r--r--israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ReciprocalMap.java49
-rw-r--r--israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/SoloCollection.java66
8 files changed, 833 insertions, 0 deletions
diff --git a/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ArraySet.java b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ArraySet.java
new file mode 100644
index 0000000..3447adc
--- /dev/null
+++ b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ArraySet.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2003 - 2007 Israfil Consulting Services Corporation
+ * Copyright (c) 2003 - 2007 Christian Edward Gruber
+ * All Rights Reserved
+ *
+ * This software is licensed under the Berkeley Standard Distribution license,
+ * (BSD license), as defined below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Israfil Consulting Services nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $Id: ArraySet.java 76 2006-08-03 15:37:05Z cgruber $
+ */
+package net.israfil.foundation.collections;
+
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * An ArrayList backed Set implementation, whose primary purpose is
+ * to provide a Set that maintains the order of elements based on
+ * indexes and/or the order in which items are added. Most
+ * particularly it's to guarrantee deterministic results of an
+ * iterator, where the iterator provides each element in the order
+ * of the underlying list.
+ *
+ * Unlike a LinkedHashSet, this implementation leaves a duplicate
+ * element in its original position. It's performance characteristics
+ * on input are similar, since a comparison still has to happen
+ * for de-dupliation, but obtaining the item by index is constant time.
+ *
+ * TODO: Consider making this a SortedSet, using the list order as the guarrantee. Not sure if it's a legit use of the API.
+ * @See java.util.LinkedHashSet
+ * @author <a href="mailto:cgruber@israfil.net">Christian Edward Gruber </a>
+ */
+public class ArraySet<E> extends AbstractSet<E> {
+
+ private transient ArrayList<E> internalList;
+
+ public ArraySet() {
+ internalList = new ArrayList<E>();
+ }
+
+ public ArraySet(int initialCapacity) {
+ internalList = new ArrayList<E>(initialCapacity);
+ }
+
+ public ArraySet(Collection<E> col) {
+ internalList = new ArrayList<E>(col);
+ Iterator<E> i = col.iterator();
+ while (i.hasNext()) {
+ internalList.add(i.next());
+ }
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return internalList.iterator();
+ }
+
+ @Override
+ public int size() {
+ return internalList.size();
+ }
+
+ @Override
+ public boolean add(E o) {
+ if (internalList.contains(o)) return false;
+ else {
+ internalList.add(o);
+ return true;
+ }
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return internalList.remove(o);
+ }
+
+ public E get(Integer index) {
+ return internalList.get(index);
+ }
+}
diff --git a/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ArrayUtils.java b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ArrayUtils.java
new file mode 100644
index 0000000..880de92
--- /dev/null
+++ b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ArrayUtils.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2003, 2004, 2005, 2006 Israfil Consulting Services Corporation
+ * Copyright (c) 2003, 2004, 2005, 2006 Christian Edward Gruber
+ * All Rights Reserved
+ *
+ * This software is licensed under the Berkeley Standard Distribution license,
+ * (BSD license), as defined below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Israfil Consulting Services nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $Id: ArrayUtils.java 48 2006-02-23 06:11:53Z cgruber $
+ */
+package net.israfil.foundation.collections;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * An array utility class. This class is generic, so its usage is similar
+ * to the following:
+ * Foo[] foo1 = new Foo[]{ aFoo, bFoo, cFoo };
+ * Foo[] foo2 = new Foo[]{ dFoo, eFoo, fFoo };
+ * Foo[] fooResult = ArrayUtils.add(new Foo[],foo1,foo2);
+ *
+ * fooResult would be equivalent: new Foo[]{ aFoo, bFoo, cFoo, dFoo, eFoo, fFoo }
+ *
+ * This util is mostly helpful for putting together large batches of like
+ * arrays into a long single array, such as large groups of parameter lists
+ * or whatever.
+ *
+ * @author <a href="mailto:cgruber@israfil.net">Christian Edward Gruber </a>
+ */
+public class ArrayUtils {
+ private static final Logger logger = Logger.getLogger(ArrayUtils.class.getName());
+
+ /**
+ * Adds arrays of like type creating a new array containing
+ * all elements of the added arrays. Note that you have to
+ * pass in a typed array, because you can't create an array
+ * from a generic type in the code.
+ *
+ * i.e. you can't do this with Generics.
+ * <pre>
+ * public class Foo<T> {
+ * public T[] getArray() {
+ * T[] array = new T[a];
+ * }
+ * }
+ * </pre>
+ *
+ * However, as described in the tests, you can simply pass
+ * it an empty array of that type.
+ *
+ * @param resultBucket An array of the type you are attempting to aggregate. Can be empty. If it has sufficient space, it will be used for the aggregated result.
+ * @param arrays The arrays to be aggregated.
+ * @return An array of the provided type, containing the aggregated contents of the provided arrays.
+ */
+ public static <E> E[] aggregate(E[] resultBucket, E[] ... arrays)
+ {
+ logger.log(Level.FINER,Array.newInstance(arrays.getClass().getComponentType(),0).getClass().getCanonicalName());
+ List<E> resultList = new ArrayList<E>();
+ for (E[] t : arrays) {
+ for (E element : t) {
+ resultList.add(element);
+ }
+ }
+ logger.log(Level.FINER,resultList.toString());
+ return (E[])resultList.toArray(resultBucket);
+ }
+
+ /**
+ * A method that tests the eqivalence (content equality) of
+ * two arrays.
+ * @param a1
+ * @param a2
+ * @return
+ */
+ public static boolean equivalent(Object[] o1, Object[] o2) {
+ if (o1 == null && (o2 == null || o2.length == 0)) return true;
+ if (o2 == null && o1.length == 0) return true;
+ if (o1.length != o2.length) return false;
+ for (int i = 0; i < o1.length; i++) {
+ if (o1[i] != o2[i]) return false;
+ }
+ return true;
+ }
+
+}
+
diff --git a/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/IterableResultSet.java b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/IterableResultSet.java
new file mode 100644
index 0000000..9258c6f
--- /dev/null
+++ b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/IterableResultSet.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2006 Israfil Consulting Services Corporation
+ * Copyright (c) 2006 Christian Edward Gruber
+ * All Rights Reserved
+ *
+ * This software is licensed under the Berkeley Standard Distribution license,
+ * (BSD license), as defined below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Israfil Consulting Services nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $Id: IterableResultSet.java 26 2006-02-13 16:35:44Z cgruber $
+ */
+package net.israfil.foundation.collections;
+
+import java.lang.ref.WeakReference;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A simple wrapper that provides an Iterable implementation back-ended
+ * by a result-set. Allows a ResultSet to be used in a JDK 5.0 extended
+ * for-loop syntax.
+ *
+ * No result set can have more than one Iterable wrapper around it at a time.
+ * However, it is impossible for this object to know implicitly when it is
+ * no longer required (to free the reference). Therefore, when this
+ * wrapper is concluded, it should be disposed of via the dispose() method.
+ *
+ * @author <a href="mailto:cgruber@israfil.net">Christian Edward Gruber </a>
+ */
+public class IterableResultSet implements Iterable<Map<String,Object>> {
+
+ protected static final Map<ResultSet,IterableResultSet> iterables = new WeakHashMap<ResultSet,IterableResultSet>();
+ protected final WeakReference<ResultSet> resultRef;
+
+ public IterableResultSet(ResultSet result) {
+ if (iterables.containsKey(result)) throw new RuntimeException("Cannot have two IterableResultSet wrappers around the same resultset.");
+ this.resultRef = new WeakReference<ResultSet>(result);
+ }
+
+ public Iterator<Map<String,Object>> iterator() {
+ if (resultRef.get() == null) throw new RuntimeException("ResultSet object not available to iterate.");
+ return new ResultSetIterator(resultRef.get());
+ }
+
+ public void dispose() {
+ ResultSet rs = resultRef.get();
+ if (rs == null) return;
+ if (iterables.containsKey(rs)) {
+ iterables.get(rs).dispose();
+ }
+ resultRef.clear();
+ }
+
+ public static class ResultSetIterator implements Iterator<Map<String,Object>> {
+ private static final Logger logger = Logger.getLogger(ResultSetIterator.class.getName());
+ protected ResultSet result;
+
+ boolean hasNext = true;
+
+
+ public ResultSetIterator(ResultSet result) {
+ this.result = result;
+ try {
+ hasNext = result.first();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean hasNext() {
+ return hasNext;
+ }
+
+ public Map<String,Object> next() {
+ try {
+ Map<String,Object> row = new HashMap<String,Object>();
+ for(int i = 1; i <= result.getMetaData().getColumnCount(); i++) {
+ row.put(result.getMetaData().getColumnName(i),result.getObject(i));
+ }
+ hasNext = result.next();
+ return row;
+ } catch (SQLException e) {
+ logger.log(Level.FINER,"SQLException thrown while iterating across result set.",e);
+ return null;
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Removal of records from underlying result set not supported.");
+ }
+
+ public void dispose() {
+ if (iterables.containsKey(result)) iterables.remove(result);
+ result = null;
+ }
+
+ public void finalize() throws Throwable {
+ dispose();
+ super.finalize();
+ }
+ }
+}
+
+
diff --git a/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/RandomOrderIterable.java b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/RandomOrderIterable.java
new file mode 100644
index 0000000..3b5656d
--- /dev/null
+++ b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/RandomOrderIterable.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007 Israfil Consulting Services Corporation
+ * Copyright (c) 2007 Christian Edward Gruber
+ * All Rights Reserved
+ *
+ * This software is licensed under the Berkeley Standard Distribution license,
+ * (BSD license), as defined below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Israfil Consulting Services nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $Id: IterableResultSet.java 26 2006-02-13 16:35:44Z cgruber $
+ */
+package net.israfil.foundation.collections;
+
+import java.security.SecureRandom;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Random;
+
+/**
+ * A simple wrapper that provides an Iterable implementation that wraps
+ * a collection and returns a RandomOrderIterator when asked for an iterator.
+ *
+ * No result set can have more than one Iterable wrapper around it at a time.
+ * However, it is impossible for this object to know implicitly when it is
+ * no longer required (to free the reference). Therefore, when this
+ * wrapper is concluded, it should be disposed of via the dispose() method.
+ *
+ * @author <a href="mailto:cgruber@israfil.net">Christian Edward Gruber </a>
+ */
+public class RandomOrderIterable<E> implements Iterable<E> {
+
+ private Collection<E> _collection;
+ private Random _random = null;
+
+ public RandomOrderIterable(Collection<E> collection) {
+ _collection = collection;
+ }
+
+ public RandomOrderIterable(Collection<E> collection, Random random) {
+ this(collection);
+ _random = random;
+ }
+
+ public Iterator<E> iterator() {
+ return new RandomOrderIterator<E>(_collection,(_random == null) ? new SecureRandom() : _random);
+ }
+
+}
+
+
diff --git a/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/RandomOrderIterator.java b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/RandomOrderIterator.java
new file mode 100644
index 0000000..8b97e4a
--- /dev/null
+++ b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/RandomOrderIterator.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2007 Israfil Consulting Services Corporation
+ * Copyright (c) 2007 Christian Edward Gruber
+ * All Rights Reserved
+ *
+ * This software is licensed under the Berkeley Standard Distribution license,
+ * (BSD license), as defined below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Israfil Consulting Services nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $Id: ArraySet.java 76 2006-08-03 15:37:05Z cgruber $
+ */
+package net.israfil.foundation.collections;
+
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * An iterator that is constructed from a collection and returns the
+ * contents of the collection in random order. Note that this is
+ * an iterator over a copy of the collection, not the collection
+ * itself, so remove() is not supported, and underlying changes
+ * to the original collection will not be reflected in this iterator.
+ *
+ * @author <a href="mailto:cgruber@israfil.net">Christian Edward Gruber </a>
+ */
+public class RandomOrderIterator<E> implements Iterator<E> {
+
+ private transient List<E> _collection;
+
+ private transient Random _random = new SecureRandom();
+
+ private transient List<Integer> _indexes;
+
+
+ public RandomOrderIterator(Collection<E> collection) {
+ _collection = new ArrayList<E>(collection);
+ _indexes = new LinkedList<Integer>();
+ for (int i = 0; i < _collection.size();i++) {
+ _indexes.add(i); // populate index source.
+ }
+ }
+
+ public RandomOrderIterator(Collection<E> collection, Random random) {
+ this(collection);
+ this._random = random;
+ }
+
+ public boolean hasNext() {
+ return _indexes.size() > 0;
+ }
+
+ public E next() {
+ Integer index = _indexes.remove(_random.nextInt(_indexes.size()));
+ return _collection.get(index);
+ }
+
+ /**
+ * Because of the means required to track the current node,
+ * removing anything from the underlying collection is not supported.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+}
diff --git a/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ReciprocalHashMap.java b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ReciprocalHashMap.java
new file mode 100644
index 0000000..0ac0164
--- /dev/null
+++ b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ReciprocalHashMap.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2003, Christian Edward Gruber
+ * Copyright (c) 2003, Israfil Consulting Services Corporation
+ *
+ * This software is licensed under the Berkeley Standard Distribution license,
+ * (BSD license), as defined below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Israfil Consulting Services nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $Id: ReciprocalHashMap.java 129 2006-12-31 23:20:02Z cgruber $
+ */
+package net.israfil.foundation.collections;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A two-way map, backed by java.util.HashMaps, where each key matches one
+ * value and is unique, and where each value maps to a key, and is unique
+ * among all values.
+ *
+ * @author <a href="mailto:cgruber@israfil.net">Christian Edward Gruber</a>
+ *
+ */
+public class ReciprocalHashMap<K,V> extends java.util.AbstractMap<K,V>
+ implements ReciprocalMap<K,V> {
+
+ Set<Map.Entry<K,V>> entrySetByKey = new HashSet<Map.Entry<K,V>>();
+ Set<Map.Entry<V,K>> entrySetByValue = new HashSet<Map.Entry<V,K>>();
+
+ @Override
+ public Set<Map.Entry<K,V>> entrySet() {
+ return entrySetByKey;
+ }
+
+ public Set<Map.Entry<V,K>> entrySetByValue() {
+ return entrySetByValue;
+ }
+
+ public boolean contains(K key, V value) {
+ V value1 = get(key);
+ if (value == value1) return true;
+ else if (value == null) return false; // assume null == null handled.
+ else return value.equals(value1);
+ }
+
+ public Entry<V,K> getEntryByValue(V value) {
+ Iterator<Entry<V,K>> i = entrySetByValue().iterator();
+ if (value==null) {
+ while (i.hasNext()) {
+ Entry<V,K> e = i.next();
+ if (e.getKey()==null) return e;
+ }
+ } else {
+ while (i.hasNext()) {
+ Entry<V,K> e = i.next();
+ if (value.equals(e.getKey())) return e;
+ }
+ }
+ return null;
+ }
+ public Entry<K,V> getEntryByKey(K value) {
+ Iterator<Entry<K,V>> i = entrySet().iterator();
+ if (value==null) {
+ while (i.hasNext()) {
+ Entry<K,V> e = i.next();
+ if (e.getKey()==null) return e;
+ }
+ } else {
+ while (i.hasNext()) {
+ Entry<K,V> e = i.next();
+ if (value.equals(e.getKey())) return e;
+ }
+ }
+ return null;
+ }
+
+ public K getKey(V value) {
+ Entry<V,K> e = getEntryByValue(value);
+ return (e == null) ? null : e.getValue();
+ }
+
+ public V getValue(K key) {
+ Entry<K,V> e = getEntryByKey(key);
+ return (e == null) ? null : e.getValue();
+ }
+
+ public K removeByValue(V value) {
+ Entry<V,K> valEntry = getEntryByValue(value);
+ Entry<K,V> keyEntry = getEntryByKey(valEntry.getValue());
+ if (keyEntry != null) entrySetByKey.remove(keyEntry);
+ if (valEntry != null) entrySetByValue.remove(valEntry);
+ return keyEntry.getKey();
+ }
+
+ public V removeByKey(K key) {
+ Entry<K,V> keyEntry = getEntryByKey(key);
+ Entry<V,K> valEntry = getEntryByValue(keyEntry.getValue());
+ if (keyEntry != null) entrySetByKey.remove(keyEntry);
+ if (valEntry != null) entrySetByValue.remove(valEntry);
+ return valEntry.getKey();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public V remove(Object key) {
+ return this.removeByKey((K)key);
+ }
+
+
+ @Override public V put(K key, V value) {
+ Entry<K,V> keyEntry = getEntryByKey(key);
+ Entry<V,K> valueEntry = getEntryByValue(value);
+
+ V oldValue = null;
+
+ if (keyEntry != null) {
+ Entry<V,K> inverseKeyEntry = getEntryByValue(keyEntry.getValue());
+ keyEntry.getKey();
+ entrySetByKey.remove(keyEntry);
+ entrySetByValue.remove(inverseKeyEntry);
+ }
+ if (valueEntry != null) {
+ Entry<K,V> inverseValueEntry = getEntryByKey(valueEntry.getValue());
+ oldValue = valueEntry.getKey();
+ entrySetByValue.remove(valueEntry);
+ entrySetByKey.remove(inverseValueEntry);
+ }
+ entrySetByKey.add(new ReciprocalEntry<K,V>(key,value));
+ entrySetByValue.add(new ReciprocalEntry<V,K>(value,key));
+
+ return oldValue;
+ }
+
+ static class ReciprocalEntry<K, V> implements Entry<K, V> {
+ private K key;
+ private V value;
+
+ public ReciprocalEntry(K key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public K getKey() { return key; }
+
+ public V getValue() { return value; }
+
+ public V setValue(V value) {
+ V oldValue = this.value;
+ this.value = value;
+ return oldValue;
+ }
+
+ public int hashCode() {
+ return ((key == null) ? 0 : key.hashCode()) ^
+ ((value == null) ? 0 : value.hashCode());
+ }
+
+ @Override public String toString() {
+ return "ReciprocalEntry[" + key + "=" + value + "]";
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Map.Entry)) return false;
+ try {
+ Map.Entry<K,V> e = (Map.Entry<K,V>)o;
+ return safeEquals(key, e.getKey()) && safeEquals(value, e.getValue());
+ } catch (ClassCastException cce) {
+ return false;
+ }
+ }
+
+ private static boolean safeEquals(Object o1, Object o2) {
+ return (o1 == null ? o2 == null : o1.equals(o2));
+ }
+ }
+
+} \ No newline at end of file
diff --git a/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ReciprocalMap.java b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ReciprocalMap.java
new file mode 100644
index 0000000..687d3ed
--- /dev/null
+++ b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ReciprocalMap.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2003, Christian Edward Gruber
+ * Copyright (c) 2003, Israfil Consulting Services Corporation
+ *
+ * This software is licensed under the Berkeley Standard Distribution license,
+ * (BSD license), as defined below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Israfil Consulting Services nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $Id: ReciprocalMap.java 129 2006-12-31 23:20:02Z cgruber $
+ */
+package net.israfil.foundation.collections;
+
+import java.util.Map;
+
+/**
+ * Interface for a two-way map, where each key matches one value and is unique,
+ * and where each value maps to a key, and is unique among all values.
+ *
+ * @author <a href="mailto:cgruber@israfil.net">Christian Edward Gruber</a>
+ */
+public interface ReciprocalMap<K,V> extends Map<K,V> {
+ public boolean contains( K key, V value );
+ public K getKey( V value );
+ public K removeByValue( V value );
+ public V getValue( K key );
+ public V removeByKey( K key );
+}
diff --git a/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/SoloCollection.java b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/SoloCollection.java
new file mode 100644
index 0000000..83a9f66
--- /dev/null
+++ b/israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/SoloCollection.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2006 Israfil Consulting Services Corporation
+ * Copyright (c) 2006 Christian Edward Gruber
+ * All Rights Reserved
+ *
+ * This software is licensed under the Berkeley Standard Distribution license,
+ * (BSD license), as defined below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Israfil Consulting Services nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $Id: ArraySet.java 19 2006-01-30 21:52:52Z cgruber $
+ */
+package net.israfil.foundation.collections;
+
+import java.util.AbstractCollection;
+import java.util.Iterator;
+
+/**
+ * A simple unmodifyable implementation of Collection that takes a single (possibly
+ * null) constructor parameter. The collection then "contains" this single object.
+ *
+ * @author <a href="mailto:cgruber@israfil.net">Christian Edward Gruber </a>
+ */
+//@Copyright(years={"2006"},owner="Israfil Consulting Services Corporation",license="BSD")
+
+public class SoloCollection<E> extends AbstractCollection<E> {
+ protected final E o;
+ public SoloCollection(E o) {
+ super();
+ this.o = o;
+ }
+
+ public Iterator<E> iterator() {
+ return new Iterator<E>() {
+ boolean beforeFirst = true;
+ public boolean hasNext() { return beforeFirst; }
+ public E next() { beforeFirst = false; return o; }
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove from a singleton colelction");
+ }
+ };
+ }
+
+ public int size() { return 1; }
+}