org.semanticweb.owlapi.util.CollectionFactory Maven / Gradle / Ivy
The newest version!
/*
* This file is part of the OWL API.
*
* The contents of this file are subject to the LGPL License, Version 3.0.
*
* Copyright (C) 2011, The University of Manchester
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If
* not, see http://www.gnu.org/licenses/.
*
*
* Alternatively, the contents of this file may be used under the terms of the Apache License,
* Version 2.0 in which case, the provisions of the Apache License Version 2.0 are applicable
* instead of those above.
*
* Copyright 2011, University of Manchester
*
* 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 org.semanticweb.owlapi.util;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
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.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/** Author: Matthew Horridge
* The University Of Manchester
* Bio-Health Informatics Group
* Date: 10-Jan-2007
*
*/
public class CollectionFactory {
private static final AtomicInteger expectedThreads = new AtomicInteger(8);
/** @param value
* the number of expected threads that will access threadsafe
* collections; useful for increasing the concurrency in
* ConcurrentHashMaps */
public static void setExpectedThreads(int value) {
expectedThreads.set(value);
}
/** @return The current number of expected threads. */
public static int getExpectedThreads() {
return expectedThreads.get();
}
/** @return fresh non threadsafe set */
public static Set createSet() {
// TODO large number of sets stay very small, wasting space
return new HashSet();
}
/** @return fresh non threadsafe list */
public static List createList() {
return new CopyOnWriteArrayList();
}
/** @param c
* values to add to the set
* @return fresh non threadsafe set */
public static Set createSet(Collection c) {
return new HashSet(c);
}
/** @param initialCapacity
* initial capacity for the new set
* @return fresh non threadsafe set */
public static Set createSet(int initialCapacity) {
return new HashSet(initialCapacity);
}
/** @return fresh map */
public static Map createMap() {
return new HashMap();
}
/** @return a new weak hashmap wrapped as a synchronized map */
public static Map> createSyncWeakMap() {
return Collections.synchronizedMap(new WeakHashMap>());
}
/** @param elements
* values to add to the set
* @return fresh non threadsafe set */
public static Set createSet(T... elements) {
Set result = createSet();
for (T t : elements) {
result.add(t);
}
return result;
}
/** @return fresh threadsafe set */
public static Set createSyncSet() {
ConcurrentHashMap internalMap = createSyncMap();
return Collections.newSetFromMap(internalMap);
}
/** @return fresh threadsafe hashmap */
public static ConcurrentHashMap createSyncMap() {
return new ConcurrentHashMap(16, 0.75F, expectedThreads.get());
}
/** this class implements a Set using a ConcurrentHashMap as backing
* structure; compared to the default HashSet implementation, this structure
* is threadsafe without being completely synchronized, so it offers better
* performances */
private static final class SyncSet implements Set {
private final ConcurrentHashMap> backingMap;
public SyncSet(ConcurrentHashMap> map) {
backingMap = map;
}
public SyncSet() {
this(new ConcurrentHashMap>());
}
public SyncSet(Collection delegate) {
this();
for (T d : delegate) {
add(d);
}
}
@Override
public boolean add(T e) {
return backingMap.put(e, this) == null;
}
@Override
public boolean addAll(Collection extends T> c) {
boolean toReturn = false;
for (T o : c) {
toReturn = toReturn || add(o);
}
return toReturn;
}
@Override
public void clear() {
backingMap.clear();
}
@Override
public boolean contains(Object o) {
return backingMap.containsKey(o);
}
@Override
public boolean containsAll(Collection> c) {
boolean toReturn = true;
for (Object o : c) {
toReturn = toReturn && contains(o);
if (!toReturn) {
return toReturn;
}
}
return toReturn;
}
@Override
public boolean isEmpty() {
return backingMap.isEmpty();
}
@Override
public Iterator iterator() {
return backingMap.keySet().iterator();
}
@Override
public int size() {
return backingMap.size();
}
@Override
public boolean remove(Object o) {
return backingMap.remove(o) != null;
}
@Override
public boolean removeAll(Collection> c) {
boolean toReturn = false;
for (Object o : c) {
toReturn = toReturn || remove(o);
}
return toReturn;
}
@Override
public boolean retainAll(Collection> c) {
boolean toReturn = false;
for (Map.Entry> e : backingMap.entrySet()) {
if (!c.contains(e.getKey())) {
toReturn = true;
backingMap.remove(e.getKey());
}
}
return toReturn;
}
@Override
public Object[] toArray() {
return backingMap.keySet().toArray();
}
@Override
public Type[] toArray(Type[] a) {
return backingMap.keySet().toArray(a);
}
@SuppressWarnings("rawtypes")
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (obj instanceof SyncSet) {
return this.backingMap.keySet().equals(
((SyncSet) obj).backingMap.keySet());
}
if (obj instanceof Collection) {
return new HashSet(this).equals(obj);
}
return false;
}
@Override
public int hashCode() {
return backingMap.hashCode();
}
}
/** @param source
* the collection to lazily copy
* @return a lazy defensive copy for source; the source collection will not
* be copied until a method that modifies the collection gets
* called, e.g., add(), addAll() */
public static Set getCopyOnRequestSet(Collection source) {
return getCopyOnRequestSetFromMutableCollection(source);
}
/** @param source
* @return copy on request that builds a list from the input set */
public static Set
getCopyOnRequestSetFromMutableCollection(Collection source) {
if (source == null || source.isEmpty()) {
return Collections.emptySet();
}
return new ConditionalCopySet(source, true);
}
/** @param source
* @return copy on request that does not build a list immediately */
public static Set getCopyOnRequestSetFromImmutableCollection(
Collection source) {
if (source == null || source.isEmpty()) {
return Collections.emptySet();
}
return new ConditionalCopySet(source, false);
}
/** @param source
* initial values
* @return a threadsafe copy on request set */
public static Set getThreadSafeCopyOnRequestSet(Set source) {
return new ThreadSafeConditionalCopySet(source);
}
/** a set implementation that uses a delegate collection for all read-only
* operations and makes a copy if changes are attempted. Useful for cheap
* defensive copies: no costly rehashing on the original collection is made
* unless changes are attempted. Changes are not mirrored back to the
* original collection, although changes to the original set BEFORE changes
* to the copy are reflected in the copy. If the source collection is not
* supposed to change, then this collection behaves just like a regular
* defensive copy; if the source collection can change, then this collection
* should be built from a cheap copy of the original collection. For
* example, if the source collection is a set, it can be copied into a list;
* the cost of the copy operation from set to list is approximately 1/3 of
* the cost of copying into a new HashSet. This is not efficient if the most
* common operations performed on the copy are contains() or containsAll(),
* since they are more expensive for lists wrt sets; a counter for these
* calls is maintained by the collection, so if a large number of
* contains/containsAll calls takes place, the delegate is turned into a
* regular set. This implementation is not threadsafe even if the source set
* is: there is no lock during the copy, and the new set is not threadsafe.
*
* @param
* the type contained */
public static class ConditionalCopySet implements Set {
private boolean copyDone = false;
protected Collection delegate;
private final static int maxContains = 10;
private int containsCounter = 0;
/** @param source
* initial elements
* @param listCopy
* true if a copy must be made */
public ConditionalCopySet(Collection source, boolean listCopy) {
if (listCopy) {
this.delegate = new ArrayList(source);
} else {
this.delegate = source;
}
}
@SuppressWarnings("rawtypes")
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (obj instanceof ConditionalCopySet) {
return delegate.containsAll(((ConditionalCopySet) obj).delegate)
&& ((ConditionalCopySet>) obj).delegate.containsAll(delegate);
}
if (obj instanceof Collection) {
return delegate.containsAll((Collection>) obj)
&& ((Collection>) obj).containsAll(delegate);
}
return false;
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public String toString() {
return delegate.toString();
}
@Override
public boolean add(T arg0) {
if (!copyDone) {
copyDone = true;
delegate = new HashSet(delegate);
}
return delegate.add(arg0);
}
@Override
public boolean addAll(Collection extends T> arg0) {
if (!copyDone) {
copyDone = true;
delegate = new HashSet(delegate);
}
return delegate.addAll(arg0);
}
@Override
public void clear() {
if (!copyDone) {
copyDone = true;
delegate = new HashSet();
}
delegate.clear();
}
@Override
public boolean contains(Object arg0) {
containsCounter++;
if (containsCounter >= maxContains && !copyDone) {
// many calls to contains, inefficient if the delegate is not a
// set
if (!(delegate instanceof Set)) {
copyDone = true;
delegate = new HashSet(delegate);
}
}
return delegate.contains(arg0);
}
@Override
public boolean containsAll(Collection> arg0) {
containsCounter++;
if (containsCounter >= maxContains && !copyDone) {
// many calls to contains, inefficient if the delegate is not a
// set
if (!(delegate instanceof Set)) {
copyDone = true;
delegate = new HashSet(delegate);
}
}
return delegate.containsAll(arg0);
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public Iterator iterator() {
return delegate.iterator();
}
@Override
public boolean remove(Object arg0) {
if (!copyDone) {
copyDone = true;
delegate = new HashSet(delegate);
}
return delegate.remove(arg0);
}
@Override
public boolean removeAll(Collection> arg0) {
if (!copyDone) {
copyDone = true;
delegate = new HashSet(delegate);
}
return delegate.removeAll(arg0);
}
@Override
public boolean retainAll(Collection> arg0) {
if (!copyDone) {
copyDone = true;
delegate = new HashSet(delegate);
}
return delegate.retainAll(arg0);
}
@Override
public int size() {
return delegate.size();
}
@Override
public Object[] toArray() {
return delegate.toArray();
}
@Override
public Type[] toArray(Type[] arg0) {
return delegate.toArray(arg0);
}
}
/** this class behaves like ConditionalCopySet except it is designed to be
* threadsafe; multiple thread access is regulated by a readwritelock;
* modifications will create a copy based on SyncSet.
*
* @param
* the type contained */
public static class ThreadSafeConditionalCopySet implements Set {
private volatile boolean copyDone = false;
private Collection delegate;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
private final static int maxContains = 10;
private final AtomicInteger containsCounter = new AtomicInteger(0);
/** @param source
* initial values */
public ThreadSafeConditionalCopySet(Collection source) {
this.delegate = new ArrayList(source);
}
@Override
public boolean equals(Object obj) {
try {
readLock.lock();
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (obj instanceof ConditionalCopySet) {
return delegate.equals(((ConditionalCopySet>) obj).delegate);
}
if (obj instanceof Set) {
return delegate.equals(obj);
}
return false;
} finally {
readLock.unlock();
}
}
@Override
public int hashCode() {
try {
readLock.lock();
return delegate.hashCode();
} finally {
readLock.unlock();
}
}
@Override
public boolean add(T arg0) {
try {
writeLock.lock();
if (!copyDone) {
copyDone = true;
delegate = new SyncSet(delegate);
}
return delegate.add(arg0);
} finally {
writeLock.unlock();
}
}
@Override
public boolean addAll(Collection extends T> arg0) {
try {
writeLock.lock();
if (!copyDone) {
copyDone = true;
delegate = new SyncSet(delegate);
}
return delegate.addAll(arg0);
} finally {
writeLock.unlock();
}
}
@Override
public void clear() {
try {
writeLock.lock();
if (!copyDone) {
copyDone = true;
delegate = new SyncSet();
}
delegate.clear();
} finally {
writeLock.unlock();
}
}
@Override
public boolean contains(Object arg0) {
/*
* note: the check on the number of contains and on the copyDone
* flag is intentionally not made inside a lock; these operations
* will not stop other threads from accessing the collection, and
* the lack of synchronization means that a few contains/containsAll
* calls might not be recorded; the result is that the copy
* optimization would be delayed. This is not an issue, since
* maxContains is only a rough estimate.
*/
if (!copyDone) {
if (containsCounter.incrementAndGet() >= maxContains && !copyDone) {
try {
writeLock.lock();
// many calls to contains, inefficient if the delegate
// is not a set
// copyDone is doublechecked, but here it's protected by
// the write
// lock as in all other instances in which its value is
// changed
if (!copyDone && !(delegate instanceof Set)) {
copyDone = true;
delegate = new SyncSet(delegate);
}
// skip the second portion of the method: no need to
// reacquire
// the lock, it's already a write lock
return delegate.contains(arg0);
} finally {
writeLock.unlock();
}
}
}
try {
readLock.lock();
return delegate.contains(arg0);
} finally {
readLock.unlock();
}
}
@Override
public boolean containsAll(Collection> arg0) {
if (!copyDone) {
if (containsCounter.incrementAndGet() >= maxContains && !copyDone) {
try {
writeLock.lock();
// many calls to contains, inefficient if the delegate
// is not a set
// copyDone is doublechecked, but here it's protected by
// the write
// lock as in all other instances in which its value is
// changed
if (!copyDone && !(delegate instanceof Set)) {
copyDone = true;
delegate = new SyncSet(delegate);
}
// skip the second portion of the method: no need to
// reacquire
// the lock, it's already a write lock
return delegate.containsAll(arg0);
} finally {
writeLock.unlock();
}
}
}
try {
readLock.lock();
return delegate.containsAll(arg0);
} finally {
readLock.unlock();
}
}
@Override
public boolean isEmpty() {
try {
readLock.lock();
return delegate.isEmpty();
} finally {
readLock.unlock();
}
}
@Override
public Iterator iterator() {
try {
readLock.lock();
return delegate.iterator();
} finally {
readLock.unlock();
}
}
@Override
public boolean remove(Object arg0) {
try {
writeLock.lock();
if (!copyDone) {
copyDone = true;
delegate = new SyncSet(delegate);
}
return delegate.remove(arg0);
} finally {
writeLock.unlock();
}
}
@Override
public boolean removeAll(Collection> arg0) {
try {
writeLock.lock();
if (!copyDone) {
copyDone = true;
delegate = new SyncSet(delegate);
}
return delegate.removeAll(arg0);
} finally {
writeLock.unlock();
}
}
@Override
public boolean retainAll(Collection> arg0) {
try {
writeLock.lock();
if (!copyDone) {
copyDone = true;
delegate = new SyncSet(delegate);
}
return delegate.retainAll(arg0);
} finally {
writeLock.unlock();
}
}
@Override
public int size() {
try {
readLock.lock();
return delegate.size();
} finally {
readLock.unlock();
}
}
@Override
public Object[] toArray() {
try {
readLock.lock();
return delegate.toArray();
} finally {
readLock.unlock();
}
}
@Override
public Type[] toArray(Type[] arg0) {
try {
readLock.lock();
return delegate.toArray(arg0);
} finally {
readLock.unlock();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy