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&lt;S&gt; 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