Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.mms.util;
     18 
     19 import java.lang.ref.SoftReference;
     20 import java.util.LinkedHashMap;
     21 import java.util.Map;
     22 
     23 /**
     24  * A simple cache with the option of using {@link SoftReference SoftReferences} to play well with
     25  * the garbage collector and an LRU cache eviction algorithm to limit the number
     26  * of {@link SoftReference SoftReferences}.
     27  * <p>
     28  * The interface of this class is a subset of {@link Map}.
     29  *
     30  * from Peter Balwin and books app.
     31  */
     32 public class SimpleCache<K, V> {
     33 
     34     /**
     35      * A simple LRU cache to prevent the number of {@link Map.Entry} instances
     36      * from growing infinitely.
     37      */
     38     @SuppressWarnings("serial")
     39     private class SoftReferenceMap extends LinkedHashMap<K, SoftReference<V>> {
     40 
     41         private final int mMaxCapacity;
     42 
     43         public SoftReferenceMap(int initialCapacity, int maxCapacity, float loadFactor) {
     44             super(initialCapacity, loadFactor, true);
     45             mMaxCapacity = maxCapacity;
     46         }
     47 
     48         @Override
     49         protected boolean removeEldestEntry(Map.Entry<K, SoftReference<V>> eldest) {
     50             return size() > mMaxCapacity;
     51         }
     52     }
     53 
     54     @SuppressWarnings("serial")
     55     private class HardReferenceMap extends LinkedHashMap<K, V> {
     56 
     57         private final int mMaxCapacity;
     58 
     59         public HardReferenceMap(int initialCapacity, int maxCapacity, float loadFactor) {
     60             super(initialCapacity, loadFactor, true);
     61             mMaxCapacity = maxCapacity;
     62         }
     63 
     64         @Override
     65         protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
     66             return size() > mMaxCapacity;
     67         }
     68     }
     69 
     70     private static <V> V unwrap(SoftReference<V> ref) {
     71         return ref != null ? ref.get() : null;
     72     }
     73 
     74     private final SoftReferenceMap mSoftReferences;
     75     private final HardReferenceMap mHardReferences;
     76 
     77     /**
     78      * Constructor.
     79      *
     80      * @param initialCapacity the initial capacity for the cache.
     81      * @param maxCapacity the maximum capacity for the
     82      *            cache (this value may be large if soft references are used because
     83      *            {@link SoftReference SoftReferences} don't consume much memory compared to the
     84      *            larger data they typically contain).
     85      * @param loadFactor the initial load balancing factor for the internal
     86      *            {@link LinkedHashMap}
     87      */
     88     public SimpleCache(int initialCapacity, int maxCapacity, float loadFactor,
     89             boolean useHardReferences) {
     90         if (useHardReferences) {
     91             mSoftReferences = null;
     92             mHardReferences = new HardReferenceMap(initialCapacity, maxCapacity, loadFactor);
     93         } else {
     94             mSoftReferences = new SoftReferenceMap(initialCapacity, maxCapacity, loadFactor);
     95             mHardReferences = null;
     96         }
     97     }
     98 
     99     /**
    100      * See {@link Map#get(Object)}.
    101      */
    102     public V get(Object key) {
    103         return mSoftReferences != null ? unwrap(mSoftReferences.get(key))
    104                 : mHardReferences.get(key);
    105     }
    106 
    107     /**
    108      * See {@link Map#put(Object, Object)}.
    109      */
    110     public V put(K key, V value) {
    111         return mSoftReferences != null ?
    112                 unwrap(mSoftReferences.put(key, new SoftReference<V>(value)))
    113                 : mHardReferences.put(key, value);
    114     }
    115 
    116     /**
    117      * See {@link Map#clear()}.
    118      */
    119     public void clear() {
    120         if (mSoftReferences != null) {
    121             mSoftReferences.clear();
    122         } else {
    123             mHardReferences.clear();
    124         }
    125     }
    126 
    127     /**
    128      * See {@link Map#remove(Object)}.
    129      */
    130     public V remove(K key) {
    131         if (mSoftReferences != null) {
    132             return unwrap(mSoftReferences.remove(key));
    133         } else {
    134             return mHardReferences.remove(key);
    135         }
    136     }
    137 
    138 }
    139