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 &);
42     UnifiedCacheBase &operator=(const UnifiedCacheBase &);
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