diff options
author | Bananeweizen <Bananeweizen@gmx.de> | 2012-04-08 13:29:05 +0200 |
---|---|---|
committer | Bananeweizen <Bananeweizen@gmx.de> | 2012-04-08 13:29:05 +0200 |
commit | fd801ec1e37979db07aa64fec318954b37929558 (patch) | |
tree | 24271052a444d251d787f74c1c2f90a92a7a102c /main/src/cgeo | |
parent | b00eaf91c9258907bcd6f7897cd690c79ae9a1f0 (diff) | |
parent | 5fd86fa6a69fdc3e87cb04b59395e070851de1dd (diff) | |
download | cgeo-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.java | 6 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/connector/gc/GCBase.java | 4 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/gcvote/GCVote.java | 5 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/maps/CGeoMap.java | 4 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/utils/BoundedList.java | 46 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java | 24 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java | 93 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java | 173 |
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); + } + } + +} |