Home | History | Annotate | Download | only in impl
      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) 2016, International Business Machines Corporation and
      7  * others. All Rights Reserved.
      8  *******************************************************************************
      9  */
     10 package android.icu.impl;
     11 
     12 import java.lang.ref.Reference;
     13 import java.lang.ref.SoftReference;
     14 
     15 import android.icu.util.ICUException;
     16 
     17 /**
     18  * Value type for cache items:
     19  * Holds a value either via a direct reference or via a {@link Reference},
     20  * depending on the current "strength" when {@code getInstance()} was called.
     21  *
     22  * <p>The value is <i>conceptually<i> immutable.
     23  * If it is held via a direct reference, then it is actually immutable.
     24  *
     25  * <p>A {@code Reference} may be cleared (garbage-collected),
     26  * after which {@code get()} returns null.
     27  * It can then be reset via {@code resetIfAbsent()}.
     28  * The new value should be the same as, or equivalent to, the old value.
     29  *
     30  * <p>Null values are supported. They can be distinguished from cleared values
     31  * via {@code isNull()}.
     32  *
     33  * @param <V> Cache instance value type
     34  * @hide Only a subset of ICU is exposed in Android
     35  */
     36 public abstract class CacheValue<V> {
     37     /**
     38      * "Strength" of holding a value in CacheValue instances.
     39      * The default strength is {@code SOFT}.
     40      */
     41     public enum Strength {
     42         /**
     43          * Subsequent {@code getInstance()}-created objects
     44          * will hold direct references to their values.
     45          */
     46         STRONG,
     47         /**
     48          * Subsequent {@code getInstance()}-created objects
     49          * will hold {@link SoftReference}s to their values.
     50          */
     51         SOFT
     52     };
     53     private static volatile Strength strength = Strength.SOFT;
     54 
     55     @SuppressWarnings("rawtypes")
     56     private static final CacheValue NULL_VALUE = new NullValue();
     57 
     58     /**
     59      * Changes the "strength" of value references for subsequent {@code getInstance()} calls.
     60      */
     61     public static void setStrength(Strength strength) { CacheValue.strength = strength; }
     62 
     63     /**
     64      * Returns true if the "strength" is set to {@code STRONG}.
     65      */
     66     public static boolean futureInstancesWillBeStrong() { return strength == Strength.STRONG; }
     67 
     68     /**
     69      * Returns a CacheValue instance that holds the value.
     70      * It holds it directly if the value is null or if the current "strength" is {@code STRONG}.
     71      * Otherwise, it holds it via a {@link Reference}.
     72      */
     73     @SuppressWarnings("unchecked")
     74     public static <V> CacheValue<V> getInstance(V value) {
     75         if (value == null) {
     76             return NULL_VALUE;
     77         }
     78         return strength == Strength.STRONG ? new StrongValue<V>(value) : new SoftValue<V>(value);
     79     }
     80 
     81     /**
     82      * Distinguishes a null value from a Reference value that has been cleared.
     83      *
     84      * @return true if this object represents a null value.
     85      */
     86     public boolean isNull() { return false; }
     87     /**
     88      * Returns the value (which can be null),
     89      * or null if it was held in a Reference and has been cleared.
     90      */
     91     public abstract V get();
     92     /**
     93      * If the value was held via a {@link Reference} which has been cleared,
     94      * then it is replaced with a new {@link Reference} to the new value,
     95      * and the new value is returned.
     96      * The old and new values should be the same or equivalent.
     97      *
     98      * <p>Otherwise the old value is returned.
     99      *
    100      * @param value Replacement value, for when the current {@link Reference} has been cleared.
    101      * @return The old or new value.
    102      */
    103     public abstract V resetIfCleared(V value);
    104 
    105     private static final class NullValue<V> extends CacheValue<V> {
    106         @Override
    107         public boolean isNull() { return true; }
    108         @Override
    109         public V get() { return null; }
    110         @Override
    111         public V resetIfCleared(V value) {
    112             if (value != null) {
    113                 throw new ICUException("resetting a null value to a non-null value");
    114             }
    115             return null;
    116         }
    117     }
    118 
    119     private static final class StrongValue<V> extends CacheValue<V> {
    120         private V value;
    121 
    122         StrongValue(V value) { this.value = value; }
    123         @Override
    124         public V get() { return value; }
    125         @Override
    126         public V resetIfCleared(V value) {
    127             // value and this.value should be equivalent, but
    128             // we do not require equals() to be implemented appropriately.
    129             return this.value;
    130         }
    131     }
    132 
    133     private static final class SoftValue<V> extends CacheValue<V> {
    134         private volatile Reference<V> ref;  // volatile for unsynchronized get()
    135 
    136         SoftValue(V value) { ref = new SoftReference<V>(value); }
    137         @Override
    138         public V get() { return ref.get(); }
    139         @Override
    140         public synchronized V resetIfCleared(V value) {
    141             V oldValue = ref.get();
    142             if (oldValue == null) {
    143                 ref = new SoftReference<V>(value);
    144                 return value;
    145             } else {
    146                 // value and oldValue should be equivalent, but
    147                 // we do not require equals() to be implemented appropriately.
    148                 return oldValue;
    149             }
    150         }
    151     }
    152 }
    153