All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 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 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 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