aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo
diff options
context:
space:
mode:
authorBananeweizen <Bananeweizen@gmx.de>2012-04-08 13:29:05 +0200
committerBananeweizen <Bananeweizen@gmx.de>2012-04-08 13:29:05 +0200
commitfd801ec1e37979db07aa64fec318954b37929558 (patch)
tree24271052a444d251d787f74c1c2f90a92a7a102c /main/src/cgeo
parentb00eaf91c9258907bcd6f7897cd690c79ae9a1f0 (diff)
parent5fd86fa6a69fdc3e87cb04b59395e070851de1dd (diff)
downloadcgeo-fd801ec1e37979db07aa64fec318954b37929558.zip
cgeo-fd801ec1e37979db07aa64fec318954b37929558.tar.gz
cgeo-fd801ec1e37979db07aa64fec318954b37929558.tar.bz2
Merge remote-tracking branch 'teschi/issue#1304'
Conflicts: main/src/cgeo/geocaching/maps/CGeoMap.java
Diffstat (limited to 'main/src/cgeo')
-rw-r--r--main/src/cgeo/geocaching/CacheCache.java6
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCBase.java4
-rw-r--r--main/src/cgeo/geocaching/gcvote/GCVote.java5
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java4
-rw-r--r--main/src/cgeo/geocaching/utils/BoundedList.java46
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java24
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java93
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java173
8 files changed, 275 insertions, 80 deletions
diff --git a/main/src/cgeo/geocaching/CacheCache.java b/main/src/cgeo/geocaching/CacheCache.java
index a2b5324..a84f1bd 100644
--- a/main/src/cgeo/geocaching/CacheCache.java
+++ b/main/src/cgeo/geocaching/CacheCache.java
@@ -1,7 +1,7 @@
package cgeo.geocaching;
import cgeo.geocaching.cgData.StorageLocation;
-import cgeo.geocaching.utils.LeastRecentlyUsedCache;
+import cgeo.geocaching.utils.LeastRecentlyUsedMap;
import org.apache.commons.lang3.StringUtils;
@@ -14,12 +14,12 @@ import org.apache.commons.lang3.StringUtils;
public class CacheCache {
private static final int MAX_CACHED_CACHES = 1000;
- final private LeastRecentlyUsedCache<String, cgCache> cachesCache;
+ final private LeastRecentlyUsedMap<String, cgCache> cachesCache;
private static CacheCache instance = null;
private CacheCache() {
- cachesCache = new LeastRecentlyUsedCache<String, cgCache>(MAX_CACHED_CACHES);
+ cachesCache = new LeastRecentlyUsedMap.LruCache<String, cgCache>(MAX_CACHED_CACHES);
}
public static CacheCache getInstance() {
diff --git a/main/src/cgeo/geocaching/connector/gc/GCBase.java b/main/src/cgeo/geocaching/connector/gc/GCBase.java
index 871e75a..d09f9af 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCBase.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCBase.java
@@ -17,7 +17,7 @@ import cgeo.geocaching.network.Login;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.ui.Formatter;
import cgeo.geocaching.utils.BaseUtils;
-import cgeo.geocaching.utils.LeastRecentlyUsedCache;
+import cgeo.geocaching.utils.LeastRecentlyUsedMap;
import cgeo.geocaching.utils.Log;
import org.apache.commons.collections.CollectionUtils;
@@ -180,7 +180,7 @@ public class GCBase {
try {
- final LeastRecentlyUsedCache<String, String> nameCache = new LeastRecentlyUsedCache<String, String>(2000); // JSON id, cache name
+ final LeastRecentlyUsedMap<String, String> nameCache = new LeastRecentlyUsedMap.LruCache<String, String>(2000); // JSON id, cache name
if (StringUtils.isEmpty(data)) {
throw new JSONException("No page given");
diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java
index 2f2f370..eb0320f 100644
--- a/main/src/cgeo/geocaching/gcvote/GCVote.java
+++ b/main/src/cgeo/geocaching/gcvote/GCVote.java
@@ -4,14 +4,13 @@ import cgeo.geocaching.Settings;
import cgeo.geocaching.cgCache;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
-import cgeo.geocaching.utils.LeastRecentlyUsedCache;
+import cgeo.geocaching.utils.LeastRecentlyUsedMap;
import cgeo.geocaching.utils.Log;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -29,7 +28,7 @@ public final class GCVote {
private static final Pattern patternVoteElement = Pattern.compile("<vote ([^>]+)>", Pattern.CASE_INSENSITIVE);
private static final int MAX_CACHED_RATINGS = 1000;
- private static LeastRecentlyUsedCache<String, GCVoteRating> ratingsCache = new LeastRecentlyUsedCache<String, GCVoteRating>(MAX_CACHED_RATINGS);
+ private static LeastRecentlyUsedMap<String, GCVoteRating> ratingsCache = new LeastRecentlyUsedMap.LruCache<String, GCVoteRating>(MAX_CACHED_RATINGS);
/**
* Get user rating for a given guid or geocode. For a guid first the ratings cache is checked
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index e424bcc..f6d3f8f 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -36,8 +36,8 @@ import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OnMapDragListener;
import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl;
import cgeo.geocaching.network.Login;
-import cgeo.geocaching.utils.BoundedList;
import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.LeastRecentlyUsedSet;
import cgeo.geocaching.utils.Log;
import org.apache.commons.collections.CollectionUtils;
@@ -171,7 +171,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
private static Map<Integer, LayerDrawable> overlaysCache = new HashMap<Integer, LayerDrawable>();
private int cachesCnt = 0;
/** List of caches in the viewport */
- private final BoundedList<cgCache> caches = new BoundedList<cgCache>(MAX_CACHES);
+ private final LeastRecentlyUsedSet<cgCache> caches = new LeastRecentlyUsedSet<cgCache>(MAX_CACHES);
// storing for offline
private ProgressDialog waitDialog = null;
private int detailTotal = 0;
diff --git a/main/src/cgeo/geocaching/utils/BoundedList.java b/main/src/cgeo/geocaching/utils/BoundedList.java
deleted file mode 100644
index 3fa1112..0000000
--- a/main/src/cgeo/geocaching/utils/BoundedList.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package cgeo.geocaching.utils;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Base class for a limited list.
- *
- * @author blafoo
- */
-public class BoundedList<T> extends ArrayList<T> {
-
- private static final long serialVersionUID = -5077882607489806620L;
- private final int maxEntries;
-
- public BoundedList(int maxEntries) {
- this.maxEntries = maxEntries;
- }
-
- private void removeElements(int count) {
- for (int i = 0; i < count; i++) {
- this.remove(0);
- }
- }
-
- @Override
- public boolean add(T item) {
- removeElements(this.size() + 1 - maxEntries);
- return super.add(item);
- }
-
- @Override
- public boolean addAll(Collection<? extends T> collection) {
- if (collection.size() > this.size()) {
- this.clear();
- for (T item : collection) {
- this.add(item);
- }
- return false;
- } else {
- removeElements(this.size() + collection.size() - maxEntries);
- return super.addAll(collection);
- }
- }
-
-}
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java
deleted file mode 100644
index 6d18cf5..0000000
--- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package cgeo.geocaching.utils;
-
-import java.util.LinkedHashMap;
-
-/**
- * Base class for a caching cache. Don't mix up with a geocache !
- *
- * @author blafoo
- */
-public class LeastRecentlyUsedCache<K, V> extends LinkedHashMap<K, V> {
-
- private static final long serialVersionUID = -5077882607489806620L;
- private final int maxEntries;
-
- public LeastRecentlyUsedCache(int maxEntries) {
- this.maxEntries = maxEntries;
- }
-
- @Override
- protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
- return size() > maxEntries;
- }
-
-}
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java
new file mode 100644
index 0000000..8a7d23f
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java
@@ -0,0 +1,93 @@
+package cgeo.geocaching.utils;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Base class for caching objects. Don't mix up with a geocache !
+ *
+ * The LeastRecentlyUsedMap is basically a LinkedHashMap which can be configured to have certain modes of operation:
+ * <ul>
+ * <li> LRU_CACHE means that the elements are updated in the LinkedList on every get() access,
+ * so the objects that are dropped are the ones that haven't been used the longest</li>
+ * <li> BOUNDED means that objects are updated only when they are put,
+ * so the objects that are dropped are the ones that haven't been written the longest</li>
+ * </ul>
+ *
+ * @author blafoo
+ * @author Teschi
+ */
+public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> {
+
+ private static enum OperationModes {
+ LRU_CACHE, BOUNDED
+ }
+
+ private static final long serialVersionUID = -5077882607489806620L;
+
+ private final int maxEntries;
+ private final OperationModes opMode;
+
+ // store the HashMap parameters for serialization, as we can't access the originals in the LinkedHashMap
+ final int initialCapacity;
+ final float loadFactor;
+
+ protected LeastRecentlyUsedMap(int maxEntries, int initialCapacity, float loadFactor, OperationModes opMode) {
+ super(initialCapacity, loadFactor, (opMode==OperationModes.LRU_CACHE));
+ this.initialCapacity = initialCapacity;
+ this.loadFactor = loadFactor;
+ this.maxEntries = maxEntries;
+ this.opMode = opMode;
+ }
+
+ protected LeastRecentlyUsedMap(int maxEntries, OperationModes opMode) {
+ this(maxEntries, 16, 0.75f, opMode);
+ }
+
+ @Override
+ public V put(K key, V value) {
+ // in case the underlying Map is not running with accessOrder==true, the map won't notice any changes
+ // of existing keys, so for the normal BOUNDED mode we remove and put the value to get its order updated.
+ if (opMode == OperationModes.BOUNDED && containsKey(key)) {
+ final V oldVal = remove(key);
+ put(key, value);
+ return oldVal;
+ } else {
+ return super.put(key, value);
+ }
+ }
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+ return size() > maxEntries;
+ }
+
+ public int getMaxEntries() {
+ return maxEntries;
+ }
+
+ public static class LruCache<K, V> extends LeastRecentlyUsedMap<K, V> {
+ private static final long serialVersionUID = 9028478916221334454L;
+
+ public LruCache(int maxEntries, int initialCapacity, float loadFactor) {
+ super(maxEntries, initialCapacity, loadFactor, OperationModes.LRU_CACHE);
+ }
+
+ public LruCache(int maxEntries) {
+ super(maxEntries, OperationModes.LRU_CACHE);
+ }
+ }
+
+ public static class Bounded<K, V> extends LeastRecentlyUsedMap<K, V> {
+
+ private static final long serialVersionUID = -1476389304214398315L;
+
+ public Bounded(int maxEntries, int initialCapacity, float loadFactor) {
+ super(maxEntries, initialCapacity, loadFactor, OperationModes.BOUNDED);
+ }
+
+ public Bounded(int maxEntries) {
+ super(maxEntries, OperationModes.BOUNDED);
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
new file mode 100644
index 0000000..72728ec
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
@@ -0,0 +1,173 @@
+package cgeo.geocaching.utils;
+
+import java.util.AbstractSet;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * 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.
+ *
+ * @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()
+ *
+ * @see HashSet
+ */
+ @Override
+ public Iterator<E> iterator() {
+ return map.keySet().iterator();
+ }
+
+ /**
+ * Copy of the HashSet code if size()
+ *
+ * @see HashSet
+ */
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ /**
+ * Copy of the HashSet code if isEmpty()
+ *
+ * @see HashSet
+ */
+ @Override
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /**
+ * Copy of the HashSet code if contains()
+ *
+ * @see HashSet
+ */
+ @Override
+ public boolean contains(Object o) {
+ return map.containsKey(o);
+ }
+
+ /**
+ * Copy of the HashSet code if add()
+ *
+ * @see HashSet
+ */
+ @Override
+ public boolean add(E e) {
+ return map.put(e, PRESENT) == null;
+ }
+
+ /**
+ * Copy of the HashSet code if remove()
+ *
+ * @see HashSet
+ */
+ @Override
+ public boolean remove(Object o) {
+ return map.remove(o) == PRESENT;
+ }
+
+ /**
+ * Copy of the HashSet code if clear()
+ *
+ * @see HashSet
+ */
+ @Override
+ public void clear() {
+ map.clear();
+ }
+
+ /**
+ * Copy of the HashSet code if clone()
+ *
+ * @see HashSet
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object clone() {
+ try {
+ final LeastRecentlyUsedSet<E> newSet = (LeastRecentlyUsedSet<E>) super.clone();
+ newSet.map = (LeastRecentlyUsedMap<E, Object>) map.clone();
+ return newSet;
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+}