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