]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/sharedobject.h
ICU-59152.0.1.tar.gz
[apple/icu.git] / icuSources / common / sharedobject.h
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 /**
21 * Base class for unified cache exposing enough methods to SharedObject
22 * instances to allow their addRef() and removeRef() methods to
23 * update cache metrics. No other part of ICU, except for SharedObject,
24 * should directly call the methods of this base class.
25 */
26 class U_COMMON_API UnifiedCacheBase : public UObject {
27 public:
28 UnifiedCacheBase() { }
29
30 /**
31 * Called by addRefWhileHoldingCacheLock() when the hard reference count
32 * of its instance goes from 0 to 1.
33 */
34 virtual void incrementItemsInUse() const = 0;
35
36 /**
37 * Called by removeRef() when the hard reference count of its instance
38 * drops from 1 to 0.
39 */
40 virtual void decrementItemsInUseWithLockingAndEviction() const = 0;
41
42 /**
43 * Called by removeRefWhileHoldingCacheLock() when the hard reference
44 * count of its instance drops from 1 to 0.
45 */
46 virtual void decrementItemsInUse() const = 0;
47 virtual ~UnifiedCacheBase();
48 private:
49 UnifiedCacheBase(const UnifiedCacheBase &);
50 UnifiedCacheBase &operator=(const UnifiedCacheBase &);
51 };
52
53 /**
54 * Base class for shared, reference-counted, auto-deleted objects.
55 * Subclasses can be immutable.
56 * If they are mutable, then they must implement their copy constructor
57 * so that copyOnWrite() works.
58 *
59 * Either stack-allocate, use LocalPointer, or use addRef()/removeRef().
60 * Sharing requires reference-counting.
61 */
62 class U_COMMON_API SharedObject : public UObject {
63 public:
64 /** Initializes totalRefCount, softRefCount to 0. */
65 SharedObject() :
66 totalRefCount(0),
67 softRefCount(0),
68 hardRefCount(0),
69 cachePtr(NULL) {}
70
71 /** Initializes totalRefCount, softRefCount to 0. */
72 SharedObject(const SharedObject &other) :
73 UObject(other),
74 totalRefCount(0),
75 softRefCount(0),
76 hardRefCount(0),
77 cachePtr(NULL) {}
78
79 virtual ~SharedObject();
80
81 /**
82 * Increments the number of references to this object. Thread-safe.
83 */
84 void addRef() const { addRef(FALSE); }
85
86 /**
87 * Increments the number of references to this object.
88 * Must be called only from within the internals of UnifiedCache and
89 * only while the cache global mutex is held.
90 */
91 void addRefWhileHoldingCacheLock() const { addRef(TRUE); }
92
93 /**
94 * Increments the number of soft references to this object.
95 * Must be called only from within the internals of UnifiedCache and
96 * only while the cache global mutex is held.
97 */
98 void addSoftRef() const;
99
100 /**
101 * Decrements the number of references to this object. Thread-safe.
102 */
103 void removeRef() const { removeRef(FALSE); }
104
105 /**
106 * Decrements the number of references to this object.
107 * Must be called only from within the internals of UnifiedCache and
108 * only while the cache global mutex is held.
109 */
110 void removeRefWhileHoldingCacheLock() const { removeRef(TRUE); }
111
112 /**
113 * Decrements the number of soft references to this object.
114 * Must be called only from within the internals of UnifiedCache and
115 * only while the cache global mutex is held.
116 */
117 void removeSoftRef() const;
118
119 /**
120 * Returns the reference counter including soft references.
121 * Uses a memory barrier.
122 */
123 int32_t getRefCount() const;
124
125 /**
126 * Returns the count of soft references only.
127 * Must be called only from within the internals of UnifiedCache and
128 * only while the cache global mutex is held.
129 */
130 int32_t getSoftRefCount() const { return softRefCount; }
131
132 /**
133 * Returns the count of hard references only. Uses a memory barrier.
134 * Used for testing the cache. Regular clients won't need this.
135 */
136 int32_t getHardRefCount() const;
137
138 /**
139 * If noHardReferences() == TRUE then this object has no hard references.
140 * Must be called only from within the internals of UnifiedCache.
141 */
142 inline UBool noHardReferences() const { return getHardRefCount() == 0; }
143
144 /**
145 * If hasHardReferences() == TRUE then this object has hard references.
146 * Must be called only from within the internals of UnifiedCache.
147 */
148 inline UBool hasHardReferences() const { return getHardRefCount() != 0; }
149
150 /**
151 * If noSoftReferences() == TRUE then this object has no soft references.
152 * Must be called only from within the internals of UnifiedCache and
153 * only while the cache global mutex is held.
154 */
155 UBool noSoftReferences() const { return (softRefCount == 0); }
156
157 /**
158 * Deletes this object if it has no references or soft references.
159 */
160 void deleteIfZeroRefCount() const;
161
162 /**
163 * @internal For UnifedCache use only to register this object with itself.
164 * Must be called before this object is exposed to multiple threads.
165 */
166 void registerWithCache(const UnifiedCacheBase *ptr) const {
167 cachePtr = ptr;
168 }
169
170 /**
171 * Returns a writable version of ptr.
172 * If there is exactly one owner, then ptr itself is returned as a
173 * non-const pointer.
174 * If there are multiple owners, then ptr is replaced with a
175 * copy-constructed clone,
176 * and that is returned.
177 * Returns NULL if cloning failed.
178 *
179 * T must be a subclass of SharedObject.
180 */
181 template<typename T>
182 static T *copyOnWrite(const T *&ptr) {
183 const T *p = ptr;
184 if(p->getRefCount() <= 1) { return const_cast<T *>(p); }
185 T *p2 = new T(*p);
186 if(p2 == NULL) { return NULL; }
187 p->removeRef();
188 ptr = p2;
189 p2->addRef();
190 return p2;
191 }
192
193 /**
194 * Makes dest an owner of the object pointed to by src while adjusting
195 * reference counts and deleting the previous object dest pointed to
196 * if necessary. Before this call is made, dest must either be NULL or
197 * be included in the reference count of the object it points to.
198 *
199 * T must be a subclass of SharedObject.
200 */
201 template<typename T>
202 static void copyPtr(const T *src, const T *&dest) {
203 if(src != dest) {
204 if(dest != NULL) { dest->removeRef(); }
205 dest = src;
206 if(src != NULL) { src->addRef(); }
207 }
208 }
209
210 /**
211 * Equivalent to copyPtr(NULL, dest).
212 */
213 template<typename T>
214 static void clearPtr(const T *&ptr) {
215 if (ptr != NULL) {
216 ptr->removeRef();
217 ptr = NULL;
218 }
219 }
220
221 private:
222 mutable u_atomic_int32_t totalRefCount;
223
224 // Any thread modifying softRefCount must hold the global cache mutex
225 mutable int32_t softRefCount;
226
227 mutable u_atomic_int32_t hardRefCount;
228 mutable const UnifiedCacheBase *cachePtr;
229 void addRef(UBool withCacheLock) const;
230 void removeRef(UBool withCacheLock) const;
231
232 };
233
234 U_NAMESPACE_END
235
236 #endif