ProjectAres/Util/core/src/main/java/tc/oc/commons/core/util/Maybe.java

225 lines
5.4 KiB
Java

package tc.oc.commons.core.util;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Mutable equivalent of {@link Optional} that implements {@link Set}.
*
* The interface provides default implementations of all methods except
* {@link #orElse(Object)}, {@link #set(Object)}, and {@link #clear()}.
*
* You should also implement {@link #equals(Object)} and {@link #hashCode()}
* to match the contract specified in {@link Set} (which is not allowed
* in an interface, unfortunately).
*/
public interface Maybe<E> extends Set<E> {
E orElse(E that);
void set(E value);
default E get() {
final E e = orElse(null);
if(e == null) {
throw new NoSuchElementException("No value present");
}
return e;
}
default boolean isPresent() {
return orElse(null) != null;
}
default Optional<E> toOptional() {
return Optional.ofNullable(orElse(null));
}
@Override
default int size() {
return isPresent() ? 1 : 0;
}
@Override
default boolean isEmpty() {
return !isPresent();
}
@Override
default boolean contains(Object e) {
final E value = orElse(null);
return value != null && value.equals(e);
}
@Override
default Iterator<E> iterator() {
return new Iterator<E>() {
boolean done;
@Override
public boolean hasNext() {
return !done && isPresent();
}
@Override
public E next() {
final E value = orElse(null);
if(value == null) {
throw new NoSuchElementException();
}
done = true;
return value;
}
};
}
@Override
default Object[] toArray() {
final E value = orElse(null);
return value == null ? ArrayUtils.zeroObjects()
: new Object[] {value};
}
@Override
default <T> T[] toArray(T[] a) {
final E value = orElse(null);
if(value != null) {
if(a.length < 1) {
a = (T[]) Array.newInstance(a.getClass().getComponentType(), 1);
}
a[0] = (T) value;
}
return a;
}
@Override
default boolean add(E e) {
if(e == null) throw new NullPointerException();
final E value = orElse(null);
if(value == null) {
set(e);
return true;
} else if(value.equals(e)) {
return false;
} else {
throw new IllegalStateException("A different value is already present");
}
}
@Override
default boolean remove(Object e) {
if(contains(e)) {
clear();
return true;
}
return false;
}
@Override
default boolean containsAll(Collection<?> c) {
final E value = orElse(null);
if(value == null) {
return c.isEmpty();
} else {
for(Object e : c) {
if(!value.equals(e)) return false;
}
return true;
}
}
@Override
default boolean addAll(Collection<? extends E> c) {
boolean changed = false;
for(Object e : c) {
if(add((E) e)) changed = true;
}
return changed;
}
@Override
default boolean retainAll(Collection<?> c) {
final E value = orElse(null);
if(value == null || c.contains(value)) return false;
clear();
return true;
}
@Override
default boolean removeAll(Collection<?> c) {
final E value = orElse(null);
if(value == null || !c.contains(value)) return false;
clear();
return true;
}
class Impl<E> implements Maybe<E> {
private E value;
private Impl() {}
private Impl(E value) {
set(value);
}
@Override
public boolean equals(Object that) {
if(this == that) return true;
if(!(that instanceof Set)) return false;
final E value = orElse(null);
final Iterator it = ((Set) that).iterator();
if(value == null) {
return !it.hasNext();
} else
return it.hasNext() && value.equals(it.next());
}
@Override
public int hashCode() {
final E value = orElse(null);
return value == null ? 0 : value.hashCode();
}
@Override
public E orElse(E that) {
final E value = this.value;
return value != null ? value : that;
}
@Override
public void set(E value) {
if(value == null) throw new NullPointerException();
this.value = value;
}
@Override
public void clear() {
value = null;
}
}
static <E> Maybe<E> empty() {
return new Impl<>();
}
static <E> Maybe<E> of(E value) {
return new Impl<>(value);
}
static <E> Maybe<E> ofNullable(@Nullable E value) {
return value != null ? of(value) : empty();
}
static <E> Maybe<E> ofOptional(Optional<E> value) {
return value.isPresent() ? of(value.get()) : empty();
}
}