Lazy values: change encoding, now NOT_COMPUTED is an explicit object, and null is stored as such

This commit is contained in:
Andrey Breslav
2013-09-30 19:28:04 +04:00
parent 51dfdf795f
commit 48605074aa
3 changed files with 18 additions and 12 deletions
@@ -114,7 +114,7 @@ public class LockBasedStorageManager implements StorageManager {
return new LockBasedLazyValue<T>(lock, computable) { return new LockBasedLazyValue<T>(lock, computable) {
@Override @Override
protected Object recursionDetected() { protected Object recursionDetected() {
return WrappedValues.escapeNull(onRecursiveCall); return onRecursiveCall;
} }
}; };
} }
@@ -141,13 +141,14 @@ public class LockBasedStorageManager implements StorageManager {
private static class LockBasedLazyValue<T> implements NullableLazyValue<T> { private static class LockBasedLazyValue<T> implements NullableLazyValue<T> {
private static final Object NOT_COMPUTED = new Object();
private static final Object COMPUTING = new Object(); private static final Object COMPUTING = new Object();
private final Object lock; private final Object lock;
private final Computable<T> computable; private final Computable<T> computable;
@Nullable @Nullable
private volatile Object value = null; private volatile Object value = NOT_COMPUTED;
public LockBasedLazyValue(@NotNull Object lock, @NotNull Computable<T> computable) { public LockBasedLazyValue(@NotNull Object lock, @NotNull Computable<T> computable) {
this.lock = lock; this.lock = lock;
@@ -157,23 +158,23 @@ public class LockBasedStorageManager implements StorageManager {
@Override @Override
public T compute() { public T compute() {
Object _value = value; Object _value = value;
if (_value != null && _value != COMPUTING) return WrappedValues.unescapeExceptionOrNull(_value); if (_value != NOT_COMPUTED && _value != COMPUTING) return WrappedValues.unescapeThrowable(_value);
synchronized (lock) { synchronized (lock) {
_value = value; _value = value;
if (_value == COMPUTING) { if (_value == COMPUTING) {
Object result = recursionDetected(); Object result = recursionDetected();
if (result != null) { if (result != NOT_COMPUTED) {
return WrappedValues.unescapeExceptionOrNull(result); return WrappedValues.unescapeThrowable(result);
} }
} }
if (_value != null) return WrappedValues.unescapeExceptionOrNull(_value); if (_value != NOT_COMPUTED) return WrappedValues.unescapeThrowable(_value);
value = COMPUTING; value = COMPUTING;
try { try {
T typedValue = computable.compute(); T typedValue = computable.compute();
value = WrappedValues.escapeNull(typedValue); value = typedValue;
postCompute(typedValue); postCompute(typedValue);
return typedValue; return typedValue;
} }
@@ -185,7 +186,7 @@ public class LockBasedStorageManager implements StorageManager {
} }
/** /**
* @return {@code null} to proceed, a wrapped value otherwise, see WrappedValues * @return {@code NOT_COMPUTED} to proceed, a value or wrapped exception otherwise, see WrappedValues
* @throws DO NOT throw exceptions from implementations of this method, instead return WrappedValues.escapeThrowable(exception) * @throws DO NOT throw exceptions from implementations of this method, instead return WrappedValues.escapeThrowable(exception)
*/ */
@Nullable @Nullable
@@ -44,9 +44,8 @@ public interface StorageManager {
/** /**
* @param onRecursiveCall is called if the computation calls itself recursively. * @param onRecursiveCall is called if the computation calls itself recursively.
* If this parameter is null, an exception will be thrown on a recursive call. * If this parameter is null, an exception will be thrown on a recursive call,
* If this function returns null, the computation proceeds recursively, * otherwise it should return a result of WrappedValues.escapeThrowable() method
* otherwise it should return a result of WrappedValues.escape*() method
* @param postCompute is called after the value is computed, but before any other thread sees it (the current thread may * @param postCompute is called after the value is computed, but before any other thread sees it (the current thread may
* see it in between) * see it in between)
*/ */
@@ -58,10 +58,16 @@ public class WrappedValues {
@Nullable @Nullable
public static <V> V unescapeExceptionOrNull(@NotNull Object value) { public static <V> V unescapeExceptionOrNull(@NotNull Object value) {
return unescapeNull(unescapeThrowable(value));
}
@Nullable
public static <V> V unescapeThrowable(@Nullable Object value) {
if (value instanceof ThrowableWrapper) { if (value instanceof ThrowableWrapper) {
throw ExceptionUtils.rethrow(((ThrowableWrapper) value).getThrowable()); throw ExceptionUtils.rethrow(((ThrowableWrapper) value).getThrowable());
} }
return unescapeNull(value); //noinspection unchecked
return (V) value;
} }
} }