SharedObject.java revision 836e6b40a94ec3fb7545a76cb072960442b7eee9
1/* GENERATED SOURCE. DO NOT MODIFY. */
2/*
3*******************************************************************************
4* Copyright (C) 2013-2014, International Business Machines
5* Corporation and others.  All Rights Reserved.
6*******************************************************************************
7* SharedObject.java, ported from sharedobject.h/.cpp
8*
9* C++ version created on: 2013dec19
10* created by: Markus W. Scherer
11*/
12
13package android.icu.impl.coll;
14
15import java.util.concurrent.atomic.AtomicInteger;
16
17import android.icu.util.ICUCloneNotSupportedException;
18
19/**
20 * Base class for shared, reference-counted, auto-deleted objects.
21 * Java subclasses are mutable and must implement clone().
22 *
23 * <p>In C++, the SharedObject base class is used for both memory and ownership management.
24 * In Java, memory management (deletion after last reference is gone)
25 * is up to the garbage collector,
26 * but the reference counter is still used to see whether the referent is the sole owner.
27 *
28 * <p>Usage:
29 * <pre>
30 * class S extends SharedObject {
31 *     public clone() { ... }
32 * }
33 *
34 * // Either use the nest class Reference (which costs an extra allocation),
35 * // or duplicate its code in the class that uses S
36 * // (which duplicates code and is more error-prone).
37 * class U {
38 *     // For read-only access, use s.readOnly().
39 *     // For writable access, use S ownedS = s.copyOnWrite();
40 *     private SharedObject.Reference&lt;S&gt; s;
41 *     // Returns a writable version of s.
42 *     // If there is exactly one owner, then s itself is returned.
43 *     // If there are multiple owners, then s is replaced with a clone,
44 *     // and that is returned.
45 *     private S getOwnedS() {
46 *         return s.copyOnWrite();
47 *     }
48 *     public U clone() {
49 *         ...
50 *         c.s = s.clone();
51 *         ...
52 *     }
53 * }
54 *
55 * class V {
56 *     // For read-only access, use s directly.
57 *     // For writable access, use S ownedS = getOwnedS();
58 *     private S s;
59 *     // Returns a writable version of s.
60 *     // If there is exactly one owner, then s itself is returned.
61 *     // If there are multiple owners, then s is replaced with a clone,
62 *     // and that is returned.
63 *     private S getOwnedS() {
64 *         if(s.getRefCount() > 1) {
65 *             S ownedS = s.clone();
66 *             s.removeRef();
67 *             s = ownedS;
68 *             ownedS.addRef();
69 *         }
70 *         return s;
71 *     }
72 *     public U clone() {
73 *         ...
74 *         s.addRef();
75 *         ...
76 *     }
77 *     protected void finalize() {
78 *         ...
79 *         if(s != null) {
80 *             s.removeRef();
81 *             s = null;
82 *         }
83 *         ...
84 *     }
85 * }
86 * </pre>
87 *
88 * Either use only Java memory management, or use addRef()/removeRef().
89 * Sharing requires reference-counting.
90 *
91 * TODO: Consider making this more widely available inside ICU,
92 * or else adopting a different model.
93 * @hide Only a subset of ICU is exposed in Android
94 * @hide All android.icu classes are currently hidden
95 */
96public class SharedObject implements Cloneable {
97    /**
98     * Similar to a smart pointer, basically a port of the static methods of C++ SharedObject.
99     */
100    public static final class Reference<T extends SharedObject> implements Cloneable {
101        private T ref;
102
103        public Reference(T r) {
104            ref = r;
105            if(r != null) {
106                r.addRef();
107            }
108        }
109
110        @SuppressWarnings("unchecked")
111        @Override
112        public Reference<T> clone() {
113            Reference<T> c;
114            try {
115                c = (Reference<T>)super.clone();
116            } catch (CloneNotSupportedException e) {
117                // Should never happen.
118                throw new ICUCloneNotSupportedException(e);
119            }
120            if(ref != null) {
121                ref.addRef();
122            }
123            return c;
124        }
125
126        public T readOnly() { return ref; }
127
128        /**
129         * Returns a writable version of the reference.
130         * If there is exactly one owner, then the reference itself is returned.
131         * If there are multiple owners, then the reference is replaced with a clone,
132         * and that is returned.
133         */
134        public T copyOnWrite() {
135            T r = ref;
136            if(r.getRefCount() <= 1) { return r; }
137            @SuppressWarnings("unchecked")
138            T r2 = (T)r.clone();
139            r.removeRef();
140            ref = r2;
141            r2.addRef();
142            return r2;
143        }
144
145        public void clear() {
146            if(ref != null) {
147                ref.removeRef();
148                ref = null;
149            }
150        }
151
152        @Override
153        protected void finalize() throws Throwable {
154            super.finalize();
155            clear();
156        }
157    }
158
159    /** Initializes refCount to 0. */
160    public SharedObject() {}
161
162    /** Initializes refCount to 0. */
163    @Override
164    public SharedObject clone() {
165        SharedObject c;
166        try {
167            c = (SharedObject)super.clone();
168        } catch (CloneNotSupportedException e) {
169            // Should never happen.
170            throw new ICUCloneNotSupportedException(e);
171        }
172        c.refCount = new AtomicInteger();
173        return c;
174    }
175
176    /**
177     * Increments the number of references to this object. Thread-safe.
178     */
179    public final void addRef() { refCount.incrementAndGet(); }
180    /**
181     * Decrements the number of references to this object,
182     * and auto-deletes "this" if the number becomes 0. Thread-safe.
183     */
184    public final void removeRef() {
185        // Deletion in Java is up to the garbage collector.
186        refCount.decrementAndGet();
187    }
188
189    /**
190     * Returns the reference counter. Uses a memory barrier.
191     */
192    public final int getRefCount() { return refCount.get(); }
193
194    public final void deleteIfZeroRefCount() {
195        // Deletion in Java is up to the garbage collector.
196    }
197
198    private AtomicInteger refCount = new AtomicInteger();
199}
200