/* Copyright 2009 Ben Gunter * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.sourceforge.stripes.util; import java.util.Collection; import java.util.Iterator; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * A set based on {@link ConcurrentHashMap}. The Javadoc for the constructors in this class were * copied from the Java 1.5 Javadoc for {@link ConcurrentHashMap} and changed to reflect that this * is a Set and not a Map. See the Javadoc for {@link ConcurrentHashMap} for information on * performance characteristics, etc. * * @author Ben Gunter */ public class ConcurrentHashSet<T> implements Set<T> { /** The value object that will be put in the map since it does not accept null values. */ private static final Object VALUE = new Object(); /** The map that backs this set. */ private ConcurrentMap<T, Object> map; /** * Creates a new, empty map with a default initial capacity, load factor, and concurrencyLevel. */ public ConcurrentHashSet() { map = new ConcurrentHashMap<T, Object>(); } /** * Creates a new, empty map with the specified initial capacity, and with default load factor * and concurrencyLevel. * * @param initialCapacity the initial capacity. The implementation performs internal sizing to * accommodate this many elements. * @throws IllegalArgumentException if the initial capacity of elements is negative. */ public ConcurrentHashSet(int initialCapacity) { map = new ConcurrentHashMap<T, Object>(initialCapacity); } /** * Creates a new, empty map with the specified initial capacity, load factor, and concurrency * level. * * @param initialCapacity the initial capacity. The implementation performs internal sizing to * accommodate this many elements. * @param loadFactor the load factor threshold, used to control resizing. Resizing may be * performed when the average number of elements per bin exceeds this threshold. * @param concurrencyLevel - the estimated number of concurrently updating threads. The * implementation performs internal sizing to try to accommodate this many threads. * @throws IllegalArgumentException if the initial capacity is negative or the load factor or * concurrencyLevel are nonpositive. */ public ConcurrentHashSet(int initialCapacity, float loadFactor, int concurrencyLevel) { map = new ConcurrentHashMap<T, Object>(initialCapacity, loadFactor, concurrencyLevel); } /** * Creates a new set with the same elements as the given set. The set is created with a capacity * of twice the number of elements in the given set or 11 (whichever is greater), and a default * load factor and concurrencyLevel. * * @param set The set */ public ConcurrentHashSet(Set<? extends T> set) { this(Math.max(set.size() * 2, 11)); addAll(set); } public boolean add(T e) { return map.putIfAbsent(e, VALUE) == null; } public boolean addAll(Collection<? extends T> c) { boolean b = false; for (T t : c) { b = b || map.putIfAbsent(t, VALUE) == null; } return b; } public void clear() { map.clear(); } public boolean contains(Object o) { return map.keySet().contains(o); } public boolean containsAll(Collection<?> c) { return map.keySet().containsAll(c); } public boolean isEmpty() { return map.isEmpty(); } public Iterator<T> iterator() { return map.keySet().iterator(); } public boolean remove(Object o) { return map.remove(o) != null; } public boolean removeAll(Collection<?> c) { return map.keySet().removeAll(c); } public boolean retainAll(Collection<?> c) { return map.keySet().retainAll(c); } public int size() { return map.size(); } public Object[] toArray() { return map.keySet().toArray(); } public <E> E[] toArray(E[] a) { return map.keySet().toArray(a); } }