Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2011 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 libcore.util;
     18 
     19 import java.util.LinkedHashMap;
     20 import java.util.Map;
     21 
     22 /**
     23  * A minimal least-recently-used cache for libcore. Prefer {@code
     24  * android.util.LruCache} where that is available.
     25  */
     26 public class BasicLruCache<K, V> {
     27     private final LinkedHashMap<K, V> map;
     28     private final int maxSize;
     29 
     30     public BasicLruCache(int maxSize) {
     31         if (maxSize <= 0) {
     32             throw new IllegalArgumentException("maxSize <= 0");
     33         }
     34         this.maxSize = maxSize;
     35         this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
     36     }
     37 
     38     /**
     39      * Returns the value for {@code key} if it exists in the cache or can be
     40      * created by {@code #create}. If a value was returned, it is moved to the
     41      * head of the queue. This returns null if a value is not cached and cannot
     42      * be created.
     43      */
     44     public synchronized final V get(K key) {
     45         if (key == null) {
     46             throw new NullPointerException("key == null");
     47         }
     48 
     49         V result = map.get(key);
     50         if (result != null) {
     51             return result;
     52         }
     53 
     54         result = create(key);
     55 
     56         if (result != null) {
     57             map.put(key, result);
     58             trimToSize(maxSize);
     59         }
     60         return result;
     61     }
     62 
     63     /**
     64      * Caches {@code value} for {@code key}. The value is moved to the head of
     65      * the queue.
     66      *
     67      * @return the previous value mapped by {@code key}. Although that entry is
     68      *     no longer cached, it has not been passed to {@link #entryEvicted}.
     69      */
     70     public synchronized final V put(K key, V value) {
     71         if (key == null) {
     72             throw new NullPointerException("key == null");
     73         } else if (value == null) {
     74             throw new NullPointerException("value == null");
     75         }
     76 
     77         V previous = map.put(key, value);
     78         trimToSize(maxSize);
     79         return previous;
     80     }
     81 
     82     private void trimToSize(int maxSize) {
     83         while (map.size() > maxSize) {
     84             Map.Entry<K, V> toEvict = map.eldest();
     85 
     86             K key = toEvict.getKey();
     87             V value = toEvict.getValue();
     88             map.remove(key);
     89 
     90             entryEvicted(key, value);
     91         }
     92     }
     93 
     94     /**
     95      * Called for entries that have reached the tail of the least recently used
     96      * queue and are be removed. The default implementation does nothing.
     97      */
     98     protected void entryEvicted(K key, V value) {}
     99 
    100     /**
    101      * Called after a cache miss to compute a value for the corresponding key.
    102      * Returns the computed value or null if no value can be computed. The
    103      * default implementation returns null.
    104      */
    105     protected V create(K key) {
    106         return null;
    107     }
    108 
    109     /**
    110      * Returns a copy of the current contents of the cache, ordered from least
    111      * recently accessed to most recently accessed.
    112      */
    113     public synchronized final Map<K, V> snapshot() {
    114         return new LinkedHashMap<K, V>(map);
    115     }
    116 
    117     /**
    118      * Clear the cache, calling {@link #entryEvicted} on each removed entry.
    119      */
    120     public synchronized final void evictAll() {
    121         trimToSize(0);
    122     }
    123 }
    124