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