From 7c279747beb43c7e88633a6228a155a30e6834f7 Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Mon, 27 May 2024 11:38:33 -0400 Subject: Initial import --- .../israfil/foundation/collections/ArraySet.java | 105 +++++++++++ .../israfil/foundation/collections/ArrayUtils.java | 113 ++++++++++++ .../foundation/collections/IterableResultSet.java | 132 ++++++++++++++ .../collections/RandomOrderIterable.java | 72 ++++++++ .../collections/RandomOrderIterator.java | 94 ++++++++++ .../foundation/collections/ReciprocalHashMap.java | 202 +++++++++++++++++++++ .../foundation/collections/ReciprocalMap.java | 49 +++++ .../foundation/collections/SoloCollection.java | 66 +++++++ 8 files changed, 833 insertions(+) create mode 100644 israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ArraySet.java create mode 100644 israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ArrayUtils.java create mode 100644 israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/IterableResultSet.java create mode 100644 israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/RandomOrderIterable.java create mode 100644 israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/RandomOrderIterator.java create mode 100644 israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ReciprocalHashMap.java create mode 100644 israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/ReciprocalMap.java create mode 100644 israfil-foundation-collections/src/main/java/net/israfil/foundation/collections/SoloCollection.java (limited to 'israfil-foundation-collections/src/main/java') 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 Christian Edward Gruber + */ +public class ArraySet extends AbstractSet { + + private transient ArrayList internalList; + + public ArraySet() { + internalList = new ArrayList(); + } + + public ArraySet(int initialCapacity) { + internalList = new ArrayList(initialCapacity); + } + + public ArraySet(Collection col) { + internalList = new ArrayList(col); + Iterator i = col.iterator(); + while (i.hasNext()) { + internalList.add(i.next()); + } + } + + @Override + public Iterator 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 Christian Edward Gruber + */ +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. + *
+     *   public class Foo {
+     *       public T[] getArray() {
+     *   		T[] array = new T[a];
+     * 	     }
+     *   }
+     * 
+ * + * 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[] aggregate(E[] resultBucket, E[] ... arrays) + { + logger.log(Level.FINER,Array.newInstance(arrays.getClass().getComponentType(),0).getClass().getCanonicalName()); + List resultList = new ArrayList(); + 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 Christian Edward Gruber + */ +public class IterableResultSet implements Iterable> { + + protected static final Map iterables = new WeakHashMap(); + protected final WeakReference 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(result); + } + + public Iterator> 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> { + 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 next() { + try { + Map row = new HashMap(); + 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 Christian Edward Gruber + */ +public class RandomOrderIterable implements Iterable { + + private Collection _collection; + private Random _random = null; + + public RandomOrderIterable(Collection collection) { + _collection = collection; + } + + public RandomOrderIterable(Collection collection, Random random) { + this(collection); + _random = random; + } + + public Iterator iterator() { + return new RandomOrderIterator(_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 Christian Edward Gruber + */ +public class RandomOrderIterator implements Iterator { + + private transient List _collection; + + private transient Random _random = new SecureRandom(); + + private transient List _indexes; + + + public RandomOrderIterator(Collection collection) { + _collection = new ArrayList(collection); + _indexes = new LinkedList(); + for (int i = 0; i < _collection.size();i++) { + _indexes.add(i); // populate index source. + } + } + + public RandomOrderIterator(Collection 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 Christian Edward Gruber + * + */ +public class ReciprocalHashMap extends java.util.AbstractMap + implements ReciprocalMap { + + Set> entrySetByKey = new HashSet>(); + Set> entrySetByValue = new HashSet>(); + + @Override + public Set> entrySet() { + return entrySetByKey; + } + + public Set> 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 getEntryByValue(V value) { + Iterator> i = entrySetByValue().iterator(); + if (value==null) { + while (i.hasNext()) { + Entry e = i.next(); + if (e.getKey()==null) return e; + } + } else { + while (i.hasNext()) { + Entry e = i.next(); + if (value.equals(e.getKey())) return e; + } + } + return null; + } + public Entry getEntryByKey(K value) { + Iterator> i = entrySet().iterator(); + if (value==null) { + while (i.hasNext()) { + Entry e = i.next(); + if (e.getKey()==null) return e; + } + } else { + while (i.hasNext()) { + Entry e = i.next(); + if (value.equals(e.getKey())) return e; + } + } + return null; + } + + public K getKey(V value) { + Entry e = getEntryByValue(value); + return (e == null) ? null : e.getValue(); + } + + public V getValue(K key) { + Entry e = getEntryByKey(key); + return (e == null) ? null : e.getValue(); + } + + public K removeByValue(V value) { + Entry valEntry = getEntryByValue(value); + Entry 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 keyEntry = getEntryByKey(key); + Entry 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 keyEntry = getEntryByKey(key); + Entry valueEntry = getEntryByValue(value); + + V oldValue = null; + + if (keyEntry != null) { + Entry inverseKeyEntry = getEntryByValue(keyEntry.getValue()); + keyEntry.getKey(); + entrySetByKey.remove(keyEntry); + entrySetByValue.remove(inverseKeyEntry); + } + if (valueEntry != null) { + Entry inverseValueEntry = getEntryByKey(valueEntry.getValue()); + oldValue = valueEntry.getKey(); + entrySetByValue.remove(valueEntry); + entrySetByKey.remove(inverseValueEntry); + } + entrySetByKey.add(new ReciprocalEntry(key,value)); + entrySetByValue.add(new ReciprocalEntry(value,key)); + + return oldValue; + } + + static class ReciprocalEntry implements Entry { + 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 e = (Map.Entry)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 Christian Edward Gruber + */ +public interface ReciprocalMap extends Map { + 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 Christian Edward Gruber + */ +//@Copyright(years={"2006"},owner="Israfil Consulting Services Corporation",license="BSD") + +public class SoloCollection extends AbstractCollection { + protected final E o; + public SoloCollection(E o) { + super(); + this.o = o; + } + + public Iterator iterator() { + return new Iterator() { + 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; } +} -- cgit v1.2.3