All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cdc.util.enums.AbstractMask Maven / Gradle / Ivy

package cdc.util.enums;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;

import cdc.util.function.IterableUtils;
import cdc.util.function.Predicates;
import cdc.util.lang.Checks;
import cdc.util.lang.CollectionUtils;

/**
 * Mask (set) of values belonging to a list type.
 * 

* Objects of this class are immutable. *

* A typical implementation should look like this: *

{@code
 * public final class FooMask extends AbstractEnumMask {
 *     public static final Support SUPPORT = support(FooMask.class, FooMask::new, FooType, Nullable.FALSE);
 *
 *     private FooMask(Support support,
 *                     Set values) {
 *         super(support, values);
 *     }
 * }
 * }
* For a standard enum, one can declare: *
{@code
 * public final class FooMask extends AbstractEnumMask {
 *     public static final Support SUPPORT = support(FooMask.class, FooMask::new, Foo.class, Nullable.FALSE);
 *
 *     private FooMask(Support support,
 *                     Set values) {
 *         super(support, values);
 *     }
 * }
 * }
* * @author Damien Carbonne * @param The mask type. * @param The enum type. */ public class AbstractMask, V> implements Mask { /** * The associated support class. */ protected final MaskSupport support; /** * The mask values. */ protected final Set values; protected AbstractMask(MaskSupport support, Set values) { Checks.isNotNull(support, "support"); this.support = support; this.values = Collections.unmodifiableSet(values); checkValues(); } @FunctionalInterface protected static interface Creator, V> { public M create(MaskSupport support, Set values); } /** * Creates a Support implementation. * * @param The mask type. * @param The enum type. * @param maskClass The mask class. * @param creator The mask factory. * @param type The type. * @param nullable {@code Nullable.TRUE} if  {@code null} is a valid value. * @return A Support implementation. */ protected static , V> MaskSupport support(Class maskClass, Creator creator, ListType type, Nullable nullable) { Checks.isNotNull(maskClass, "maskClass"); Checks.isNotNull(creator, "creator"); Checks.isNotNull(type, "type"); Checks.isNotNull(nullable, "nullable"); return new SupportImpl<>(maskClass, creator, type, nullable); } /** * Creates a Support implementation for a standard enum. * * @param The mask type. * @param The enum type. * @param maskClass The mask class. * @param creator The mask factory. * @param enumClass The enum class. * @param nullable {@code Nullable.TRUE} if  {@code null} is a valid value. * @return A Support implementation. */ protected static , V extends Enum> MaskSupport support(Class maskClass, Creator creator, Class enumClass, Nullable nullable) { Checks.isNotNull(maskClass, "maskClass"); Checks.isNotNull(creator, "creator"); Checks.isNotNull(enumClass, "enumClass"); Checks.isNotNull(nullable, "nullable"); return support(maskClass, creator, EnumTypes.getEnumType(enumClass), nullable); } private void checkValue(V value) { Checks.isTrue(value != null || isNullable(), "null is not supported"); } private void checkOther(M other) { Checks.isNotNull(other, "other"); Checks.isTrue(support.isNullable() == other.support.isNullable(), "Cannot mix masks with different nullable"); } private void checkValues() { Checks.isTrue(isNullable() || !values.contains((V) null), "null is not supported"); } @Override public MaskSupport getSupport() { return support; } @Override public boolean isNullable() { return support.isNullable(); } @Override public boolean isEmpty() { return values.isEmpty(); } @Override public boolean isFull() { if (values.size() != support.getType().getValues().size() + (isNullable() ? 1 : 0)) { return false; } else { return this.equals(full()); } } @Override public Set getValues() { return values; } @Override public boolean isSet(V value) { checkValue(value); return values.contains(value); } @Override public boolean isClear(V value) { checkValue(value); return !values.contains(value); } @Override public M set(V value, boolean enabled) { checkValue(value); return enabled ? set(value) : clear(value); } @Override public M set(V value) { checkValue(value); if (isSet(value)) { return support.getMaskClass().cast(this); } else { final Set tmp = new HashSet<>(); tmp.addAll(getValues()); tmp.add(value); return support.create(tmp); } } @Override public M clear(V value) { checkValue(value); if (isSet(value)) { final Set tmp = new HashSet<>(); tmp.addAll(getValues()); tmp.remove(value); return support.create(tmp); } else { return support.getMaskClass().cast(this); } } @Override public M setAll(boolean enabled) { return support.create(enabled); } @Override public M empty() { return setAll(false); } @Override public M full() { return setAll(true); } @Override public M and(M other) { checkOther(other); final Set tmp = new HashSet<>(); tmp.addAll(getValues()); tmp.retainAll(other.getValues()); return support.create(tmp); } @Override @SuppressWarnings("unchecked") public M and(V... values) { final M other = support.create(values); return and(other); } @Override public M or(M other) { checkOther(other); final Set tmp = new HashSet<>(); tmp.addAll(getValues()); tmp.addAll(other.getValues()); return support.create(tmp); } @Override @SuppressWarnings("unchecked") public M or(V... values) { final M other = support.create(values); return or(other); } @Override public M not() { final Set tmp = new HashSet<>(); tmp.addAll(support.getType().getValues()); if (support.isNullable()) { tmp.add(null); } tmp.removeAll(getValues()); return support.create(tmp); } @Override public final boolean contains(M other) { checkOther(other); return and(other).equals(other); } @Override @SafeVarargs public final boolean contains(V... values) { final M other = support.create(values); return contains(other); } @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(support.getMaskClass().isInstance(other))) { return false; } final M o = support.getMaskClass().cast(other); return support.getType().equals(o.support.getType()) && support.isNullable() == o.support.isNullable() && this.values.equals(o.values); } @Override public int hashCode() { return support.getType().hashCode() + (support.isNullable() ? 1 : 0) + values.hashCode(); } @Override public String toString(Function valueToString, String separator) { final StringBuilder builder = new StringBuilder(); boolean first = true; for (final V value : getSupport().getType().getValues()) { if (isSet(value)) { if (first) { first = false; } else { builder.append(separator); } builder.append(valueToString.apply(value)); } } if (isNullable() && isSet(null)) { if (!first) { builder.append(separator); } builder.append(valueToString.apply(null)); } return builder.toString(); } @Override public String toString() { return toString(o -> o == null ? "null" : o.toString(), "|"); } private static final class SupportImpl, V> implements MaskSupport { public final Class cls; private final Creator creator; private final ListType type; private final Nullable nullable; private final M empty; public SupportImpl(Class cls, Creator creator, ListType type, Nullable nullable) { this.cls = cls; this.creator = creator; this.type = type; this.nullable = nullable; this.empty = creator.create(this, Collections.emptySet()); } @Override public Class getMaskClass() { return cls; } @Override public ListType getType() { return type; } @Override public boolean isNullable() { return nullable == Nullable.TRUE; } @Override public M empty() { return empty; } @Override public M full() { return create(Predicates.alwaysTrue()); } @Override public M create() { return empty; } @Override public M create(V value) { return creator.create(this, CollectionUtils.toUnmodifiableSet(value)); } @SuppressWarnings("unchecked") @Override public M create(V... values) { return creator.create(this, CollectionUtils.toUnmodifiableSet(values)); } @Override public M create(Iterable values) { return creator.create(this, IterableUtils.toUnmodifiableSet(values)); } @Override public M create(Predicate predicate) { final Set values; if (nullable.isTrue()) { values = IterableUtils.toUnmodifiableSet(IterableUtils.join(type.getValues(), (V) null), predicate); } else { values = IterableUtils.toUnmodifiableSet(type.getValues(), predicate); } return creator.create(this, values); } @Override public M create(boolean enabled) { return create(enabled ? Predicates.alwaysTrue() : Predicates.alwaysFalse()); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy