aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java')
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java198
1 files changed, 198 insertions, 0 deletions
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
new file mode 100644
index 0000000..eea7a11
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
@@ -0,0 +1,198 @@
+package cgeo.geocaching.utils;
+
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Synchronized set wrapper for the LeastRecentlyUsedMap.
+ *
+ * This code is heavily based on the HashSet code that represent Map as a Set.
+ * Unfortunately HashSet does not allow to use a custom Map as its Storage.
+ * Therefore overriding removeEldestEntry() is impossible for a normal LinkedHashSet.
+ *
+ * Synchronization is added to guard against concurrent modification. Iterator
+ * access has to be guarded externally or the synchronized getAsList method can be used
+ * to get a clone for iteration
+ *
+ * @author Teschi
+ */
+public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
+ implements Cloneable, java.io.Serializable {
+
+ private static final long serialVersionUID = -1942301031191419547L;
+
+ private transient LeastRecentlyUsedMap<E, Object> map;
+ private static final Object PRESENT = new Object();
+
+ public LeastRecentlyUsedSet(int maxEntries, int initialCapacity, float loadFactor) {
+ // because we don't use any Map.get() methods from the Set, BOUNDED and LRU_CACHE have the exact same Behaviour
+ // So we useLRU_CACHE mode because it should perform a bit better (as it doesn't re-add explicitly)
+ map = new LeastRecentlyUsedMap.LruCache<E, Object>(maxEntries, initialCapacity, loadFactor);
+ }
+
+ public LeastRecentlyUsedSet(int maxEntries) {
+ map = new LeastRecentlyUsedMap.LruCache<E, Object>(maxEntries);
+ }
+
+ /**
+ * Copy of the HashSet code if iterator()
+ * Iterator access has to be synchronized externally!
+ *
+ * @see HashSet
+ */
+ @Override
+ public Iterator<E> iterator() {
+ return map.keySet().iterator();
+ }
+
+ /**
+ * Synchronized access to set size
+ * Copy of the HashSet code if size()
+ *
+ * @see HashSet
+ */
+ @Override
+ public synchronized int size() {
+ return map.size();
+ }
+
+ /**
+ * Synchronized check of set emptiness
+ * Copy of the HashSet code if isEmpty()
+ *
+ * @see HashSet
+ */
+ @Override
+ public synchronized boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /**
+ * Synchronized check for containment
+ * Copy of the HashSet code if contains()
+ *
+ * @see HashSet
+ */
+ @Override
+ public synchronized boolean contains(Object o) {
+ return map.containsKey(o);
+ }
+
+ /**
+ * Synchronized addition of an item
+ * Copy of the HashSet code if add()
+ *
+ * @see HashSet
+ */
+ @Override
+ public synchronized boolean add(E e) {
+ return map.put(e, PRESENT) == null;
+ }
+
+ /**
+ * Synchronized removal of a contained item
+ * Copy of the HashSet code if remove()
+ *
+ * @see HashSet
+ */
+ @Override
+ public synchronized boolean remove(Object o) {
+ return map.remove(o) == PRESENT;
+ }
+
+ /**
+ * Synchronized clearing of the set
+ * Copy of the HashSet code if clear()
+ *
+ * @see HashSet
+ */
+ @Override
+ public synchronized void clear() {
+ map.clear();
+ }
+
+ /**
+ * (synchronized) Clone of the set
+ * Copy of the HashSet code if clone()
+ *
+ * @see HashSet
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object clone() {
+ try {
+ synchronized (this) {
+ final LeastRecentlyUsedSet<E> newSet = (LeastRecentlyUsedSet<E>) super.clone();
+ newSet.map = (LeastRecentlyUsedMap<E, Object>) map.clone();
+ return newSet;
+ }
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+ /**
+ * Creates a clone as a list in a synchronized fashion.
+ *
+ * @return List based clone of the set
+ */
+ public synchronized List<E> getAsList() {
+ return new ArrayList<E>(this);
+ }
+
+ /**
+ * Serialization version of HashSet with the additional parameters for the custom Map
+ *
+ * @see HashSet
+ */
+ private void writeObject(java.io.ObjectOutputStream s)
+ throws java.io.IOException {
+ // Write out any hidden serialization magic
+ s.defaultWriteObject();
+
+ // Write out HashMap capacity and load factor
+ s.writeInt(map.initialCapacity);
+ s.writeFloat(map.loadFactor);
+ s.writeInt(map.getMaxEntries());
+
+ // Write out size
+ s.writeInt(map.size());
+
+ // Write out all elements in the proper order.
+ for (final Iterator<E> i = map.keySet().iterator(); i.hasNext();) {
+ s.writeObject(i.next());
+ }
+ }
+
+ /**
+ * Serialization version of HashSet with the additional parameters for the custom Map
+ *
+ * @see HashSet
+ */
+ @SuppressWarnings("unchecked")
+ private void readObject(java.io.ObjectInputStream s)
+ throws java.io.IOException, ClassNotFoundException {
+ // Read in any hidden serialization magic
+ s.defaultReadObject();
+
+ // Read in HashMap capacity and load factor and create backing HashMap
+ final int capacity = s.readInt();
+ final float loadFactor = s.readFloat();
+ final int maxEntries = s.readInt();
+
+ map = new LeastRecentlyUsedMap.LruCache<E, Object>(maxEntries, capacity, loadFactor);
+
+ // Read in size
+ final int size = s.readInt();
+
+ // Read in all elements in the proper order.
+ for (int i = 0; i < size; i++) {
+ E e = (E) s.readObject();
+ map.put(e, PRESENT);
+ }
+ }
+
+}