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