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
18U_NAMESPACE_BEGIN
19
20class 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 */
28class U_COMMON_API UnifiedCacheBase : public UObject {
29public:
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();
40private:
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 */
54class U_COMMON_API SharedObject : public UObject {
55public:
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
163private:
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
182U_NAMESPACE_END
183
184#endif
185