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
16U_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 */
27class U_COMMON_API SharedObject : public UObject {
28public:
29    /** Initializes refCount to 0. */
30    SharedObject() : refCount(0) {}
31
32    /** Initializes refCount to 0. */
33    SharedObject(const SharedObject &/*other*/) : refCount(0) {}
34    virtual ~SharedObject();
35
36    /**
37     * Increments the number of references to this object. Thread-safe.
38     */
39    void addRef() const;
40
41    /**
42     * Decrements the number of references to this object,
43     * and auto-deletes "this" if the number becomes 0. Thread-safe.
44     */
45    void removeRef() const;
46
47    /**
48     * Returns the reference counter. Uses a memory barrier.
49     */
50    int32_t getRefCount() const;
51
52    void deleteIfZeroRefCount() const;
53
54    /**
55     * Returns a writable version of ptr.
56     * If there is exactly one owner, then ptr itself is returned as a
57     *  non-const pointer.
58     * If there are multiple owners, then ptr is replaced with a
59     * copy-constructed clone,
60     * and that is returned.
61     * Returns NULL if cloning failed.
62     *
63     * T must be a subclass of SharedObject.
64     */
65    template<typename T>
66    static T *copyOnWrite(const T *&ptr) {
67        const T *p = ptr;
68        if(p->getRefCount() <= 1) { return const_cast<T *>(p); }
69        T *p2 = new T(*p);
70        if(p2 == NULL) { return NULL; }
71        p->removeRef();
72        ptr = p2;
73        p2->addRef();
74        return p2;
75    }
76
77    /**
78     * Makes dest an owner of the object pointed to by src while adjusting
79     * reference counts and deleting the previous object dest pointed to
80     * if necessary. Before this call is made, dest must either be NULL or
81     * own its object.
82     *
83     * T must be a subclass of SharedObject.
84     */
85    template<typename T>
86    static void copyPtr(const T *src, const T *&dest) {
87        if(src != dest) {
88            if(dest != NULL) { dest->removeRef(); }
89            dest = src;
90            if(src != NULL) { src->addRef(); }
91        }
92    }
93
94    /**
95     * Equivalent to copy(NULL, dest).
96     */
97    template<typename T>
98    static void clearPtr(const T *&ptr) {
99        if (ptr != NULL) {
100            ptr->removeRef();
101            ptr = NULL;
102        }
103    }
104
105private:
106    mutable u_atomic_int32_t refCount;
107};
108
109U_NAMESPACE_END
110
111#endif
112