/*
* 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);
}
}
}