Imported Upstream version 54.1
[platform/upstream/icu.git] / source / common / unifiedcache.h
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