blob: c1e8e4a9b8d2e3f31dc22223fa97cd16339d45d6 [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.
*/
#ifndef _DECAF_UTIL_LINKEDHASHMAP_H_
#define _DECAF_UTIL_LINKEDHASHMAP_H_
#include <decaf/util/Config.h>
#include <decaf/util/HashMap.h>
namespace decaf {
namespace util {
/**
* Hashed and linked list implementation of the Map interface, with predictable iteration order.
*
* This implementation differs from HashMap in that it maintains a doubly-linked list running
* through all of its entries. This linked list defines the iteration ordering, which is
* normally the order in which keys were inserted into the map (insertion-order). Note that
* insertion order is not affected if a key is re-inserted into the map. (A key k is reinserted
* into a map m if m.put(k, v) is invoked when m.containsKey(k) would return true immediately
* prior to the invocation.)
*
* This implementation spares its clients from the unspecified, generally chaotic ordering
* provided by HashMap, without incurring the increased cost associated with TreeMap. It can
* be used to produce a copy of a map that has the same order as the original, regardless of
* the original map's implementation:
*
* void foo(Map m) {
* Map copy = new LinkedHashMap(m);
* ...
* }
*
* This technique is particularly useful if a module takes a map on input, copies it, and later
* returns results whose order is determined by that of the copy. (Clients generally appreciate
* having things returned in the same order they were presented.)
*
* A special constructor is provided to create a linked hash map whose order of iteration is the
* order in which its entries were last accessed, from least-recently accessed to most-recently
* (access-order). This kind of map is well-suited to building LRU caches. Invoking the put or
* get method results in an access to the corresponding entry (assuming it exists after the
* invocation completes). The putAll method generates one entry access for each mapping in the
* specified map, in the order that key-value mappings are provided by the specified map's entry
* set iterator. No other methods generate entry accesses. In particular, operations on
* collection-views do not affect the order of iteration of the backing map.
*
* The removeEldestEntry(MapEntry) method may be overridden to impose a policy for removing
* stale mappings automatically when new mappings are added to the map. When the entries are
* about to be removed from the map the onEviction method is called giving subclasses a
* chance to delete pointer values or perform other cleanup prior to the mapping being
* removed.
*
* This class provides all of the optional Map operations. Like HashMap, it provides
* constant-time performance for the basic operations (add, contains and remove), assuming
* the hash function disperses elements properly among the buckets. Performance is likely
* to be just slightly below that of HashMap, due to the added expense of maintaining the
* linked list, with one exception: Iteration over the collection-views of a LinkedHashMap
* requires time proportional to the size of the map, regardless of its capacity. Iteration
* over a HashMap is likely to be more expensive, requiring time proportional to its capacity.
*
* A linked hash map has two parameters that affect its performance: initial capacity and load
* factor. They are defined precisely as for HashMap. Note, however, that the penalty for
* choosing an excessively high value for initial capacity is less severe for this class than
* for HashMap, as iteration times for this class are unaffected by capacity.
*
* Note that this implementation is not synchronized. If multiple threads access a linked hash
* map concurrently, and at least one of the threads modifies the map structurally, it must
* be synchronized externally. This is typically accomplished by synchronizing on some object
* that naturally encapsulates the map. If no such object exists, the map should be "wrapped"
* using the Collections.synchronizedMap method. This is best done at creation time, to prevent
* accidental unsynchronized access to the map:
*
* Map<K,V>* m = Collections::synchronizedMap(new LinkedHashMap(...));
*
* A structural modification is any operation that adds or deletes one or more mappings or, in
* the case of access-ordered linked hash maps, affects iteration order. In insertion-ordered
* linked hash maps, merely changing the value associated with a key that is already contained
* in the map is not a structural modification. In access-ordered linked hash maps, merely
* querying the map with get is a structural modification.)
*
* The iterators returned by the iterator method of the collections returned by all of this
* class's collection view methods are fail-fast: if the map is structurally modified at any
* time after the iterator is created, in any way except through the iterator's own remove
* method, the iterator will throw a ConcurrentModificationException. Thus, in the face of
* concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary,
* non-deterministic behavior at an undetermined time in the future.
*
* Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally
* speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent
* modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis.
* Therefore, it would be wrong to write a program that depended on this exception for its
* correctness: the fail-fast behavior of iterators should be used only to detect bugs.
*
* @since 1.0
*/
template<typename K, typename V, typename HASHCODE = HashCode<K> >
class LinkedHashMap : public HashMap<K, V, HASHCODE> {
private:
class LinkedHashMapEntry : public HashMap<K, V, HASHCODE>::HashMapEntry {
private:
LinkedHashMapEntry(const LinkedHashMapEntry&);
LinkedHashMapEntry& operator= (const LinkedHashMapEntry&);
public:
LinkedHashMapEntry* chainForward;
LinkedHashMapEntry* chainBackward;
public:
LinkedHashMapEntry(const K& key, const V& value, int hash) :
HashMap<K, V, HASHCODE>::HashMapEntry(key, value, hash), chainForward(), chainBackward() {
}
LinkedHashMapEntry(const K& key, const V& value) :
HashMap<K, V, HASHCODE>::HashMapEntry(key, value), chainForward(), chainBackward() {
}
};
private:
bool accessOrder;
mutable LinkedHashMapEntry* head;
mutable LinkedHashMapEntry* tail;
private:
class AbstractMapIterator {
protected:
int expectedModCount;
LinkedHashMapEntry* futureEntry;
LinkedHashMapEntry* currentEntry;
LinkedHashMap* associatedMap;
private:
AbstractMapIterator(const AbstractMapIterator&);
AbstractMapIterator& operator= (const AbstractMapIterator&);
public:
AbstractMapIterator(LinkedHashMap* parent) : expectedModCount(parent->modCount),
futureEntry(parent->head),
currentEntry(NULL),
associatedMap(parent) {
}
virtual ~AbstractMapIterator() {}
void checkConcurrentMod() const {
if (expectedModCount != associatedMap->modCount) {
throw ConcurrentModificationException(
__FILE__, __LINE__, "LinkedHashMap modified outside this iterator");
}
}
virtual bool checkHasNext() const {
return (futureEntry != NULL);
}
void makeNext() {
checkConcurrentMod();
if (!checkHasNext()) {
throw decaf::util::NoSuchElementException(
__FILE__, __LINE__, "No next element");
}
currentEntry = futureEntry;
futureEntry = futureEntry->chainForward;
}
virtual void doRemove() {
checkConcurrentMod();
if (currentEntry == NULL) {
throw decaf::lang::exceptions::IllegalStateException(
__FILE__, __LINE__, "Remove called before call to next()");
}
LinkedHashMapEntry* entry = currentEntry;
LinkedHashMapEntry* prev = entry->chainBackward;
LinkedHashMapEntry* next = entry->chainForward;
LinkedHashMap* map = associatedMap;
// currentEntry gets deleted here.
associatedMap->removeEntry(currentEntry);
currentEntry = NULL;
if (prev != NULL) {
prev->chainForward = next;
if (next != NULL) {
next->chainBackward = prev;
} else {
map->tail = prev;
}
} else {
map->head = next;
if (next != NULL) {
next->chainBackward = NULL;
} else {
map->tail = NULL;
}
}
expectedModCount++;
}
};
class EntryIterator : public Iterator< MapEntry<K,V> >, public AbstractMapIterator {
private:
EntryIterator(const EntryIterator&);
EntryIterator& operator= (const EntryIterator&);
public:
EntryIterator(LinkedHashMap* parent) : AbstractMapIterator(parent) {
}
virtual ~EntryIterator() {}
virtual bool hasNext() const {
return this->checkHasNext();
}
virtual MapEntry<K, V> next() {
this->makeNext();
return *(this->currentEntry);
}
virtual void remove() {
this->doRemove();
}
};
class KeyIterator : public Iterator<K>, public AbstractMapIterator {
private:
KeyIterator(const KeyIterator&);
KeyIterator& operator= (const KeyIterator&);
public:
KeyIterator(LinkedHashMap* parent) : AbstractMapIterator(parent) {
}
virtual ~KeyIterator() {}
virtual bool hasNext() const {
return this->checkHasNext();
}
virtual K next() {
this->makeNext();
return this->currentEntry->getKey();
}
virtual void remove() {
this->doRemove();
}
};
class ValueIterator : public Iterator<V>, public AbstractMapIterator {
private:
ValueIterator(const ValueIterator&);
ValueIterator& operator= (const ValueIterator&);
public:
ValueIterator(LinkedHashMap* parent) : AbstractMapIterator(parent) {
}
virtual ~ValueIterator() {}
virtual bool hasNext() const {
return this->checkHasNext();
}
virtual V next() {
this->makeNext();
return this->currentEntry->getValue();
}
virtual void remove() {
this->doRemove();
}
};
private:
class ConstAbstractMapIterator {
protected:
int expectedModCount;
const LinkedHashMapEntry* futureEntry;
const LinkedHashMapEntry* currentEntry;
const LinkedHashMap* associatedMap;
private:
ConstAbstractMapIterator(const ConstAbstractMapIterator&);
ConstAbstractMapIterator& operator= (const ConstAbstractMapIterator&);
public:
ConstAbstractMapIterator(const LinkedHashMap* parent) : expectedModCount(parent->modCount),
futureEntry(parent->head),
currentEntry(NULL),
associatedMap(parent) {
}
virtual ~ConstAbstractMapIterator() {}
virtual bool checkHasNext() const {
return (futureEntry != NULL);
}
void checkConcurrentMod() const {
if (expectedModCount != associatedMap->modCount) {
throw ConcurrentModificationException(
__FILE__, __LINE__, "LinkedHashMap modified outside this iterator");
}
}
void makeNext() {
checkConcurrentMod();
if (!checkHasNext()) {
throw decaf::util::NoSuchElementException(
__FILE__, __LINE__, "No next element");
}
currentEntry = futureEntry;
futureEntry = futureEntry->chainForward;
}
};
class ConstEntryIterator : public Iterator< MapEntry<K,V> >, public ConstAbstractMapIterator {
private:
ConstEntryIterator(const ConstEntryIterator&);
ConstEntryIterator& operator= (const ConstEntryIterator&);
public:
ConstEntryIterator(const LinkedHashMap* parent) : ConstAbstractMapIterator(parent) {
}
virtual ~ConstEntryIterator() {}
virtual bool hasNext() const {
return this->checkHasNext();
}
virtual MapEntry<K, V> next() {
this->makeNext();
return *(this->currentEntry);
}
virtual void remove() {
throw lang::exceptions::UnsupportedOperationException(
__FILE__, __LINE__, "Cannot write to a const Iterator." );
}
};
class ConstKeyIterator : public Iterator<K>, public ConstAbstractMapIterator {
private:
ConstKeyIterator(const ConstKeyIterator&);
ConstKeyIterator& operator= (const ConstKeyIterator&);
public:
ConstKeyIterator(const LinkedHashMap* parent) : ConstAbstractMapIterator(parent) {
}
virtual ~ConstKeyIterator() {}
virtual bool hasNext() const {
return this->checkHasNext();
}
virtual K next() {
this->makeNext();
return this->currentEntry->getKey();
}
virtual void remove() {
throw lang::exceptions::UnsupportedOperationException(
__FILE__, __LINE__, "Cannot write to a const Iterator." );
}
};
class ConstValueIterator : public Iterator<V>, public ConstAbstractMapIterator {
private:
ConstValueIterator(const ConstValueIterator&);
ConstValueIterator& operator= (const ConstValueIterator&);
public:
ConstValueIterator(const LinkedHashMap* parent) : ConstAbstractMapIterator(parent) {
}
virtual ~ConstValueIterator() {}
virtual bool hasNext() const {
return this->checkHasNext();
}
virtual V next() {
this->makeNext();
return this->currentEntry->getValue();
}
virtual void remove() {
throw lang::exceptions::UnsupportedOperationException(
__FILE__, __LINE__, "Cannot write to a const Iterator." );
}
};
private:
// Special Set implementation that is backed by this HashMap
class LinkedHashMapEntrySet : public HashMap<K, V, HASHCODE>::HashMapEntrySet {
private:
LinkedHashMap* associatedMap;
private:
LinkedHashMapEntrySet(const LinkedHashMapEntrySet&);
LinkedHashMapEntrySet& operator= (const LinkedHashMapEntrySet&);
public:
LinkedHashMapEntrySet(LinkedHashMap* parent) :
HashMap<K, V, HASHCODE>::HashMapEntrySet(parent), associatedMap(parent) {
}
virtual ~LinkedHashMapEntrySet() {}
virtual Iterator< MapEntry<K, V> >* iterator() {
return new EntryIterator(associatedMap);
}
virtual Iterator< MapEntry<K, V> >* iterator() const {
return new ConstEntryIterator(associatedMap);
}
};
// Special Set implementation that is backed by this HashMap
class ConstLinkedHashMapEntrySet : public HashMap<K, V, HASHCODE>::ConstHashMapEntrySet {
private:
const LinkedHashMap* associatedMap;
private:
ConstLinkedHashMapEntrySet(const ConstLinkedHashMapEntrySet&);
ConstLinkedHashMapEntrySet& operator= (const ConstLinkedHashMapEntrySet&);
public:
ConstLinkedHashMapEntrySet(const LinkedHashMap* parent) :
HashMap<K, V, HASHCODE>::ConstHashMapEntrySet(parent), associatedMap(parent) {
}
virtual ~ConstLinkedHashMapEntrySet() {}
virtual Iterator< MapEntry<K, V> >* iterator() {
throw decaf::lang::exceptions::UnsupportedOperationException(
__FILE__, __LINE__, "Can't return a non-const iterator for a const collection");
}
virtual Iterator< MapEntry<K, V> >* iterator() const {
return new ConstEntryIterator(associatedMap);
}
};
private:
class LinkedHashMapKeySet : public HashMap<K, V, HASHCODE>::HashMapKeySet {
private:
LinkedHashMap* associatedMap;
private:
LinkedHashMapKeySet(const LinkedHashMapKeySet&);
LinkedHashMapKeySet& operator= (const LinkedHashMapKeySet&);
public:
LinkedHashMapKeySet(LinkedHashMap* parent) :
HashMap<K, V, HASHCODE>::HashMapKeySet(parent), associatedMap(parent) {
}
virtual ~LinkedHashMapKeySet() {}
virtual Iterator<K>* iterator() {
return new KeyIterator(this->associatedMap);
}
virtual Iterator<K>* iterator() const {
return new ConstKeyIterator(this->associatedMap);
}
};
class ConstLinkedHashMapKeySet : public HashMap<K, V, HASHCODE>::ConstHashMapKeySet {
private:
const LinkedHashMap* associatedMap;
private:
ConstLinkedHashMapKeySet(const ConstLinkedHashMapKeySet&);
ConstLinkedHashMapKeySet& operator= (const ConstLinkedHashMapKeySet&);
public:
ConstLinkedHashMapKeySet(const LinkedHashMap* parent) :
HashMap<K, V, HASHCODE>::ConstHashMapKeySet(parent), associatedMap(parent) {
}
virtual ~ConstLinkedHashMapKeySet() {}
using HashMap<K, V, HASHCODE>::ConstHashMapKeySet::iterator;
virtual Iterator<K>* iterator() const {
return new ConstKeyIterator(this->associatedMap);
}
};
private:
class LinkedHashMapValueCollection : public HashMap<K, V, HASHCODE>::HashMapValueCollection {
private:
LinkedHashMap* associatedMap;
private:
LinkedHashMapValueCollection(const LinkedHashMapValueCollection&);
LinkedHashMapValueCollection& operator= (const LinkedHashMapValueCollection&);
public:
LinkedHashMapValueCollection(LinkedHashMap* parent) :
HashMap<K, V, HASHCODE>::HashMapValueCollection(parent), associatedMap(parent) {
}
virtual ~LinkedHashMapValueCollection() {}
virtual Iterator<V>* iterator() {
return new ValueIterator(this->associatedMap);
}
virtual Iterator<V>* iterator() const {
return new ConstValueIterator(this->associatedMap);
}
};
class ConstLinkedHashMapValueCollection : public HashMap<K, V, HASHCODE>::ConstHashMapValueCollection {
private:
const LinkedHashMap* associatedMap;
private:
ConstLinkedHashMapValueCollection(const ConstLinkedHashMapValueCollection&);
ConstLinkedHashMapValueCollection& operator= (const ConstLinkedHashMapValueCollection&);
public:
ConstLinkedHashMapValueCollection(const LinkedHashMap* parent) :
HashMap<K, V, HASHCODE>::ConstHashMapValueCollection(parent), associatedMap(parent) {
}
virtual ~ConstLinkedHashMapValueCollection() {}
virtual Iterator<V>* iterator() const {
return new ConstValueIterator(this->associatedMap);
}
using HashMap<K, V, HASHCODE>::ConstHashMapValueCollection::iterator;
};
public:
/**
* Constructs an empty insertion-ordered LinkedHashMap instance with the default
* initial capacity (16) and load factor (0.75).
*/
LinkedHashMap() : HashMap<K, V, HASHCODE>(), accessOrder(false), head(), tail() {
}
/**
* Constructs a new LinkedHashMap instance with the specified capacity.
*
* @param capacity
* The initial capacity of this map.
*
* @throws IllegalArgumentException if the capacity is less than zero.
*/
LinkedHashMap(int capacity) : HashMap<K, V, HASHCODE>(capacity), accessOrder(false), head(), tail() {
}
/**
* Constructs a new {@code LinkedHashMap} instance with the specified
* capacity and load factor.
*
* @param capacity
* The initial capacity of this map.
* @param load
* The initial load factor for this map.
*
* @throws IllegalArgumentException
* If the capacity is less than zero or the load factor is less or equal to zero.
*/
LinkedHashMap(int capacity, float load) :
HashMap<K, V, HASHCODE>(capacity, load), accessOrder(false), head(), tail() {
}
/**
* Constructs a new {@code LinkedHashMap} instance with the specified
* capacity, load factor and a flag specifying the ordering behavior.
*
* @param capacity
* The initial capacity of this map.
* @param load
* The initial load factor for this map.
* @param order
* True if the ordering should be done based on the last access (from
* least-recently accessed to most-recently accessed), and false if
* the ordering should be the order in which the entries were inserted.
*
* @throws IllegalArgumentException
* If the capacity is less than zero or the load factor is less or equal to zero.
*/
LinkedHashMap(int capacity, float load, bool order) :
HashMap<K, V, HASHCODE>(capacity, load), accessOrder(order), head(), tail() {
}
/**
* Constructs a new LinkedHashMap instance containing the mappings
* from the specified map. The order of the elements is preserved.
*
* @param map
* The mappings to add to this Map instance.
*/
LinkedHashMap(const HashMap<K,V>& map) : HashMap<K, V, HASHCODE>(map), accessOrder(false), head(), tail() {
}
virtual ~LinkedHashMap() {}
protected:
/**
* This method is queried from the put and putAll methods to check if the
* eldest member of the map should be deleted before adding the new member.
* If this map was created with accessOrder = true, then the result of
* removeEldestEntry is assumed to be false.
*
* @param eldest
* The entry to check if it should be removed.
*
* @return true if the eldest member should be removed.
*/
virtual bool removeEldestEntry(const MapEntry<K, V>& eldest DECAF_UNUSED) {
return false;
}
/**
* This method is called when the removeEldestEntry has returned true and a
* MapEntry is about to be removed from the Map. This method allows for Maps
* that contain pointers in their MapEntry object to have a chance to properly
* delete the pointer when the entry is removed.
*
* @param eldest
* The MapEntry value that is about to be removed from the Map.
*/
virtual void onEviction(const MapEntry<K, V>& eldest DECAF_UNUSED) {}
public:
virtual bool containsValue(const V& value) const {
LinkedHashMapEntry* entry = head;
while (entry != NULL) {
if (value == entry->getValue()) {
return true;
}
entry = entry->chainForward;
}
return false;
}
virtual void clear() {
HashMap<K, V, HASHCODE>::clear();
this->head = NULL;
this->tail = NULL;
}
virtual bool put(const K& key, const V& value) {
bool result = this->putImpl(key, value);
if (this->removeEldestEntry(*head)) {
this->onEviction(*head);
this->remove(head->getKey());
}
return result;
}
virtual bool put(const K& key, const V& value, V& oldValue) {
bool result = this->putImpl(key, value, oldValue);
if (this->removeEldestEntry(*head)) {
this->onEviction(*head);
this->remove(head->getKey());
}
return result;
}
virtual V remove(const K& key) {
LinkedHashMapEntry* toRemove = (LinkedHashMapEntry*) this->removeEntry(key);
if (toRemove != NULL) {
LinkedHashMapEntry* prev = toRemove->chainBackward;
LinkedHashMapEntry* next = toRemove->chainForward;
if (prev != NULL) {
prev->chainForward = next;
} else {
head = next;
}
if (next != NULL) {
next->chainBackward = prev;
} else {
tail = prev;
}
V oldValue = toRemove->getValue();
delete toRemove;
return oldValue;
}
throw NoSuchElementException(
__FILE__, __LINE__, "Specified key not present in the Map.");
}
virtual Set< MapEntry<K,V> >& entrySet() {
if (this->cachedEntrySet == NULL) {
this->cachedEntrySet.reset(new LinkedHashMapEntrySet(this));
}
return *(this->cachedEntrySet);
}
virtual const Set< MapEntry<K,V> >& entrySet() const {
if (this->cachedConstEntrySet == NULL) {
this->cachedConstEntrySet.reset(new ConstLinkedHashMapEntrySet(this));
}
return *(this->cachedConstEntrySet);
}
virtual Set<K>& keySet() {
if (this->cachedKeySet == NULL) {
this->cachedKeySet.reset(new LinkedHashMapKeySet(this));
}
return *(this->cachedKeySet);
}
virtual const Set<K>& keySet() const {
if (this->cachedConstKeySet == NULL) {
this->cachedConstKeySet.reset(new ConstLinkedHashMapKeySet(this));
}
return *(this->cachedConstKeySet);
}
virtual Collection<V>& values() {
if (this->cachedValueCollection == NULL) {
this->cachedValueCollection.reset(new LinkedHashMapValueCollection(this));
}
return *(this->cachedValueCollection);
}
virtual const Collection<V>& values() const {
if (this->cachedConstValueCollection == NULL) {
this->cachedConstValueCollection.reset(new ConstLinkedHashMapValueCollection(this));
}
return *(this->cachedConstValueCollection);
}
virtual std::string toString() const {
return "LinkedHashMap";
}
protected:
virtual LinkedHashMapEntry* getEntry(const K& key) const {
LinkedHashMapEntry* result = NULL;
int hash = this->hashFunc(key);
int index = hash & (this->elementData.length() - 1);
result = (LinkedHashMapEntry*) this->findKeyEntry(key, index, hash);
if (result != NULL && accessOrder && tail != result) {
LinkedHashMapEntry* prev = result->chainBackward;
LinkedHashMapEntry* next = result->chainForward;
next->chainBackward = prev;
if (prev != NULL) {
prev->chainForward = next;
} else {
head = next;
}
result->chainForward = NULL;
result->chainBackward = tail;
tail->chainForward = result;
tail = result;
}
return result;
}
virtual typename HashMap<K, V, HASHCODE>::HashMapEntry* createEntry(const K& key, int index, const V& value) {
LinkedHashMapEntry* entry = new LinkedHashMapEntry(key, value);
entry->next = this->elementData[index];
this->elementData[index] = entry;
linkEntry(entry);
return entry;
}
virtual typename HashMap<K, V, HASHCODE>::HashMapEntry* createHashedEntry(const K& key, int index, int hash) {
LinkedHashMapEntry* entry = new LinkedHashMapEntry(key, V(), hash);
entry->next = this->elementData[index];
this->elementData[index] = entry;
linkEntry(entry);
return entry;
}
void linkEntry(LinkedHashMapEntry* entry) {
if (tail == entry) {
return;
}
if (head == NULL) {
// Check if the map is empty
head = tail = entry;
return;
}
// we need to link the new entry into either the head or tail
// of the chain depending on if the LinkedHashMap is accessOrder or not
LinkedHashMapEntry* prev = entry->chainBackward;
LinkedHashMapEntry* next = entry->chainForward;
if (prev == NULL) {
if (next != NULL) {
// The entry must be the head but not the tail
if (accessOrder) {
head = next;
next->chainBackward = NULL;
entry->chainBackward = tail;
entry->chainForward = NULL;
tail->chainForward = entry;
tail = entry;
}
} else {
// This is a new entry
entry->chainBackward = tail;
entry->chainForward = NULL;
tail->chainForward = entry;
tail = entry;
}
return;
}
if (next == NULL) {
// The entry must be the tail so we can't get here
return;
}
// The entry is neither the head nor tail
if (accessOrder) {
prev->chainForward = next;
next->chainBackward = prev;
entry->chainForward = NULL;
entry->chainBackward = tail;
tail->chainForward = entry;
tail = entry;
}
}
virtual bool putImpl(const K& key, const V& value) {
V oldValue;
return putImpl(key, value, oldValue);
}
virtual bool putImpl(const K& key, const V& value, V& oldValue) {
LinkedHashMapEntry* entry;
if (this->elementCount == 0) {
head = tail = NULL;
}
bool replaced = true;
int hash = this->hashFunc(key);
int index = hash & (this->elementData.length() - 1);
entry = (LinkedHashMapEntry*) this->findKeyEntry(key, index, hash);
if (entry == NULL) {
this->modCount++;
if (++this->elementCount > this->threshold) {
this->rehash();
index = hash & (this->elementData.length() - 1);
}
entry = (LinkedHashMapEntry*) this->createHashedEntry(key, index, hash);
replaced = false;
} else {
this->linkEntry(entry);
oldValue = entry->getValue();
}
entry->setValue(value);
return replaced;
}
};
}}
#endif /* _DECAF_UTIL_LINKEDHASHMAP_H_ */