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<S> 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