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

cdc.applic.expressions.content.StringSet Maven / Gradle / Ivy

There is a newer version: 0.13.3
Show newest version
package cdc.applic.expressions.content;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import cdc.applic.expressions.SyntacticException;
import cdc.applic.expressions.parsing.SItemsParsing;
import cdc.util.lang.Checks;
import cdc.util.lang.CollectionUtils;

/**
 * Implementation of {@link SItemSet} containing {@link StringSItem}s.
 * 

* Order of definition of SItems is preserved.
* Duplicates are removed. * * @author Damien Carbonne */ public final class StringSet extends AbstractSItemSet implements CheckedSet, CountableSet, Comparable { /** * A Comparator based on StringValue alphabetical comparison. *

* Use {@link #lexicographicComparator(Comparator)} for more elaborated comparators. */ public static final Comparator LEXICOGRAPHIC_COMPARATOR = (s1, s2) -> { if (s1 == s2) { return 0; } if (s1 == null || s2 == null) { return s1 == null ? -1 : 1; } return CollectionUtils.compareLexicographic(s1.values, s2.values); }; private static final List NO_VALUES = Collections.emptyList(); /** * Unmodifiable list (check this in constructors). */ private final List values; /** * The empty {@link StringSet}. */ public static final StringSet EMPTY = of(); /** * The {@link StringSet} than only contains the {@link StringValue#PATTERN_UNKNOWN}. */ public static final StringSet UNKNOWN = of(StringValue.PATTERN_UNKNOWN); private StringSet(Collection values) { Checks.isNotNull(values, "values"); if (values.isEmpty()) { this.values = NO_VALUES; } else { final List list = new ArrayList<>(); final Set set = new HashSet<>(); for (final StringValue value : values) { if (value == null) { throw new IllegalArgumentException("Null value"); } if (!set.contains(value)) { set.add(value); list.add(value); } } this.values = Collections.unmodifiableList(list); } } /** * Converts an {@link SItemSet} set to a {@link StringSet}. * * @param set The set. * @return The conversion of {@code set} to a {@link StringSet}. * @throws IllegalArgumentException When {@code set} can not be converted to a {@link StringSet}. */ public static StringSet convert(SItemSet set) { if (set instanceof StringSet) { return (StringSet) set; } else if (set.isEmpty()) { return EMPTY; } else if (set.isCompliantWith(StringSet.class)) { // Should not throw ClassCastException return new StringSet(convert(set.getItems(), StringValue.class)); } else { throw new IllegalArgumentException("Can not convert this set to " + StringSet.class.getSimpleName()); } } /** * Creates a {@link StringSet} from the String representation of its content. * * @param content The content. * @return A new instance of {@link StringSet}. * @throws SyntacticException When {@code content} can not be parsed as a {@link StringSet}. */ public static StringSet of(String content) { return of(SItemsParsing.toStringValues(content)); } /** * Creates a {@link StringSet} from an array of {@link StringValue StringValues}. * * @param values The values. * @return A new instance of {@link StringSet}. * @throws IllegalArgumentException When a value is {@code null}. */ public static StringSet of(StringValue... values) { return of(Arrays.asList(values)); } /** * Creates a {@link StringSet} from a collection of {@link StringValue StringValues}. * * @param values The values. * @return A new instance of {@link UncheckedSet}. * @throws IllegalArgumentException When a value is {@code null}. */ public static StringSet of(Collection values) { return new StringSet(values); } @Override public long getExtent() { if (contains(StringValue.PATTERN_UNKNOWN)) { return CountableSet.UNDEFINED_NUMBER_OF_VALUES; } else { return values.size(); } } @Override public StringSet getChecked() { return this; } @Override public StringSet getBest() { return this; } @Override public boolean isEmpty() { return values.isEmpty(); } @Override public boolean containsRanges() { return false; } @Override public boolean isSingleton() { // No intervals return values.size() == 1 && !StringValue.PATTERN_UNKNOWN.equals(values.get(0)); } @Override public StringValue getSingletonValue() { checkIsSingleton(); return values.get(0); } @Override public boolean isValid() { return true; } @Override public boolean isChecked() { return true; } @Override public List getItems() { return values; } @Override public boolean contains(SItem item) { Checks.isNotNull(item, ITEM); if (item instanceof StringValue) { return contains((StringValue) item); } else { throw nonSupportedItem(item); } } @Override public StringSet union(SItem item) { Checks.isNotNull(item, ITEM); if (item instanceof StringValue) { return union((StringValue) item); } else { throw nonSupportedItem(item); } } @Override public StringSet union(SItemSet set) { Checks.isNotNull(set, SET); if (set.isCompliantWith(getClass())) { return union(convert(set)); } else { throw nonSupportedSet(set); } } @Override public StringSet intersection(SItem item) { Checks.isNotNull(item, ITEM); if (item instanceof StringValue) { return intersection((StringValue) item); } else { throw nonSupportedItem(item); } } @Override public StringSet intersection(SItemSet set) { Checks.isNotNull(set, SET); if (set.isCompliantWith(getClass())) { return intersection(convert(set)); } else { throw nonSupportedSet(set); } } @Override public StringSet remove(SItem item) { Checks.isNotNull(item, ITEM); if (item instanceof StringValue) { return remove((StringValue) item); } else { throw nonSupportedItem(item); } } @Override public StringSet remove(SItemSet set) { Checks.isNotNull(set, SET); if (set.isCompliantWith(getClass())) { return remove(convert(set)); } else { throw nonSupportedSet(set); } } /** * @return {@code true} if this set contains {@link StringValue#PATTERN_UNKNOWN}. */ public boolean containsPatternAny() { return values.contains(StringValue.PATTERN_UNKNOWN); } @Override public boolean contains(StringValue value) { // No special handling of PATTERN_ANY is needed // We want: // {...} contains A -> false, not true return values.contains(value); } @Override public boolean contains(StringSet other) { // No special handling of PATTERN_ANY is needed // We want: // {...} contains {A} -> false, not true return this.values.containsAll(other.values); } @Override public StringSet union(StringValue value) { Checks.isNotNull(value, VALUE); // No special handling of PATTERN_ANY is needed // We don't want to simplify normal values. // So, {A, ...} union B -> {A, B, ...}, not {...} if (contains(value)) { return this; } final List tmp = new ArrayList<>(); tmp.addAll(this.values); tmp.add(value); return new StringSet(tmp); } @Override public StringSet union(StringSet set) { Checks.isNotNull(set, SET); // No special handling of PATTERN_ANY is needed // We don't want to simplify normal values. // So, {A, ...} union {B} -> {A, B, ...}, not {...} if (contains(set)) { return this; } final List tmp = new ArrayList<>(); tmp.addAll(this.values); for (final StringValue value : set.values) { if (!tmp.contains(value)) { tmp.add(value); } } return new StringSet(tmp); } @Override public StringSet intersection(StringValue value) { Checks.isNotNull(value, VALUE); // PATTERN_ANY is handled correctly // {A, ...} intersection B -> {} // {A, ...} intersection ... -> {...} if (contains(value)) { return of(value); } else { return EMPTY; } } @Override public StringSet intersection(StringSet set) { Checks.isNotNull(set, SET); // Special handling of PATTERN_ANY // We want this: // {A, ...} intersection {B, ...} -> {...} // {A, ...} intersection {B} -> {} // {A} intersection {B, ...} -> {} // {A, B} intersection {B, C} -> {B} final List tmp = new ArrayList<>(); for (final StringValue value : getItems()) { if (set.contains(value)) { tmp.add(value); } } if (tmp.isEmpty()) { return EMPTY; } else { return new StringSet(tmp); } } @Override public StringSet remove(StringValue value) { Checks.isNotNull(value, VALUE); // Special handling of PATTERN_ANY // We want this: // {A,B, ...} remove A -> {B, ...} // {A,B, ...} remove ... -> {A, B} // This looks strange, but ... represents all unknown values. if (!contains(value)) { return this; } final List tmp = new ArrayList<>(); tmp.addAll(this.values); tmp.remove(value); return new StringSet(tmp); } @Override public StringSet remove(StringSet set) { Checks.isNotNull(set, SET); final List tmp = new ArrayList<>(); tmp.addAll(this.values); tmp.removeAll(set.values); if (tmp.isEmpty()) { return EMPTY; } else { return new StringSet(tmp); } } /** * Creates a lexicographic Comparator based on a specific StringValue comparator. * * @param comparator The StringValue comparator. * @return A new lexicographic Comparator based on {@code comparator}. */ public static Comparator lexicographicComparator(Comparator comparator) { return (s1, s2) -> { if (s1 == s2) { return 0; } if (s1 == null || s2 == null) { return s1 == null ? -1 : 1; } return CollectionUtils.compareLexicographic(s1.values, s2.values, comparator); }; } @Override public boolean equals(Object object) { if (this == object) { return true; } if (isEmpty() && object instanceof SItemSet && ((SItemSet) object).isEmpty()) { return true; } if (!(object instanceof StringSet)) { return false; } final StringSet other = (StringSet) object; return values.equals(other.values); } @Override public int hashCode() { return values.hashCode(); } @Override public int compareTo(StringSet o) { if (this == o) { return 0; } if (o == null) { return 1; } else { return CollectionUtils.compareLexicographic(getItems(), o.getItems()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy