/* * Copyright 2016 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.diffplug.common.base; import java.util.Objects; import java.util.function.Consumer; import java.util.function.DoubleConsumer; import java.util.function.DoubleSupplier; import java.util.function.Function; import java.util.function.IntConsumer; import java.util.function.IntSupplier; import java.util.function.LongConsumer; import java.util.function.LongSupplier; import java.util.function.Supplier; /** * Provides get/set access to a mutable non-null value. */ public interface Box<T> extends Supplier<T>, Consumer<T> { /** Sets the value which will later be returned by get(). */ void set(T value); /** * Delegates to set(). * * @deprecated Provided to satisfy the {@link Consumer} interface; use {@link #set} instead. */ @Deprecated default void accept(T value) { set(value); } /** * Performs a set() on the result of a get(). * * Some implementations may provide atomic semantics, * but it's not required. */ default T modify(Function<? super T, ? extends T> mutator) { T modified = mutator.apply(get()); set(modified); return modified; } /** * Maps one {@code Box} to another {@code Box}, preserving any * {@link #modify(Function)} guarantees of the underlying Box. */ default <R> Box<R> map(Converter<T, R> converter) { return new Mapped<>(this, converter); } static final class Mapped<T, R> implements Box<R> { private final Box<T> delegate; private final Converter<T, R> converter; public Mapped(Box<T> delegate, Converter<T, R> converter) { this.delegate = delegate; this.converter = converter; } @Override public R get() { return converter.convertNonNull(delegate.get()); } @Override public void set(R value) { delegate.set(converter.revertNonNull(value)); } /** Shortcut for doing a set() on the result of a get(). */ @Override public R modify(Function<? super R, ? extends R> mutator) { Box.Nullable<R> result = Box.Nullable.of(null); delegate.modify(input -> { R unmappedResult = mutator.apply(converter.convertNonNull(input)); result.set(unmappedResult); return converter.revertNonNull(unmappedResult); }); return result.get(); } @Override public String toString() { return "[" + delegate + " mapped to " + get() + " by " + converter + "]"; } } /** * Creates a `Box` holding the given value in a `volatile` field. * * Every call to {@link #set(Object)} confirms that the argument * is actually non-null, and the value is stored in a volatile variable. */ public static <T> Box<T> ofVolatile(T value) { return new Volatile<>(value); } static final class Volatile<T> implements Box<T> { private volatile T obj; private Volatile(T init) { set(init); } @Override public T get() { return obj; } @Override public void set(T obj) { this.obj = Objects.requireNonNull(obj); } @Override public String toString() { return "Box.ofVolatile[" + get() + "]"; } } /** * Creates a `Box` holding the given value in a non-`volatile` field. * * The value is stored in standard non-volatile * field, and non-null-ness is not checked on * every call to set. */ public static <T> Box<T> of(T value) { return new Default<>(value); } static final class Default<T> implements Box<T> { private T obj; private Default(T init) { set(init); } @Override public T get() { return obj; } @Override public void set(T obj) { this.obj = Objects.requireNonNull(obj); } @Override public String toString() { return "Box.of[" + get() + "]"; } } /** Creates a `Box` from a `Supplier` and a `Consumer`. */ public static <T> Box<T> from(Supplier<T> getter, Consumer<T> setter) { Objects.requireNonNull(getter); Objects.requireNonNull(setter); return new Box<T>() { @Override public T get() { return Objects.requireNonNull(getter.get()); } @Override public void set(T value) { setter.accept(Objects.requireNonNull(value)); } @Override public String toString() { return "Box.from[" + get() + "]"; } }; } /** Provides get/set access to a mutable nullable value. */ public interface Nullable<T> extends Supplier<T>, Consumer<T> { /** Sets the value which will later be returned by get(). */ void set(@javax.annotation.Nullable T value); /** * Delegates to set(). * * @deprecated Provided to satisfy the {@code Function} interface; use {@link #set} instead. */ @Deprecated default void accept(@javax.annotation.Nullable T value) { set(value); } /** Shortcut for doing a set() on the result of a get(). */ default T modify(Function<? super T, ? extends T> mutator) { T modified = mutator.apply(get()); set(modified); return modified; } /** * Maps one {@code Box} to another {@code Box}, preserving any * {@link #modify(Function)} guarantees of the underlying Box. */ default <R> Nullable<R> map(ConverterNullable<T, R> converter) { return new Nullable.Mapped<>(this, converter); } static final class Mapped<T, R> implements Nullable<R> { private final Nullable<T> delegate; private final ConverterNullable<T, R> converter; public Mapped(Nullable<T> delegate, ConverterNullable<T, R> converter) { this.delegate = delegate; this.converter = converter; } @Override public R get() { return converter.convert(delegate.get()); } @Override public void set(R value) { delegate.set(converter.revert(value)); } /** Shortcut for doing a set() on the result of a get(). */ @Override public R modify(Function<? super R, ? extends R> mutator) { Box.Nullable<R> result = Box.Nullable.of(null); delegate.modify(input -> { R unmappedResult = mutator.apply(converter.convert(input)); result.set(unmappedResult); return converter.revert(unmappedResult); }); return result.get(); } @Override public String toString() { return "[" + delegate + " mapped to " + get() + " by " + converter + "]"; } } /** Creates a `Box.Nullable` holding the given possibly-null value in a `volatile` field. */ public static <T> Nullable<T> ofVolatile(@javax.annotation.Nullable T init) { return new Volatile<>(init); } /** Creates a `Box.Nullable` holding a null value in a `volatile` field. */ public static <T> Nullable<T> ofVolatileNull() { return ofVolatile(null); } static class Volatile<T> implements Box.Nullable<T> { private volatile T obj; private Volatile(T init) { set(init); } @Override public T get() { return obj; } @Override public void set(@javax.annotation.Nullable T obj) { this.obj = obj; } @Override public String toString() { return "Box.Nullable.ofVolatile[" + get() + "]"; } } /** Creates a `Box.Nullable` holding the given possibly-null value in a non-`volatile` field. */ public static <T> Nullable<T> of(@javax.annotation.Nullable T init) { return new Default<>(init); } /** Creates a `Box.Nullable` holding null value in a non-`volatile` field. */ public static <T> Nullable<T> ofNull() { return of(null); } static class Default<T> implements Box.Nullable<T> { private T obj; private Default(T init) { this.obj = init; } @Override public T get() { return obj; } @Override public void set(T obj) { this.obj = obj; } @Override public String toString() { return "Box.Nullable.of[" + get() + "]"; } } /** Creates a `Box.Nullable` from a `Supplier` and a `Consumer`. */ public static <T> Nullable<T> from(Supplier<T> getter, Consumer<T> setter) { Objects.requireNonNull(getter); Objects.requireNonNull(setter); return new Nullable<T>() { @Override public T get() { return getter.get(); } @Override public void set(T value) { setter.accept(value); } @Override public String toString() { return "Box.Nullable.from[" + get() + "]"; } }; } } /** A `Box` for primitive doubles. */ public interface Dbl extends DoubleSupplier, DoubleConsumer, Box<Double> { /** Sets the value which will later be returned by get(). */ void set(double value); @Override double getAsDouble(); /** * Delegates to {@link #getAsDouble()}. * * @deprecated Provided to satisfy {@code Box<Double>}; use {@link #getAsDouble()} instead. * */ @Override @Deprecated default Double get() { return getAsDouble(); } /** * Delegates to {@link #set(double)}. * * @deprecated Provided to satisfy {@code Box<Double>}; use {@link #set(double)} instead. */ @Override @Deprecated default void set(Double value) { set(value.doubleValue()); } /** * Delegates to {@link #set(double)}. * * @deprecated Provided to satisfy the {@link DoubleConsumer}; use {@link #set(double)} instead. */ @Deprecated @Override default void accept(double value) { set(value); } /** Creates a `Box.Dbl` holding the given value in a non-`volatile` field. */ public static Dbl of(double value) { return new Default(value); } static class Default implements Box.Dbl { private double obj; private Default(double init) { set(init); } @Override public double getAsDouble() { return obj; } @Override public void set(double obj) { this.obj = obj; } @Override public String toString() { return "Box.Dbl.of[" + getAsDouble() + "]"; } } /** Creates a `Box.Dbl` from a `DoubleSupplier` and a `DoubleConsumer`. */ public static Dbl from(DoubleSupplier getter, DoubleConsumer setter) { return new Dbl() { @Override public double getAsDouble() { return getter.getAsDouble(); } @Override public void set(double value) { setter.accept(value); } @Override public String toString() { return "Box.Dbl.from[" + get() + "]"; } }; } } /** A `Box` for primitive ints. */ public interface Int extends IntSupplier, IntConsumer, Box<Integer> { /** Sets the value which will later be returned by {@link #getAsInt()}. */ void set(int value); @Override int getAsInt(); /** * Delegates to {@link #getAsInt()}. * * @deprecated Provided to satisfy {@code Box<Integer>}; use {@link #getAsInt()} instead. * */ @Override @Deprecated default Integer get() { return getAsInt(); } /** * Delegates to {@link #set(int)}. * * @deprecated Provided to satisfy {@code Box<Integer>}; use {@link #set(int)} instead. */ @Override @Deprecated default void set(Integer value) { set(value.intValue()); } /** * Delegates to {@link #set}. * * @deprecated Provided to satisfy the {@link IntConsumer} interface; use {@link #set(int)} instead. */ @Deprecated @Override default void accept(int value) { set(value); } /** Creates a `Box.Int` holding the given value in a non-`volatile` field. */ public static Int of(int value) { return new Default(value); } static class Default implements Box.Int { private int obj; private Default(int init) { set(init); } @Override public int getAsInt() { return obj; } @Override public void set(int obj) { this.obj = obj; } @Override public String toString() { return "Box.Int.of[" + get() + "]"; } } /** Creates a `Box.Int` from a `IntSupplier` and a `IntConsumer`. */ public static Int from(IntSupplier getter, IntConsumer setter) { return new Int() { @Override public int getAsInt() { return getter.getAsInt(); } @Override public void set(int value) { setter.accept(value); } @Override public String toString() { return "Box.Int.from[" + get() + "]"; } }; } } /** A `Box` for primitive longs. */ public interface Lng extends LongSupplier, LongConsumer, Box<Long> { /** Sets the value which will later be returned by {@link #getAsLong()}. */ void set(long value); @Override long getAsLong(); /** * Auto-boxed getter. * * @deprecated Provided to satisfy {@code Box<Long>} interface; use {@link #getAsLong()} instead. * */ @Override @Deprecated default Long get() { return getAsLong(); } /** * Delegates to {@link #set(long)}. * * @deprecated Provided to satisfy {@code Box<Long>} interface; use {@link #set(long)} instead. */ @Override @Deprecated default void set(Long value) { set(value.longValue()); } /** * Delegates to {@link #set(long)}. * * @deprecated Provided to satisfy {@link LongConsumer} interface; use {@link #set(long)} instead. */ @Deprecated @Override default void accept(long value) { set(value); } /** Creates a `Box.Long` holding the given value in a non-`volatile` field. */ public static Lng of(long value) { return new Default(value); } static class Default implements Box.Lng { private long obj; private Default(long init) { set(init); } @Override public long getAsLong() { return obj; } @Override public void set(long obj) { this.obj = obj; } @Override public String toString() { return "Box.Long.of[" + get() + "]"; } } /** Creates a `Box.Long` from a `LongSupplier` and a `LongConsumer`. */ public static Lng from(LongSupplier getter, LongConsumer setter) { return new Lng() { @Override public long getAsLong() { return getter.getAsLong(); } @Override public void set(long value) { setter.accept(value); } @Override public String toString() { return "Box.Long.from[" + get() + "]"; } }; } } }