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

com.ibm.icu.impl.CacheValue 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) 2016, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 */
package com.ibm.icu.impl;

import java.lang.ref.Reference;
import java.lang.ref.SoftReference;

import com.ibm.icu.util.ICUException;

/**
 * Value type for cache items:
 * Holds a value either via a direct reference or via a {@link Reference},
 * depending on the current "strength" when {@code getInstance()} was called.
 *
 * 

The value is conceptually immutable. * If it is held via a direct reference, then it is actually immutable. * *

A {@code Reference} may be cleared (garbage-collected), * after which {@code get()} returns null. * It can then be reset via {@code resetIfAbsent()}. * The new value should be the same as, or equivalent to, the old value. * *

Null values are supported. They can be distinguished from cleared values * via {@code isNull()}. * * @param Cache instance value type */ public abstract class CacheValue { /** * "Strength" of holding a value in CacheValue instances. * The default strength is {@code SOFT}. */ public enum Strength { /** * Subsequent {@code getInstance()}-created objects * will hold direct references to their values. */ STRONG, /** * Subsequent {@code getInstance()}-created objects * will hold {@link SoftReference}s to their values. */ SOFT }; private static volatile Strength strength = Strength.SOFT; @SuppressWarnings("rawtypes") private static final CacheValue NULL_VALUE = new NullValue(); /** * Changes the "strength" of value references for subsequent {@code getInstance()} calls. */ public static void setStrength(Strength strength) { CacheValue.strength = strength; } /** * Returns true if the "strength" is set to {@code STRONG}. */ public static boolean futureInstancesWillBeStrong() { return strength == Strength.STRONG; } /** * Returns a CacheValue instance that holds the value. * It holds it directly if the value is null or if the current "strength" is {@code STRONG}. * Otherwise, it holds it via a {@link Reference}. */ @SuppressWarnings("unchecked") public static CacheValue getInstance(V value) { if (value == null) { return NULL_VALUE; } return strength == Strength.STRONG ? new StrongValue(value) : new SoftValue(value); } /** * Distinguishes a null value from a Reference value that has been cleared. * * @return true if this object represents a null value. */ public boolean isNull() { return false; } /** * Returns the value (which can be null), * or null if it was held in a Reference and has been cleared. */ public abstract V get(); /** * If the value was held via a {@link Reference} which has been cleared, * then it is replaced with a new {@link Reference} to the new value, * and the new value is returned. * The old and new values should be the same or equivalent. * *

Otherwise the old value is returned. * * @param value Replacement value, for when the current {@link Reference} has been cleared. * @return The old or new value. */ public abstract V resetIfCleared(V value); private static final class NullValue extends CacheValue { @Override public boolean isNull() { return true; } @Override public V get() { return null; } @Override public V resetIfCleared(V value) { if (value != null) { throw new ICUException("resetting a null value to a non-null value"); } return null; } } private static final class StrongValue extends CacheValue { private V value; StrongValue(V value) { this.value = value; } @Override public V get() { return value; } @Override public V resetIfCleared(V value) { // value and this.value should be equivalent, but // we do not require equals() to be implemented appropriately. return this.value; } } private static final class SoftValue extends CacheValue { private volatile Reference ref; // volatile for unsynchronized get() SoftValue(V value) { ref = new SoftReference(value); } @Override public V get() { return ref.get(); } @Override public synchronized V resetIfCleared(V value) { V oldValue = ref.get(); if (oldValue == null) { ref = new SoftReference(value); return value; } else { // value and oldValue should be equivalent, but // we do not require equals() to be implemented appropriately. return oldValue; } } } }