/******************************************************************************* * Copyright (c) 2004, 2007 IBM Corporation and Cambridge Semantics Incorporated. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * File: $Source: /cvsroot/slrp/common/com.ibm.adtech.java.util/src/com/ibm/adtech/java/util/Collections.java,v $ * Created by: Lee Feigenbaum ( <a href="mailto:feigenbl@us.ibm.com">feigenbl@us.ibm.com </a>) * Created on: 10/23/2006 * Revision: $Id: Collections.java 167 2007-07-31 14:11:13Z mroy $ * * Contributors: IBM Corporation - initial API and implementation * Cambridge Semantics Incorporated - Fork to Anzo *******************************************************************************/ package org.openanzo.rdf.utils; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.openanzo.rdf.URI; /** * Set of collection utilities * * @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com </a>) * */ public class Collections { /** * Create the cartesian product for a collection of collections * * @param collections * the list of collections whose cartesian product is being determined. * @param <T> * Type of objects in collection * @return a set of collections each of which is an element in the cartesian product of the given collections */ static final public <T> Set<Collection<T>> cartesianProduct(List<Collection<T>> collections) { List<Iterator<T>> iterators = new ArrayList<Iterator<T>>(); for (Collection<T> c : collections) iterators.add(c.iterator()); HashSet<Collection<T>> product = new HashSet<Collection<T>>(); ArrayList<T> tuple = new ArrayList<T>(); // initialize the tuple with the first element from every iterator for (Iterator<T> it : iterators) { if (!it.hasNext()) return product; tuple.add(it.next()); } boolean hadNext; do { hadNext = false; product.add(new ArrayList<T>(tuple)); for (int i = 0; i < iterators.size(); i++) { Iterator<T> it = iterators.get(i); if (it.hasNext()) { tuple.set(i, it.next()); hadNext = true; break; } // reset this iterator it = collections.get(i).iterator(); iterators.set(i, it); // get the first item from this iterator tuple.set(i, it.next()); // we let the for-loop keep going so that the next iterator will get incremented // since we're rolling forward } } while (hadNext); return product; } /** * Add all the elements of an iterable into a colleciton * * @param <E> * type to add * @param source * source of elements * @param destination * destination of elements */ static final public <E> void addAll(Iterable<E> source, Collection<E> destination) { for (E e : source) { destination.add(e); } } /** * Convert an iterable to a collection * * @param <E> * type of collection * @param source * source of elements * @return destination collection */ static final public <E> Collection<E> toList(Iterable<E> source) { java.util.ArrayList<E> list = new java.util.ArrayList<E>(); addAll(source, list); return list; } /** * Add the source elements to the destination collection * * @param source * source elements * @param destination * destination of elements * @param <T> * type of elements */ public final static <T> void addAllIfNotNull(Collection<T> source, Collection<T> destination) { if (source != null) { destination.addAll(source); } } /** * Add the source elements to the destination collection * * @param source * source elements * @param destination * destination of elements * @param <T> * type of elements */ public final static <T> void addAllArrayIfNotNull(T[] source, Collection<T> destination) { if (source != null) { for (T t : source) { destination.add(t); } } } /** * Add source elements to the destination if it doesn't already contain the element * * @param <T> * type of elements * @param source * source of elements * @param destination * destination collection */ public final static <T> void addAllUnique(Collection<T> source, Collection<T> destination) { if (source != null) { for (T element : source) { if (!destination.contains(element)) { destination.add(element); } } } } /** * Copy the contents of a collection to a new collection. This tries to use efficient clone if possible. * * @param <T> * type of objects in collection * @param source * source elements * @return copy of original. */ @SuppressWarnings("unchecked") public final static <T> Collection<T> copyCollection(Collection<T> source) { if (source instanceof HashSet) { return (Collection<T>) ((HashSet<T>) source).clone(); } else if (source instanceof ArrayList) { return (Collection<T>) ((ArrayList<T>) source).clone(); } else { return new ArrayList<T>(source); } } /** * Copy the contents of a collection to a new collection. This tries to use efficient clone if possible. * * @param <T> * type of objects in collection * @param source * source elements * @return copy of original. */ @SuppressWarnings("unchecked") public final static <T> Set<T> copySet(Set<T> source) { if (source instanceof HashSet) { return (Set<T>) ((HashSet<T>) source).clone(); } else { return new HashSet<T>(source); } } /** * @param <T> * Type of elements in set * @param source * source array of elements * @return Set containing source elements */ public final static <T> Set<T> asSet(T[] source) { if (source == null) { return java.util.Collections.<T> emptySet(); } else { Set<T> set = new HashSet<T>(source.length); for (T t : source) { set.add(t); } return set; } } /** * Given 2 sets of URIs, determine of any of the member URIs are within the group URIs * * @param group * Set of URIs which membership is being determined * @param members * Set of URIs which to find membership of group * @return true if at least 1 member is within the group */ public static boolean memberOf(Set<URI> group, Set<URI> members) { if (members == null || members.size() == 0 || group == null || group.size() == 0) return false; for (URI member : members) { if (group.contains(member)) return true; } return false; } /** * A thread-safe variant of {@link Map} in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying map. * <p> * This is ordinarily too costly, but may be <em>more</em> efficient than alternatives when traversal operations vastly out-number mutations, and is useful * when you cannot or don't want to synchronise traversals, yet need to preclude interference among concurrent threads. The "snapshot" style iterators on * the collections returned by {@link #entrySet()}, {@link #keySet()} and {@link #values()} use a reference to the internal map at the point that the * iterator was created. This array never changes during the lifetime of the iterator, so interference is impossible and the iterator is guaranteed not to * throw <tt>ConcurrentModificationException</tt>. The iterators will not reflect additions, removals, or changes to the list since the iterator was * created. Element-changing operations on iterators and collections themselves (remove, set, and add) are not supported. These methods throw * {@link UnsupportedOperationException}. * <p> * The actual copy is performed by a supplied {@link CopyFunction} object. The Factory is responsible for the underlying Map implementation (for instance a * HashMap, TreeMap, ListOrderedMap etc.) and therefore the semantics of what this map will cope with as far as null keys and values, iteration ordering * etc. * <p> * There are supplied {@link Functions} for the common Collections {@link Map} implementations. */ static public class CopyOnWriteMap<K, V> implements Map<K, V> { private volatile Map<K, V> delegate; private final CopyFunction<K, V> factory; /** * Create a new CopyOnWriteMap with the supplied Map to initialise the values and the Factory for creating our actual delegate instances. * * @param map * @param factory */ public CopyOnWriteMap(Map<K, V> map, CopyFunction<K, V> factory) { this.delegate = factory.copy(map); this.factory = factory; } public CopyOnWriteMap(CopyFunction<K, V> factory) { this(java.util.Collections.<K, V> emptyMap(), factory); } public Map<K, V> currentInstance() { return delegate; } // ---------------------------------------------------------------------------------------------- // mutable operations public synchronized void clear() { Map<K, V> map = factory.copy(delegate); map.clear(); delegate = map; } public synchronized V remove(Object key) { Map<K, V> map = factory.copy(delegate); V result = map.remove(key); delegate = map; return result; } public synchronized V put(K key, V value) { Map<K, V> map = factory.copy(delegate); V result = map.put(key, value); delegate = map; return result; } public synchronized void putAll(Map<? extends K, ? extends V> t) { Map<K, V> map = factory.copy(delegate); map.putAll(t); delegate = map; } // ------------------------------------------------------------------------------------------ // unmodifiable set views public Set<Map.Entry<K, V>> entrySet() { return java.util.Collections.unmodifiableSet(delegate.entrySet()); } public Set<K> keySet() { return java.util.Collections.unmodifiableSet(delegate.keySet()); } public Collection<V> values() { return java.util.Collections.unmodifiableCollection(delegate.values()); } // ---------------------------------------------------------------------------------------- // simple immutable getters public boolean containsKey(Object key) { return delegate.containsKey(key); } public boolean containsValue(Object value) { return delegate.containsValue(value); } public V get(Object key) { return delegate.get(key); } public boolean isEmpty() { return delegate.isEmpty(); } public int size() { return delegate.size(); } @Override public boolean equals(Object o) { return delegate.equals(o); } @Override public int hashCode() { return delegate.hashCode(); } /* * not on the Map interface, but delegate to the internal map anyway as * AbstractMap provides a handy toString() */ @Override public String toString() { return delegate.toString(); } } /** * Copy the current map. Always done under a lock so we don't get multiple threads doing this concurrently. */ public static interface CopyFunction<K, V> { /** * Create a new map copied from the one supplied. Implementations should not keep a reference to this map, and must not modify the map after it has been * returned. This will be called under synchronisation, so it should not do any IO or blocking operations. * * @param map * the map to copy. Will not be null. * @return a new copied map. Must not be null. */ Map<K, V> copy(Map<K, V> map); } /** * Factories that create the standard Collections {@link Map} implementations. */ public static final class Functions { public static <K, V> CopyFunction<K, V> hash() { return new CopyFunction<K, V>() { public Map<K, V> copy(Map<K, V> map) { return new HashMap<K, V>(map); } }; } public static <K, V> CopyFunction<K, V> tree() { return new CopyFunction<K, V>() { public Map<K, V> copy(Map<K, V> map) { return new TreeMap<K, V>(map); } }; } } }