package xapi.fu;
import xapi.fu.In1Out1.In1Out1Unsafe;
/**
* A lazy-initialized object.
*
* Beware that this lazy object will be synchronized upon every get until it return non-null,
* unless you supply a concrete value to the constructor of the class.
*
* If you are supplying a value directly to a Lazy, be aware that Lazy.lazy1() and the default constructors do not tolerate nulls.
* They will call assert valueAcceptable(ctorValue), which defaults to only allow non-null values.
*
* If you want to explicitly allow null, use {@link LazyNullable} or {@link Lazy#ofNullable(Object)}
*
* @author James X. Nelson (james@wetheinter.net)
* Created on 14/12/15.
*/
public class Lazy <T> implements Out1<T>, IsLazy {
// This is volatile because the first read to this proxy will immutabilize the result of the constructot Out1,
// thus, we want all other threads to notice that the Lazy has changed,
// without calling the expensive synchronized proxy needed to safely "lock once" on a deferred value
private volatile Out1<T> proxy;
@Override
public final T out1() {
return proxy.out1();
}
// First, the easy constructor... a reference to a value...
public Lazy(T value) {
// If you have a concrete value, skip the expensive proxy sync; either use an immutable wrapper, or the shared NULL pointer
proxy = valueAcceptable(value) ? Immutable.immutable1(value) : NULL;
}
private interface ProxySupplier <T> extends Out1<T> { }
@SuppressWarnings("unchecked")
public Lazy(Out1<T> supplier) {
proxy = proxySupplier(supplier);
}
private Out1<T> proxySupplier(Out1<T> supplier) {
// The constructor of Lazy closes over this constructor using this array as a writable reference.
// Note that we are not putting this in a field because we don't want anyone to muck with it;
final ProxySupplier<T>[] prox = new ProxySupplier[1];
prox[0] = () -> {
// take turns looking at the memory slot
synchronized (prox) {
if (proxy == prox[0]) {
// first on in tries the provider;
T value = supplier.out1();
// default acceptable value is non-null
if (valueAcceptable(value)) {
// We only override the proxy if the value is non-null,
// or if you specifically implemented LazyNullable.
proxy = Immutable.immutable1(value);
prox[0] = null;
}
return value;
}
}
return proxy.out1();
};
return prox[0];
}
/*
The Default acceptable value is non-null.
This exists for you to override.
*/
protected boolean valueAcceptable(T value) {
return value != null;
}
public static <T> Lazy<T> immutable1(T value) {
return new Lazy<>(value == null ? NULL : new Lazy<>(value));
}
public final boolean isNull1() {
// proxy is volatile, only pay to read it once.
final Out1<T> value = proxy;
// be as lazy as possible, but no lazier; safety first!
return value == NULL || value == null || value.out1() == null;
}
public final boolean isFull1() {
// proxy is volatile, only pay to read it once.
final Out1<T> value = proxy;
// be as lazy as possible; don't even call the method if we know it might be null.
return value != NULL && value != null && value.out1() != null;
}
public final boolean isResolved() {
return !isUnresolved();
}
public final boolean isUnresolved() {
return proxy instanceof ProxySupplier;
}
public final T assertAcceptable1() {
T out = out1();
assert valueAcceptable(out);
return out;
}
public final T assertNull1() {
T out = out1();
assert out == null && isNull1() && !isFull1();
return out;
}
public final T assertFull1() {
T out = out1();
assert out != null : "Lazy " + this + ", returned value was null; expected it to be full; ";
assert !isNull1() : "Lazy " + this + " .isNull1() returned true, despite out1() returning non-null";
assert isFull1() : "Lazy " + this + " .isFull1() did not return true, despite out1() returning non-null";
return out;
}
public static <T> Lazy<T> deferred1(Out1<T> supplier) {
return supplier instanceof Lazy ?
(Lazy<T>)supplier :
new Lazy<>(supplier) ;
}
public static <T> Lazy<T> immediate1(Out1<T> supplier) {
return immutable1(supplier.out1());
}
public static <I, T> Lazy<T> immediate1(In1Out1<I, T> supplier, Out1<I> value) {
return immutable1(supplier.apply(value));
}
public static <I, T> Lazy<T> immediate1(In1Out1<I, T> supplier, I value) {
return immutable1(supplier.io(value));
}
public static <I, T> Lazy<T> immediate1Unsafe(In1Out1Unsafe<I, T> supplier, Out1<I> value) {
return immutable1(supplier.apply(value));
}
public static <I, T> Lazy<T> immediate1Unsafe(In1Out1Unsafe<I, T> supplier, I value) {
return immutable1(supplier.io(value));
}
public static <I, T> Lazy<T> deferSupplier(In1Out1<I, T> supplier, I value) {
final Out1<T> factory = ()->supplier.io(value);
return new Lazy<>(factory);
}
public static <I, T> Lazy<T> deferSupplierUnsafe(In1Out1Unsafe<I, T> supplier, I value) {
final Out1<T> factory = ()->supplier.io(value);
return new Lazy<>(factory);
}
public static <I, T> Lazy<T> deferBoth(In1Out1<I, T> supplier, Out1<I> value) {
final Out1<T> factory = ()->supplier.io(value.out1());
return new Lazy<>(factory);
}
public static <I1, I2, T> Lazy<T> deferBoth(In2Out1<I1, I2, T> supplier, Out1<I1> o1, Out1<I2> o2) {
final Out1<T> factory = ()->supplier.io(o1.out1(), o2.out1());
return new Lazy<>(factory);
}
public static <I1, I2, T> Lazy<T> deferSupplier(In2Out1<I1, I2, T> supplier, I1 o1, I2 o2) {
final Out1<T> factory = ()->supplier.io(o1, o2);
return new Lazy<>(factory);
}
public static <I, T> Lazy<T> deferSupplierUnsafe(In1Out1Unsafe<I, T> supplier, Out1Unsafe<I> value) {
final Out1<T> factory = ()->supplier.io(value.out1());
return new Lazy<>(factory);
}
public static <I, T> Lazy<T> deferSupplierImmediateValue(In1Out1<I, T> supplier, Out1<I> value) {
final I whenCreated = value.out1();
final Out1<T> factory = ()->supplier.io(whenCreated);
return new Lazy<>(factory);
}
public static <I, T> Lazy<T> deferSupplierImmediateValue(In1Out1Unsafe<I, T> supplier, Out1Unsafe<I> value) {
final I whenCreated = value.out1();
final Out1<T> factory = ()->supplier.io(whenCreated);
return new Lazy<>(factory);
}
public static <T> LazyNullable<T> ofNullable(T value) {
return new LazyNullable<>(value);
}
public static <T> LazyNullable<T> ofNullableDeferred(Out1<T> supplier) {
return new LazyNullable<>(supplier);
}
public static <T> LazyNullable<T> ofNullableImmediate(Out1<T> supplier) {
return ofNullable(supplier.out1());
}
public static <I, T> LazyNullable<T> ofNullable(In1Out1<I, T> supplier, I value) {
final Out1<T> factory = ()->supplier.io(value);
return new LazyNullable<>(factory);
}
public static <I, T> LazyNullable<T> ofNullableDeferred(In1Out1<I, T> supplier, Out1<I> value) {
final Out1<T> factory = supplier.supplyDeferred(value);
return new LazyNullable<>(factory);
}
public static <I, T> LazyNullable<T> ofNullableDeferredConcrete(In1Out1<I, T> supplier, I value) {
final Out1<T> factory = supplier.supply(value);
return new LazyNullable<>(factory);
}
public static <I, T> LazyNullable<T> ofNullableImmediate(In1Out1<I, T> supplier, Out1<I> value) {
final Out1<T> factory = supplier.supplyImmediate(value);
// Note that we do not resolve the supplier immediate, it only resolves the value immediately.
// If you want to resolve the whole expression immediately, you should not be using a Lazy. :-)
return new LazyNullable<>(factory);
}
public boolean isImmutable() {
return proxy instanceof Immutable || proxy instanceof IsImmutable;
}
public final boolean isMutable() {
return !isImmutable();
}
@SuppressWarnings({"all"})
public static final Lazy LAZY_NULL = new LazyNullable(Out1.NULL);
private static class LazyNullable<T> extends Lazy<T> {
/**
* If you don't want to take up RAM with a bunch of pointers to potentially null values,
* consider using this memory address to represent a null provider (just beware you lose generic information!)
*/
public LazyNullable(Out1<T> supplier) {
super(supplier == null ? NULL : supplier);
}
public LazyNullable(T value) {
super(value);
}
@Override
protected boolean valueAcceptable(T value) {
return true;
}
}
}