1 /*
2 ******************************************************************************
3 * Copyright (C) 2014, International Business Machines
4 * Corporation and others.  All Rights Reserved.
5 ******************************************************************************
6 * sharedobject.h
7 */
8 
9 #ifndef __SHAREDOBJECT_H__
10 #define __SHAREDOBJECT_H__
11 
12 
13 #include "unicode/uobject.h"
14 #include "umutex.h"
15 
16 U_NAMESPACE_BEGIN
17 
18 /**
19  * Base class for shared, reference-counted, auto-deleted objects.
20  * Subclasses can be immutable.
21  * If they are mutable, then they must implement their copy constructor
22  * so that copyOnWrite() works.
23  *
24  * Either stack-allocate, use LocalPointer, or use addRef()/removeRef().
25  * Sharing requires reference-counting.
26  */
27 class U_COMMON_API SharedObject : public UObject {
28 public:
29     /** Initializes totalRefCount, softRefCount to 0. */
SharedObject()30     SharedObject() : totalRefCount(0), softRefCount(0) {}
31 
32     /** Initializes totalRefCount, softRefCount to 0. */
SharedObject(const SharedObject & other)33     SharedObject(const SharedObject &other)
34         : UObject(other),
35           totalRefCount(0),
36           softRefCount(0) {}
37 
38     virtual ~SharedObject();
39 
40     /**
41      * Increments the number of references to this object. Thread-safe.
42      */
43     void addRef() const;
44 
45     /**
46      * Increments the number of soft references to this object. Thread-safe.
47      */
48     void addSoftRef() const;
49 
50     /**
51      * Decrements the number of references to this object. Thread-safe.
52      */
53     void removeRef() const;
54 
55     /**
56      * Decrements the number of soft references to this object. Thread-safe.
57      */
58     void removeSoftRef() const;
59 
60     /**
61      * Returns the reference counter including soft references.
62      * Uses a memory barrier.
63      */
64     int32_t getRefCount() const;
65 
66     /**
67      * Returns the count of soft references only. Uses a memory barrier.
68      * Used for testing the cache. Regular clients won't need this.
69      */
70     int32_t getSoftRefCount() const;
71 
72     /**
73      * If allSoftReferences() == TRUE then this object has only soft
74      * references. The converse is not necessarily true.
75      */
76     UBool allSoftReferences() const;
77 
78     /**
79      * Deletes this object if it has no references or soft references.
80      */
81     void deleteIfZeroRefCount() const;
82 
83     /**
84      * Returns a writable version of ptr.
85      * If there is exactly one owner, then ptr itself is returned as a
86      *  non-const pointer.
87      * If there are multiple owners, then ptr is replaced with a
88      * copy-constructed clone,
89      * and that is returned.
90      * Returns NULL if cloning failed.
91      *
92      * T must be a subclass of SharedObject.
93      */
94     template<typename T>
copyOnWrite(const T * & ptr)95     static T *copyOnWrite(const T *&ptr) {
96         const T *p = ptr;
97         if(p->getRefCount() <= 1) { return const_cast<T *>(p); }
98         T *p2 = new T(*p);
99         if(p2 == NULL) { return NULL; }
100         p->removeRef();
101         ptr = p2;
102         p2->addRef();
103         return p2;
104     }
105 
106     /**
107      * Makes dest an owner of the object pointed to by src while adjusting
108      * reference counts and deleting the previous object dest pointed to
109      * if necessary. Before this call is made, dest must either be NULL or
110      * be included in the reference count of the object it points to.
111      *
112      * T must be a subclass of SharedObject.
113      */
114     template<typename T>
copyPtr(const T * src,const T * & dest)115     static void copyPtr(const T *src, const T *&dest) {
116         if(src != dest) {
117             if(dest != NULL) { dest->removeRef(); }
118             dest = src;
119             if(src != NULL) { src->addRef(); }
120         }
121     }
122 
123     /**
124      * Equivalent to copyPtr(NULL, dest).
125      */
126     template<typename T>
clearPtr(const T * & ptr)127     static void clearPtr(const T *&ptr) {
128         if (ptr != NULL) {
129             ptr->removeRef();
130             ptr = NULL;
131         }
132     }
133 
134 private:
135     mutable u_atomic_int32_t totalRefCount;
136     mutable u_atomic_int32_t softRefCount;
137 };
138 
139 U_NAMESPACE_END
140 
141 #endif
142