Merge \\"LruCache: avoid copying keys in lookup\\" am: 896c6b14ae
am: 4476929073
Change-Id: I3c49a22c68c8a66c912f08e3b7cdd8340de69532
This commit is contained in:
commit
d20120ae1f
2 changed files with 58 additions and 15 deletions
|
|
@ -56,36 +56,55 @@ public:
|
||||||
private:
|
private:
|
||||||
LruCache(const LruCache& that); // disallow copy constructor
|
LruCache(const LruCache& that); // disallow copy constructor
|
||||||
|
|
||||||
struct Entry {
|
// Super class so that we can have entries having only a key reference, for searches.
|
||||||
|
class KeyedEntry {
|
||||||
|
public:
|
||||||
|
virtual const TKey& getKey() const = 0;
|
||||||
|
// Make sure the right destructor is executed so that keys and values are deleted.
|
||||||
|
virtual ~KeyedEntry() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Entry final : public KeyedEntry {
|
||||||
|
public:
|
||||||
TKey key;
|
TKey key;
|
||||||
TValue value;
|
TValue value;
|
||||||
Entry* parent;
|
Entry* parent;
|
||||||
Entry* child;
|
Entry* child;
|
||||||
|
|
||||||
Entry(TKey key_, TValue value_) : key(key_), value(value_), parent(NULL), child(NULL) {
|
Entry(TKey _key, TValue _value) : key(_key), value(_value), parent(NULL), child(NULL) {
|
||||||
}
|
}
|
||||||
const TKey& getKey() const { return key; }
|
const TKey& getKey() const final { return key; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HashForEntry : public std::unary_function<Entry*, hash_t> {
|
class EntryForSearch : public KeyedEntry {
|
||||||
size_t operator() (const Entry* entry) const {
|
public:
|
||||||
return hash_type(entry->key);
|
const TKey& key;
|
||||||
|
EntryForSearch(const TKey& key_) : key(key_) {
|
||||||
|
}
|
||||||
|
const TKey& getKey() const final { return key; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HashForEntry : public std::unary_function<KeyedEntry*, hash_t> {
|
||||||
|
size_t operator() (const KeyedEntry* entry) const {
|
||||||
|
return hash_type(entry->getKey());
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EqualityForHashedEntries : public std::unary_function<Entry*, hash_t> {
|
struct EqualityForHashedEntries : public std::unary_function<KeyedEntry*, hash_t> {
|
||||||
bool operator() (const Entry* lhs, const Entry* rhs) const {
|
bool operator() (const KeyedEntry* lhs, const KeyedEntry* rhs) const {
|
||||||
return lhs->key == rhs->key;
|
return lhs->getKey() == rhs->getKey();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::unordered_set<Entry*, HashForEntry, EqualityForHashedEntries> LruCacheSet;
|
// All entries in the set will be Entry*. Using the weaker KeyedEntry as to allow entries
|
||||||
|
// that have only a key reference, for searching.
|
||||||
|
typedef std::unordered_set<KeyedEntry*, HashForEntry, EqualityForHashedEntries> LruCacheSet;
|
||||||
|
|
||||||
void attachToCache(Entry& entry);
|
void attachToCache(Entry& entry);
|
||||||
void detachFromCache(Entry& entry);
|
void detachFromCache(Entry& entry);
|
||||||
|
|
||||||
typename LruCacheSet::iterator findByKey(const TKey& key) {
|
typename LruCacheSet::iterator findByKey(const TKey& key) {
|
||||||
Entry entryForSearch(key, mNullValue);
|
EntryForSearch entryForSearch(key);
|
||||||
typename LruCacheSet::iterator result = mSet->find(&entryForSearch);
|
typename LruCacheSet::iterator result = mSet->find(&entryForSearch);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -124,11 +143,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
const TValue& value() const {
|
const TValue& value() const {
|
||||||
return (*mIterator)->value;
|
// All the elements in the set are of type Entry. See comment in the definition
|
||||||
|
// of LruCacheSet above.
|
||||||
|
return reinterpret_cast<Entry *>(*mIterator)->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TKey& key() const {
|
const TKey& key() const {
|
||||||
return (*mIterator)->key;
|
return (*mIterator)->getKey();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
const LruCache<TKey, TValue>& mCache;
|
const LruCache<TKey, TValue>& mCache;
|
||||||
|
|
@ -171,7 +192,9 @@ const TValue& LruCache<TKey, TValue>::get(const TKey& key) {
|
||||||
if (find_result == mSet->end()) {
|
if (find_result == mSet->end()) {
|
||||||
return mNullValue;
|
return mNullValue;
|
||||||
}
|
}
|
||||||
Entry *entry = *find_result;
|
// All the elements in the set are of type Entry. See comment in the definition
|
||||||
|
// of LruCacheSet above.
|
||||||
|
Entry *entry = reinterpret_cast<Entry*>(*find_result);
|
||||||
detachFromCache(*entry);
|
detachFromCache(*entry);
|
||||||
attachToCache(*entry);
|
attachToCache(*entry);
|
||||||
return entry->value;
|
return entry->value;
|
||||||
|
|
@ -199,7 +222,9 @@ bool LruCache<TKey, TValue>::remove(const TKey& key) {
|
||||||
if (find_result == mSet->end()) {
|
if (find_result == mSet->end()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Entry* entry = *find_result;
|
// All the elements in the set are of type Entry. See comment in the definition
|
||||||
|
// of LruCacheSet above.
|
||||||
|
Entry* entry = reinterpret_cast<Entry*>(*find_result);
|
||||||
mSet->erase(entry);
|
mSet->erase(entry);
|
||||||
if (mListener) {
|
if (mListener) {
|
||||||
(*mListener)(entry->key, entry->value);
|
(*mListener)(entry->key, entry->value);
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,14 @@ struct KeyWithPointer {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct KeyFailsOnCopy : public ComplexKey {
|
||||||
|
public:
|
||||||
|
KeyFailsOnCopy(const KeyFailsOnCopy& key) : ComplexKey(key) {
|
||||||
|
ADD_FAILURE();
|
||||||
|
}
|
||||||
|
KeyFailsOnCopy(int key) : ComplexKey(key) { }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -95,6 +103,10 @@ template<> inline android::hash_t hash_type(const KeyWithPointer& value) {
|
||||||
return hash_type(*value.ptr);
|
return hash_type(*value.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> inline android::hash_t hash_type(const KeyFailsOnCopy& value) {
|
||||||
|
return hash_type<ComplexKey>(value);
|
||||||
|
}
|
||||||
|
|
||||||
class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
|
class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
|
||||||
public:
|
public:
|
||||||
EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
|
EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
|
||||||
|
|
@ -437,4 +449,10 @@ TEST_F(LruCacheTest, RemoveNonMember) {
|
||||||
EXPECT_EQ(std::unordered_set<int>({ 4, 5, 6 }), returnedValues);
|
EXPECT_EQ(std::unordered_set<int>({ 4, 5, 6 }), returnedValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(LruCacheTest, DontCopyKeyInGet) {
|
||||||
|
LruCache<KeyFailsOnCopy, KeyFailsOnCopy> cache(1);
|
||||||
|
// Check that get doesn't copy the key
|
||||||
|
cache.get(KeyFailsOnCopy(0));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue