1721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor/*
2721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor * Copyright (C) 2012 The Android Open Source Project
3721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor *
4721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor * Licensed under the Apache License, Version 2.0 (the "License");
5721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor * you may not use this file except in compliance with the License.
6721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor * You may obtain a copy of the License at
7721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor *
8721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor *      http://www.apache.org/licenses/LICENSE-2.0
9721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor *
10721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor * Unless required by applicable law or agreed to in writing, software
11721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor * distributed under the License is distributed on an "AS IS" BASIS,
12721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor * See the License for the specific language governing permissions and
14721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor * limitations under the License.
15721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor */
1651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
1751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorpackage com.android.mms.util;
1851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
1951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport java.lang.ref.SoftReference;
2051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport java.util.LinkedHashMap;
2151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorimport java.util.Map;
2251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
2351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor/**
24721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor * A simple cache with the option of using {@link SoftReference SoftReferences} to play well with
2551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * the garbage collector and an LRU cache eviction algorithm to limit the number
2651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * of {@link SoftReference SoftReferences}.
2751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * <p>
2851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * The interface of this class is a subset of {@link Map}.
2951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor *
3051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor * from Peter Balwin and books app.
3151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor */
3251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylorpublic class SimpleCache<K, V> {
3351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
3451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    /**
3551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     * A simple LRU cache to prevent the number of {@link Map.Entry} instances
3651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     * from growing infinitely.
3751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     */
3851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    @SuppressWarnings("serial")
3951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    private class SoftReferenceMap extends LinkedHashMap<K, SoftReference<V>> {
4051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
4151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor        private final int mMaxCapacity;
4251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
4351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor        public SoftReferenceMap(int initialCapacity, int maxCapacity, float loadFactor) {
4451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor            super(initialCapacity, loadFactor, true);
4551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor            mMaxCapacity = maxCapacity;
4651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor        }
4751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
4851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor        @Override
4951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor        protected boolean removeEldestEntry(Map.Entry<K, SoftReference<V>> eldest) {
5051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor            return size() > mMaxCapacity;
5151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor        }
5251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    }
5351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
54721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor    @SuppressWarnings("serial")
55721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor    private class HardReferenceMap extends LinkedHashMap<K, V> {
56721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor
57721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        private final int mMaxCapacity;
58721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor
59721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        public HardReferenceMap(int initialCapacity, int maxCapacity, float loadFactor) {
60721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor            super(initialCapacity, loadFactor, true);
61721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor            mMaxCapacity = maxCapacity;
62721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        }
63721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor
64721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        @Override
65721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
66721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor            return size() > mMaxCapacity;
67721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        }
68721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor    }
69721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor
7051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    private static <V> V unwrap(SoftReference<V> ref) {
7151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor        return ref != null ? ref.get() : null;
7251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    }
7351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
74721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor    private final SoftReferenceMap mSoftReferences;
75721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor    private final HardReferenceMap mHardReferences;
7651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
7751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    /**
7851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     * Constructor.
7951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     *
80721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor     * @param initialCapacity the initial capacity for the cache.
81721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor     * @param maxCapacity the maximum capacity for the
82721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor     *            cache (this value may be large if soft references are used because
83721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor     *            {@link SoftReference SoftReferences} don't consume much memory compared to the
8451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     *            larger data they typically contain).
8551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     * @param loadFactor the initial load balancing factor for the internal
8651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     *            {@link LinkedHashMap}
8751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     */
88721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor    public SimpleCache(int initialCapacity, int maxCapacity, float loadFactor,
89721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor            boolean useHardReferences) {
90721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        if (useHardReferences) {
91721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor            mSoftReferences = null;
92721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor            mHardReferences = new HardReferenceMap(initialCapacity, maxCapacity, loadFactor);
93721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        } else {
94721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor            mSoftReferences = new SoftReferenceMap(initialCapacity, maxCapacity, loadFactor);
95721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor            mHardReferences = null;
96721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        }
9751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    }
9851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
9951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    /**
10051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     * See {@link Map#get(Object)}.
10151e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     */
10251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    public V get(Object key) {
103721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        return mSoftReferences != null ? unwrap(mSoftReferences.get(key))
104721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor                : mHardReferences.get(key);
10551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    }
10651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
10751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    /**
10851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     * See {@link Map#put(Object, Object)}.
10951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     */
11051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    public V put(K key, V value) {
111721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        return mSoftReferences != null ?
112721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor                unwrap(mSoftReferences.put(key, new SoftReference<V>(value)))
113721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor                : mHardReferences.put(key, value);
11451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    }
11551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor
11651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    /**
11751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     * See {@link Map#clear()}.
11851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor     */
11951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    public void clear() {
120721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        if (mSoftReferences != null) {
121721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor            mSoftReferences.clear();
122721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        } else {
123721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor            mHardReferences.clear();
124721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor        }
12551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor    }
126b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor
127b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor    /**
128b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor     * See {@link Map#remove(Object)}.
129b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor     */
130b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor    public V remove(K key) {
131b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor        if (mSoftReferences != null) {
132b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor            return unwrap(mSoftReferences.remove(key));
133b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor        } else {
134b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor            return mHardReferences.remove(key);
135b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor        }
136b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor    }
137b8eae066a7ba60722de07300bf990d519f5c81d8Tom Taylor
13851e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor}
139