1*d57664e9SAndroid Build Coastguard Worker //
2*d57664e9SAndroid Build Coastguard Worker // Copyright 2012 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker //
4*d57664e9SAndroid Build Coastguard Worker // Manage a resource ID cache.
5*d57664e9SAndroid Build Coastguard Worker
6*d57664e9SAndroid Build Coastguard Worker #define LOG_TAG "ResourceIdCache"
7*d57664e9SAndroid Build Coastguard Worker
8*d57664e9SAndroid Build Coastguard Worker #include <utils/String16.h>
9*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
10*d57664e9SAndroid Build Coastguard Worker #include "ResourceIdCache.h"
11*d57664e9SAndroid Build Coastguard Worker #include <map>
12*d57664e9SAndroid Build Coastguard Worker
13*d57664e9SAndroid Build Coastguard Worker static size_t mHits = 0;
14*d57664e9SAndroid Build Coastguard Worker static size_t mMisses = 0;
15*d57664e9SAndroid Build Coastguard Worker static size_t mCollisions = 0;
16*d57664e9SAndroid Build Coastguard Worker
17*d57664e9SAndroid Build Coastguard Worker static const size_t MAX_CACHE_ENTRIES = 2048;
18*d57664e9SAndroid Build Coastguard Worker static const android::String16 TRUE16("1");
19*d57664e9SAndroid Build Coastguard Worker static const android::String16 FALSE16("0");
20*d57664e9SAndroid Build Coastguard Worker
21*d57664e9SAndroid Build Coastguard Worker struct CacheEntry {
22*d57664e9SAndroid Build Coastguard Worker // concatenation of the relevant strings into a single instance
23*d57664e9SAndroid Build Coastguard Worker android::String16 hashedName;
24*d57664e9SAndroid Build Coastguard Worker uint32_t id;
25*d57664e9SAndroid Build Coastguard Worker
CacheEntryCacheEntry26*d57664e9SAndroid Build Coastguard Worker CacheEntry() {}
CacheEntryCacheEntry27*d57664e9SAndroid Build Coastguard Worker CacheEntry(const android::String16& name, uint32_t resId) : hashedName(name), id(resId) { }
28*d57664e9SAndroid Build Coastguard Worker };
29*d57664e9SAndroid Build Coastguard Worker
30*d57664e9SAndroid Build Coastguard Worker static std::map< uint32_t, CacheEntry > mIdMap;
31*d57664e9SAndroid Build Coastguard Worker
32*d57664e9SAndroid Build Coastguard Worker
33*d57664e9SAndroid Build Coastguard Worker // djb2; reasonable choice for strings when collisions aren't particularly important
hashround(uint32_t hash,int c)34*d57664e9SAndroid Build Coastguard Worker static inline uint32_t hashround(uint32_t hash, int c) {
35*d57664e9SAndroid Build Coastguard Worker return ((hash << 5) + hash) + c; /* hash * 33 + c */
36*d57664e9SAndroid Build Coastguard Worker }
37*d57664e9SAndroid Build Coastguard Worker
hash(const android::String16 & hashableString)38*d57664e9SAndroid Build Coastguard Worker static uint32_t hash(const android::String16& hashableString) {
39*d57664e9SAndroid Build Coastguard Worker uint32_t hash = 5381;
40*d57664e9SAndroid Build Coastguard Worker const char16_t* str = hashableString.c_str();
41*d57664e9SAndroid Build Coastguard Worker while (int c = *str++) hash = hashround(hash, c);
42*d57664e9SAndroid Build Coastguard Worker return hash;
43*d57664e9SAndroid Build Coastguard Worker }
44*d57664e9SAndroid Build Coastguard Worker
45*d57664e9SAndroid Build Coastguard Worker namespace android {
46*d57664e9SAndroid Build Coastguard Worker
makeHashableName(const android::String16 & package,const android::String16 & type,const android::String16 & name,bool onlyPublic)47*d57664e9SAndroid Build Coastguard Worker static inline String16 makeHashableName(const android::String16& package,
48*d57664e9SAndroid Build Coastguard Worker const android::String16& type,
49*d57664e9SAndroid Build Coastguard Worker const android::String16& name,
50*d57664e9SAndroid Build Coastguard Worker bool onlyPublic) {
51*d57664e9SAndroid Build Coastguard Worker String16 hashable = String16(name);
52*d57664e9SAndroid Build Coastguard Worker hashable += type;
53*d57664e9SAndroid Build Coastguard Worker hashable += package;
54*d57664e9SAndroid Build Coastguard Worker hashable += (onlyPublic ? TRUE16 : FALSE16);
55*d57664e9SAndroid Build Coastguard Worker return hashable;
56*d57664e9SAndroid Build Coastguard Worker }
57*d57664e9SAndroid Build Coastguard Worker
lookup(const android::String16 & package,const android::String16 & type,const android::String16 & name,bool onlyPublic)58*d57664e9SAndroid Build Coastguard Worker uint32_t ResourceIdCache::lookup(const android::String16& package,
59*d57664e9SAndroid Build Coastguard Worker const android::String16& type,
60*d57664e9SAndroid Build Coastguard Worker const android::String16& name,
61*d57664e9SAndroid Build Coastguard Worker bool onlyPublic) {
62*d57664e9SAndroid Build Coastguard Worker const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
63*d57664e9SAndroid Build Coastguard Worker const uint32_t hashcode = hash(hashedName);
64*d57664e9SAndroid Build Coastguard Worker std::map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode);
65*d57664e9SAndroid Build Coastguard Worker if (item == mIdMap.end()) {
66*d57664e9SAndroid Build Coastguard Worker // cache miss
67*d57664e9SAndroid Build Coastguard Worker mMisses++;
68*d57664e9SAndroid Build Coastguard Worker return 0;
69*d57664e9SAndroid Build Coastguard Worker }
70*d57664e9SAndroid Build Coastguard Worker
71*d57664e9SAndroid Build Coastguard Worker // legit match?
72*d57664e9SAndroid Build Coastguard Worker if (hashedName == (*item).second.hashedName) {
73*d57664e9SAndroid Build Coastguard Worker mHits++;
74*d57664e9SAndroid Build Coastguard Worker return (*item).second.id;
75*d57664e9SAndroid Build Coastguard Worker }
76*d57664e9SAndroid Build Coastguard Worker
77*d57664e9SAndroid Build Coastguard Worker // collision
78*d57664e9SAndroid Build Coastguard Worker mCollisions++;
79*d57664e9SAndroid Build Coastguard Worker mIdMap.erase(hashcode);
80*d57664e9SAndroid Build Coastguard Worker return 0;
81*d57664e9SAndroid Build Coastguard Worker }
82*d57664e9SAndroid Build Coastguard Worker
83*d57664e9SAndroid Build Coastguard Worker // returns the resource ID being stored, for callsite convenience
store(const android::String16 & package,const android::String16 & type,const android::String16 & name,bool onlyPublic,uint32_t resId)84*d57664e9SAndroid Build Coastguard Worker uint32_t ResourceIdCache::store(const android::String16& package,
85*d57664e9SAndroid Build Coastguard Worker const android::String16& type,
86*d57664e9SAndroid Build Coastguard Worker const android::String16& name,
87*d57664e9SAndroid Build Coastguard Worker bool onlyPublic,
88*d57664e9SAndroid Build Coastguard Worker uint32_t resId) {
89*d57664e9SAndroid Build Coastguard Worker if (mIdMap.size() < MAX_CACHE_ENTRIES) {
90*d57664e9SAndroid Build Coastguard Worker const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
91*d57664e9SAndroid Build Coastguard Worker const uint32_t hashcode = hash(hashedName);
92*d57664e9SAndroid Build Coastguard Worker mIdMap[hashcode] = CacheEntry(hashedName, resId);
93*d57664e9SAndroid Build Coastguard Worker }
94*d57664e9SAndroid Build Coastguard Worker return resId;
95*d57664e9SAndroid Build Coastguard Worker }
96*d57664e9SAndroid Build Coastguard Worker
dump()97*d57664e9SAndroid Build Coastguard Worker void ResourceIdCache::dump() {
98*d57664e9SAndroid Build Coastguard Worker printf("ResourceIdCache dump:\n");
99*d57664e9SAndroid Build Coastguard Worker printf("Size: %zd\n", mIdMap.size());
100*d57664e9SAndroid Build Coastguard Worker printf("Hits: %zd\n", mHits);
101*d57664e9SAndroid Build Coastguard Worker printf("Misses: %zd\n", mMisses);
102*d57664e9SAndroid Build Coastguard Worker printf("(Collisions: %zd)\n", mCollisions);
103*d57664e9SAndroid Build Coastguard Worker }
104*d57664e9SAndroid Build Coastguard Worker
105*d57664e9SAndroid Build Coastguard Worker }
106