Compare commits
2 Commits
7de7d5e6cb
...
c0ddacb25e
| Author | SHA1 | Date | |
|---|---|---|---|
| c0ddacb25e | |||
| a56febbbb5 |
@@ -16,7 +16,7 @@ dependencies {
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
withSourcesJar()
|
||||
|
||||
toolchain {
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class BigBitFlagSet implements FlagSet<BigInteger, BigInteger> {
|
||||
public BigInteger empty() {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
|
||||
public BigInteger union(BigInteger first, BigInteger second) {
|
||||
return first.or(second);
|
||||
}
|
||||
|
||||
public BigInteger intersection(BigInteger first, BigInteger second) {
|
||||
return first.and(second);
|
||||
}
|
||||
|
||||
public BigInteger difference(BigInteger first, BigInteger second) {
|
||||
return first.andNot(second);
|
||||
}
|
||||
|
||||
public boolean isSuperset(BigInteger first, BigInteger second) {
|
||||
return first.and(second).equals(second);
|
||||
}
|
||||
|
||||
public Iterable<BigInteger> enumerate(BigInteger flags) {
|
||||
return new IterableBitFlags(flags);
|
||||
}
|
||||
|
||||
public BigInteger minimum(BigInteger flags) {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
|
||||
public BigInteger maximum(BigInteger flags) {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
|
||||
private record IterableBitFlags(BigInteger value) implements Iterable<BigInteger> {
|
||||
public Iterator<BigInteger> iterator() {
|
||||
return new BitFlagsIterator(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
private static class BitFlagsIterator implements Iterator<BigInteger> {
|
||||
private BigInteger value;
|
||||
private BigInteger current;
|
||||
|
||||
public BitFlagsIterator(BigInteger value) {
|
||||
this.value = value;
|
||||
this.current = BigInteger.ONE;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return !this.value.equals(BigInteger.ZERO);
|
||||
}
|
||||
|
||||
public BigInteger next() {
|
||||
if (this.value.equals(BigInteger.ZERO)) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
while (!this.value.testBit(0)) {
|
||||
this.value = this.value.shiftRight(1);
|
||||
this.current = this.current.shiftLeft(1);
|
||||
}
|
||||
|
||||
BigInteger element = this.current;
|
||||
this.value = this.value.shiftRight(1);
|
||||
this.current = this.current.shiftLeft(1);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class BitFlagSet implements FlagSet<Integer, Integer> {
|
||||
public Integer empty() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Integer union(Integer first, Integer second) {
|
||||
return first | second;
|
||||
}
|
||||
|
||||
public Integer intersection(Integer first, Integer second) {
|
||||
return first & second;
|
||||
}
|
||||
|
||||
public Integer difference(Integer first, Integer second) {
|
||||
return first & ~second;
|
||||
}
|
||||
|
||||
public boolean isSuperset(Integer first, Integer second) {
|
||||
return (first & second) == second;
|
||||
}
|
||||
|
||||
public Iterable<Integer> enumerate(Integer flags) {
|
||||
return new IterableBitFlags(flags);
|
||||
}
|
||||
|
||||
public Integer minimum(Integer flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Integer maximum(Integer flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private record IterableBitFlags(int value) implements Iterable<Integer> {
|
||||
public Iterator<Integer> iterator() {
|
||||
return new BitFlagsIterator(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
private static class BitFlagsIterator implements Iterator<Integer> {
|
||||
private int value;
|
||||
private int current;
|
||||
|
||||
public BitFlagsIterator(int value) {
|
||||
this.value = value;
|
||||
this.current = 1;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return this.value != 0;
|
||||
}
|
||||
|
||||
public Integer next() {
|
||||
if (this.value == 0) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
while ((this.value & 1) == 0) {
|
||||
this.value >>= 1;
|
||||
this.current <<= 1;
|
||||
}
|
||||
|
||||
int element = this.current;
|
||||
this.value >>= 1;
|
||||
this.current <<= 1;
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents a single flag defined in a {@link FlagGraph}.
|
||||
*
|
||||
* @param <V> The type of the flag's value.
|
||||
* @param <S> A set of this type of flags.
|
||||
*/
|
||||
public interface FlagDefinition<V, S> {
|
||||
/**
|
||||
* The alias of the flag. A composed flag always has an alias.
|
||||
*/
|
||||
Optional<String> alias();
|
||||
|
||||
/**
|
||||
* The value of the flag. A composed flag has no value.
|
||||
*/
|
||||
Optional<V> value();
|
||||
|
||||
/**
|
||||
* Test if this flag and all its parents are present in the set.
|
||||
*
|
||||
* @param set A set of flags.
|
||||
* @return {@code true} if the set includes this flags and its parents.
|
||||
*/
|
||||
boolean isIn(S set);
|
||||
|
||||
/**
|
||||
* Add this flag and all its parents to the set.
|
||||
*
|
||||
* @param set A set of flags.
|
||||
* @return A new set of flags containing the flags from the {@code set}, this flag and its parents.
|
||||
*/
|
||||
S addTo(S set);
|
||||
|
||||
/**
|
||||
* Removes this flag and all its children from the set.
|
||||
*
|
||||
* @param set A set of flags.
|
||||
* @return A new set of flags containing the flags from the {@code set} except this flag and its children.
|
||||
*/
|
||||
S removeFrom(S set);
|
||||
|
||||
/**
|
||||
* Adds or removes this flag from the set depending on the specified boolean value.
|
||||
* If {@code value} is {@code true}, flags will be added so that {@link #isIn} returns {@code true.}
|
||||
* If {@code value} is {@code false}, flags will be removed so that {@link #isIn} returns {@code false.}
|
||||
*
|
||||
* @param set A set of flags.
|
||||
* @return A new set of flags.
|
||||
*/
|
||||
default S setIn(S set, boolean value) {
|
||||
if (value) {
|
||||
return this.addTo(set);
|
||||
} else {
|
||||
return this.removeFrom(set);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add this flag and all its parents to the set if they aren't already present,
|
||||
* and removes this flag otherwise.
|
||||
*
|
||||
* @param set A set of flags.
|
||||
* @return A new set of flags.
|
||||
*/
|
||||
default S toggle(S set) {
|
||||
if (!this.isIn(set)) {
|
||||
return this.addTo(set);
|
||||
} else {
|
||||
return this.removeFrom(set);
|
||||
}
|
||||
}
|
||||
}
|
||||
415
java/tatsuki/src/main/java/fr/louisdevie/tatsuki/FlagGraph.java
Normal file
415
java/tatsuki/src/main/java/fr/louisdevie/tatsuki/FlagGraph.java
Normal file
@@ -0,0 +1,415 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents a group of flags of type {@link V} and the relationships between
|
||||
* them.
|
||||
*
|
||||
* @param <V> The type of the flag values.
|
||||
* @param <S> The type used to contain the flags.
|
||||
*/
|
||||
public abstract class FlagGraph<V, S> {
|
||||
private final HashMap<V, FlagDefinition<V, S>> definitionsByValue;
|
||||
private final HashMap<String, FlagDefinition<V, S>> definitionsByAlias;
|
||||
|
||||
protected FlagGraph(Collection<? extends FlagDefinition<V, S>> c) {
|
||||
this.definitionsByValue = new HashMap<>();
|
||||
this.definitionsByAlias = new HashMap<>();
|
||||
|
||||
for (var definition : c) {
|
||||
if (definition.value().isPresent()) {
|
||||
V value = definition.value().get();
|
||||
if (this.definitionsByValue.put(value, definition) != null) {
|
||||
throw new IllegalArgumentException(String.format("Duplicate value \"%s\"", value));
|
||||
}
|
||||
if (definition.alias().isPresent()) {
|
||||
String alias = definition.alias().get();
|
||||
if (this.definitionsByAlias.put(alias, definition) != null) {
|
||||
throw new IllegalArgumentException(String.format("Duplicate alias \"%s\"", alias));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String alias = definition.alias().orElseThrow(() ->
|
||||
new IllegalArgumentException("Invalid flag definition: a composed flag must always have an alias")
|
||||
);
|
||||
if (this.definitionsByAlias.put(alias, definition) != null) {
|
||||
throw new IllegalArgumentException(String.format("Duplicate alias \"%s\"", alias));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of definitions in this graph.
|
||||
*/
|
||||
public int size() {
|
||||
return this.definitionsByValue.size() +
|
||||
(int) this.definitionsByAlias.values().stream()
|
||||
.filter(d -> d.value().isEmpty())
|
||||
.count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this graph contains no definitions.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return this.definitionsByValue.isEmpty() && this.definitionsByAlias.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this graph contains a definition with the specified value.
|
||||
*/
|
||||
public boolean containsValue(V value) {
|
||||
return this.definitionsByValue.containsKey(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this graph contains a definition with the specified alias.
|
||||
*/
|
||||
public boolean containsAlias(String alias) {
|
||||
return this.definitionsByAlias.containsKey(alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified definition belongs to this graph.
|
||||
*/
|
||||
public boolean containsDefinition(FlagDefinition<V, S> definition) {
|
||||
return this.definitionsByValue.containsValue(definition) || this.definitionsByAlias.containsValue(definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flag definition with the specified value.
|
||||
*
|
||||
* @param value The base value of the flag.
|
||||
* @return An {@link Optional} of the corresponding definition, or an empty
|
||||
* {@link Optional} if there is no definition with this value.
|
||||
*/
|
||||
public Optional<FlagDefinition<V, S>> definitionOf(V value) {
|
||||
return Optional.ofNullable(this.definitionsByValue.get(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flag definition with the specified alias.
|
||||
*
|
||||
* @param alias The alias of the flag.
|
||||
* @return An {@link Optional} of the corresponding definition, or an empty
|
||||
* {@link Optional} if there is no definition with this alias.
|
||||
*/
|
||||
public Optional<FlagDefinition<V, S>> definitionNamed(String alias) {
|
||||
return Optional.ofNullable(this.definitionsByAlias.get(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} view of the aliases defined in this graph.
|
||||
*/
|
||||
public Set<String> aliasSet() {
|
||||
return new ReadOnlyKeySet<>(this.definitionsByAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} view of the values defined in this graph.
|
||||
*/
|
||||
public Set<V> valueSet() {
|
||||
return new ReadOnlyKeySet<>(this.definitionsByValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} view of all the defined flags.
|
||||
*/
|
||||
public Set<FlagDefinition<V, S>> definitions() {
|
||||
return new DefinitionSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a set of flags from a list of values.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract S of(V... values);
|
||||
|
||||
/**
|
||||
* Creates a set of flags from a list of aliases.
|
||||
*/
|
||||
public abstract S named(String... aliases);
|
||||
|
||||
/**
|
||||
* Checks whether the first set of flags includes at least one of the flags
|
||||
* from the second set. If there is no required flags, the result will always be `false`.
|
||||
* A flag is considered to be part of the set only if all of its parents are
|
||||
* present too.
|
||||
*
|
||||
* @param flags - A set of flags.
|
||||
* @param required - The flags to search for in the first set.
|
||||
*/
|
||||
public abstract boolean hasAny(S flags, S required);
|
||||
|
||||
/**
|
||||
* Checks whether the first set of flags includes all the flags from the
|
||||
* second set. If there is no required flags, the result will always be `true`.
|
||||
* A flag is considered to be part of the set only if all of its parents are
|
||||
* present too.
|
||||
*
|
||||
* @param flags - A set of flags.
|
||||
* @param required - The flags to search for in the first set.
|
||||
*/
|
||||
public abstract boolean hasAll(S flags, S required);
|
||||
|
||||
/**
|
||||
* Filters a flag set so that it only contains the flags that were defined
|
||||
* in this set. If a flags is missing some of its parents, it will not be
|
||||
* included in the result.
|
||||
*
|
||||
* @param flags The set of flags to filter.
|
||||
* @return A new set of flags.
|
||||
* @see #maximum
|
||||
*/
|
||||
public abstract S minimum(S flags);
|
||||
|
||||
/**
|
||||
* Filters a flag set so that it only contains the flags that were defined
|
||||
* in this set. If a flags is missing some of its parents, they will be
|
||||
* added to the result.
|
||||
*
|
||||
* @param flags The set of flags to filter.
|
||||
* @return A new set of flags.
|
||||
* @see #minimum
|
||||
*/
|
||||
public abstract S maximum(S flags);
|
||||
|
||||
private static class ReadOnlyKeySet<K> implements Set<K> {
|
||||
private final Set<K> underlying;
|
||||
|
||||
public ReadOnlyKeySet(HashMap<K, ?> map) {
|
||||
this.underlying = map.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.underlying.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.underlying.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return this.underlying.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<K> iterator() {
|
||||
return this.underlying.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return this.underlying.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return this.underlying.toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(K key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return this.underlying.containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends K> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static class DefinitionIterator<V, S> implements Iterator<FlagDefinition<V, S>> {
|
||||
private final Iterator<FlagDefinition<V, S>> byValueIterator;
|
||||
private final Iterator<FlagDefinition<V, S>> byAliasIterator;
|
||||
private FlagDefinition<V, S> nextDefinition;
|
||||
|
||||
public DefinitionIterator(HashMap<?, FlagDefinition<V, S>> byValue, HashMap<?, FlagDefinition<V, S>> byAlias) {
|
||||
this.byValueIterator = byValue.values().iterator();
|
||||
this.byAliasIterator = byAlias.values().iterator();
|
||||
this.lookahead();
|
||||
}
|
||||
|
||||
private void lookahead() {
|
||||
FlagDefinition<V, S> found = null;
|
||||
if (this.byValueIterator.hasNext()) {
|
||||
found = this.byValueIterator.next();
|
||||
}
|
||||
while (found == null && this.byAliasIterator.hasNext()) {
|
||||
found = this.byAliasIterator.next();
|
||||
if (found.alias().isPresent()) {
|
||||
found = null;
|
||||
}
|
||||
}
|
||||
this.nextDefinition = found;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.nextDefinition != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlagDefinition<V, S> next() {
|
||||
var nextDefinition = this.nextDefinition;
|
||||
if (nextDefinition == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
this.lookahead();
|
||||
return nextDefinition;
|
||||
}
|
||||
}
|
||||
|
||||
private class DefinitionSet implements Set<FlagDefinition<V, S>> {
|
||||
@Override
|
||||
public int size() {
|
||||
return FlagGraph.this.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return FlagGraph.this.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
// noinspection SuspiciousMethodCalls
|
||||
return FlagGraph.this.definitionsByValue.containsValue(o) ||
|
||||
FlagGraph.this.definitionsByAlias.containsValue(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<FlagDefinition<V, S>> iterator() {
|
||||
return new DefinitionIterator<>(FlagGraph.this.definitionsByValue, FlagGraph.this.definitionsByAlias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
int maxSize = FlagGraph.this.definitionsByValue.size() + FlagGraph.this.definitionsByAlias.size();
|
||||
Object[] array = new Object[maxSize];
|
||||
int i = 0;
|
||||
for (var definition : FlagGraph.this.definitionsByValue.values()) {
|
||||
array[i++] = definition;
|
||||
}
|
||||
for (var definition : FlagGraph.this.definitionsByAlias.values()) {
|
||||
if (definition.value().isEmpty()) {
|
||||
array[i++] = definition;
|
||||
}
|
||||
}
|
||||
return Arrays.copyOf(array, i);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T[] toArray(T[] a) {
|
||||
int maxSize = FlagGraph.this.definitionsByValue.size() + FlagGraph.this.definitionsByAlias.size();
|
||||
T[] array = (T[]) Array.newInstance(a.getClass().componentType(), maxSize);
|
||||
;
|
||||
int i = 0;
|
||||
for (var definition : FlagGraph.this.definitionsByValue.values()) {
|
||||
array[i++] = (T) definition;
|
||||
}
|
||||
for (var definition : FlagGraph.this.definitionsByAlias.values()) {
|
||||
if (definition.value().isEmpty()) {
|
||||
array[i++] = (T) definition;
|
||||
}
|
||||
}
|
||||
if (i > a.length) {
|
||||
return Arrays.copyOf(array, i);
|
||||
} else {
|
||||
Arrays.fill(a, null);
|
||||
System.arraycopy(array, 0, a, 0, i);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(FlagDefinition<V, S> vsFlagDefinition) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
boolean result = true;
|
||||
for (Object o : c) {
|
||||
result = this.contains(o);
|
||||
if (!result) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends FlagDefinition<V, S>> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Set<?> otherSet)) return false;
|
||||
|
||||
int count = 0;
|
||||
for (var definition : FlagGraph.this.definitionsByValue.values()) {
|
||||
if (!otherSet.contains(definition)) return false;
|
||||
count++;
|
||||
}
|
||||
for (var definition : FlagGraph.this.definitionsByAlias.values()) {
|
||||
if (definition.value().isEmpty()) {
|
||||
if (!otherSet.contains(definition)) return false;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count == otherSet.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
/**
|
||||
* Represents a group of flags of type {@link F} and the relationships between
|
||||
* them. It also provides methods to use {@link S} as a set of those flags.
|
||||
*
|
||||
* @param <F> The type of values in the set.
|
||||
* @param <S> The type to be used as a set.
|
||||
*/
|
||||
public interface FlagSet<F, S> {
|
||||
/**
|
||||
* Creates an empty set of flags.
|
||||
*/
|
||||
S empty();
|
||||
|
||||
/**
|
||||
* Computes the union of two sets of flags.
|
||||
*
|
||||
* @param first The first set of flags.
|
||||
* @param second The second set of flags.
|
||||
* @return A new set that contains the flags of both sets.
|
||||
*/
|
||||
S union(S first, S second);
|
||||
|
||||
/**
|
||||
* Computes the intersection of two set of flags.
|
||||
*
|
||||
* @param first The first set of flags.
|
||||
* @param second The second set of flags.
|
||||
* @return A new set that contains the flags that appear both in the first
|
||||
* set and the second set.
|
||||
*/
|
||||
S intersection(S first, S second);
|
||||
|
||||
/**
|
||||
* Computes the difference of two set of flags.
|
||||
*
|
||||
* @param first The first set of flags.
|
||||
* @param second The second set of flags (that will be subtracted from the
|
||||
* first).
|
||||
* @return A new set that contains the flags of the first set that do not
|
||||
* appear in the second.
|
||||
*/
|
||||
S difference(S first, S second);
|
||||
|
||||
/**
|
||||
* Checks whether the first set of flags is a superset of the second.
|
||||
*
|
||||
* @param first The first set of flags.
|
||||
* @param second The second set of flags.
|
||||
*/
|
||||
boolean isSuperset(S first, S second);
|
||||
|
||||
/**
|
||||
* Returns an iterable over the individual flags in a set.
|
||||
*
|
||||
* @param flags A set of flags.
|
||||
*/
|
||||
Iterable<F> enumerate(S flags);
|
||||
|
||||
/**
|
||||
* Filters a flag set so that it only contains the flags that were defined
|
||||
* in this set. If a flags is missing some of its parents, it will not be
|
||||
* included in the result.
|
||||
*
|
||||
* @param flags The set of flags to filter.
|
||||
* @return A new set of flags.
|
||||
* @see #maximum
|
||||
*/
|
||||
S minimum(S flags);
|
||||
|
||||
/**
|
||||
* Filters a flag set so that it only contains the flags that were defined
|
||||
* in this set. If a flags is missing some of its parents, they will be
|
||||
* added to the result.
|
||||
*
|
||||
* @param flags The set of flags to filter.
|
||||
* @return A new set of flags.
|
||||
* @see #minimum
|
||||
*/
|
||||
S maximum(S flags);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import fr.louisdevie.tatsuki.builders.BitFlagSetBuilder;
|
||||
import fr.louisdevie.tatsuki.builders.syntax.DefineFlag;
|
||||
import fr.louisdevie.tatsuki.builders.syntax.SelectFlagSetType;
|
||||
|
||||
public class FlagSetBuilder implements SelectFlagSetType {
|
||||
public DefineFlag<BitFlagSet> useBitFlags() {
|
||||
return new BitFlagSetBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class LongBitFlagSet implements FlagSet<Long, Long> {
|
||||
public Long empty() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public Long union(Long first, Long second) {
|
||||
return first | second;
|
||||
}
|
||||
|
||||
public Long intersection(Long first, Long second) {
|
||||
return first & second;
|
||||
}
|
||||
|
||||
public Long difference(Long first, Long second) {
|
||||
return first & ~second;
|
||||
}
|
||||
|
||||
public boolean isSuperset(Long first, Long second) {
|
||||
return (first & second) == second;
|
||||
}
|
||||
|
||||
public Iterable<Long> enumerate(Long flags) {
|
||||
return new IterableBitFlags(flags);
|
||||
}
|
||||
|
||||
public Long minimum(Long flags) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public Long maximum(Long flags) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
private record IterableBitFlags(long value) implements Iterable<Long> {
|
||||
public Iterator<Long> iterator() {
|
||||
return new BitFlagsIterator(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
private static class BitFlagsIterator implements Iterator<Long> {
|
||||
private long value;
|
||||
private long current;
|
||||
|
||||
public BitFlagsIterator(long value) {
|
||||
this.value = value;
|
||||
this.current = 1L;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return this.value != 0L;
|
||||
}
|
||||
|
||||
public Long next() {
|
||||
if (this.value == 0L) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
while ((this.value & 1L) == 0L) {
|
||||
this.value >>= 1;
|
||||
this.current <<= 1;
|
||||
}
|
||||
|
||||
long element = this.current;
|
||||
this.value >>= 1;
|
||||
this.current <<= 1;
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package fr.louisdevie.tatsuki.bitflags;
|
||||
|
||||
import fr.louisdevie.tatsuki.FlagGraph;
|
||||
import fr.louisdevie.tatsuki.FlagDefinition;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class BigBitFlagGraph extends FlagGraph<BigInteger, BigInteger> {
|
||||
|
||||
protected BigBitFlagGraph(Collection<FlagDefinition<BigInteger, BigInteger>> c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger of(BigInteger... values) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger named(String... aliases) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAny(BigInteger flags, BigInteger required) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAll(BigInteger flags, BigInteger required) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger minimum(BigInteger flags) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger maximum(BigInteger flags) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package fr.louisdevie.tatsuki.bitflags;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class BigBitFlagIterator implements Iterator<BigInteger> {
|
||||
private BigInteger value;
|
||||
private BigInteger current;
|
||||
|
||||
public BigBitFlagIterator(BigInteger value) {
|
||||
this.value = value;
|
||||
this.current = BigInteger.ONE;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return !this.value.equals(BigInteger.ZERO);
|
||||
}
|
||||
|
||||
public BigInteger next() {
|
||||
if (this.value.equals(BigInteger.ZERO)) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
while (!this.value.testBit(0)) {
|
||||
this.value = this.value.shiftRight(1);
|
||||
this.current = this.current.shiftLeft(1);
|
||||
}
|
||||
|
||||
BigInteger element = this.current;
|
||||
this.value = this.value.shiftRight(1);
|
||||
this.current = this.current.shiftLeft(1);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package fr.louisdevie.tatsuki.bitflags;
|
||||
|
||||
import fr.louisdevie.tatsuki.FlagGraph;
|
||||
import fr.louisdevie.tatsuki.FlagDefinition;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class BitFlagGraph extends FlagGraph<Integer, Integer> {
|
||||
protected BitFlagGraph(Collection<FlagDefinition<Integer, Integer>> c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer of(Integer... values) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer named(String... aliases) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAny(Integer flags, Integer required) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAll(Integer flags, Integer required) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer minimum(Integer flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer maximum(Integer flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package fr.louisdevie.tatsuki.bitflags;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class BitFlagIterator implements Iterator<Integer> {
|
||||
private int value;
|
||||
private int current;
|
||||
|
||||
public BitFlagIterator(int value) {
|
||||
this.value = value;
|
||||
this.current = 1;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return this.value != 0;
|
||||
}
|
||||
|
||||
public Integer next() {
|
||||
if (this.value == 0) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
while ((this.value & 1) == 0) {
|
||||
this.value >>= 1;
|
||||
this.current <<= 1;
|
||||
}
|
||||
|
||||
int element = this.current;
|
||||
this.value >>= 1;
|
||||
this.current <<= 1;
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package fr.louisdevie.tatsuki.bitflags;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Iterator;
|
||||
|
||||
public final class BitFlags {
|
||||
/**
|
||||
* Computes the union of two sets of bitflags.
|
||||
* Any bits that are set in either of the inputs will be set in the result.
|
||||
*/
|
||||
public static int union(int first, int second) {
|
||||
return first | second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the union of two sets of bitflags.
|
||||
* Any bits that are set in either of the inputs will be set in the result.
|
||||
*/
|
||||
public static long union(long first, long second) {
|
||||
return first | second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the union of two sets of bitflags.
|
||||
* Any bits that are set in either of the inputs will be set in the result.
|
||||
*/
|
||||
public static BigInteger union(BigInteger first, BigInteger second) {
|
||||
return first.or(second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the intersection of two sets of bitflags.
|
||||
* Only bits that are set in both of the inputs will be set in the result.
|
||||
*/
|
||||
public static int intersection(int first, int second) {
|
||||
return first & second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the intersection of two sets of bitflags.
|
||||
* Only bits that are set in both of the inputs will be set in the result.
|
||||
*/
|
||||
public static long intersection(long first, long second) {
|
||||
return first & second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the intersection of two sets of bitflags.
|
||||
* Only bits that are set in both of the inputs will be set in the result.
|
||||
*/
|
||||
public static BigInteger intersection(BigInteger first, BigInteger second) {
|
||||
return first.and(second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the difference between two sets of bitflags.
|
||||
* Only bits that are set in the first input and not set in the second will be set in the result.
|
||||
*/
|
||||
public static int difference(int first, int second) {
|
||||
return first & ~second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the difference between two sets of bitflags.
|
||||
* Only bits that are set in the first input and not set in the second will be set in the result.
|
||||
*/
|
||||
public static long difference(long first, long second) {
|
||||
return first & ~second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the difference between two sets of bitflags.
|
||||
* Only bits that are set in the first input and not set in the second will be set in the result.
|
||||
*/
|
||||
public static BigInteger difference(BigInteger first, BigInteger second) {
|
||||
return first.andNot(second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a set of bitflags is a superset of the other.
|
||||
* Return `true` if every bit that is set in the second input is also set in the first.
|
||||
*/
|
||||
public static boolean isSuperset(int first, int second) {
|
||||
return (first & second) == second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a set of bitflags is a superset of the other.
|
||||
* Return `true` if every bit that is set in the second input is also set in the first.
|
||||
*/
|
||||
public static boolean isSuperset(long first, long second) {
|
||||
return (first & second) == second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a set of bitflags is a superset of the other.
|
||||
* Return `true` if every bit that is set in the second input is also set in the first.
|
||||
*/
|
||||
public static boolean isSuperset(BigInteger first, BigInteger second) {
|
||||
return first.and(second).equals(second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterable over the individual bits that are set.
|
||||
*/
|
||||
public static Iterable<Integer> enumerate(int flags) {
|
||||
return new IterableInteger(flags);
|
||||
}
|
||||
|
||||
private record IterableInteger(int value) implements Iterable<Integer> {
|
||||
public Iterator<Integer> iterator() {
|
||||
return new BitFlagIterator(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterable over the individual bits that are set.
|
||||
*/
|
||||
public static Iterable<Long> enumerate(long flags) {
|
||||
return new IterableLong(flags);
|
||||
}
|
||||
|
||||
private record IterableLong(long value) implements Iterable<Long> {
|
||||
public Iterator<Long> iterator() {
|
||||
return new LongBitFlagIterator(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterable over the individual bits that are set.
|
||||
*/
|
||||
public static Iterable<BigInteger> enumerate(BigInteger flags) {
|
||||
return new IterableBigInteger(flags);
|
||||
}
|
||||
|
||||
private record IterableBigInteger(BigInteger value) implements Iterable<BigInteger> {
|
||||
public Iterator<BigInteger> iterator() {
|
||||
return new BigBitFlagIterator(this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package fr.louisdevie.tatsuki.bitflags;
|
||||
|
||||
import fr.louisdevie.tatsuki.FlagGraph;
|
||||
import fr.louisdevie.tatsuki.FlagDefinition;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class LongBitFlagGraph extends FlagGraph<Long, Long> {
|
||||
|
||||
protected LongBitFlagGraph(Collection<FlagDefinition<Long, Long>> c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long of(Long... values) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long named(String... aliases) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAny(Long flags, Long required) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAll(Long flags, Long required) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long minimum(Long flags) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long maximum(Long flags) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package fr.louisdevie.tatsuki.bitflags;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class LongBitFlagIterator implements Iterator<Long> {
|
||||
private long value;
|
||||
private long current;
|
||||
|
||||
public LongBitFlagIterator(long value) {
|
||||
this.value = value;
|
||||
this.current = 1L;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return this.value != 0L;
|
||||
}
|
||||
|
||||
public Long next() {
|
||||
if (this.value == 0L) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
while ((this.value & 1L) == 0L) {
|
||||
this.value >>= 1;
|
||||
this.current <<= 1;
|
||||
}
|
||||
|
||||
long element = this.current;
|
||||
this.value >>= 1;
|
||||
this.current <<= 1;
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package fr.louisdevie.tatsuki.builders;
|
||||
|
||||
import fr.louisdevie.tatsuki.BitFlagSet;
|
||||
import fr.louisdevie.tatsuki.builders.syntax.DefineFlag;
|
||||
import fr.louisdevie.tatsuki.builders.syntax.SetValueOrCompose;
|
||||
|
||||
public class BitFlagSetBuilder implements DefineFlag<BitFlagSet> {
|
||||
public SetValueOrCompose<BitFlagSet> define(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public BitFlagSet build() {
|
||||
return new BitFlagSet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package fr.louisdevie.tatsuki.builders;
|
||||
|
||||
import fr.louisdevie.tatsuki.builders.syntax.AsOrComposeValues;
|
||||
import fr.louisdevie.tatsuki.builders.syntax.AsOrRequiresOrDefineOrComposeValues;
|
||||
import fr.louisdevie.tatsuki.builders.syntax.RequiresOrDefineOrComposeValues;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public abstract class FlagSetBuilder<V, R> implements AsOrRequiresOrDefineOrComposeValues<V, R>, AsOrComposeValues<V, R> {
|
||||
private final ArrayList<PartialFlagDefinition<V>> definitions;
|
||||
private final HashMap<String, PartialFlagDefinition<V>> aliasToDefinition;
|
||||
private final HashMap<V, PartialFlagDefinition<V>> valueToDefinition;
|
||||
|
||||
private PartialFlagDefinition<V> currentDefinition;
|
||||
|
||||
protected FlagSetBuilder() {
|
||||
this.definitions = new ArrayList<>();
|
||||
this.aliasToDefinition = new HashMap<>();
|
||||
this.valueToDefinition = new HashMap<>();
|
||||
|
||||
this.currentDefinition = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequiresOrDefineOrComposeValues<V, R> as(String alias) {
|
||||
if (this.currentDefinition == null) {
|
||||
throw new IllegalStateException("Attempt to set an alias while there is no current definition");
|
||||
}
|
||||
this.currentDefinition.setAlias(alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequiresOrDefineOrComposeValues<V, R> requires(String... aliases) {
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public RequiresOrDefineOrComposeValues<V, R> requiresValues(V... values) {
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsOrRequiresOrDefineOrComposeValues<V, R> defineValue(V value) {
|
||||
this.finishCurrentDefinition();
|
||||
this.currentDefinition = new PartialValueFlagDefinition<>(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsOrComposeValues<V, R> compose(String... aliases) {
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public AsOrComposeValues<V, R> composeValues(V... values) {
|
||||
if (this.currentDefinition != null && !this.currentDefinition.isComposition()) {
|
||||
this.finishCurrentDefinition();
|
||||
}
|
||||
this.currentDefinition = new PartialComposedFlagDefinition<>();
|
||||
|
||||
for (V value: values) {
|
||||
this.currentDefinition.addParent(this.referenceToValue(value));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void finishCurrentDefinition() {
|
||||
if (this.currentDefinition != null) {
|
||||
this.definitions.add(this.currentDefinition);
|
||||
this.currentDefinition = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected ArrayList<PartialFlagDefinition<V>> partialDefinitions() {
|
||||
return this.definitions;
|
||||
}
|
||||
|
||||
private PartialFlagDefinition<V> referenceToValue(V value) {
|
||||
var definition = this.valueToDefinition.get(value);
|
||||
if (definition == null) {
|
||||
definition = new ForwardReferenceByValue<>(value);
|
||||
}
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package fr.louisdevie.tatsuki.builders;
|
||||
|
||||
class ForwardReferenceByValue<V> implements PartialFlagDefinition<V> {
|
||||
private final V value;
|
||||
|
||||
public ForwardReferenceByValue(V value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlias(String alias) {
|
||||
throw new UnsupportedOperationException("Attempt to modify a forward reference");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParent(PartialFlagDefinition<V> parent) {
|
||||
throw new UnsupportedOperationException("Attempt to modify a forward reference");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComposition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alias() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public V value() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package fr.louisdevie.tatsuki.builders;
|
||||
|
||||
class PartialComposedFlagDefinition<V> implements PartialFlagDefinition<V> {
|
||||
public PartialComposedFlagDefinition() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlias(String alias) {
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParent(PartialFlagDefinition<V> parent) {
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComposition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alias() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public V value() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package fr.louisdevie.tatsuki.builders;
|
||||
|
||||
public interface PartialFlagDefinition<V> {
|
||||
void setAlias(String alias);
|
||||
|
||||
void addParent(PartialFlagDefinition<V> parent);
|
||||
|
||||
boolean isComposition();
|
||||
|
||||
String alias();
|
||||
|
||||
V value();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package fr.louisdevie.tatsuki.builders;
|
||||
|
||||
class PartialValueFlagDefinition<V> implements PartialFlagDefinition<V> {
|
||||
private final V value;
|
||||
private String alias;
|
||||
|
||||
public PartialValueFlagDefinition(V value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlias(String alias) {
|
||||
if (alias == null) {
|
||||
throw new NullPointerException("null flag alias");
|
||||
}
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParent(PartialFlagDefinition<V> parent) {
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComposition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alias() {
|
||||
return this.alias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V value() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package fr.louisdevie.tatsuki.builders.syntax;
|
||||
|
||||
|
||||
public interface AsOrComposeValues<V, R> {
|
||||
/**
|
||||
* Give the flag an alias to reference it elsewhere.
|
||||
*
|
||||
* @param alias An alias for the flag.
|
||||
*
|
||||
* @throws NullPointerException when {@code alias} is {@code null}.
|
||||
* @throws IllegalArgumentException when two flags are given the same alias.
|
||||
*/
|
||||
DefineOrComposeValues<V, R> as(String alias);
|
||||
|
||||
/**
|
||||
* Combine multiple flags together.
|
||||
*
|
||||
* @param values The values of the flags to combine.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
AsOrComposeValues<V, R> composeValues(V... values);
|
||||
|
||||
/**
|
||||
* Combine multiple flags together.
|
||||
*
|
||||
* @param aliases The aliases of the flags to combine.
|
||||
*/
|
||||
AsOrComposeValues<V, R> compose(String... aliases);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package fr.louisdevie.tatsuki.builders.syntax;
|
||||
|
||||
public interface AsOrRequiresOrDefineOrComposeValues<V, R> extends RequiresOrDefineOrComposeValues<V, R> {
|
||||
/**
|
||||
* Give the flag an alias to reference it elsewhere.
|
||||
*
|
||||
* @param alias An alias for the flag.
|
||||
*
|
||||
* @throws NullPointerException when {@code alias} is {@code null}.
|
||||
* @throws IllegalArgumentException when two flags are given the same alias.
|
||||
*/
|
||||
RequiresOrDefineOrComposeValues<V, R> as(String alias);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package fr.louisdevie.tatsuki.builders.syntax;
|
||||
|
||||
import fr.louisdevie.tatsuki.BitFlagSet;
|
||||
|
||||
public interface DefineFlag<X> {
|
||||
SetValueOrCompose<X> define(String name);
|
||||
|
||||
X build();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package fr.louisdevie.tatsuki.builders.syntax;
|
||||
|
||||
|
||||
public interface DefineOrComposeValues<V, R> {
|
||||
/**
|
||||
* Define a flag with the given value.
|
||||
*
|
||||
* @param value The value of the flag.
|
||||
* @throws NullPointerException when {@code value} is {@code null}.
|
||||
* @throws IllegalArgumentException when two flags are defined with the same value, or when {@code value} is not an
|
||||
* appropriate value for the type of flag set you are building.
|
||||
*/
|
||||
AsOrRequiresOrDefineOrComposeValues<V, R> defineValue(V value);
|
||||
|
||||
/**
|
||||
* Combine multiple flags together.
|
||||
*
|
||||
* @param aliases The aliases of the flags to combine.
|
||||
*/
|
||||
AsOrComposeValues<V, R> compose(String... aliases);
|
||||
|
||||
/**
|
||||
* Combine multiple flags together.
|
||||
*
|
||||
* @param values The values of the flags to combine.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
AsOrComposeValues<V, R> composeValues(V... values);
|
||||
|
||||
/**
|
||||
* Build a flag set with the flags previously defined.
|
||||
*/
|
||||
R build();
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package fr.louisdevie.tatsuki.builders.syntax;
|
||||
|
||||
public interface RequireParentsOrDefineFlag<X> extends DefineFlag<X> {
|
||||
DefineFlag<X> requires(String ...flags);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package fr.louisdevie.tatsuki.builders.syntax;
|
||||
|
||||
public interface RequiresOrDefineOrComposeValues<V, R> extends DefineOrComposeValues<V, R> {
|
||||
/**
|
||||
* Define the "parents" of this flag. A flag is not considered enabled unless all its parents are also enabled.
|
||||
* @param aliases The names of the required flags.
|
||||
*/
|
||||
RequiresOrDefineOrComposeValues<V, R> requires(String... aliases);
|
||||
|
||||
/**
|
||||
* Define the "parents" of this flag. A flag is not considered enabled unless all its parents are also enabled.
|
||||
* @param values The values of the required flags.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
RequiresOrDefineOrComposeValues<V, R> requiresValues(V... values);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package fr.louisdevie.tatsuki.builders.syntax;
|
||||
|
||||
import fr.louisdevie.tatsuki.BitFlagSet;
|
||||
|
||||
public interface SelectFlagSetType {
|
||||
DefineFlag<BitFlagSet> useBitFlags();
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package fr.louisdevie.tatsuki.builders.syntax;
|
||||
|
||||
public interface SetValueOrCompose<X> {
|
||||
RequireParentsOrDefineFlag<X> withValue(int value);
|
||||
|
||||
DefineFlag<X> compose(String ...flags);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package fr.louisdevie.tatsuki.collections;
|
||||
|
||||
import fr.louisdevie.tatsuki.FlagDefinition;
|
||||
import fr.louisdevie.tatsuki.builders.PartialFlagDefinition;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
class SetFlagDefinition<E> implements FlagDefinition<E, Set<E>> {
|
||||
private final String alias;
|
||||
private final E value;
|
||||
|
||||
private SetFlagDefinition(String alias, E value) {
|
||||
this.alias = alias;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static <E> SetFlagDefinition<E> fromPartial(PartialFlagDefinition<E> partialFlagDefinition) {
|
||||
return new SetFlagDefinition<>(partialFlagDefinition.alias(), partialFlagDefinition.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> alias() {
|
||||
return Optional.ofNullable(this.alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<E> value() {
|
||||
return Optional.ofNullable(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIn(Set<E> set) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<E> addTo(Set<E> set) {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<E> removeFrom(Set<E> set) {
|
||||
return Set.of();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package fr.louisdevie.tatsuki.collections;
|
||||
|
||||
import fr.louisdevie.tatsuki.FlagGraph;
|
||||
import fr.louisdevie.tatsuki.builders.FlagSetBuilder;
|
||||
import fr.louisdevie.tatsuki.builders.syntax.DefineOrComposeValues;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SetFlagGraph<E> extends FlagGraph<E, Set<E>> {
|
||||
SetFlagGraph(Collection<SetFlagDefinition<E>> c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
public static <E> DefineOrComposeValues<E, SetFlagGraph<E>> builder() {
|
||||
return new Builder<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<E> of(E... values) {
|
||||
return Arrays.stream(values)
|
||||
.filter(this::containsValue)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<E> named(String... aliases) {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAny(Set<E> flags, Set<E> required) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAll(Set<E> flags, Set<E> required) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<E> minimum(Set<E> flags) {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<E> maximum(Set<E> flags) {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
static class Builder<E> extends FlagSetBuilder<E, SetFlagGraph<E>> {
|
||||
@Override
|
||||
public SetFlagGraph<E> build() {
|
||||
this.finishCurrentDefinition();
|
||||
var definitions = this.partialDefinitions().stream().map(SetFlagDefinition::fromPartial).toList();
|
||||
return new SetFlagGraph<>(definitions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package fr.louisdevie.tatsuki.definition;
|
||||
|
||||
interface FlagDefinition<S> {
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package fr.louisdevie.tatsuki.definition;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class FlagDefinitionMap<F, S> {
|
||||
private Map<F, FlagDefinition<S>> _container;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import fr.louisdevie.tatsuki.bitflags.BigBitFlagGraph;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
@@ -8,21 +9,21 @@ import java.util.List;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
|
||||
public class BigBitFlagSetTests {
|
||||
private static BigInteger big(int value) {
|
||||
public class BigBitFlagGraphTests {
|
||||
/*private static BigInteger big(int value) {
|
||||
return BigInteger.valueOf(value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void empty() {
|
||||
var flags = new BigBitFlagSet();
|
||||
var flags = new BigBitFlagGraph();
|
||||
|
||||
assertEquals(big(0), flags.empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void union() {
|
||||
final var flags = new BigBitFlagSet();
|
||||
final var flags = new BigBitFlagGraph();
|
||||
|
||||
assertEquals(big(0), flags.union(big(0), big(0)));
|
||||
assertEquals(big(1), flags.union(big(1), big(0)));
|
||||
@@ -33,7 +34,7 @@ public class BigBitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void difference() {
|
||||
var flags = new BigBitFlagSet();
|
||||
var flags = new BigBitFlagGraph();
|
||||
|
||||
assertEquals(big(0), flags.difference(big(0), big(0)));
|
||||
assertEquals(big(1), flags.difference(big(1), big(0)));
|
||||
@@ -44,7 +45,7 @@ public class BigBitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void intersection() {
|
||||
var flags = new BigBitFlagSet();
|
||||
var flags = new BigBitFlagGraph();
|
||||
|
||||
assertEquals(big(0), flags.intersection(big(0), big(0)));
|
||||
assertEquals(big(0), flags.intersection(big(1), big(0)));
|
||||
@@ -56,7 +57,7 @@ public class BigBitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void isSuperset() {
|
||||
var flags = new BigBitFlagSet();
|
||||
var flags = new BigBitFlagGraph();
|
||||
|
||||
assertTrue(flags.isSuperset(big(0), big(0)));
|
||||
assertTrue(flags.isSuperset(big(3), big(0)));
|
||||
@@ -68,7 +69,7 @@ public class BigBitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void enumerate() {
|
||||
var flags = new BigBitFlagSet();
|
||||
var flags = new BigBitFlagGraph();
|
||||
|
||||
assertIterableEquals(List.of(), flags.enumerate(big(0)));
|
||||
assertIterableEquals(List.of(big(1)), flags.enumerate(big(1)));
|
||||
@@ -76,5 +77,5 @@ public class BigBitFlagSetTests {
|
||||
assertIterableEquals(List.of(big(1), big(2)), flags.enumerate(big(3)));
|
||||
assertIterableEquals(List.of(big(1), big(2), big(8)), flags.enumerate(big(11)));
|
||||
assertIterableEquals(List.of(big(4), big(32), big(64)), flags.enumerate(big(100)));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import fr.louisdevie.tatsuki.bitflags.BitFlagGraph;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
@@ -7,17 +8,17 @@ import java.util.List;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
|
||||
public class BitFlagSetTests {
|
||||
@Test
|
||||
public class BitFlagGraphTests {
|
||||
/*@Test
|
||||
public void empty() {
|
||||
var flags = new BitFlagSet();
|
||||
var flags = new BitFlagGraph();
|
||||
|
||||
assertEquals(0, flags.empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void union() {
|
||||
final var flags = new BitFlagSet();
|
||||
final var flags = new BitFlagGraph();
|
||||
|
||||
assertEquals(0, flags.union(0, 0));
|
||||
assertEquals(1, flags.union(1, 0));
|
||||
@@ -28,7 +29,7 @@ public class BitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void difference() {
|
||||
var flags = new BitFlagSet();
|
||||
var flags = new BitFlagGraph();
|
||||
|
||||
assertEquals(0, flags.difference(0, 0));
|
||||
assertEquals(1, flags.difference(1, 0));
|
||||
@@ -39,7 +40,7 @@ public class BitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void intersection() {
|
||||
var flags = new BitFlagSet();
|
||||
var flags = new BitFlagGraph();
|
||||
|
||||
assertEquals(0, flags.intersection(0, 0));
|
||||
assertEquals(0, flags.intersection(1, 0));
|
||||
@@ -51,7 +52,7 @@ public class BitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void isSuperset() {
|
||||
var flags = new BitFlagSet();
|
||||
var flags = new BitFlagGraph();
|
||||
|
||||
assertTrue(flags.isSuperset(0, 0));
|
||||
assertTrue(flags.isSuperset(3, 0));
|
||||
@@ -63,7 +64,7 @@ public class BitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void enumerate() {
|
||||
var flags = new BitFlagSet();
|
||||
var flags = new BitFlagGraph();
|
||||
|
||||
assertIterableEquals(List.of(), flags.enumerate(0));
|
||||
assertIterableEquals(List.of(1), flags.enumerate(1));
|
||||
@@ -71,5 +72,5 @@ public class BitFlagSetTests {
|
||||
assertIterableEquals(List.of(1, 2), flags.enumerate(3));
|
||||
assertIterableEquals(List.of(1, 2, 8), flags.enumerate(11));
|
||||
assertIterableEquals(List.of(4, 32, 64), flags.enumerate(100));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class FlagGraphTests {
|
||||
@Test
|
||||
public void size() {
|
||||
final var noFlags = new MockFlagGraph();
|
||||
|
||||
assertEquals(0, noFlags.size());
|
||||
|
||||
final var flags = new MockFlagGraph(
|
||||
new MockFlagDefinition("A", "1"),
|
||||
new MockFlagDefinition("B", null),
|
||||
new MockFlagDefinition(null, "2")
|
||||
);
|
||||
|
||||
assertEquals(3, flags.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEmpty() {
|
||||
final var noFlags = new MockFlagGraph();
|
||||
|
||||
assertTrue(noFlags.isEmpty());
|
||||
|
||||
final var flags = new MockFlagGraph(
|
||||
new MockFlagDefinition("A", "x"),
|
||||
new MockFlagDefinition("B", null),
|
||||
new MockFlagDefinition(null, "y")
|
||||
);
|
||||
|
||||
assertFalse(flags.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsValue() {
|
||||
final var flags = new MockFlagGraph(
|
||||
new MockFlagDefinition("A", "x"),
|
||||
new MockFlagDefinition("B", null),
|
||||
new MockFlagDefinition(null, "y")
|
||||
);
|
||||
|
||||
assertTrue(flags.containsValue("A"));
|
||||
assertTrue(flags.containsValue("B"));
|
||||
assertFalse(flags.containsValue("C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsAlias() {
|
||||
final var flags = new MockFlagGraph(
|
||||
new MockFlagDefinition("A", "x"),
|
||||
new MockFlagDefinition("B", null),
|
||||
new MockFlagDefinition(null, "y")
|
||||
);
|
||||
|
||||
assertTrue(flags.containsAlias("x"));
|
||||
assertTrue(flags.containsAlias("y"));
|
||||
assertFalse(flags.containsAlias("z"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsDefinition() {
|
||||
final var inGraph = new MockFlagDefinition("A", "x");
|
||||
final var notInGraph = new MockFlagDefinition("B", "y");
|
||||
final var flags = new MockFlagGraph(inGraph);
|
||||
|
||||
assertTrue(flags.containsDefinition(inGraph));
|
||||
assertFalse(flags.containsDefinition(notInGraph));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void definitionOf() {
|
||||
final var x = new MockFlagDefinition("A", "x");
|
||||
final var y = new MockFlagDefinition("B", "y");
|
||||
final var flags = new MockFlagGraph(x, y);
|
||||
|
||||
assertTrue(flags.definitionOf("A").isPresent());
|
||||
assertSame(x, flags.definitionOf("A").get());
|
||||
|
||||
assertTrue(flags.definitionOf("B").isPresent());
|
||||
assertSame(y, flags.definitionOf("B").get());
|
||||
|
||||
assertTrue(flags.definitionOf("C").isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void definitionNamed() {
|
||||
final var x = new MockFlagDefinition("A", "x");
|
||||
final var y = new MockFlagDefinition("B", "y");
|
||||
final var flags = new MockFlagGraph(x, y);
|
||||
|
||||
assertTrue(flags.definitionNamed("x").isPresent());
|
||||
assertSame(x, flags.definitionNamed("x").get());
|
||||
|
||||
assertTrue(flags.definitionNamed("y").isPresent());
|
||||
assertSame(y, flags.definitionNamed("y").get());
|
||||
|
||||
assertTrue(flags.definitionNamed("z").isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aliasSet() {
|
||||
final var flags = new MockFlagGraph(
|
||||
new MockFlagDefinition("A", "x"),
|
||||
new MockFlagDefinition("B", null),
|
||||
new MockFlagDefinition(null, "y")
|
||||
);
|
||||
|
||||
assertEquals(Set.of("x", "y"), flags.aliasSet());
|
||||
|
||||
assertThrows(UnsupportedOperationException.class, () -> flags.aliasSet().remove("x"));
|
||||
assertThrows(UnsupportedOperationException.class, () -> flags.aliasSet().add("z"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueSet() {
|
||||
final var flags = new MockFlagGraph(
|
||||
new MockFlagDefinition("A", "x"),
|
||||
new MockFlagDefinition("B", null),
|
||||
new MockFlagDefinition(null, "y")
|
||||
);
|
||||
|
||||
assertEquals(Set.of("A", "B"), flags.valueSet());
|
||||
|
||||
assertThrows(UnsupportedOperationException.class, () -> flags.valueSet().remove("A"));
|
||||
assertThrows(UnsupportedOperationException.class, () -> flags.valueSet().add("C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void definitions() {
|
||||
final var x = new MockFlagDefinition("A", "x");
|
||||
final var B = new MockFlagDefinition("B", null);
|
||||
final var y = new MockFlagDefinition(null, "y");
|
||||
final var flags = new MockFlagGraph(x, B, y);
|
||||
|
||||
assertEquals(Set.of(x, B, y), flags.definitions());
|
||||
|
||||
assertThrows(UnsupportedOperationException.class, () -> flags.valueSet().remove("A"));
|
||||
assertThrows(UnsupportedOperationException.class, () -> flags.valueSet().add("C"));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import fr.louisdevie.tatsuki.bitflags.LongBitFlagGraph;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
@@ -7,17 +8,17 @@ import java.util.List;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
|
||||
public class LongBitFlagSetTests {
|
||||
@Test
|
||||
public class LongBitFlagGraphTests {
|
||||
/*@Test
|
||||
public void empty() {
|
||||
var flags = new LongBitFlagSet();
|
||||
var flags = new LongBitFlagGraph();
|
||||
|
||||
assertEquals(0L, flags.empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void union() {
|
||||
final var flags = new LongBitFlagSet();
|
||||
final var flags = new LongBitFlagGraph();
|
||||
|
||||
assertEquals(0L, flags.union(0L, 0L));
|
||||
assertEquals(1L, flags.union(1L, 0L));
|
||||
@@ -28,7 +29,7 @@ public class LongBitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void difference() {
|
||||
var flags = new LongBitFlagSet();
|
||||
var flags = new LongBitFlagGraph();
|
||||
|
||||
assertEquals(0L, flags.difference(0L, 0L));
|
||||
assertEquals(1L, flags.difference(1L, 0L));
|
||||
@@ -39,7 +40,7 @@ public class LongBitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void intersection() {
|
||||
var flags = new LongBitFlagSet();
|
||||
var flags = new LongBitFlagGraph();
|
||||
|
||||
assertEquals(0L, flags.intersection(0L, 0L));
|
||||
assertEquals(0L, flags.intersection(1L, 0L));
|
||||
@@ -51,7 +52,7 @@ public class LongBitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void isSuperset() {
|
||||
var flags = new LongBitFlagSet();
|
||||
var flags = new LongBitFlagGraph();
|
||||
|
||||
assertTrue(flags.isSuperset(0L, 0L));
|
||||
assertTrue(flags.isSuperset(3L, 0L));
|
||||
@@ -63,7 +64,7 @@ public class LongBitFlagSetTests {
|
||||
|
||||
@Test
|
||||
public void enumerate() {
|
||||
var flags = new LongBitFlagSet();
|
||||
var flags = new LongBitFlagGraph();
|
||||
|
||||
assertIterableEquals(List.of(), flags.enumerate(0L));
|
||||
assertIterableEquals(List.of(1L), flags.enumerate(1L));
|
||||
@@ -71,5 +72,5 @@ public class LongBitFlagSetTests {
|
||||
assertIterableEquals(List.of(1L, 2L), flags.enumerate(3L));
|
||||
assertIterableEquals(List.of(1L, 2L, 8L), flags.enumerate(11L));
|
||||
assertIterableEquals(List.of(4L, 32L, 64L), flags.enumerate(100L));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class MockFlagDefinition implements FlagDefinition<String, String> {
|
||||
private final String value;
|
||||
private final String alias;
|
||||
|
||||
public MockFlagDefinition(String value, String alias) {
|
||||
this.value = value;
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> alias() {
|
||||
return Optional.ofNullable(this.alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> value() {
|
||||
return Optional.ofNullable(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIn(String set) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String addTo(String set) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String removeFrom(String set) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package fr.louisdevie.tatsuki;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class MockFlagGraph extends FlagGraph<String, String> {
|
||||
@SafeVarargs
|
||||
public MockFlagGraph(FlagDefinition<String, String>... definitions) {
|
||||
super(Arrays.stream(definitions).toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String of(String... values) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String named(String... aliases) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAny(String flags, String required) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAll(String flags, String required) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String minimum(String flags) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String maximum(String flags) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package fr.louisdevie.tatsuki.bitflags;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static fr.louisdevie.tatsuki.testing.Assertions.assertYields;
|
||||
import static fr.louisdevie.tatsuki.testing.Factory.big;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class BitFlagsTests {
|
||||
@Test
|
||||
public void union() {
|
||||
assertEquals(0, BitFlags.union(0, 0));
|
||||
assertEquals(1, BitFlags.union(1, 0));
|
||||
assertEquals(2, BitFlags.union(0, 2));
|
||||
assertEquals(3, BitFlags.union(1, 2));
|
||||
assertEquals(7, BitFlags.union(3, 6));
|
||||
|
||||
assertEquals(0L, BitFlags.union(0L, 0L));
|
||||
assertEquals(1L, BitFlags.union(1L, 0L));
|
||||
assertEquals(2L, BitFlags.union(0L, 2L));
|
||||
assertEquals(3L, BitFlags.union(1L, 2L));
|
||||
assertEquals(7L, BitFlags.union(3L, 6L));
|
||||
|
||||
assertEquals(big(0), BitFlags.union(big(0), big(0)));
|
||||
assertEquals(big(1), BitFlags.union(big(1), big(0)));
|
||||
assertEquals(big(2), BitFlags.union(big(0), big(2)));
|
||||
assertEquals(big(3), BitFlags.union(big(1), big(2)));
|
||||
assertEquals(big(7), BitFlags.union(big(3), big(6)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void difference() {
|
||||
assertEquals(0, BitFlags.difference(0, 0));
|
||||
assertEquals(1, BitFlags.difference(1, 0));
|
||||
assertEquals(1, BitFlags.difference(3, 6));
|
||||
assertEquals(4, BitFlags.difference(6, 3));
|
||||
assertEquals(8, BitFlags.difference(8, 17));
|
||||
|
||||
assertEquals(0L, BitFlags.difference(0L, 0L));
|
||||
assertEquals(1L, BitFlags.difference(1L, 0L));
|
||||
assertEquals(1L, BitFlags.difference(3L, 6L));
|
||||
assertEquals(4L, BitFlags.difference(6L, 3L));
|
||||
assertEquals(8L, BitFlags.difference(8L, 17L));
|
||||
|
||||
assertEquals(big(0), BitFlags.difference(big(0), big(0)));
|
||||
assertEquals(big(1), BitFlags.difference(big(1), big(0)));
|
||||
assertEquals(big(1), BitFlags.difference(big(3), big(6)));
|
||||
assertEquals(big(4), BitFlags.difference(big(6), big(3)));
|
||||
assertEquals(big(8), BitFlags.difference(big(8), big(17)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void intersection() {
|
||||
assertEquals(0, BitFlags.intersection(0, 0));
|
||||
assertEquals(0, BitFlags.intersection(1, 0));
|
||||
assertEquals(0, BitFlags.intersection(1, 2));
|
||||
assertEquals(1, BitFlags.intersection(1, 3));
|
||||
assertEquals(1, BitFlags.intersection(11, 5));
|
||||
assertEquals(3, BitFlags.intersection(11, 7));
|
||||
|
||||
assertEquals(0L, BitFlags.intersection(0L, 0L));
|
||||
assertEquals(0L, BitFlags.intersection(1L, 0L));
|
||||
assertEquals(0L, BitFlags.intersection(1L, 2L));
|
||||
assertEquals(1L, BitFlags.intersection(1L, 3L));
|
||||
assertEquals(1L, BitFlags.intersection(11L, 5L));
|
||||
assertEquals(3L, BitFlags.intersection(11L, 7L));
|
||||
|
||||
assertEquals(big(0), BitFlags.intersection(big(0), big(0)));
|
||||
assertEquals(big(0), BitFlags.intersection(big(1), big(0)));
|
||||
assertEquals(big(0), BitFlags.intersection(big(1), big(2)));
|
||||
assertEquals(big(1), BitFlags.intersection(big(1), big(3)));
|
||||
assertEquals(big(1), BitFlags.intersection(big(11), big(5)));
|
||||
assertEquals(big(3), BitFlags.intersection(big(11), big(7)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSuperset() {
|
||||
assertTrue(BitFlags.isSuperset(0, 0));
|
||||
assertTrue(BitFlags.isSuperset(3, 0));
|
||||
assertTrue(BitFlags.isSuperset(3, 1));
|
||||
assertTrue(BitFlags.isSuperset(3, 3));
|
||||
assertFalse(BitFlags.isSuperset(0, 3));
|
||||
assertFalse(BitFlags.isSuperset(8, 4));
|
||||
|
||||
assertTrue(BitFlags.isSuperset(0L, 0L));
|
||||
assertTrue(BitFlags.isSuperset(3L, 0L));
|
||||
assertTrue(BitFlags.isSuperset(3L, 1L));
|
||||
assertTrue(BitFlags.isSuperset(3L, 3L));
|
||||
assertFalse(BitFlags.isSuperset(0L, 3L));
|
||||
assertFalse(BitFlags.isSuperset(8L, 4L));
|
||||
|
||||
assertTrue(BitFlags.isSuperset(big(0), big(0)));
|
||||
assertTrue(BitFlags.isSuperset(big(3), big(0)));
|
||||
assertTrue(BitFlags.isSuperset(big(3), big(1)));
|
||||
assertTrue(BitFlags.isSuperset(big(3), big(3)));
|
||||
assertFalse(BitFlags.isSuperset(big(0), big(3)));
|
||||
assertFalse(BitFlags.isSuperset(big(8), big(4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enumerate() {
|
||||
assertYields(List.of(), BitFlags.enumerate(0));
|
||||
assertYields(List.of(1), BitFlags.enumerate(1));
|
||||
assertYields(List.of(2), BitFlags.enumerate(2));
|
||||
assertYields(List.of(1, 2), BitFlags.enumerate(3));
|
||||
assertYields(List.of(4, 32, 64), BitFlags.enumerate(100));
|
||||
|
||||
assertYields(List.of(), BitFlags.enumerate(0L));
|
||||
assertYields(List.of(1L), BitFlags.enumerate(1L));
|
||||
assertYields(List.of(2L), BitFlags.enumerate(2L));
|
||||
assertYields(List.of(1L, 2L), BitFlags.enumerate(3L));
|
||||
assertYields(List.of(4L, 32L, 64L), BitFlags.enumerate(100L));
|
||||
|
||||
assertYields(List.of(), BitFlags.enumerate(big(0)));
|
||||
assertYields(List.of(big(1)), BitFlags.enumerate(big(1)));
|
||||
assertYields(List.of(big(2)), BitFlags.enumerate(big(2)));
|
||||
assertYields(List.of(big(1), big(2)), BitFlags.enumerate(big(3)));
|
||||
assertYields(List.of(big(4), big(32), big(64)), BitFlags.enumerate(big(100)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package fr.louisdevie.tatsuki.collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class SetFlagGraphTests {
|
||||
@Test
|
||||
public void of() {
|
||||
final var flags = SetFlagGraph.<Integer>builder()
|
||||
.defineValue(12).as("a")
|
||||
.defineValue(45).as("b")
|
||||
.defineValue(78).as("c")
|
||||
.build();
|
||||
|
||||
assertEquals(Set.of(), flags.of());
|
||||
assertEquals(Set.of(12), flags.of(12));
|
||||
assertEquals(Set.of(12, 78), flags.of(12, 54, 78));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void named() {
|
||||
final var flags = SetFlagGraph.<Integer>builder()
|
||||
.defineValue(12).as("a")
|
||||
.defineValue(45).as("b")
|
||||
.defineValue(78).as("c")
|
||||
.compose("a", "b").as("ab")
|
||||
.build();
|
||||
|
||||
assertEquals(Set.of(), flags.named());
|
||||
assertEquals(Set.of(12), flags.named("a"));
|
||||
assertEquals(Set.of(12, 45, 78), flags.named("ab", "c"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAny() {
|
||||
final var flags = SetFlagGraph.<Integer>builder()
|
||||
.defineValue(12)
|
||||
.defineValue(45).requiresValues(12)
|
||||
.defineValue(78)
|
||||
.build();
|
||||
|
||||
assertFalse(flags.hasAny(Set.of(), Set.of()));
|
||||
assertFalse(flags.hasAny(Set.of(12, 45, 78), Set.of()));
|
||||
assertTrue(flags.hasAny(Set.of(12, 45, 78), Set.of(12)));
|
||||
assertTrue(flags.hasAny(Set.of(12), Set.of(12, 78)));
|
||||
assertFalse(flags.hasAny(Set.of(45, 78), Set.of(45)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAll() {
|
||||
final var flags = SetFlagGraph.<Integer>builder()
|
||||
.defineValue(12)
|
||||
.defineValue(45).requiresValues(12)
|
||||
.defineValue(78)
|
||||
.build();
|
||||
|
||||
assertTrue(flags.hasAll(Set.of(), Set.of()));
|
||||
assertTrue(flags.hasAll(Set.of(12, 45, 78), Set.of()));
|
||||
assertTrue(flags.hasAll(Set.of(12, 45, 78), Set.of(12)));
|
||||
assertFalse(flags.hasAll(Set.of(12), Set.of(12, 78)));
|
||||
assertFalse(flags.hasAll(Set.of(45, 78), Set.of(45)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maximum() {
|
||||
final var flags = SetFlagGraph.<Integer>builder()
|
||||
.defineValue(12)
|
||||
.defineValue(45).requiresValues(12)
|
||||
.defineValue(78).requiresValues(45)
|
||||
.build();
|
||||
|
||||
assertEquals(Set.of(), flags.maximum(Set.of()));
|
||||
assertEquals(Set.of(12), flags.maximum(Set.of(12)));
|
||||
assertEquals(Set.of(12, 45), flags.maximum(Set.of(45)));
|
||||
assertEquals(Set.of(12, 45, 78), flags.maximum(Set.of(78)));
|
||||
assertEquals(Set.of(), flags.maximum(Set.of(99)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minimum() {
|
||||
final var flags = SetFlagGraph.<Integer>builder()
|
||||
.defineValue(12)
|
||||
.defineValue(45).requiresValues(12)
|
||||
.defineValue(78).requiresValues(45)
|
||||
.build();
|
||||
|
||||
assertEquals(Set.of(), flags.minimum(Set.of()));
|
||||
assertEquals(Set.of(12), flags.minimum(Set.of(12)));
|
||||
assertEquals(Set.of(), flags.minimum(Set.of(45)));
|
||||
assertEquals(Set.of(12, 45), flags.minimum(Set.of(12, 45)));
|
||||
assertEquals(Set.of(12), flags.minimum(Set.of(12, 78)));
|
||||
assertEquals(Set.of(12, 45, 78), flags.minimum(Set.of(12, 45, 78)));
|
||||
assertEquals(Set.of(), flags.minimum(Set.of(99)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package fr.louisdevie.tatsuki.testing;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class Assertions {
|
||||
public static void assertYields(List<?> expected, Iterable<?> actual) {
|
||||
Queue<?> remaining = new ArrayDeque<>(expected);
|
||||
for (Object actualElement : actual) {
|
||||
if (remaining.isEmpty()) {
|
||||
fail(String.format("Iterable yielded <%s> (no more elements were expected)", actualElement.toString()));
|
||||
}
|
||||
Object expectedElement = remaining.poll();
|
||||
if (!expectedElement.equals(actualElement)) {
|
||||
fail(String.format("Iterable yielded <%s> (expected <%s>)", actualElement.toString(), expectedElement.toString()));
|
||||
}
|
||||
}
|
||||
if (!remaining.isEmpty()) {
|
||||
fail(
|
||||
"Iterable did not yield " +
|
||||
remaining.stream()
|
||||
.map(obj -> String.format("<%s>", obj.toString()))
|
||||
.collect(Collectors.joining(", "))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertYieldsUnordered(List<?> expected, Iterable<?> actual) {
|
||||
List<?> remaining = new ArrayList<>(expected);
|
||||
for (Object actualElement : actual) {
|
||||
int i = remaining.indexOf(actualElement);
|
||||
if (i == -1) {
|
||||
String expectation;
|
||||
if (remaining.isEmpty()) {
|
||||
expectation = "no more elements were expected";
|
||||
} else {
|
||||
expectation = "expected one of " +
|
||||
remaining.stream()
|
||||
.map(obj -> String.format("<%s>", obj.toString()))
|
||||
.collect(Collectors.joining(", "));
|
||||
}
|
||||
fail(String.format("Iterable yielded <%s> (%s)", actualElement.toString(), expectation));
|
||||
} else {
|
||||
remaining.remove(i);
|
||||
}
|
||||
}
|
||||
if (!remaining.isEmpty()) {
|
||||
fail(
|
||||
"Iterable did not yield " +
|
||||
remaining.stream()
|
||||
.map(obj -> String.format("<%s>", obj.toString()))
|
||||
.collect(Collectors.joining(", "))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package fr.louisdevie.tatsuki.testing;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class Factory {
|
||||
public static BigInteger big(int value) {
|
||||
return BigInteger.valueOf(value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user