Home | History | Annotate | Download | only in coll
      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&lt;S&gt; 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