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