164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// Copyright (C) 2016 and later: Unicode, Inc. and others. 264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html 3f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius/* 4f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius****************************************************************************** 5c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert* Copyright (C) 2015, International Business Machines Corporation and 6f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius* others. All Rights Reserved. 7f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius****************************************************************************** 8f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius* 9f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius* File UNIFIEDCACHE.H - The ICU Unified cache. 10f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius****************************************************************************** 11f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius*/ 12f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 13f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#ifndef __UNIFIED_CACHE_H__ 14f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#define __UNIFIED_CACHE_H__ 15f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 16f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#include "utypeinfo.h" // for 'typeid' to work 17f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 18f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#include "unicode/uobject.h" 19f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#include "unicode/locid.h" 20f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#include "sharedobject.h" 21f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#include "unicode/unistr.h" 22f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#include "cstring.h" 23f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#include "ustr_imp.h" 24f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 25f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusstruct UHashtable; 26f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusstruct UHashElement; 27f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 28f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_NAMESPACE_BEGIN 29f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 30f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusclass UnifiedCache; 31f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 32f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius/** 33c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * A base class for all cache keys. 34f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 35f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusclass U_COMMON_API CacheKeyBase : public UObject { 36f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius public: 37c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert CacheKeyBase() : fCreationStatus(U_ZERO_ERROR), fIsMaster(FALSE) {} 38f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 39f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 40f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Copy constructor. Needed to support cloning. 41f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 42f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius CacheKeyBase(const CacheKeyBase &other) 43c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert : UObject(other), fCreationStatus(other.fCreationStatus), fIsMaster(FALSE) { } 44f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual ~CacheKeyBase(); 45f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 46f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 47f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Returns the hash code for this object. 48f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 49f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual int32_t hashCode() const = 0; 50f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 51f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 52f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Clones this object polymorphically. Caller owns returned value. 53f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 54f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual CacheKeyBase *clone() const = 0; 55f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 56f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 57f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Equality operator. 58f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 59f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual UBool operator == (const CacheKeyBase &other) const = 0; 60f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 61f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 62f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Create a new object for this key. Called by cache on cache miss. 63f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * createObject must add a reference to the object it returns. Note 64f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * that getting an object from the cache and returning it without calling 65f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * removeRef on it satisfies this requirement. It can also return NULL 66f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * and set status to an error. 67f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * 68f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * @param creationContext the context in which the object is being 69f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * created. May be NULL. 70f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * @param status Implementations can return a failure here. 71f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * In addition, implementations may return a 72f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * non NULL object and set a warning status. 73f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 74f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual const SharedObject *createObject( 75f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const void *creationContext, UErrorCode &status) const = 0; 76f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 77f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 78f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Writes a description of this key to buffer and returns buffer. Written 79f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * description is NULL terminated. 80f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 81f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual char *writeDescription(char *buffer, int32_t bufSize) const = 0; 82f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 83f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 84f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Inequality operator. 85f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 86f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UBool operator != (const CacheKeyBase &other) const { 87f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return !(*this == other); 88f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 89f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius private: 90c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert mutable UErrorCode fCreationStatus; 91c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert mutable UBool fIsMaster; 92f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius friend class UnifiedCache; 93f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}; 94f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 95f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 96f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 97f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius/** 98f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Templated version of CacheKeyBase. 99f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * A key of type LocaleCacheKey<T> maps to a value of type T. 100f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 101f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliustemplate<typename T> 102f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusclass CacheKey : public CacheKeyBase { 103f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius public: 104f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual ~CacheKey() { } 105f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 106f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * The template parameter, T, determines the hash code returned. 107f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 108f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual int32_t hashCode() const { 109f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const char *s = typeid(T).name(); 110f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return ustr_hashCharsN(s, uprv_strlen(s)); 111f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 112f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 113f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 114f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Use the value type, T, as the description. 115f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 116f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual char *writeDescription(char *buffer, int32_t bufLen) const { 117f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const char *s = typeid(T).name(); 118f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius uprv_strncpy(buffer, s, bufLen); 119f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius buffer[bufLen - 1] = 0; 120f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return buffer; 121f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 122f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 123f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 124f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Two objects are equal if they are of the same type. 125f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 126f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual UBool operator == (const CacheKeyBase &other) const { 127f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return typeid(*this) == typeid(other); 128f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 129f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}; 130f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 131f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius/** 132f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Cache key based on locale. 133f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * A key of type LocaleCacheKey<T> maps to a value of type T. 134f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 135f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliustemplate<typename T> 136f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusclass LocaleCacheKey : public CacheKey<T> { 137f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius protected: 138f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius Locale fLoc; 139f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius public: 140f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius LocaleCacheKey(const Locale &loc) : fLoc(loc) {}; 141f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius LocaleCacheKey(const LocaleCacheKey<T> &other) 142f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius : CacheKey<T>(other), fLoc(other.fLoc) { } 143f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual ~LocaleCacheKey() { } 144f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual int32_t hashCode() const { 14564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert return (int32_t)(37u * (uint32_t)CacheKey<T>::hashCode() + (uint32_t)fLoc.hashCode()); 146f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 147f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual UBool operator == (const CacheKeyBase &other) const { 148f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius // reflexive 149f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if (this == &other) { 150f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return TRUE; 151f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 152f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if (!CacheKey<T>::operator == (other)) { 153f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return FALSE; 154f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 155f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius // We know this and other are of same class because operator== on 156f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius // CacheKey returned true. 157f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const LocaleCacheKey<T> *fOther = 158f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius static_cast<const LocaleCacheKey<T> *>(&other); 159f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return fLoc == fOther->fLoc; 160f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 161f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual CacheKeyBase *clone() const { 162f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return new LocaleCacheKey<T>(*this); 163f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 164f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual const T *createObject( 165f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const void *creationContext, UErrorCode &status) const; 166f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 167f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Use the locale id as the description. 168f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 169f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual char *writeDescription(char *buffer, int32_t bufLen) const { 170f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const char *s = fLoc.getName(); 171f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius uprv_strncpy(buffer, s, bufLen); 172f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius buffer[bufLen - 1] = 0; 173f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return buffer; 174f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 175f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 176f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}; 177f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 178f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius/** 179f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * The unified cache. A singleton type. 180c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Design doc here: 181c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * https://docs.google.com/document/d/1RwGQJs4N4tawNbf809iYDRCvXoMKqDJihxzYt1ysmd8/edit?usp=sharing 182f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 183c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubertclass U_COMMON_API UnifiedCache : public UnifiedCacheBase { 184f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius public: 185f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 186f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * @internal 187c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Do not call directly. Instead use UnifiedCache::getInstance() as 188c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * there should be only one UnifiedCache in an application. 189f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 190f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UnifiedCache(UErrorCode &status); 191f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 192f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 193f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Returns the cache instance. 194f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 195c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert static UnifiedCache *getInstance(UErrorCode &status); 196f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 197f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 198f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Fetches a value from the cache by key. Equivalent to 199f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * get(key, NULL, ptr, status); 200f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 201f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius template<typename T> 202f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius void get( 203f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const CacheKey<T>& key, 204f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const T *&ptr, 205f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UErrorCode &status) const { 206f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius get(key, NULL, ptr, status); 207f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 208f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 209f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 210f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Fetches value from the cache by key. 211f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * 212f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * @param key the cache key. 213f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * @param creationContext passed verbatim to createObject method of key 214f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * @param ptr On entry, ptr must be NULL or be included if 215f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * the reference count of the object it points 216f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * to. On exit, ptr points to the fetched object 217f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * from the cache or is left unchanged on 218f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * failure. Caller must call removeRef on ptr 219f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * if set to a non NULL value. 220f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * @param status Any error returned here. May be set to a 221f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * warning value even if ptr is set. 222f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 223f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius template<typename T> 224f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius void get( 225f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const CacheKey<T>& key, 226f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const void *creationContext, 227f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const T *&ptr, 228f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UErrorCode &status) const { 229f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if (U_FAILURE(status)) { 230f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return; 231f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 232f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UErrorCode creationStatus = U_ZERO_ERROR; 233f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const SharedObject *value = NULL; 234f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius _get(key, value, creationContext, creationStatus); 235f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const T *tvalue = (const T *) value; 236f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if (U_SUCCESS(creationStatus)) { 237f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius SharedObject::copyPtr(tvalue, ptr); 238f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 239f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius SharedObject::clearPtr(tvalue); 240f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius // Take care not to overwrite a warning status passed in with 241f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius // another warning or U_ZERO_ERROR. 242f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if (status == U_ZERO_ERROR || U_FAILURE(creationStatus)) { 243f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius status = creationStatus; 244f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 245f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 246f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 247f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#ifdef UNIFIED_CACHE_DEBUG 248f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 249f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Dumps the contents of this cache to standard error. Used for testing of 250f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * cache only. 251f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 252f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius void dumpContents() const; 253f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#endif 254f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 255f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 256f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Convenience method to get a value of type T from cache for a 257f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * particular locale with creationContext == NULL. 258f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * @param loc the locale 259f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * @param ptr On entry, must be NULL or included in the ref count 260f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * of the object to which it points. 261f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * On exit, fetched value stored here or is left 262f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * unchanged on failure. Caller must call removeRef on 263f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * ptr if set to a non NULL value. 264f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * @param status Any error returned here. May be set to a 265f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * warning value even if ptr is set. 266f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 267f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius template<typename T> 268f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius static void getByLocale( 269f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const Locale &loc, const T *&ptr, UErrorCode &status) { 270f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const UnifiedCache *cache = getInstance(status); 271f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if (U_FAILURE(status)) { 272f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return; 273f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 274f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius cache->get(LocaleCacheKey<T>(loc), ptr, status); 275f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 276f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 277f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#ifdef UNIFIED_CACHE_DEBUG 278f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 279f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Dumps the cache contents to stderr. For testing only. 280f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 281f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius static void dump(); 282f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#endif 283f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 284f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 285f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Returns the number of keys in this cache. For testing only. 286f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 287f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius int32_t keyCount() const; 288f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 289f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius /** 290f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Removes any values from cache that are not referenced outside 291f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * the cache. 292f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius */ 293f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius void flush() const; 294f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 295c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert /** 296c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Configures at what point evcition of unused entries will begin. 297c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Eviction is triggered whenever the number of unused entries exeeds 298c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * BOTH count AND (number of in-use items) * (percentageOfInUseItems / 100). 299c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Once the number of unused entries drops below one of these, 300c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * eviction ceases. Because eviction happens incrementally, 301c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * the actual unused entry count may exceed both these numbers 302c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * from time to time. 303c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * 304c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * A cache entry is defined as unused if it is not essential to guarantee 305c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * that for a given key X, the cache returns the same reference to the 306c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * same value as long as the client already holds a reference to that 307c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * value. 308c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * 309c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * If this method is never called, the default settings are 1000 and 100%. 310c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * 311c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Although this method is thread-safe, it is designed to be called at 312c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * application startup. If it is called in the middle of execution, it 313c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * will have no immediate effect on the cache. However over time, the 314c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * cache will perform eviction slices in an attempt to honor the new 315c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * settings. 316c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * 317c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * If a client already holds references to many different unique values 318c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * in the cache such that the number of those unique values far exeeds 319c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * "count" then the cache may not be able to maintain this maximum. 320c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * However, if this happens, the cache still guarantees that the number of 321c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * unused entries will remain only a small percentage of the total cache 322c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * size. 323c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * 324c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * If the parameters passed are negative, setEvctionPolicy sets status to 325c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * U_ILLEGAL_ARGUMENT_ERROR. 326c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert */ 327c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert void setEvictionPolicy( 328c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert int32_t count, int32_t percentageOfInUseItems, UErrorCode &status); 329c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert 330c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert 331c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert /** 332c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Returns how many entries have been auto evicted during the lifetime 333c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * of this cache. This only includes auto evicted entries, not 334c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * entries evicted because of a call to flush(). 335c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert */ 336c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert int64_t autoEvictedCount() const; 337c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert 338c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert /** 339c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Returns the unused entry count in this cache. For testing only, 340c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert * Regular clients will not need this. 341c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert */ 342c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert int32_t unusedCount() const; 343c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert 344c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert virtual void incrementItemsInUse() const; 345c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert virtual void decrementItemsInUseWithLockingAndEviction() const; 346c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert virtual void decrementItemsInUse() const; 347f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius virtual ~UnifiedCache(); 348f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius private: 349f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UHashtable *fHashtable; 350c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert mutable int32_t fEvictPos; 351c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert mutable int32_t fItemsInUseCount; 352c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert int32_t fMaxUnused; 353c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert int32_t fMaxPercentageOfInUse; 354c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert mutable int64_t fAutoEvictedCount; 355f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UnifiedCache(const UnifiedCache &other); 356f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UnifiedCache &operator=(const UnifiedCache &other); 357f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UBool _flush(UBool all) const; 358f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius void _get( 359f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const CacheKeyBase &key, 360f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const SharedObject *&value, 361f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const void *creationContext, 362f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UErrorCode &status) const; 363f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UBool _poll( 364f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const CacheKeyBase &key, 365f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const SharedObject *&value, 366f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UErrorCode &status) const; 367f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius void _putNew( 368f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const CacheKeyBase &key, 369f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const SharedObject *value, 370f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const UErrorCode creationStatus, 371f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UErrorCode &status) const; 372f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius void _putIfAbsentAndGet( 373f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const CacheKeyBase &key, 374f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const SharedObject *&value, 375f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UErrorCode &status) const; 376c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert const UHashElement *_nextElement() const; 377c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert int32_t _computeCountOfItemsToEvict() const; 378c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert void _runEvictionSlice() const; 379c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert void _registerMaster( 380c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert const CacheKeyBase *theKey, const SharedObject *value) const; 381c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert void _put( 382c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert const UHashElement *element, 383c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert const SharedObject *value, 384c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert const UErrorCode status) const; 385f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#ifdef UNIFIED_CACHE_DEBUG 386f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius void _dumpContents() const; 387f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#endif 388c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert static void copyPtr(const SharedObject *src, const SharedObject *&dest); 389c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert static void clearPtr(const SharedObject *&ptr); 390f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius static void _fetch( 391f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const UHashElement *element, 392f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const SharedObject *&value, 393f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius UErrorCode &status); 394f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius static UBool _inProgress(const UHashElement *element); 395c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert static UBool _inProgress( 396c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert const SharedObject *theValue, UErrorCode creationStatus); 397c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert static UBool _isEvictable(const UHashElement *element); 398f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}; 399f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 400f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_NAMESPACE_END 401f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 402f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#endif 403