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) {
@Override
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 final Object NOT_COMPUTED = new Object();
private static final Object COMPUTING = new Object();
private final Object lock;
private final Computable<T> computable;
@Nullable
private volatile Object value = null;
private volatile Object value = NOT_COMPUTED;
public LockBasedLazyValue(@NotNull Object lock, @NotNull Computable<T> computable) {
this.lock = lock;
@@ -157,23 +158,23 @@ public class LockBasedStorageManager implements StorageManager {
@Override
public T compute() {
Object _value = value;
if (_value != null && _value != COMPUTING) return WrappedValues.unescapeExceptionOrNull(_value);
if (_value != NOT_COMPUTED && _value != COMPUTING) return WrappedValues.unescapeThrowable(_value);
synchronized (lock) {
_value = value;
if (_value == COMPUTING) {
Object result = recursionDetected();
if (result != null) {
return WrappedValues.unescapeExceptionOrNull(result);
if (result != NOT_COMPUTED) {
return WrappedValues.unescapeThrowable(result);
}
}
if (_value != null) return WrappedValues.unescapeExceptionOrNull(_value);
if (_value != NOT_COMPUTED) return WrappedValues.unescapeThrowable(_value);
value = COMPUTING;
try {
T typedValue = computable.compute();
value = WrappedValues.escapeNull(typedValue);
value = typedValue;
postCompute(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)
*/
@Nullable
@@ -44,9 +44,8 @@ public interface StorageManager {
/**
* @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 function returns null, the computation proceeds recursively,
* otherwise it should return a result of WrappedValues.escape*() method
* If this parameter is null, an exception will be thrown on a recursive call,
* otherwise it should return a result of WrappedValues.escapeThrowable() method
* @param postCompute is called after the value is computed, but before any other thread sees it (the current thread may
* see it in between)
*/
@@ -58,10 +58,16 @@ public class WrappedValues {
@Nullable
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) {
throw ExceptionUtils.rethrow(((ThrowableWrapper) value).getThrowable());
}
return unescapeNull(value);
//noinspection unchecked
return (V) value;
}
}