1 /* 2 ****************************************************************************** 3 * Copyright (C) 2014, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ****************************************************************************** 6 * 7 * File UNIFIEDCACHE.H - The ICU Unified cache. 8 ****************************************************************************** 9 */ 10 11 #ifndef __UNIFIED_CACHE_H__ 12 #define __UNIFIED_CACHE_H__ 13 14 #include "utypeinfo.h" // for 'typeid' to work 15 16 #include "unicode/uobject.h" 17 #include "unicode/locid.h" 18 #include "sharedobject.h" 19 #include "unicode/unistr.h" 20 #include "cstring.h" 21 #include "ustr_imp.h" 22 23 struct UHashtable; 24 struct UHashElement; 25 26 U_NAMESPACE_BEGIN 27 28 class UnifiedCache; 29 30 /** 31 * A base class for all cache keys 32 */ 33 class U_COMMON_API CacheKeyBase : public UObject { 34 public: 35 CacheKeyBase() : creationStatus(U_ZERO_ERROR) {} 36 37 /** 38 * Copy constructor. Needed to support cloning. 39 */ 40 CacheKeyBase(const CacheKeyBase &other) 41 : UObject(other), creationStatus(other.creationStatus) { } 42 virtual ~CacheKeyBase(); 43 44 /** 45 * Returns the hash code for this object. 46 */ 47 virtual int32_t hashCode() const = 0; 48 49 /** 50 * Clones this object polymorphically. Caller owns returned value. 51 */ 52 virtual CacheKeyBase *clone() const = 0; 53 54 /** 55 * Equality operator. 56 */ 57 virtual UBool operator == (const CacheKeyBase &other) const = 0; 58 59 /** 60 * Create a new object for this key. Called by cache on cache miss. 61 * createObject must add a reference to the object it returns. Note 62 * that getting an object from the cache and returning it without calling 63 * removeRef on it satisfies this requirement. It can also return NULL 64 * and set status to an error. 65 * 66 * @param creationContext the context in which the object is being 67 * created. May be NULL. 68 * @param status Implementations can return a failure here. 69 * In addition, implementations may return a 70 * non NULL object and set a warning status. 71 */ 72 virtual const SharedObject *createObject( 73 const void *creationContext, UErrorCode &status) const = 0; 74 75 /** 76 * Writes a description of this key to buffer and returns buffer. Written 77 * description is NULL terminated. 78 */ 79 virtual char *writeDescription(char *buffer, int32_t bufSize) const = 0; 80 81 /** 82 * Inequality operator. 83 */ 84 UBool operator != (const CacheKeyBase &other) const { 85 return !(*this == other); 86 } 87 private: 88 mutable UErrorCode creationStatus; 89 friend class UnifiedCache; 90 }; 91 92 93 94 /** 95 * Templated version of CacheKeyBase. 96 * A key of type LocaleCacheKey<T> maps to a value of type T. 97 */ 98 template<typename T> 99 class CacheKey : public CacheKeyBase { 100 public: 101 virtual ~CacheKey() { } 102 /** 103 * The template parameter, T, determines the hash code returned. 104 */ 105 virtual int32_t hashCode() const { 106 const char *s = typeid(T).name(); 107 return ustr_hashCharsN(s, uprv_strlen(s)); 108 } 109 110 /** 111 * Use the value type, T, as the description. 112 */ 113 virtual char *writeDescription(char *buffer, int32_t bufLen) const { 114 const char *s = typeid(T).name(); 115 uprv_strncpy(buffer, s, bufLen); 116 buffer[bufLen - 1] = 0; 117 return buffer; 118 } 119 120 /** 121 * Two objects are equal if they are of the same type. 122 */ 123 virtual UBool operator == (const CacheKeyBase &other) const { 124 return typeid(*this) == typeid(other); 125 } 126 }; 127 128 /** 129 * Cache key based on locale. 130 * A key of type LocaleCacheKey<T> maps to a value of type T. 131 */ 132 template<typename T> 133 class LocaleCacheKey : public CacheKey<T> { 134 protected: 135 Locale fLoc; 136 public: 137 LocaleCacheKey(const Locale &loc) : fLoc(loc) {}; 138 LocaleCacheKey(const LocaleCacheKey<T> &other) 139 : CacheKey<T>(other), fLoc(other.fLoc) { } 140 virtual ~LocaleCacheKey() { } 141 virtual int32_t hashCode() const { 142 return 37 *CacheKey<T>::hashCode() + fLoc.hashCode(); 143 } 144 virtual UBool operator == (const CacheKeyBase &other) const { 145 // reflexive 146 if (this == &other) { 147 return TRUE; 148 } 149 if (!CacheKey<T>::operator == (other)) { 150 return FALSE; 151 } 152 // We know this and other are of same class because operator== on 153 // CacheKey returned true. 154 const LocaleCacheKey<T> *fOther = 155 static_cast<const LocaleCacheKey<T> *>(&other); 156 return fLoc == fOther->fLoc; 157 } 158 virtual CacheKeyBase *clone() const { 159 return new LocaleCacheKey<T>(*this); 160 } 161 virtual const T *createObject( 162 const void *creationContext, UErrorCode &status) const; 163 /** 164 * Use the locale id as the description. 165 */ 166 virtual char *writeDescription(char *buffer, int32_t bufLen) const { 167 const char *s = fLoc.getName(); 168 uprv_strncpy(buffer, s, bufLen); 169 buffer[bufLen - 1] = 0; 170 return buffer; 171 } 172 173 }; 174 175 /** 176 * The unified cache. A singleton type. 177 */ 178 class U_COMMON_API UnifiedCache : public UObject { 179 public: 180 /** 181 * @internal 182 */ 183 UnifiedCache(UErrorCode &status); 184 185 /** 186 * Returns the cache instance. 187 */ 188 static const UnifiedCache *getInstance(UErrorCode &status); 189 190 /** 191 * Fetches a value from the cache by key. Equivalent to 192 * get(key, NULL, ptr, status); 193 */ 194 template<typename T> 195 void get( 196 const CacheKey<T>& key, 197 const T *&ptr, 198 UErrorCode &status) const { 199 get(key, NULL, ptr, status); 200 } 201 202 /** 203 * Fetches value from the cache by key. 204 * 205 * @param key the cache key. 206 * @param creationContext passed verbatim to createObject method of key 207 * @param ptr On entry, ptr must be NULL or be included if 208 * the reference count of the object it points 209 * to. On exit, ptr points to the fetched object 210 * from the cache or is left unchanged on 211 * failure. Caller must call removeRef on ptr 212 * if set to a non NULL value. 213 * @param status Any error returned here. May be set to a 214 * warning value even if ptr is set. 215 */ 216 template<typename T> 217 void get( 218 const CacheKey<T>& key, 219 const void *creationContext, 220 const T *&ptr, 221 UErrorCode &status) const { 222 if (U_FAILURE(status)) { 223 return; 224 } 225 UErrorCode creationStatus = U_ZERO_ERROR; 226 const SharedObject *value = NULL; 227 _get(key, value, creationContext, creationStatus); 228 const T *tvalue = (const T *) value; 229 if (U_SUCCESS(creationStatus)) { 230 SharedObject::copyPtr(tvalue, ptr); 231 } 232 SharedObject::clearPtr(tvalue); 233 // Take care not to overwrite a warning status passed in with 234 // another warning or U_ZERO_ERROR. 235 if (status == U_ZERO_ERROR || U_FAILURE(creationStatus)) { 236 status = creationStatus; 237 } 238 } 239 240 #ifdef UNIFIED_CACHE_DEBUG 241 /** 242 * Dumps the contents of this cache to standard error. Used for testing of 243 * cache only. 244 */ 245 void dumpContents() const; 246 #endif 247 248 /** 249 * Convenience method to get a value of type T from cache for a 250 * particular locale with creationContext == NULL. 251 * @param loc the locale 252 * @param ptr On entry, must be NULL or included in the ref count 253 * of the object to which it points. 254 * On exit, fetched value stored here or is left 255 * unchanged on failure. Caller must call removeRef on 256 * ptr if set to a non NULL value. 257 * @param status Any error returned here. May be set to a 258 * warning value even if ptr is set. 259 */ 260 template<typename T> 261 static void getByLocale( 262 const Locale &loc, const T *&ptr, UErrorCode &status) { 263 const UnifiedCache *cache = getInstance(status); 264 if (U_FAILURE(status)) { 265 return; 266 } 267 cache->get(LocaleCacheKey<T>(loc), ptr, status); 268 } 269 270 #ifdef UNIFIED_CACHE_DEBUG 271 /** 272 * Dumps the cache contents to stderr. For testing only. 273 */ 274 static void dump(); 275 #endif 276 277 /** 278 * Returns the number of keys in this cache. For testing only. 279 */ 280 int32_t keyCount() const; 281 282 /** 283 * Removes any values from cache that are not referenced outside 284 * the cache. 285 */ 286 void flush() const; 287 288 virtual ~UnifiedCache(); 289 private: 290 UHashtable *fHashtable; 291 UnifiedCache(const UnifiedCache &other); 292 UnifiedCache &operator=(const UnifiedCache &other); 293 UBool _flush(UBool all) const; 294 void _get( 295 const CacheKeyBase &key, 296 const SharedObject *&value, 297 const void *creationContext, 298 UErrorCode &status) const; 299 UBool _poll( 300 const CacheKeyBase &key, 301 const SharedObject *&value, 302 UErrorCode &status) const; 303 void _putNew( 304 const CacheKeyBase &key, 305 const SharedObject *value, 306 const UErrorCode creationStatus, 307 UErrorCode &status) const; 308 void _putIfAbsentAndGet( 309 const CacheKeyBase &key, 310 const SharedObject *&value, 311 UErrorCode &status) const; 312 #ifdef UNIFIED_CACHE_DEBUG 313 void _dumpContents() const; 314 #endif 315 static void _put( 316 const UHashElement *element, 317 const SharedObject *value, 318 const UErrorCode status); 319 static void _fetch( 320 const UHashElement *element, 321 const SharedObject *&value, 322 UErrorCode &status); 323 static UBool _inProgress(const UHashElement *element); 324 }; 325 326 U_NAMESPACE_END 327 328 #endif 329