All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ibm.icu.impl.coll.SharedObject Maven / Gradle / Ivy

There is a newer version: 2.12.15
Show newest version
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
/*
*******************************************************************************
* Copyright (C) 2013-2014, International Business Machines
* Corporation and others.  All Rights Reserved.
*******************************************************************************
* SharedObject.java, ported from sharedobject.h/.cpp
*
* C++ version created on: 2013dec19
* created by: Markus W. Scherer
*/

package com.ibm.icu.impl.coll;

import java.util.concurrent.atomic.AtomicInteger;

import com.ibm.icu.util.ICUCloneNotSupportedException;

/**
 * Base class for shared, reference-counted, auto-deleted objects.
 * Java subclasses are mutable and must implement clone().
 *
 * 

In C++, the SharedObject base class is used for both memory and ownership management. * In Java, memory management (deletion after last reference is gone) * is up to the garbage collector, * but the reference counter is still used to see whether the referent is the sole owner. * *

Usage: *

 * class S extends SharedObject {
 *     public clone() { ... }
 * }
 *
 * // Either use the nest class Reference (which costs an extra allocation),
 * // or duplicate its code in the class that uses S
 * // (which duplicates code and is more error-prone).
 * class U {
 *     // For read-only access, use s.readOnly().
 *     // For writable access, use S ownedS = s.copyOnWrite();
 *     private SharedObject.Reference<S> s;
 *     // Returns a writable version of s.
 *     // If there is exactly one owner, then s itself is returned.
 *     // If there are multiple owners, then s is replaced with a clone,
 *     // and that is returned.
 *     private S getOwnedS() {
 *         return s.copyOnWrite();
 *     }
 *     public U clone() {
 *         ...
 *         c.s = s.clone();
 *         ...
 *     }
 * }
 *
 * class V {
 *     // For read-only access, use s directly.
 *     // For writable access, use S ownedS = getOwnedS();
 *     private S s;
 *     // Returns a writable version of s.
 *     // If there is exactly one owner, then s itself is returned.
 *     // If there are multiple owners, then s is replaced with a clone,
 *     // and that is returned.
 *     private S getOwnedS() {
 *         if(s.getRefCount() > 1) {
 *             S ownedS = s.clone();
 *             s.removeRef();
 *             s = ownedS;
 *             ownedS.addRef();
 *         }
 *         return s;
 *     }
 *     public U clone() {
 *         ...
 *         s.addRef();
 *         ...
 *     }
 *     protected void finalize() {
 *         ...
 *         if(s != null) {
 *             s.removeRef();
 *             s = null;
 *         }
 *         ...
 *     }
 * }
 * 
* * Either use only Java memory management, or use addRef()/removeRef(). * Sharing requires reference-counting. * * TODO: Consider making this more widely available inside ICU, * or else adopting a different model. */ public class SharedObject implements Cloneable { /** * Similar to a smart pointer, basically a port of the static methods of C++ SharedObject. */ public static final class Reference implements Cloneable { private T ref; public Reference(T r) { ref = r; if(r != null) { r.addRef(); } } @SuppressWarnings("unchecked") @Override public Reference clone() { Reference c; try { c = (Reference)super.clone(); } catch (CloneNotSupportedException e) { // Should never happen. throw new ICUCloneNotSupportedException(e); } if(ref != null) { ref.addRef(); } return c; } public T readOnly() { return ref; } /** * Returns a writable version of the reference. * If there is exactly one owner, then the reference itself is returned. * If there are multiple owners, then the reference is replaced with a clone, * and that is returned. */ public T copyOnWrite() { T r = ref; if(r.getRefCount() <= 1) { return r; } @SuppressWarnings("unchecked") T r2 = (T)r.clone(); r.removeRef(); ref = r2; r2.addRef(); return r2; } public void clear() { if(ref != null) { ref.removeRef(); ref = null; } } @Override protected void finalize() throws Throwable { super.finalize(); clear(); } } /** Initializes refCount to 0. */ public SharedObject() {} /** Initializes refCount to 0. */ @Override public SharedObject clone() { SharedObject c; try { c = (SharedObject)super.clone(); } catch (CloneNotSupportedException e) { // Should never happen. throw new ICUCloneNotSupportedException(e); } c.refCount = new AtomicInteger(); return c; } /** * Increments the number of references to this object. Thread-safe. */ public final void addRef() { refCount.incrementAndGet(); } /** * Decrements the number of references to this object, * and auto-deletes "this" if the number becomes 0. Thread-safe. */ public final void removeRef() { // Deletion in Java is up to the garbage collector. refCount.decrementAndGet(); } /** * Returns the reference counter. Uses a memory barrier. */ public final int getRefCount() { return refCount.get(); } public final void deleteIfZeroRefCount() { // Deletion in Java is up to the garbage collector. } private AtomicInteger refCount = new AtomicInteger(); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy