/src/icu/source/common/unifiedcache.h
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | // © 2016 and later: Unicode, Inc. and others.  | 
2  |  | // License & terms of use: http://www.unicode.org/copyright.html  | 
3  |  | /*  | 
4  |  | ******************************************************************************  | 
5  |  | * Copyright (C) 2015, International Business Machines Corporation and  | 
6  |  | * others. All Rights Reserved.  | 
7  |  | ******************************************************************************  | 
8  |  | *  | 
9  |  | * File UNIFIEDCACHE.H - The ICU Unified cache.  | 
10  |  | ******************************************************************************  | 
11  |  | */  | 
12  |  |  | 
13  |  | #ifndef __UNIFIED_CACHE_H__  | 
14  |  | #define __UNIFIED_CACHE_H__  | 
15  |  |  | 
16  |  | #include <type_traits>  | 
17  |  |  | 
18  |  | #include "utypeinfo.h"  // for 'typeid' to work  | 
19  |  |  | 
20  |  | #include "unicode/uobject.h"  | 
21  |  | #include "unicode/locid.h"  | 
22  |  | #include "sharedobject.h"  | 
23  |  | #include "unicode/unistr.h"  | 
24  |  | #include "cstring.h"  | 
25  |  | #include "ustr_imp.h"  | 
26  |  |  | 
27  |  | struct UHashtable;  | 
28  |  | struct UHashElement;  | 
29  |  |  | 
30  |  | U_NAMESPACE_BEGIN  | 
31  |  |  | 
32  |  | class UnifiedCache;  | 
33  |  |  | 
34  |  | /**  | 
35  |  |  * A base class for all cache keys.  | 
36  |  |  */  | 
37  |  | class U_COMMON_API CacheKeyBase : public UObject { | 
38  |  |  public:  | 
39  | 0  |    CacheKeyBase() : fCreationStatus(U_ZERO_ERROR), fIsPrimary(false) {} | 
40  |  |  | 
41  |  |    /**  | 
42  |  |     * Copy constructor. Needed to support cloning.  | 
43  |  |     */  | 
44  |  |    CacheKeyBase(const CacheKeyBase &other)   | 
45  | 0  |            : UObject(other), fCreationStatus(other.fCreationStatus), fIsPrimary(false) { } | 
46  |  |    virtual ~CacheKeyBase();  | 
47  |  |  | 
48  |  |    /**  | 
49  |  |     * Returns the hash code for this object.  | 
50  |  |     */  | 
51  |  |    virtual int32_t hashCode() const = 0;  | 
52  |  |  | 
53  |  |    /**  | 
54  |  |     * Clones this object polymorphically. Caller owns returned value.  | 
55  |  |     */  | 
56  |  |    virtual CacheKeyBase *clone() const = 0;  | 
57  |  |  | 
58  |  |    /**  | 
59  |  |     * Equality operator.  | 
60  |  |     */  | 
61  |  |    virtual bool operator == (const CacheKeyBase &other) const = 0;  | 
62  |  |  | 
63  |  |    /**  | 
64  |  |     * Create a new object for this key. Called by cache on cache miss.  | 
65  |  |     * createObject must add a reference to the object it returns. Note  | 
66  |  |     * that getting an object from the cache and returning it without calling  | 
67  |  |     * removeRef on it satisfies this requirement. It can also return NULL  | 
68  |  |     * and set status to an error.  | 
69  |  |     *  | 
70  |  |     * @param creationContext the context in which the object is being  | 
71  |  |     *                        created. May be NULL.  | 
72  |  |     * @param status          Implementations can return a failure here.  | 
73  |  |     *                        In addition, implementations may return a  | 
74  |  |     *                        non NULL object and set a warning status.  | 
75  |  |     */  | 
76  |  |    virtual const SharedObject *createObject(  | 
77  |  |            const void *creationContext, UErrorCode &status) const = 0;  | 
78  |  |  | 
79  |  |    /**  | 
80  |  |     * Writes a description of this key to buffer and returns buffer. Written  | 
81  |  |     * description is NULL terminated.  | 
82  |  |     */  | 
83  |  |    virtual char *writeDescription(char *buffer, int32_t bufSize) const = 0;  | 
84  |  |  | 
85  |  |    /**  | 
86  |  |     * Inequality operator.  | 
87  |  |     */  | 
88  | 0  |    bool operator != (const CacheKeyBase &other) const { | 
89  | 0  |        return !(*this == other);  | 
90  | 0  |    }  | 
91  |  |  private:  | 
92  |  |    mutable UErrorCode fCreationStatus;  | 
93  |  |    mutable UBool fIsPrimary;  | 
94  |  |    friend class UnifiedCache;  | 
95  |  | };  | 
96  |  |  | 
97  |  |  | 
98  |  |  | 
99  |  | /**  | 
100  |  |  * Templated version of CacheKeyBase.   | 
101  |  |  * A key of type LocaleCacheKey<T> maps to a value of type T.  | 
102  |  |  */  | 
103  |  | template<typename T>  | 
104  |  | class CacheKey : public CacheKeyBase { | 
105  |  |  public:  | 
106  |  |    virtual ~CacheKey() { } | 
107  |  |    /**  | 
108  |  |     * The template parameter, T, determines the hash code returned.  | 
109  |  |     */  | 
110  | 0  |    virtual int32_t hashCode() const { | 
111  | 0  |        const char *s = typeid(T).name();  | 
112  | 0  |        return ustr_hashCharsN(s, static_cast<int32_t>(uprv_strlen(s)));  | 
113  | 0  |    } Unexecuted instantiation: icu_70::CacheKey<icu_70::CollationCacheEntry>::hashCode() const Unexecuted instantiation: icu_70::CacheKey<icu_70::DateFmtBestPattern>::hashCode() const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedDateFormatSymbols>::hashCode() const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedCalendar>::hashCode() const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedNumberFormat>::hashCode() const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedPluralRules>::hashCode() const  | 
114  |  |  | 
115  |  |    /**  | 
116  |  |     * Use the value type, T,  as the description.  | 
117  |  |     */  | 
118  | 0  |    virtual char *writeDescription(char *buffer, int32_t bufLen) const { | 
119  | 0  |        const char *s = typeid(T).name();  | 
120  | 0  |        uprv_strncpy(buffer, s, bufLen);  | 
121  | 0  |        buffer[bufLen - 1] = 0;  | 
122  | 0  |        return buffer;  | 
123  | 0  |    } Unexecuted instantiation: icu_70::CacheKey<icu_70::CollationCacheEntry>::writeDescription(char*, int) const Unexecuted instantiation: icu_70::CacheKey<icu_70::DateFmtBestPattern>::writeDescription(char*, int) const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedDateFormatSymbols>::writeDescription(char*, int) const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedCalendar>::writeDescription(char*, int) const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedNumberFormat>::writeDescription(char*, int) const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedPluralRules>::writeDescription(char*, int) const  | 
124  |  |  | 
125  |  |    /**  | 
126  |  |     * Two objects are equal if they are of the same type.  | 
127  |  |     */  | 
128  | 0  |    virtual bool operator == (const CacheKeyBase &other) const { | 
129  | 0  |        return typeid(*this) == typeid(other);  | 
130  | 0  |    } Unexecuted instantiation: icu_70::CacheKey<icu_70::CollationCacheEntry>::operator==(icu_70::CacheKeyBase const&) const Unexecuted instantiation: icu_70::CacheKey<icu_70::DateFmtBestPattern>::operator==(icu_70::CacheKeyBase const&) const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedDateFormatSymbols>::operator==(icu_70::CacheKeyBase const&) const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedCalendar>::operator==(icu_70::CacheKeyBase const&) const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedNumberFormat>::operator==(icu_70::CacheKeyBase const&) const Unexecuted instantiation: icu_70::CacheKey<icu_70::SharedPluralRules>::operator==(icu_70::CacheKeyBase const&) const  | 
131  |  | };  | 
132  |  |  | 
133  |  | /**  | 
134  |  |  * Cache key based on locale.  | 
135  |  |  * A key of type LocaleCacheKey<T> maps to a value of type T.  | 
136  |  |  */  | 
137  |  | template<typename T>  | 
138  |  | class LocaleCacheKey : public CacheKey<T> { | 
139  |  |  protected:  | 
140  |  |    Locale   fLoc;  | 
141  |  |  public:  | 
142  | 0  |    LocaleCacheKey(const Locale &loc) : fLoc(loc) {}Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::CollationCacheEntry>::LocaleCacheKey(icu_70::Locale const&) Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::DateFmtBestPattern>::LocaleCacheKey(icu_70::Locale const&) Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedDateFormatSymbols>::LocaleCacheKey(icu_70::Locale const&) Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedCalendar>::LocaleCacheKey(icu_70::Locale const&) Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedNumberFormat>::LocaleCacheKey(icu_70::Locale const&) Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedPluralRules>::LocaleCacheKey(icu_70::Locale const&)  | 
143  |  |    LocaleCacheKey(const LocaleCacheKey<T> &other)  | 
144  | 0  |            : CacheKey<T>(other), fLoc(other.fLoc) { }Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::CollationCacheEntry>::LocaleCacheKey(icu_70::LocaleCacheKey<icu_70::CollationCacheEntry> const&) Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::DateFmtBestPattern>::LocaleCacheKey(icu_70::LocaleCacheKey<icu_70::DateFmtBestPattern> const&) Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedDateFormatSymbols>::LocaleCacheKey(icu_70::LocaleCacheKey<icu_70::SharedDateFormatSymbols> const&) Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedCalendar>::LocaleCacheKey(icu_70::LocaleCacheKey<icu_70::SharedCalendar> const&) Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedNumberFormat>::LocaleCacheKey(icu_70::LocaleCacheKey<icu_70::SharedNumberFormat> const&) Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedPluralRules>::LocaleCacheKey(icu_70::LocaleCacheKey<icu_70::SharedPluralRules> const&)  | 
145  | 0  |    virtual ~LocaleCacheKey() { }Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::CollationCacheEntry>::~LocaleCacheKey() Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::DateFmtBestPattern>::~LocaleCacheKey() Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedDateFormatSymbols>::~LocaleCacheKey() Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedCalendar>::~LocaleCacheKey() Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedNumberFormat>::~LocaleCacheKey() Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedPluralRules>::~LocaleCacheKey()  | 
146  | 0  |    virtual int32_t hashCode() const { | 
147  | 0  |        return (int32_t)(37u * (uint32_t)CacheKey<T>::hashCode() + (uint32_t)fLoc.hashCode());  | 
148  | 0  |    } Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::CollationCacheEntry>::hashCode() const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::DateFmtBestPattern>::hashCode() const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedDateFormatSymbols>::hashCode() const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedCalendar>::hashCode() const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedNumberFormat>::hashCode() const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedPluralRules>::hashCode() const  | 
149  | 0  |    virtual bool operator == (const CacheKeyBase &other) const { | 
150  |  |        // reflexive  | 
151  | 0  |        if (this == &other) { | 
152  | 0  |            return true;  | 
153  | 0  |        }  | 
154  | 0  |        if (!CacheKey<T>::operator == (other)) { | 
155  | 0  |            return false;  | 
156  | 0  |        }  | 
157  |  |        // We know this and other are of same class because operator== on  | 
158  |  |        // CacheKey returned true.  | 
159  | 0  |        const LocaleCacheKey<T> *fOther =  | 
160  | 0  |                static_cast<const LocaleCacheKey<T> *>(&other);  | 
161  | 0  |        return fLoc == fOther->fLoc;  | 
162  | 0  |    } Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::CollationCacheEntry>::operator==(icu_70::CacheKeyBase const&) const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::DateFmtBestPattern>::operator==(icu_70::CacheKeyBase const&) const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedDateFormatSymbols>::operator==(icu_70::CacheKeyBase const&) const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedCalendar>::operator==(icu_70::CacheKeyBase const&) const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedNumberFormat>::operator==(icu_70::CacheKeyBase const&) const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedPluralRules>::operator==(icu_70::CacheKeyBase const&) const  | 
163  |  |  | 
164  |  | #if defined(__cpp_impl_three_way_comparison) && \  | 
165  |  |        __cpp_impl_three_way_comparison >= 201711  | 
166  |  |     // Manually resolve C++20 reversed argument order ambiguity.  | 
167  |  |     template <typename U,  | 
168  |  |               typename = typename std::enable_if_t<!std::is_same_v<T, U>>>  | 
169  |  |     inline bool operator==(const LocaleCacheKey<U>& other) const { | 
170  |  |         return operator==(static_cast<const CacheKeyBase&>(other));  | 
171  |  |     }  | 
172  |  | #endif  | 
173  |  |  | 
174  | 0  |    virtual CacheKeyBase *clone() const { | 
175  | 0  |        return new LocaleCacheKey<T>(*this);  | 
176  | 0  |    } Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::CollationCacheEntry>::clone() const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::DateFmtBestPattern>::clone() const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedDateFormatSymbols>::clone() const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedCalendar>::clone() const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedNumberFormat>::clone() const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedPluralRules>::clone() const  | 
177  |  |    virtual const T *createObject(  | 
178  |  |            const void *creationContext, UErrorCode &status) const;  | 
179  |  |    /**  | 
180  |  |     * Use the locale id as the description.  | 
181  |  |     */  | 
182  | 0  |    virtual char *writeDescription(char *buffer, int32_t bufLen) const { | 
183  | 0  |        const char *s = fLoc.getName();  | 
184  | 0  |        uprv_strncpy(buffer, s, bufLen);  | 
185  | 0  |        buffer[bufLen - 1] = 0;  | 
186  | 0  |        return buffer;  | 
187  | 0  |    } Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::CollationCacheEntry>::writeDescription(char*, int) const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::DateFmtBestPattern>::writeDescription(char*, int) const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedDateFormatSymbols>::writeDescription(char*, int) const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedCalendar>::writeDescription(char*, int) const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedNumberFormat>::writeDescription(char*, int) const Unexecuted instantiation: icu_70::LocaleCacheKey<icu_70::SharedPluralRules>::writeDescription(char*, int) const  | 
188  |  |  | 
189  |  | };  | 
190  |  |  | 
191  |  | /**  | 
192  |  |  * The unified cache. A singleton type.  | 
193  |  |  * Design doc here:  | 
194  |  |  * https://docs.google.com/document/d/1RwGQJs4N4tawNbf809iYDRCvXoMKqDJihxzYt1ysmd8/edit?usp=sharing  | 
195  |  |  */  | 
196  |  | class U_COMMON_API UnifiedCache : public UnifiedCacheBase { | 
197  |  |  public:  | 
198  |  |    /**  | 
199  |  |     * @internal  | 
200  |  |     * Do not call directly. Instead use UnifiedCache::getInstance() as  | 
201  |  |     * there should be only one UnifiedCache in an application.  | 
202  |  |     */  | 
203  |  |    UnifiedCache(UErrorCode &status);  | 
204  |  |  | 
205  |  |    /**  | 
206  |  |     * Return a pointer to the global cache instance.  | 
207  |  |     */  | 
208  |  |    static UnifiedCache *getInstance(UErrorCode &status);  | 
209  |  |  | 
210  |  |    /**  | 
211  |  |     * Fetches a value from the cache by key. Equivalent to  | 
212  |  |     * get(key, NULL, ptr, status);  | 
213  |  |     */  | 
214  |  |    template<typename T>  | 
215  |  |    void get(  | 
216  |  |            const CacheKey<T>& key,  | 
217  |  |            const T *&ptr,  | 
218  | 0  |            UErrorCode &status) const { | 
219  | 0  |        get(key, NULL, ptr, status);  | 
220  | 0  |    } Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::DateFmtBestPattern>(icu_70::CacheKey<icu_70::DateFmtBestPattern> const&, icu_70::DateFmtBestPattern const*&, UErrorCode&) const Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::SharedDateFormatSymbols>(icu_70::CacheKey<icu_70::SharedDateFormatSymbols> const&, icu_70::SharedDateFormatSymbols const*&, UErrorCode&) const Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::SharedCalendar>(icu_70::CacheKey<icu_70::SharedCalendar> const&, icu_70::SharedCalendar const*&, UErrorCode&) const Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::SharedNumberFormat>(icu_70::CacheKey<icu_70::SharedNumberFormat> const&, icu_70::SharedNumberFormat const*&, UErrorCode&) const Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::SharedPluralRules>(icu_70::CacheKey<icu_70::SharedPluralRules> const&, icu_70::SharedPluralRules const*&, UErrorCode&) const  | 
221  |  |  | 
222  |  |    /**  | 
223  |  |     * Fetches value from the cache by key.  | 
224  |  |     *  | 
225  |  |     * @param key             the cache key.  | 
226  |  |     * @param creationContext passed verbatim to createObject method of key  | 
227  |  |     * @param ptr             On entry, ptr must be NULL or be included if  | 
228  |  |     *                        the reference count of the object it points  | 
229  |  |     *                        to. On exit, ptr points to the fetched object  | 
230  |  |     *                        from the cache or is left unchanged on  | 
231  |  |     *                        failure. Caller must call removeRef on ptr  | 
232  |  |     *                        if set to a non NULL value.  | 
233  |  |     * @param status          Any error returned here. May be set to a  | 
234  |  |     *                        warning value even if ptr is set.  | 
235  |  |     */  | 
236  |  |    template<typename T>  | 
237  |  |    void get(  | 
238  |  |            const CacheKey<T>& key,  | 
239  |  |            const void *creationContext,  | 
240  |  |            const T *&ptr,  | 
241  | 0  |            UErrorCode &status) const { | 
242  | 0  |        if (U_FAILURE(status)) { | 
243  | 0  |            return;  | 
244  | 0  |        }  | 
245  | 0  |        UErrorCode creationStatus = U_ZERO_ERROR;  | 
246  | 0  |        const SharedObject *value = NULL;  | 
247  | 0  |        _get(key, value, creationContext, creationStatus);  | 
248  | 0  |        const T *tvalue = (const T *) value;  | 
249  | 0  |        if (U_SUCCESS(creationStatus)) { | 
250  | 0  |            SharedObject::copyPtr(tvalue, ptr);  | 
251  | 0  |        }  | 
252  | 0  |        SharedObject::clearPtr(tvalue);  | 
253  |  |        // Take care not to overwrite a warning status passed in with  | 
254  |  |        // another warning or U_ZERO_ERROR.  | 
255  | 0  |        if (status == U_ZERO_ERROR || U_FAILURE(creationStatus)) { | 
256  | 0  |            status = creationStatus;  | 
257  | 0  |        }  | 
258  | 0  |    } Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::CollationCacheEntry>(icu_70::CacheKey<icu_70::CollationCacheEntry> const&, void const*, icu_70::CollationCacheEntry const*&, UErrorCode&) const Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::DateFmtBestPattern>(icu_70::CacheKey<icu_70::DateFmtBestPattern> const&, void const*, icu_70::DateFmtBestPattern const*&, UErrorCode&) const Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::SharedDateFormatSymbols>(icu_70::CacheKey<icu_70::SharedDateFormatSymbols> const&, void const*, icu_70::SharedDateFormatSymbols const*&, UErrorCode&) const Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::SharedCalendar>(icu_70::CacheKey<icu_70::SharedCalendar> const&, void const*, icu_70::SharedCalendar const*&, UErrorCode&) const Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::SharedNumberFormat>(icu_70::CacheKey<icu_70::SharedNumberFormat> const&, void const*, icu_70::SharedNumberFormat const*&, UErrorCode&) const Unexecuted instantiation: void icu_70::UnifiedCache::get<icu_70::SharedPluralRules>(icu_70::CacheKey<icu_70::SharedPluralRules> const&, void const*, icu_70::SharedPluralRules const*&, UErrorCode&) const  | 
259  |  |  | 
260  |  | #ifdef UNIFIED_CACHE_DEBUG  | 
261  |  |    /**  | 
262  |  |     * Dumps the contents of this cache to standard error. Used for testing of  | 
263  |  |     * cache only.  | 
264  |  |     */  | 
265  |  |    void dumpContents() const;  | 
266  |  | #endif  | 
267  |  |  | 
268  |  |    /**  | 
269  |  |     * Convenience method to get a value of type T from cache for a  | 
270  |  |     * particular locale with creationContext == NULL.  | 
271  |  |     * @param loc    the locale  | 
272  |  |     * @param ptr    On entry, must be NULL or included in the ref count  | 
273  |  |     *               of the object to which it points.  | 
274  |  |     *               On exit, fetched value stored here or is left  | 
275  |  |     *               unchanged on failure. Caller must call removeRef on  | 
276  |  |     *               ptr if set to a non NULL value.  | 
277  |  |     * @param status Any error returned here. May be set to a  | 
278  |  |     *               warning value even if ptr is set.  | 
279  |  |     */  | 
280  |  |    template<typename T>  | 
281  |  |    static void getByLocale(  | 
282  | 0  |            const Locale &loc, const T *&ptr, UErrorCode &status) { | 
283  | 0  |        const UnifiedCache *cache = getInstance(status);  | 
284  | 0  |        if (U_FAILURE(status)) { | 
285  | 0  |            return;  | 
286  | 0  |        }  | 
287  | 0  |        cache->get(LocaleCacheKey<T>(loc), ptr, status);  | 
288  | 0  |    } Unexecuted instantiation: void icu_70::UnifiedCache::getByLocale<icu_70::SharedDateFormatSymbols>(icu_70::Locale const&, icu_70::SharedDateFormatSymbols const*&, UErrorCode&) Unexecuted instantiation: void icu_70::UnifiedCache::getByLocale<icu_70::SharedCalendar>(icu_70::Locale const&, icu_70::SharedCalendar const*&, UErrorCode&) Unexecuted instantiation: void icu_70::UnifiedCache::getByLocale<icu_70::SharedNumberFormat>(icu_70::Locale const&, icu_70::SharedNumberFormat const*&, UErrorCode&) Unexecuted instantiation: void icu_70::UnifiedCache::getByLocale<icu_70::SharedPluralRules>(icu_70::Locale const&, icu_70::SharedPluralRules const*&, UErrorCode&)  | 
289  |  |  | 
290  |  | #ifdef UNIFIED_CACHE_DEBUG  | 
291  |  |    /**  | 
292  |  |     * Dumps the cache contents to stderr. For testing only.  | 
293  |  |     */  | 
294  |  |    static void dump();  | 
295  |  | #endif  | 
296  |  |  | 
297  |  |    /**  | 
298  |  |     * Returns the number of keys in this cache. For testing only.  | 
299  |  |     */  | 
300  |  |    int32_t keyCount() const;  | 
301  |  |  | 
302  |  |    /**  | 
303  |  |     * Removes any values from cache that are not referenced outside  | 
304  |  |     * the cache.  | 
305  |  |     */  | 
306  |  |    void flush() const;  | 
307  |  |  | 
308  |  |    /**  | 
309  |  |     * Configures at what point eviction of unused entries will begin.  | 
310  |  |     * Eviction is triggered whenever the number of evictable keys exceeds  | 
311  |  |     * BOTH count AND (number of in-use items) * (percentageOfInUseItems / 100).  | 
312  |  |     * Once the number of unused entries drops below one of these,  | 
313  |  |     * eviction ceases. Because eviction happens incrementally,  | 
314  |  |     * the actual unused entry count may exceed both these numbers  | 
315  |  |     * from time to time.  | 
316  |  |     *  | 
317  |  |     * A cache entry is defined as unused if it is not essential to guarantee  | 
318  |  |     * that for a given key X, the cache returns the same reference to the  | 
319  |  |     * same value as long as the client already holds a reference to that  | 
320  |  |     * value.  | 
321  |  |     *  | 
322  |  |     * If this method is never called, the default settings are 1000 and 100%.  | 
323  |  |     *  | 
324  |  |     * Although this method is thread-safe, it is designed to be called at  | 
325  |  |     * application startup. If it is called in the middle of execution, it  | 
326  |  |     * will have no immediate effect on the cache. However over time, the  | 
327  |  |     * cache will perform eviction slices in an attempt to honor the new  | 
328  |  |     * settings.  | 
329  |  |     *  | 
330  |  |     * If a client already holds references to many different unique values  | 
331  |  |     * in the cache such that the number of those unique values far exceeds  | 
332  |  |     * "count" then the cache may not be able to maintain this maximum.  | 
333  |  |     * However, if this happens, the cache still guarantees that the number of  | 
334  |  |     * unused entries will remain only a small percentage of the total cache  | 
335  |  |     * size.  | 
336  |  |     *  | 
337  |  |     * If the parameters passed are negative, setEvctionPolicy sets status to  | 
338  |  |     * U_ILLEGAL_ARGUMENT_ERROR.  | 
339  |  |     */  | 
340  |  |    void setEvictionPolicy(  | 
341  |  |            int32_t count, int32_t percentageOfInUseItems, UErrorCode &status);  | 
342  |  |  | 
343  |  |  | 
344  |  |    /**  | 
345  |  |     * Returns how many entries have been auto evicted during the lifetime  | 
346  |  |     * of this cache. This only includes auto evicted entries, not  | 
347  |  |     * entries evicted because of a call to flush().  | 
348  |  |     */  | 
349  |  |    int64_t autoEvictedCount() const;  | 
350  |  |  | 
351  |  |    /**  | 
352  |  |     * Returns the unused entry count in this cache. For testing only,  | 
353  |  |     * Regular clients will not need this.  | 
354  |  |     */  | 
355  |  |    int32_t unusedCount() const;  | 
356  |  |  | 
357  |  |    virtual void handleUnreferencedObject() const;  | 
358  |  |    virtual ~UnifiedCache();  | 
359  |  |      | 
360  |  |  private:  | 
361  |  |    UHashtable *fHashtable;  | 
362  |  |    mutable int32_t fEvictPos;  | 
363  |  |    mutable int32_t fNumValuesTotal;  | 
364  |  |    mutable int32_t fNumValuesInUse;  | 
365  |  |    int32_t fMaxUnused;  | 
366  |  |    int32_t fMaxPercentageOfInUse;  | 
367  |  |    mutable int64_t fAutoEvictedCount;  | 
368  |  |    SharedObject *fNoValue;  | 
369  |  |      | 
370  |  |    UnifiedCache(const UnifiedCache &other);  | 
371  |  |    UnifiedCache &operator=(const UnifiedCache &other);  | 
372  |  |      | 
373  |  |    /**  | 
374  |  |     * Flushes the contents of the cache. If cache values hold references to other  | 
375  |  |     * cache values then _flush should be called in a loop until it returns false.  | 
376  |  |     *   | 
377  |  |     * On entry, gCacheMutex must be held.  | 
378  |  |     * On exit, those values with are evictable are flushed.  | 
379  |  |     *   | 
380  |  |     *  @param all if false flush evictable items only, which are those with no external  | 
381  |  |     *                    references, plus those that can be safely recreated.<br>  | 
382  |  |     *            if true, flush all elements. Any values (sharedObjects) with remaining  | 
383  |  |     *                     hard (external) references are not deleted, but are detached from  | 
384  |  |     *                     the cache, so that a subsequent removeRefs can delete them.  | 
385  |  |     *                     _flush is not thread safe when all is true.  | 
386  |  |     *   @return true if any value in cache was flushed or false otherwise.  | 
387  |  |     */  | 
388  |  |    UBool _flush(UBool all) const;  | 
389  |  |      | 
390  |  |    /**  | 
391  |  |     * Gets value out of cache.  | 
392  |  |     * On entry. gCacheMutex must not be held. value must be NULL. status  | 
393  |  |     * must be U_ZERO_ERROR.  | 
394  |  |     * On exit. value and status set to what is in cache at key or on cache  | 
395  |  |     * miss the key's createObject() is called and value and status are set to  | 
396  |  |     * the result of that. In this latter case, best effort is made to add the  | 
397  |  |     * value and status to the cache. If createObject() fails to create a value,  | 
398  |  |     * fNoValue is stored in cache, and value is set to NULL. Caller must call  | 
399  |  |     * removeRef on value if non NULL.  | 
400  |  |     */  | 
401  |  |    void _get(  | 
402  |  |            const CacheKeyBase &key,  | 
403  |  |            const SharedObject *&value,  | 
404  |  |            const void *creationContext,  | 
405  |  |            UErrorCode &status) const;  | 
406  |  |  | 
407  |  |     /**  | 
408  |  |      * Attempts to fetch value and status for key from cache.  | 
409  |  |      * On entry, gCacheMutex must not be held value must be NULL and status must  | 
410  |  |      * be U_ZERO_ERROR.  | 
411  |  |      * On exit, either returns false (In this  | 
412  |  |      * case caller should try to create the object) or returns true with value  | 
413  |  |      * pointing to the fetched value and status set to fetched status. When  | 
414  |  |      * false is returned status may be set to failure if an in progress hash  | 
415  |  |      * entry could not be made but value will remain unchanged. When true is  | 
416  |  |      * returned, caller must call removeRef() on value.  | 
417  |  |      */  | 
418  |  |     UBool _poll(  | 
419  |  |             const CacheKeyBase &key,  | 
420  |  |             const SharedObject *&value,  | 
421  |  |             UErrorCode &status) const;  | 
422  |  |       | 
423  |  |     /**  | 
424  |  |      * Places a new value and creationStatus in the cache for the given key.  | 
425  |  |      * On entry, gCacheMutex must be held. key must not exist in the cache.   | 
426  |  |      * On exit, value and creation status placed under key. Soft reference added  | 
427  |  |      * to value on successful add. On error sets status.  | 
428  |  |      */  | 
429  |  |     void _putNew(  | 
430  |  |         const CacheKeyBase &key,  | 
431  |  |         const SharedObject *value,  | 
432  |  |         const UErrorCode creationStatus,  | 
433  |  |         UErrorCode &status) const;  | 
434  |  |              | 
435  |  |     /**  | 
436  |  |      * Places value and status at key if there is no value at key or if cache  | 
437  |  |      * entry for key is in progress. Otherwise, it leaves the current value and  | 
438  |  |      * status there.  | 
439  |  |      *   | 
440  |  |      * On entry. gCacheMutex must not be held. Value must be  | 
441  |  |      * included in the reference count of the object to which it points.  | 
442  |  |      *   | 
443  |  |      * On exit, value and status are changed to what was already in the cache if  | 
444  |  |      * something was there and not in progress. Otherwise, value and status are left  | 
445  |  |      * unchanged in which case they are placed in the cache on a best-effort basis.  | 
446  |  |      * Caller must call removeRef() on value.  | 
447  |  |      */  | 
448  |  |    void _putIfAbsentAndGet(  | 
449  |  |            const CacheKeyBase &key,  | 
450  |  |            const SharedObject *&value,  | 
451  |  |            UErrorCode &status) const;  | 
452  |  |  | 
453  |  |     /**  | 
454  |  |      * Returns the next element in the cache round robin style.  | 
455  |  |      * Returns nullptr if the cache is empty.  | 
456  |  |      * On entry, gCacheMutex must be held.  | 
457  |  |      */  | 
458  |  |     const UHashElement *_nextElement() const;  | 
459  |  |      | 
460  |  |    /**  | 
461  |  |     * Return the number of cache items that would need to be evicted  | 
462  |  |     * to bring usage into conformance with eviction policy.  | 
463  |  |     *   | 
464  |  |     * An item corresponds to an entry in the hash table, a hash table element.  | 
465  |  |     *   | 
466  |  |     * On entry, gCacheMutex must be held.  | 
467  |  |     */  | 
468  |  |    int32_t _computeCountOfItemsToEvict() const;  | 
469  |  |      | 
470  |  |    /**  | 
471  |  |     * Run an eviction slice.  | 
472  |  |     * On entry, gCacheMutex must be held.  | 
473  |  |     * _runEvictionSlice runs a slice of the evict pipeline by examining the next  | 
474  |  |     * 10 entries in the cache round robin style evicting them if they are eligible.  | 
475  |  |     */  | 
476  |  |    void _runEvictionSlice() const;  | 
477  |  |    | 
478  |  |    /**  | 
479  |  |     * Register a primary cache entry. A primary key is the first key to create  | 
480  |  |     * a given  SharedObject value. Subsequent keys whose create function  | 
481  |  |     * produce references to an already existing SharedObject are not primary -  | 
482  |  |     * they can be evicted and subsequently recreated.  | 
483  |  |     *   | 
484  |  |     * On entry, gCacheMutex must be held.  | 
485  |  |     * On exit, items in use count incremented, entry is marked as a primary  | 
486  |  |     * entry, and value registered with cache so that subsequent calls to  | 
487  |  |     * addRef() and removeRef() on it correctly interact with the cache.  | 
488  |  |     */  | 
489  |  |    void _registerPrimary(const CacheKeyBase *theKey, const SharedObject *value) const;  | 
490  |  |           | 
491  |  |    /**  | 
492  |  |     * Store a value and creation error status in given hash entry.  | 
493  |  |     * On entry, gCacheMutex must be held. Hash entry element must be in progress.  | 
494  |  |     * value must be non NULL.  | 
495  |  |     * On Exit, soft reference added to value. value and status stored in hash  | 
496  |  |     * entry. Soft reference removed from previous stored value. Waiting  | 
497  |  |     * threads notified.  | 
498  |  |     */  | 
499  |  |    void _put(  | 
500  |  |            const UHashElement *element,  | 
501  |  |            const SharedObject *value,  | 
502  |  |            const UErrorCode status) const;  | 
503  |  |     /**  | 
504  |  |      * Remove a soft reference, and delete the SharedObject if no references remain.  | 
505  |  |      * To be used from within the UnifiedCache implementation only.  | 
506  |  |      * gCacheMutex must be held by caller.  | 
507  |  |      * @param value the SharedObject to be acted on.  | 
508  |  |      */  | 
509  |  |    void removeSoftRef(const SharedObject *value) const;  | 
510  |  |      | 
511  |  |    /**  | 
512  |  |     * Increment the hard reference count of the given SharedObject.  | 
513  |  |     * gCacheMutex must be held by the caller.  | 
514  |  |     * Update numValuesEvictable on transitions between zero and one reference.  | 
515  |  |     *   | 
516  |  |     * @param value The SharedObject to be referenced.  | 
517  |  |     * @return the hard reference count after the addition.  | 
518  |  |     */  | 
519  |  |    int32_t addHardRef(const SharedObject *value) const;  | 
520  |  |      | 
521  |  |   /**  | 
522  |  |     * Decrement the hard reference count of the given SharedObject.  | 
523  |  |     * gCacheMutex must be held by the caller.  | 
524  |  |     * Update numValuesEvictable on transitions between one and zero reference.  | 
525  |  |     *   | 
526  |  |     * @param value The SharedObject to be referenced.  | 
527  |  |     * @return the hard reference count after the removal.  | 
528  |  |     */  | 
529  |  |    int32_t removeHardRef(const SharedObject *value) const;  | 
530  |  |  | 
531  |  |      | 
532  |  | #ifdef UNIFIED_CACHE_DEBUG  | 
533  |  |    void _dumpContents() const;  | 
534  |  | #endif  | 
535  |  |      | 
536  |  |    /**  | 
537  |  |     *  Fetch value and error code from a particular hash entry.  | 
538  |  |     *  On entry, gCacheMutex must be held. value must be either NULL or must be  | 
539  |  |     *  included in the ref count of the object to which it points.  | 
540  |  |     *  On exit, value and status set to what is in the hash entry. Caller must  | 
541  |  |     *  eventually call removeRef on value.  | 
542  |  |     *  If hash entry is in progress, value will be set to gNoValue and status will  | 
543  |  |     *  be set to U_ZERO_ERROR.  | 
544  |  |     */  | 
545  |  |    void _fetch(const UHashElement *element, const SharedObject *&value,  | 
546  |  |                        UErrorCode &status) const;  | 
547  |  |                          | 
548  |  |     /**  | 
549  |  |      * Determine if given hash entry is in progress.  | 
550  |  |      * On entry, gCacheMutex must be held.  | 
551  |  |      */  | 
552  |  |    UBool _inProgress(const UHashElement *element) const;  | 
553  |  |      | 
554  |  |    /**  | 
555  |  |     * Determine if given hash entry is in progress.  | 
556  |  |     * On entry, gCacheMutex must be held.  | 
557  |  |     */  | 
558  |  |    UBool _inProgress(const SharedObject *theValue, UErrorCode creationStatus) const;  | 
559  |  |      | 
560  |  |    /**  | 
561  |  |     * Determine if given hash entry is eligible for eviction.  | 
562  |  |     * On entry, gCacheMutex must be held.  | 
563  |  |     */  | 
564  |  |    UBool _isEvictable(const UHashElement *element) const;  | 
565  |  | };  | 
566  |  |  | 
567  |  | U_NAMESPACE_END  | 
568  |  |  | 
569  |  | #endif  |