--- /dev/null
+/*
+ *******************************************************************************
+ * 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.
+ *
+ * <p>The value is <i>conceptually<i> immutable.
+ * If it is held via a direct reference, then it is actually immutable.
+ *
+ * <p>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.
+ *
+ * <p>Null values are supported. They can be distinguished from cleared values
+ * via {@code isNull()}.
+ *
+ * @param <V> Cache instance value type
+ */
+public abstract class CacheValue<V> {
+ /**
+ * "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 <V> CacheValue<V> getInstance(V value) {
+ if (value == null) {
+ return NULL_VALUE;
+ }
+ return strength == Strength.STRONG ? new StrongValue<V>(value) : new SoftValue<V>(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.
+ *
+ * <p>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<V> extends CacheValue<V> {
+ @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<V> extends CacheValue<V> {
+ 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<V> extends CacheValue<V> {
+ private Reference<V> ref;
+
+ SoftValue(V value) { ref = new SoftReference<V>(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<V>(value);
+ return value;
+ } else {
+ // value and oldValue should be equivalent, but
+ // we do not require equals() to be implemented appropriately.
+ return oldValue;
+ }
+ }
+ }
+}
super(container, key, resource);
String s = wholeBundle.reader.getString(resource);
// Allow the reader cache's SoftReference to do its job.
- if (s.length() < ICUResourceBundleReader.LARGE_SIZE / 2) {
+ if (s.length() < ICUResourceBundleReader.LARGE_SIZE / 2 ||
+ CacheValue.futureInstancesWillBeStrong()) {
value = s;
}
}
* <p>This cache uses int[] and Object[] arrays to minimize object creation
* and avoid auto-boxing.
*
- * <p>Large resource objects are stored in SoftReferences.
+ * <p>Large resource objects are usually stored in SoftReferences.
*
* <p>For few resources, a small table is used with binary search.
* When more resources are cached, then the data structure changes to be faster
private int levelBitsList;
private Level rootLevel;
+ private static boolean storeDirectly(int size) {
+ return size < LARGE_SIZE || CacheValue.futureInstancesWillBeStrong();
+ }
+
@SuppressWarnings("unchecked")
private static final Object putIfCleared(Object[] values, int index, Object item, int size) {
Object value = values[index];
if(!(value instanceof SoftReference)) {
- assert size < LARGE_SIZE; // Caller should be consistent for each resource.
+ // The caller should be consistent for each resource,
+ // that is, create equivalent objects of equal size every time,
+ // but the CacheValue "strength" may change over time.
+ // assert size < LARGE_SIZE;
return value;
}
assert size >= LARGE_SIZE;
if(value != null) {
return value;
}
- values[index] = new SoftReference<Object>(item);
+ values[index] = CacheValue.futureInstancesWillBeStrong() ?
+ item : new SoftReference<Object>(item);
return item;
}
return level.putIfAbsent(key, item, size);
}
keys[index] = key;
- values[index] = (size >= LARGE_SIZE) ? new SoftReference<Object>(item) : item;
+ values[index] = storeDirectly(size) ? item : new SoftReference<Object>(item);
return item;
}
// Collision: Add a child level, move the old item there,
}
++length;
keys[index] = res;
- values[index] = (size >= LARGE_SIZE) ? new SoftReference<Object>(item) : item;
+ values[index] = storeDirectly(size) ? item : new SoftReference<Object>(item);
return item;
} else /* not found && length == SIMPLE_LENGTH */ {
// Grow to become trie-like.
/*
*******************************************************************************
-* Copyright (C) 2010-2011, International Business Machines
+* Copyright (C) 2010-2016, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
*/
package com.ibm.icu.impl;
-import java.lang.ref.SoftReference;
import java.util.concurrent.ConcurrentHashMap;
/**
- * Generic, thread-safe cache implementation, storing SoftReferences to cached instances.
+ * Generic, thread-safe cache implementation, usually storing cached instances
+ * in {@link java.lang.ref.Reference}s via {@link CacheValue}s.
* To use, instantiate a subclass which implements the createInstance() method,
* and call get() with the key and the data. The get() call will use the data
* only if it needs to call createInstance(), otherwise the data is ignored.
*
- * By using SoftReferences to instances, the Java runtime can release instances
- * once they are not used any more at all. If such an instance is then requested again,
- * the get() method will call createInstance() again and also create a new SoftReference.
- * The cache holds on to its map of keys to SoftReferenced instances forever.
+ * <p>When caching instances while the CacheValue "strength" is {@code SOFT},
+ * the Java runtime can later release these instances once they are not used any more at all.
+ * If such an instance is then requested again,
+ * the getInstance() method will call createInstance() again and reset the CacheValue.
+ * The cache holds on to its map of keys to CacheValues forever.
+ *
+ * <p>A value can be null if createInstance() returns null.
+ * In this case, it must do so consistently for the same key and data.
*
* @param <K> Cache lookup key type
- * @param <V> Cache instance value type
+ * @param <V> Cache instance value type (must not be a CacheValue)
* @param <D> Data type for creating a new instance value
*
* @author Markus Scherer, Mark Davis
*/
public abstract class SoftCache<K, V, D> extends CacheBase<K, V, D> {
+ private ConcurrentHashMap<K, Object> map = new ConcurrentHashMap<K, Object>();
+
+ @SuppressWarnings("unchecked")
@Override
public final V getInstance(K key, D data) {
- // We synchronize twice, once on the map and once on valueRef,
+ // We synchronize twice, once in the ConcurrentHashMap and
+ // once in valueRef.resetIfCleared(value),
// because we prefer the fine-granularity locking of the ConcurrentHashMap
// over coarser locking on the whole cache instance.
- // We use a SettableSoftReference (a second level of indirection) because
+ // We use a CacheValue (a second level of indirection) because
// ConcurrentHashMap.putIfAbsent() never replaces the key's value, and if it were
- // a simple SoftReference we would not be able to reset its value after it has been cleared.
+ // a simple Reference we would not be able to reset its value after it has been cleared.
// (And ConcurrentHashMap.put() always replaces the value, which we don't want either.)
- SettableSoftReference<V> valueRef = map.get(key);
- V value;
- if(valueRef != null) {
- synchronized(valueRef) {
- value = valueRef.ref.get();
- if(value != null) {
- return value;
- } else {
- // The instance has been evicted, its SoftReference cleared.
- // Create and set a new instance.
- value = createInstance(key, data);
- if (value != null) {
- valueRef.ref = new SoftReference<V>(value);
- }
- return value;
- }
+ Object mapValue = map.get(key);
+ if(mapValue != null) {
+ if(!(mapValue instanceof CacheValue)) {
+ // The value was stored directly.
+ return (V)mapValue;
}
- } else /* valueRef == null */ {
- // We had never cached an instance for this key.
- value = createInstance(key, data);
- if (value == null) {
+ CacheValue<V> cv = (CacheValue<V>)mapValue;
+ if(cv.isNull()) {
return null;
}
- valueRef = map.putIfAbsent(key, new SettableSoftReference<V>(value));
- if(valueRef == null) {
- // Normal "put": Our new value is now cached.
+ V value = cv.get();
+ if(value != null) {
return value;
- } else {
- // Race condition: Another thread beat us to putting a SettableSoftReference
- // into the map. Return its value, but just in case the garbage collector
- // was aggressive, we also offer our new instance for caching.
- return valueRef.setIfAbsent(value);
}
- }
- }
- /**
- * Value type for cache items: Has a SoftReference which can be set
- * to a new value when the SoftReference has been cleared.
- * The SoftCache class sometimes accesses the ref field directly.
- *
- * @param <V> Cache instance value type
- */
- private static final class SettableSoftReference<V> {
- private SettableSoftReference(V value) {
- ref = new SoftReference<V>(value);
- }
- /**
- * If the SoftReference has been cleared, then this replaces it with a new SoftReference
- * for the new value and returns the new value; otherwise returns the current
- * SoftReference's value.
- * @param value Replacement value, for when the current reference has been cleared
- * @return The value that is held by the SoftReference, old or new
- */
- private synchronized V setIfAbsent(V value) {
- V oldValue = ref.get();
- if(oldValue == null) {
- ref = new SoftReference<V>(value);
+ // The instance has been evicted, its Reference cleared.
+ // Create and set a new instance.
+ value = createInstance(key, data);
+ return cv.resetIfCleared(value);
+ } else /* valueRef == null */ {
+ // We had never cached an instance for this key.
+ V value = createInstance(key, data);
+ mapValue = (value != null && CacheValue.futureInstancesWillBeStrong()) ?
+ value : CacheValue.getInstance(value);
+ mapValue = map.putIfAbsent(key, mapValue);
+ if(mapValue == null) {
+ // Normal "put": Our new value is now cached.
return value;
- } else {
- return oldValue;
}
+ // Race condition: Another thread beat us to putting a CacheValue
+ // into the map. Return its value, but just in case the garbage collector
+ // was aggressive, we also offer our new instance for caching.
+ if(!(mapValue instanceof CacheValue)) {
+ // The value was stored directly.
+ return (V)mapValue;
+ }
+ CacheValue<V> cv = (CacheValue<V>)mapValue;
+ return cv.resetIfCleared(value);
}
- private SoftReference<V> ref; // never null
}
- private ConcurrentHashMap<K, SettableSoftReference<V>> map =
- new ConcurrentHashMap<K, SettableSoftReference<V>>();
}
-#Wed Jun 17 11:10:12 EDT 2009
eclipse.preferences.version=1
formatter_profile=_ICU4J Standard
formatter_settings_version=11
org.eclipse.jdt.ui.javadoc=true
org.eclipse.jdt.ui.ondemandthreshold=99
org.eclipse.jdt.ui.staticondemandthreshold=99
-org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\r\n * @return the ${bare_field_name}\r\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\r\n * @param ${param} the ${bare_field_name} to set\r\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\r\n *******************************************************************************\r\n * Copyright (C) ${year}, International Business Machines Corporation and *\r\n * others. All Rights Reserved. *\r\n *******************************************************************************\r\n */</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\r\n * @author ${user}\r\n *\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\r\n * \r\n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\r\n * ${tags}\r\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\r\n * ${see_to_overridden}\r\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\r\n * ${tags}\r\n * ${see_to_target}\r\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\r\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\r\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\r\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\r\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\r\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\r\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\r\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\n *******************************************************************************\n * Copyright (C) ${year}, International Business Machines Corporation and\n * others. All Rights Reserved.\n *******************************************************************************\n */</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
--- /dev/null
+/*
+ *******************************************************************************
+ * Copyright (C) 2016, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ *******************************************************************************
+ */
+package com.ibm.icu.dev.test.impl;
+
+import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.impl.CacheValue;
+import com.ibm.icu.impl.CacheValue.Strength;
+
+public class CacheTest extends TestFmwk {
+ public CacheTest() {}
+
+ public static void main(String[] args) throws Exception {
+ new CacheTest().run(args);
+ }
+
+ /** Code coverage for CacheValue. */
+ public void testNullCacheValue() {
+ CacheValue<Object> nv = CacheValue.getInstance(null);
+ assertTrue("null CacheValue isNull()", nv.isNull());
+ assertTrue("null CacheValue get()==null", nv.get() == null);
+ assertTrue("null CacheValue reset==null", nv.resetIfCleared(null) == null);
+ try {
+ Object v = nv.resetIfCleared(this);
+ fail("null CacheValue reset(not null) should throw an Exception, returned " +
+ v + " instead");
+ } catch(Exception expected) {
+ }
+ }
+
+ /** Code coverage for CacheValue. */
+ public void testStrongCacheValue() {
+ boolean wasStrong = CacheValue.futureInstancesWillBeStrong();
+ CacheValue.setStrength(Strength.STRONG);
+ assertTrue("setStrength(STRONG).futureInstancesWillBeStrong()",
+ CacheValue.futureInstancesWillBeStrong());
+ CacheValue<Object> sv = CacheValue.<Object>getInstance(this);
+ assertFalse("strong CacheValue not isNull()", sv.isNull());
+ assertTrue("strong CacheValue get()==same", sv.get() == this);
+ // A strong CacheValue never changes value.
+ // The implementation does not check that the new value is equal to the old one,
+ // or even of equal type, so it does not matter which new value we pass in.
+ assertTrue("strong CacheValue reset==same", sv.resetIfCleared("") == this);
+ if (!wasStrong) {
+ CacheValue.setStrength(Strength.SOFT);
+ }
+ }
+
+ /** Code coverage for CacheValue. */
+ public void testSoftCacheValue() {
+ boolean wasStrong = CacheValue.futureInstancesWillBeStrong();
+ CacheValue.setStrength(Strength.SOFT);
+ assertFalse("setStrength(SOFT).futureInstancesWillBeStrong()",
+ CacheValue.futureInstancesWillBeStrong());
+ CacheValue<Object> sv = CacheValue.<Object>getInstance(this);
+ assertFalse("soft CacheValue not isNull()", sv.isNull());
+ Object v = sv.get();
+ assertTrue("soft CacheValue get()==same or null", v == this || v == null);
+ assertTrue("soft CacheValue reset==same", sv.resetIfCleared(this) == this);
+ if (wasStrong) {
+ CacheValue.setStrength(Strength.STRONG);
+ }
+ }
+}
}
public TestAll() {
- super("com.ibm.icu.dev.test.util",
- new String[] {
- "ICUServiceTest",
- "ICUServiceThreadTest",
- "ICUBinaryTest",
- "SimpleFormatterTest",
- "TextTrieMapTest"
- },
- "Test miscellaneous implementation utilities");
+ super(
+ new String[] {
+ "CacheTest"
+ },
+ "Test miscellaneous implementation classes");
}
public static final String CLASS_TARGET_NAME = "Impl";
}
-
-
public TestAll() {
super(
new String[] {
+ "ICUServiceTest",
+ "ICUServiceThreadTest",
+ "ICUBinaryTest",
+ "SimpleFormatterTest",
+ "TextTrieMapTest",
"VersionInfoTest",
"ICUResourceBundleTest",
"BytesTrieTest",