blob: 0f7fb751d8fd7b050304b98b5dc350bd3e709eaa [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.codehaus.groovy.runtime.memoize;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Represents a simple key-value cache, which is NOT thread safe and backed by a {@link java.util.Map} instance
*
* @param <K> type of the keys
* @param <V> type of the values
* @since 2.5.0
*/
public class CommonCache<K, V> implements EvictableCache<K, V>, ValueConvertable<V, Object>, Serializable {
private static final long serialVersionUID = 934699400232698324L;
/**
* The default load factor
*/
public static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* The default initial capacity
*/
public static final int DEFAULT_INITIAL_CAPACITY = 16;
private final Map<K, V> map;
/**
* Constructs a cache with unlimited size
*/
public CommonCache() {
this(new LinkedHashMap<K, V>());
}
/**
* Constructs a cache with limited size
*
* @param initialCapacity initial capacity of the cache
* @param maxSize max size of the cache
* @param evictionStrategy LRU or FIFO, see {@link org.codehaus.groovy.runtime.memoize.EvictableCache.EvictionStrategy}
*/
public CommonCache(final int initialCapacity, final int maxSize, final EvictionStrategy evictionStrategy) {
this(new LinkedHashMap<K, V>(initialCapacity, DEFAULT_LOAD_FACTOR, EvictionStrategy.LRU == evictionStrategy) {
private static final long serialVersionUID = -8012450791479726621L;
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maxSize;
}
});
}
/**
* Constructs a LRU cache with the specified initial capacity and max size.
* The LRU cache is slower than {@link LRUCache}
*
* @param initialCapacity initial capacity of the LRU cache
* @param maxSize max size of the LRU cache
*/
public CommonCache(int initialCapacity, int maxSize) {
this(initialCapacity, maxSize, EvictionStrategy.LRU);
}
/**
* Constructs a LRU cache with the default initial capacity
*
* @param maxSize max size of the LRU cache
* @see #CommonCache(int, int)
*/
public CommonCache(final int maxSize) {
this(DEFAULT_INITIAL_CAPACITY, maxSize);
}
/**
* Constructs a cache backed by the specified {@link java.util.Map} instance
*
* @param map the {@link java.util.Map} instance
*/
public CommonCache(Map<K, V> map) {
this.map = map;
}
/**
* {@inheritDoc}
*/
@Override
public V get(Object key) {
return map.get(key);
}
/**
* {@inheritDoc}
*/
@Override
public V put(K key, V value) {
return map.put(key, value);
}
/**
* {@inheritDoc}
*/
@Override
public V getAndPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
return getAndPut(key, valueProvider, true);
}
public V getAndPut(K key, ValueProvider<? super K, ? extends V> valueProvider, boolean shouldCache) {
V value = get(key);
if (null != convertValue(value)) {
return value;
}
value = null == valueProvider ? null : valueProvider.provide(key);
if (shouldCache && null != convertValue(value)) {
put(key, value);
}
return value;
}
/**
* {@inheritDoc}
*/
@Override
public Collection<V> values() {
return map.values();
}
@Override
public Set<Entry<K, V>> entrySet() {
return map.entrySet();
}
/**
* {@inheritDoc}
*/
@Override
public Set<K> keys() {
return map.keySet();
}
@Override
public boolean containsValue(Object value) {
return map.containsValue(value);
}
/**
* {@inheritDoc}
*/
@Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return size() == 0;
}
/**
* {@inheritDoc}
*/
@Override
public V remove(Object key) {
return map.remove(key);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
map.putAll(m);
}
@Override
public Set<K> keySet() {
return map.keySet();
}
/**
* {@inheritDoc}
*/
@Override
public Map<K, V> clearAll() {
Map<K, V> result = new LinkedHashMap<K, V>(map);
map.clear();
return result;
}
/**
* {@inheritDoc}
*/
@Override
public void cleanUpNullReferences() {
List<K> keys = new LinkedList<>();
for (Map.Entry<K, V> entry : map.entrySet()) {
K key = entry.getKey();
V value = entry.getValue();
if (null == value
|| (value instanceof SoftReference && null == ((SoftReference) value).get())
|| (value instanceof WeakReference && null == ((WeakReference) value).get())) {
keys.add(key);
}
}
for (K key : keys) {
map.remove(key);
}
}
@Override
public String toString() {
return map.toString();
}
/**
* {@inheritDoc}
*/
@Override
public Object convertValue(V value) {
return value;
}
}