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-2016, International Business Machines |
6 | * Corporation and others. All Rights Reserved. |
7 | ****************************************************************************** |
8 | * sharedobject.h |
9 | */ |
10 | |
11 | #ifndef __SHAREDOBJECT_H__ |
12 | #define __SHAREDOBJECT_H__ |
13 | |
14 | |
15 | #include "unicode/uobject.h" |
16 | #include "umutex.h" |
17 | |
18 | U_NAMESPACE_BEGIN |
19 | |
20 | class SharedObject; |
21 | |
22 | /** |
23 | * Base class for unified cache exposing enough methods to SharedObject |
24 | * instances to allow their addRef() and removeRef() methods to |
25 | * update cache metrics. No other part of ICU, except for SharedObject, |
26 | * should directly call the methods of this base class. |
27 | */ |
28 | class U_COMMON_API UnifiedCacheBase : public UObject { |
29 | public: |
30 | UnifiedCacheBase() { } |
31 | |
32 | /** |
33 | * Notify the cache implementation that an object was seen transitioning to |
34 | * zero hard references. The cache may use this to keep track the number of |
35 | * unreferenced SharedObjects, and to trigger evictions. |
36 | */ |
37 | virtual void handleUnreferencedObject() const = 0; |
38 | |
39 | virtual ~UnifiedCacheBase(); |
40 | private: |
41 | UnifiedCacheBase(const UnifiedCacheBase &) = delete; |
42 | UnifiedCacheBase &operator=(const UnifiedCacheBase &) = delete; |
43 | }; |
44 | |
45 | /** |
46 | * Base class for shared, reference-counted, auto-deleted objects. |
47 | * Subclasses can be immutable. |
48 | * If they are mutable, then they must implement their copy constructor |
49 | * so that copyOnWrite() works. |
50 | * |
51 | * Either stack-allocate, use LocalPointer, or use addRef()/removeRef(). |
52 | * Sharing requires reference-counting. |
53 | */ |
54 | class U_COMMON_API SharedObject : public UObject { |
55 | public: |
56 | /** Initializes totalRefCount, softRefCount to 0. */ |
57 | SharedObject() : |
58 | softRefCount(0), |
59 | hardRefCount(0), |
60 | cachePtr(nullptr) {} |
61 | |
62 | /** Initializes totalRefCount, softRefCount to 0. */ |
63 | SharedObject(const SharedObject &other) : |
64 | UObject(other), |
65 | softRefCount(0), |
66 | hardRefCount(0), |
67 | cachePtr(nullptr) {} |
68 | |
69 | virtual ~SharedObject(); |
70 | |
71 | /** |
72 | * Increments the number of hard references to this object. Thread-safe. |
73 | * Not for use from within the Unified Cache implementation. |
74 | */ |
75 | void addRef() const; |
76 | |
77 | /** |
78 | * Decrements the number of hard references to this object, and |
79 | * arrange for possible cache-eviction and/or deletion if ref |
80 | * count goes to zero. Thread-safe. |
81 | * |
82 | * Not for use from within the UnifiedCache implementation. |
83 | */ |
84 | void removeRef() const; |
85 | |
86 | /** |
87 | * Returns the number of hard references for this object. |
88 | * Uses a memory barrier. |
89 | */ |
90 | int32_t getRefCount() const; |
91 | |
92 | /** |
93 | * If noHardReferences() == true then this object has no hard references. |
94 | * Must be called only from within the internals of UnifiedCache. |
95 | */ |
96 | inline UBool noHardReferences() const { return getRefCount() == 0; } |
97 | |
98 | /** |
99 | * If hasHardReferences() == true then this object has hard references. |
100 | * Must be called only from within the internals of UnifiedCache. |
101 | */ |
102 | inline UBool hasHardReferences() const { return getRefCount() != 0; } |
103 | |
104 | /** |
105 | * Deletes this object if it has no references. |
106 | * Available for non-cached SharedObjects only. Ownership of cached objects |
107 | * is with the UnifiedCache, which is solely responsible for eviction and deletion. |
108 | */ |
109 | void deleteIfZeroRefCount() const; |
110 | |
111 | |
112 | /** |
113 | * Returns a writable version of ptr. |
114 | * If there is exactly one owner, then ptr itself is returned as a |
115 | * non-const pointer. |
116 | * If there are multiple owners, then ptr is replaced with a |
117 | * copy-constructed clone, |
118 | * and that is returned. |
119 | * Returns nullptr if cloning failed. |
120 | * |
121 | * T must be a subclass of SharedObject. |
122 | */ |
123 | template<typename T> |
124 | static T *copyOnWrite(const T *&ptr) { |
125 | const T *p = ptr; |
126 | if(p->getRefCount() <= 1) { return const_cast<T *>(p); } |
127 | T *p2 = new T(*p); |
128 | if(p2 == nullptr) { return nullptr; } |
129 | p->removeRef(); |
130 | ptr = p2; |
131 | p2->addRef(); |
132 | return p2; |
133 | } |
134 | |
135 | /** |
136 | * Makes dest an owner of the object pointed to by src while adjusting |
137 | * reference counts and deleting the previous object dest pointed to |
138 | * if necessary. Before this call is made, dest must either be nullptr or |
139 | * be included in the reference count of the object it points to. |
140 | * |
141 | * T must be a subclass of SharedObject. |
142 | */ |
143 | template<typename T> |
144 | static void copyPtr(const T *src, const T *&dest) { |
145 | if(src != dest) { |
146 | if(dest != nullptr) { dest->removeRef(); } |
147 | dest = src; |
148 | if(src != nullptr) { src->addRef(); } |
149 | } |
150 | } |
151 | |
152 | /** |
153 | * Equivalent to copyPtr(nullptr, dest). |
154 | */ |
155 | template<typename T> |
156 | static void clearPtr(const T *&ptr) { |
157 | if (ptr != nullptr) { |
158 | ptr->removeRef(); |
159 | ptr = nullptr; |
160 | } |
161 | } |
162 | |
163 | private: |
164 | /** |
165 | * The number of references from the UnifiedCache, which is |
166 | * the number of times that the sharedObject is stored as a hash table value. |
167 | * For use by UnifiedCache implementation code only. |
168 | * All access is synchronized by UnifiedCache's gCacheMutex |
169 | */ |
170 | mutable int32_t softRefCount; |
171 | friend class UnifiedCache; |
172 | |
173 | /** |
174 | * Reference count, excluding references from within the UnifiedCache implementation. |
175 | */ |
176 | mutable u_atomic_int32_t hardRefCount; |
177 | |
178 | mutable const UnifiedCacheBase *cachePtr; |
179 | |
180 | }; |
181 | |
182 | U_NAMESPACE_END |
183 | |
184 | #endif |
185 | |