|  | // | 
|  | // 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); | 
|  | } | 
|  |  | 
|  | } |