/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. */ package com.db4o.internal.caching; import java.util.*; import com.db4o.foundation.*; /** * @exclude */ class LRULongCache<V> implements PurgeableCache4<Long, V> { private static class Entry<V> { final long _key; final V _value; Entry _previous; Entry _next; public Entry(long key, V value){ _key = key; _value = value; } @Override public String toString() { return "" + _key; } } private final Hashtable4 _slots; private final int _maxSize; private int _size; private Entry _first; private Entry _last; LRULongCache(int size) { _maxSize = size; _slots = new Hashtable4(size); } public V produce(Long key, Function4<Long, V> producer, Procedure4<V> finalizer) { long longKey = key; if(_last == null){ V lastValue = producer.apply(key); if(lastValue == null){ return null; } _size = 1; Entry lastEntry = new Entry(longKey, lastValue); _slots.put(longKey, lastEntry); _first = lastEntry; _last = lastEntry; return lastValue; } final Entry<V> entry = (Entry)_slots.get(longKey); if (entry == null) { if (_size >= _maxSize) { Entry oldEntry = (Entry) _slots.remove(_last._key); _last = oldEntry._previous; _last._next = null; if (null != finalizer) { finalizer.apply((V) oldEntry._value); } _size --; } V newValue = producer.apply(key); if (newValue == null) { return null; } _size++; Entry newEntry = new Entry(longKey, newValue); _slots.put(longKey, newEntry); _first._previous = newEntry; newEntry._next = _first; _first = newEntry; return newValue; } if(_first == entry){ return entry._value; } Entry previous = entry._previous; entry._previous = null; if(_last == entry){ _last = previous; } previous._next = entry._next; if(previous._next != null){ previous._next._previous = previous; } _first._previous = entry; entry._next = _first; _first = entry; return entry._value; } public Iterator iterator() { Iterator4 i = new Iterator4 () { private Entry _cursor = _first; private Entry _current; public Object current() { return _current._value; } public boolean moveNext() { if(_cursor == null){ _current = null; return false; } _current = _cursor; _cursor = _cursor._next; return true; } public void reset() { _cursor = _first; _current = null; } }; return Iterators.platformIterator(i); } public V purge(Long key) { long longKey = key; Entry<V> entry = (Entry<V>) _slots.remove(longKey); if(entry == null){ return null; } _size --; if(_first == entry){ _first = entry._next; } if(_last == entry){ _last = entry._previous; } if(entry._previous != null){ entry._previous._next = entry._next; } if(entry._next != null){ entry._next._previous = entry._previous; } return entry._value; } }