17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert******************************************************************************* 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* Copyright (C) 2013-2014, International Business Machines 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* Corporation and others. All Rights Reserved. 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert******************************************************************************* 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* SharedObject.java, ported from sharedobject.h/.cpp 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* C++ version created on: 2013dec19 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* created by: Markus W. Scherer 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*/ 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl.coll; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.concurrent.atomic.AtomicInteger; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ICUCloneNotSupportedException; 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Base class for shared, reference-counted, auto-deleted objects. 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Java subclasses are mutable and must implement clone(). 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>In C++, the SharedObject base class is used for both memory and ownership management. 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * In Java, memory management (deletion after last reference is gone) 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is up to the garbage collector, 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * but the reference counter is still used to see whether the referent is the sole owner. 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Usage: 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * class S extends SharedObject { 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * public clone() { ... } 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * } 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Either use the nest class Reference (which costs an extra allocation), 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // or duplicate its code in the class that uses S 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // (which duplicates code and is more error-prone). 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * class U { 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // For read-only access, use s.readOnly(). 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // For writable access, use S ownedS = s.copyOnWrite(); 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * private SharedObject.Reference<S> s; 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Returns a writable version of s. 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // If there is exactly one owner, then s itself is returned. 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // If there are multiple owners, then s is replaced with a clone, 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // and that is returned. 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * private S getOwnedS() { 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * return s.copyOnWrite(); 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * } 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * public U clone() { 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ... 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * c.s = s.clone(); 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ... 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * } 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * } 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * class V { 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // For read-only access, use s directly. 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // For writable access, use S ownedS = getOwnedS(); 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * private S s; 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Returns a writable version of s. 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // If there is exactly one owner, then s itself is returned. 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // If there are multiple owners, then s is replaced with a clone, 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // and that is returned. 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * private S getOwnedS() { 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * if(s.getRefCount() > 1) { 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * S ownedS = s.clone(); 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * s.removeRef(); 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * s = ownedS; 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ownedS.addRef(); 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * } 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * return s; 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * } 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * public U clone() { 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ... 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * s.addRef(); 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ... 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * } 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * protected void finalize() { 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ... 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * if(s != null) { 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * s.removeRef(); 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * s = null; 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * } 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ... 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * } 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * } 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Either use only Java memory management, or use addRef()/removeRef(). 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sharing requires reference-counting. 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * TODO: Consider making this more widely available inside ICU, 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or else adopting a different model. 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class SharedObject implements Cloneable { 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Similar to a smart pointer, basically a port of the static methods of C++ SharedObject. 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final class Reference<T extends SharedObject> implements Cloneable { 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private T ref; 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Reference(T r) { 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ref = r; 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(r != null) { 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r.addRef(); 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unchecked") 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Reference<T> clone() { 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Reference<T> c; 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert c = (Reference<T>)super.clone(); 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (CloneNotSupportedException e) { 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Should never happen. 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new ICUCloneNotSupportedException(e); 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(ref != null) { 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ref.addRef(); 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return c; 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public T readOnly() { return ref; } 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a writable version of the reference. 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If there is exactly one owner, then the reference itself is returned. 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If there are multiple owners, then the reference is replaced with a clone, 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and that is returned. 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public T copyOnWrite() { 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert T r = ref; 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(r.getRefCount() <= 1) { return r; } 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unchecked") 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert T r2 = (T)r.clone(); 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r.removeRef(); 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ref = r2; 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r2.addRef(); 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return r2; 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void clear() { 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(ref != null) { 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ref.removeRef(); 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ref = null; 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected void finalize() throws Throwable { 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super.finalize(); 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert clear(); 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** Initializes refCount to 0. */ 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public SharedObject() {} 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** Initializes refCount to 0. */ 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public SharedObject clone() { 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SharedObject c; 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert c = (SharedObject)super.clone(); 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (CloneNotSupportedException e) { 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Should never happen. 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new ICUCloneNotSupportedException(e); 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert c.refCount = new AtomicInteger(); 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return c; 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Increments the number of references to this object. Thread-safe. 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final void addRef() { refCount.incrementAndGet(); } 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Decrements the number of references to this object, 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and auto-deletes "this" if the number becomes 0. Thread-safe. 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final void removeRef() { 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Deletion in Java is up to the garbage collector. 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert refCount.decrementAndGet(); 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the reference counter. Uses a memory barrier. 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final int getRefCount() { return refCount.get(); } 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final void deleteIfZeroRefCount() { 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Deletion in Java is up to the garbage collector. 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private AtomicInteger refCount = new AtomicInteger(); 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 197