/* * Copyright (C) 2012 The Android Open Source Project * * 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 com.android.mms.util; import java.lang.ref.SoftReference; import java.util.LinkedHashMap; import java.util.Map; /** * A simple cache with the option of using {@link SoftReference SoftReferences} to play well with * the garbage collector and an LRU cache eviction algorithm to limit the number * of {@link SoftReference SoftReferences}. * <p> * The interface of this class is a subset of {@link Map}. * * from Peter Balwin and books app. */ public class SimpleCache<K, V> { /** * A simple LRU cache to prevent the number of {@link Map.Entry} instances * from growing infinitely. */ @SuppressWarnings("serial") private class SoftReferenceMap extends LinkedHashMap<K, SoftReference<V>> { private final int mMaxCapacity; public SoftReferenceMap(int initialCapacity, int maxCapacity, float loadFactor) { super(initialCapacity, loadFactor, true); mMaxCapacity = maxCapacity; } @Override protected boolean removeEldestEntry(Map.Entry<K, SoftReference<V>> eldest) { return size() > mMaxCapacity; } } @SuppressWarnings("serial") private class HardReferenceMap extends LinkedHashMap<K, V> { private final int mMaxCapacity; public HardReferenceMap(int initialCapacity, int maxCapacity, float loadFactor) { super(initialCapacity, loadFactor, true); mMaxCapacity = maxCapacity; } @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > mMaxCapacity; } } private static <V> V unwrap(SoftReference<V> ref) { return ref != null ? ref.get() : null; } private final SoftReferenceMap mSoftReferences; private final HardReferenceMap mHardReferences; /** * Constructor. * * @param initialCapacity the initial capacity for the cache. * @param maxCapacity the maximum capacity for the * cache (this value may be large if soft references are used because * {@link SoftReference SoftReferences} don't consume much memory compared to the * larger data they typically contain). * @param loadFactor the initial load balancing factor for the internal * {@link LinkedHashMap} */ public SimpleCache(int initialCapacity, int maxCapacity, float loadFactor, boolean useHardReferences) { if (useHardReferences) { mSoftReferences = null; mHardReferences = new HardReferenceMap(initialCapacity, maxCapacity, loadFactor); } else { mSoftReferences = new SoftReferenceMap(initialCapacity, maxCapacity, loadFactor); mHardReferences = null; } } /** * See {@link Map#get(Object)}. */ public V get(Object key) { return mSoftReferences != null ? unwrap(mSoftReferences.get(key)) : mHardReferences.get(key); } /** * See {@link Map#put(Object, Object)}. */ public V put(K key, V value) { return mSoftReferences != null ? unwrap(mSoftReferences.put(key, new SoftReference<V>(value))) : mHardReferences.put(key, value); } /** * See {@link Map#clear()}. */ public void clear() { if (mSoftReferences != null) { mSoftReferences.clear(); } else { mHardReferences.clear(); } } /** * See {@link Map#remove(Object)}. */ public V remove(K key) { if (mSoftReferences != null) { return unwrap(mSoftReferences.remove(key)); } else { return mHardReferences.remove(key); } } }