/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.runtime.internal;
import java.util.function.Supplier;
/**
* Class to perform lazy value computation.
*/
public abstract class Lazy<VALUE> {
private VALUE value;
/**
* Returns the current value.
*
* @return the current value
*/
protected final VALUE getInternal() {
return value;
}
/**
* Computes the actual value lazily.
*
* @return the computed value
*/
protected abstract VALUE computeValue();
/**
* Returns the value for this object, calls {@link #computeValue()} to retrieve the value initially.
*
* @return the computed value
*/
public final VALUE get() {
if (value == null) {
value = computeValue();
}
return value;
}
/**
* Creates a new lazy value object using a supplier function to create the initial value.
*
* @param <V>
* the lazy value type
* @param supplier
* the value supplier function
* @return the lazy value object
*/
public static <V> Lazy<V> of(Supplier<V> supplier) {
return new LazyImpl<>(supplier);
}
/**
* Creates a new lazy value object using a supplier function to create the initial value.
*
* @param <V>
* the lazy value type
* @param supplier
* the value supplier function
* @return the lazy value object
*/
public static <V> Lazy<V> syncOf(Supplier<V> supplier) {
return new SyncLazyImpl<>(supplier);
}
private static final class LazyImpl<V> extends Lazy<V> {
private Supplier<V> supplier;
LazyImpl(Supplier<V> supplier) {
this.supplier = supplier;
}
@Override
protected V computeValue() {
V v = supplier.get();
supplier = null;
return v;
}
}
private static final class SyncLazyImpl<V> extends Lazy<V> {
private Supplier<V> supplier;
SyncLazyImpl(Supplier<V> supplier) {
this.supplier = supplier;
}
@Override
protected synchronized V computeValue() {
Supplier<V> supplier = this.supplier;
// Lazy#get() is not synchronized, so supplier can be null here.
if (supplier == null) {
return getInternal();
}
V v = supplier.get();
this.supplier = null;
return v;
}
}
}