225 lines
5.4 KiB
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();
|
|
}
|
|
}
|