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: UnifiedCacheBase()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. */ SharedObject()57 SharedObject() : 58 softRefCount(0), 59 hardRefCount(0), 60 cachePtr(NULL) {} 61 62 /** Initializes totalRefCount, softRefCount to 0. */ SharedObject(const SharedObject & other)63 SharedObject(const SharedObject &other) : 64 UObject(other), 65 softRefCount(0), 66 hardRefCount(0), 67 cachePtr(NULL) {} 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 */ noHardReferences()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 */ hasHardReferences()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 NULL if cloning failed. 120 * 121 * T must be a subclass of SharedObject. 122 */ 123 template<typename T> copyOnWrite(const T * & ptr)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 == NULL) { return NULL; } 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 NULL 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> copyPtr(const T * src,const T * & dest)144 static void copyPtr(const T *src, const T *&dest) { 145 if(src != dest) { 146 if(dest != NULL) { dest->removeRef(); } 147 dest = src; 148 if(src != NULL) { src->addRef(); } 149 } 150 } 151 152 /** 153 * Equivalent to copyPtr(NULL, dest). 154 */ 155 template<typename T> clearPtr(const T * & ptr)156 static void clearPtr(const T *&ptr) { 157 if (ptr != NULL) { 158 ptr->removeRef(); 159 ptr = NULL; 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