// // Copyright 2012 The Android Open Source Project // // Manage a resource ID cache. #define LOG_TAG "ResourceIdCache" #include <utils/String16.h> #include <utils/Log.h> #include "ResourceIdCache.h" #include <map> static size_t mHits = 0; static size_t mMisses = 0; static size_t mCollisions = 0; static const size_t MAX_CACHE_ENTRIES = 2048; static const android::String16 TRUE16("1"); static const android::String16 FALSE16("0"); struct CacheEntry { // concatenation of the relevant strings into a single instance android::String16 hashedName; uint32_t id; CacheEntry() {} CacheEntry(const android::String16& name, uint32_t resId) : hashedName(name), id(resId) { } }; static std::map< uint32_t, CacheEntry > mIdMap; // djb2; reasonable choice for strings when collisions aren't particularly important static inline uint32_t hashround(uint32_t hash, int c) { return ((hash << 5) + hash) + c; /* hash * 33 + c */ } static uint32_t hash(const android::String16& hashableString) { uint32_t hash = 5381; const char16_t* str = hashableString.string(); while (int c = *str++) hash = hashround(hash, c); return hash; } namespace android { static inline String16 makeHashableName(const android::String16& package, const android::String16& type, const android::String16& name, bool onlyPublic) { String16 hashable = String16(name); hashable += type; hashable += package; hashable += (onlyPublic ? TRUE16 : FALSE16); return hashable; } uint32_t ResourceIdCache::lookup(const android::String16& package, const android::String16& type, const android::String16& name, bool onlyPublic) { const String16 hashedName = makeHashableName(package, type, name, onlyPublic); const uint32_t hashcode = hash(hashedName); std::map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode); if (item == mIdMap.end()) { // cache miss mMisses++; return 0; } // legit match? if (hashedName == (*item).second.hashedName) { mHits++; return (*item).second.id; } // collision mCollisions++; mIdMap.erase(hashcode); return 0; } // returns the resource ID being stored, for callsite convenience uint32_t ResourceIdCache::store(const android::String16& package, const android::String16& type, const android::String16& name, bool onlyPublic, uint32_t resId) { if (mIdMap.size() < MAX_CACHE_ENTRIES) { const String16 hashedName = makeHashableName(package, type, name, onlyPublic); const uint32_t hashcode = hash(hashedName); mIdMap[hashcode] = CacheEntry(hashedName, resId); } return resId; } void ResourceIdCache::dump() { printf("ResourceIdCache dump:\n"); printf("Size: %zd\n", mIdMap.size()); printf("Hits: %zd\n", mHits); printf("Misses: %zd\n", mMisses); printf("(Collisions: %zd)\n", mCollisions); } }