/* * Copyright (c) 2013, SRI International * All rights reserved. * Licensed under the The BSD 3-Clause License; * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://opensource.org/licenses/BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the aic-util nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.sri.ai.util.cache; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; import com.google.common.annotations.Beta; import com.google.common.base.Function; import com.google.common.cache.CacheStats; import com.sri.ai.util.base.BinaryFunction; import com.sri.ai.util.base.NullaryFunction; import com.sri.ai.util.base.Pair; import com.sri.ai.util.collect.FunctionIterator; /** * A {@link CacheMap} that offers more flexibility than {@link DefaultCacheMap} * with respect to what exactly it stores and returns. It works as a * {@link CacheMap} between keys of type <code>K</code> and values of type * <code>V</code>. However, it actually stores <i>internal</i> keys of type * <code>K_</code> and values of type <code>V_</code>. * <p> * Such functions are by the user to provide abstractions in the sets of values * stored and recovered. * <p> * The relationship between keys and values and their stored counterparts is * given by user-defined functions. See constructors parameters names to see * what these functions should take as input and output. * * @author braz */ @Beta public class FlexibleCacheMap<K,V,K_,V_> implements CacheMap<K, V> { private Function<K, K_> fromKeyToStoredKey; private BinaryFunction<K, V, Pair<K_, V_>> fromPairToStoredPair; private BinaryFunction<K, V_, V> fromKeyAndStoredValueToValue; // private DefaultCacheMap<K_, V_> innerCacheMap; private NullaryFunction<Iterator<K>> reachableObjectIteratorMaker; public FlexibleCacheMap(long maximumSize, Function<K, K_> fromKeyToStoredKey, BinaryFunction<K, V, Pair<K_, V_>> fromPairToStoredPair, BinaryFunction<K, V_, V> fromKeyAndStoredValueToValue, NullaryFunction<Iterator<K>> reachableObjectIteratorMaker, int garbageCollectionPeriod) { this.fromKeyToStoredKey = fromKeyToStoredKey; this.fromPairToStoredPair = fromPairToStoredPair; this.fromKeyAndStoredValueToValue = fromKeyAndStoredValueToValue; this.reachableObjectIteratorMaker = reachableObjectIteratorMaker; // NullaryFunction<Iterator<K_>> storedReachableObjectIteratorMaker = makeReachableStoredObjectsIteratorMaker(reachableObjectIteratorMaker); this.innerCacheMap = new DefaultCacheMap<K_, V_>(maximumSize, storedReachableObjectIteratorMaker, garbageCollectionPeriod); } @Override public void garbageCollect(Iterator<K> reacheableObjectsIterator) { Iterator<K_> reacheableStoredKeysIterator = new FunctionIterator<K, K_>(reacheableObjectsIterator, fromKeyToStoredKey); innerCacheMap.garbageCollect(reacheableStoredKeysIterator); } @Override public void clear() { innerCacheMap.clear(); } @Override public boolean containsKey(Object key) { throw new Error("containsKey() not supported by FlexibleCacheMap"); } @Override public boolean containsValue(Object value) { throw new Error("containsValue() not supported by FlexibleCacheMap"); } @Override public Set<java.util.Map.Entry<K, V>> entrySet() { throw new Error("entrySet() not supported by FlexibleCacheMap"); } @Override public Set<K> keySet() { throw new Error("keySet() not supported by FlexibleCacheMap"); } @Override public Collection<V> values() { throw new Error("values() not supported by FlexibleCacheMap"); } @SuppressWarnings("unchecked") @Override public V get(Object key) { K_ storedKey = fromKeyToStoredKey.apply((K)key); V_ storedValue = innerCacheMap.get(storedKey); V value = storedValue == null ? null : fromKeyAndStoredValueToValue.apply((K) key, storedValue); return value; } @Override public boolean isEmpty() { return innerCacheMap.isEmpty(); } @Override public V put(K key, V value) { Pair<K_,V_> storedPair = fromPairToStoredPair.apply(key, value); V_ storedValueReturned = innerCacheMap.put(storedPair.first, storedPair.second); V result = storedValueReturned == null? null : fromKeyAndStoredValueToValue.apply(key, storedValueReturned); return result; } @Override public void putAll(Map<? extends K, ? extends V> t) { for (Map.Entry<? extends K, ? extends V> entry : t.entrySet()) { put(entry.getKey(), entry.getValue()); } } @SuppressWarnings("unchecked") @Override public V remove(Object key) { K_ storedKey = fromKeyToStoredKey.apply((K) key); V_ storedValueReturned = innerCacheMap.remove(storedKey); V result = storedValueReturned == null? null : fromKeyAndStoredValueToValue.apply((K) key, storedValueReturned); return result; } @Override public int size() { return innerCacheMap.size(); } @Override public int getGarbageCollectionPeriod() { return innerCacheMap.getGarbageCollectionPeriod(); } @Override public NullaryFunction<Iterator<K>> getReachableObjectIteratorMaker() { return reachableObjectIteratorMaker; } @Override public void setGarbageCollectionPeriod(int period) { innerCacheMap.setGarbageCollectionPeriod(period); } @Override public void setReachableObjectIteratorMaker(NullaryFunction<Iterator<K>> reachableObjectIteratorMaker) { this.reachableObjectIteratorMaker = reachableObjectIteratorMaker; NullaryFunction<Iterator<K_>> storedReachableObjectIteratorMaker = makeReachableStoredObjectsIteratorMaker(reachableObjectIteratorMaker); innerCacheMap.setReachableObjectIteratorMaker(storedReachableObjectIteratorMaker); } @Override public CacheStats stats() { return innerCacheMap.stats(); } // // PRIVATE METHODS // private NullaryFunction<Iterator<K_>> makeReachableStoredObjectsIteratorMaker( NullaryFunction<Iterator<K>> reachableObjectIteratorMaker) { NullaryFunction<Iterator<K_>> storedReachableObjectIteratorMaker = new ReachableStoredObjectIteratorMaker(reachableObjectIteratorMaker); return storedReachableObjectIteratorMaker; } private class ReachableStoredObjectIteratorMaker implements NullaryFunction<Iterator<K_>> { private NullaryFunction<Iterator<K>> reachableObjectIteratorMaker; public ReachableStoredObjectIteratorMaker(NullaryFunction<Iterator<K>> reachableObjectIteratorMaker) { super(); this.reachableObjectIteratorMaker = reachableObjectIteratorMaker; } @Override public Iterator<K_> apply() { Iterator<K> objectsIterator = reachableObjectIteratorMaker.apply(); Iterator<K_> storedKeyIterator = new FunctionIterator<K, K_>(objectsIterator, fromKeyToStoredKey); return storedKeyIterator; } } }