com.shapesecurity.functional.data.ImmutableSet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of shape-functional-java Show documentation
Show all versions of shape-functional-java Show documentation
Functional programming library
package com.shapesecurity.functional.data;
import com.shapesecurity.functional.F;
import com.shapesecurity.functional.F2;
import com.shapesecurity.functional.Pair;
import com.shapesecurity.functional.Unit;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import java.util.ArrayList;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
@CheckReturnValue
public class ImmutableSet implements Iterable {
@Nonnull
private final HashTable data;
public int length() {
return this.data.length;
}
@Nonnull
public Hasher hasher() {
return this.data.hasher;
}
ImmutableSet(@Nonnull HashTable data) {
this.data = data;
}
@Nonnull
public static ImmutableSet empty(@Nonnull Hasher hasher) {
return new ImmutableSet<>(HashTable.empty(hasher));
}
@Nonnull
public static ImmutableSet emptyUsingEquality() {
return new ImmutableSet<>(HashTable.emptyUsingEquality());
}
@Nonnull
public static ImmutableSet emptyUsingIdentity() {
return new ImmutableSet<>(HashTable.emptyUsingIdentity());
}
@Nonnull
public static ImmutableSet from(@Nonnull Hasher hasher, @Nonnull Iterable set) {
return empty(hasher).putAll(set);
}
@Nonnull
public static ImmutableSet fromUsingEquality(@Nonnull Iterable set) {
return ImmutableSet.emptyUsingEquality().putAll(set);
}
@Nonnull
public static ImmutableSet fromUsingIdentity(@Nonnull Iterable set) {
return ImmutableSet.emptyUsingIdentity().putAll(set);
}
@Nonnull
@SafeVarargs
public static ImmutableSet ofUsingIdentity(@Nonnull T... items) {
return ImmutableSet.emptyUsingIdentity().putArray(items);
}
@Nonnull
@SafeVarargs
public static ImmutableSet ofUsingEquality(@Nonnull T... items) {
return ImmutableSet.emptyUsingEquality().putArray(items);
}
@Nonnull
@SafeVarargs
public static ImmutableSet of(@Nonnull T... items) {
return ofUsingEquality(items);
}
@Deprecated
@Nonnull
public static ImmutableSet empty() {
return ImmutableSet.emptyUsingEquality();
}
@Deprecated
@Nonnull
public static ImmutableSet emptyP() {
return ImmutableSet.emptyUsingIdentity();
}
@Nonnull
public ImmutableSet put(@Nonnull B datum) {
return new ImmutableSet<>(this.data.put(datum, Unit.unit));
}
@Nonnull
public ImmutableSet putAll(@Nonnull Iterable list) {
ImmutableSet set = this;
for (B item : list) {
set = set.put(item);
}
return set;
}
@SafeVarargs
@Nonnull
public final ImmutableSet putArray(@Nonnull B... list) {
ImmutableSet set = this;
for (B b : list) {
set = set.put(b);
}
return set;
}
public boolean contains(@Nonnull T datum) {
return this.data.containsKey(datum);
}
@Nonnull
@SuppressWarnings("unchecked")
public ImmutableSet map(@Nonnull F f) {
return this.foldAbelian((val, acc) -> acc.put(f.apply(val)), ImmutableSet.empty((Hasher) this.data.hasher));
}
@Nonnull
@SuppressWarnings("unchecked")
public ImmutableSet flatMap(@Nonnull F> f) {
return this.foldAbelian((t, acc) -> {
ImmutableSet set = f.apply(t);
if (!set.data.hasher.equals(acc.data.hasher)) {
throw new UnsupportedOperationException("Hasher mismatch in flatMap.");
}
return acc.union(set);
}, ImmutableSet.empty((Hasher) this.data.hasher));
}
@Nonnull
public ImmutableSet filter(@Nonnull F f) {
return this.foldAbelian((val, acc) -> f.apply(val) ? acc.put(val) : acc, ImmutableSet.empty(this.data.hasher));
}
public ImmutableSet remove(@Nonnull T datum) {
return new ImmutableSet<>(this.data.remove(datum));
}
@Nonnull
public A foldAbelian(@Nonnull F2 f, @Nonnull A init) {
return this.data.foldRight((p, acc) -> f.apply(p.left, acc), init);
}
@Nonnull
public ImmutableSet union(@Nonnull ImmutableSet other) {
return new ImmutableSet<>(this.data.merge(other.data));
}
// Does not guarantee ordering of elements in resulting list.
@Nonnull
public ImmutableList toList() {
return this.foldAbelian((v, acc) -> acc.cons(v), ImmutableList.empty());
}
@Nonnull
public Set toSet() {
if (this.data.hasher != HashTable.equalityHasher()) {
throw new UnsupportedOperationException("Cannot call ImmutableSet::toSet on a ImmutableSet without equality hashing.");
}
Set set = new HashSet<>();
this.forEach(set::add);
return set;
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object other) {
return other instanceof ImmutableSet && this.data.length == ((ImmutableSet) other).data.length && this.data.foldLeft((memo, pair) -> memo && ((ImmutableSet) other).data.containsKey(pair.left), true);
}
@Override
@Nonnull
public Iterator iterator() {
final Iterator> mapIterator = this.data.iterator();
return new Iterator() {
@Override
public boolean hasNext() {
return mapIterator.hasNext();
}
@Override
public T next() {
return mapIterator.next().left;
}
};
}
@Nonnull
public HashTable mapToTable(@Nonnull F f) {
HashTable table = HashTable.empty(this.data.hasher);
for (T entry : this) {
table = table.put(entry, f.apply(entry));
}
return table;
}
@Nonnull
@Override
public final Spliterator spliterator() {
return Spliterators.spliterator(this.iterator(), this.length(), Spliterator.IMMUTABLE | Spliterator.NONNULL);
}
@Nonnull
public final Stream stream() {
return StreamSupport.stream(this.spliterator(), false);
}
@Nonnull
public static Collector> collector(@Nonnull Hasher hasher) {
// we use a list for state because java doesn't support our Hasher type
return new Collector, ImmutableSet>() {
@Override
public Supplier> supplier() {
return ArrayList::new;
}
@Override
public BiConsumer, T> accumulator() {
return ArrayList::add;
}
@Override
public BinaryOperator> combiner() {
return (left, right) -> {
left.addAll(right);
return left;
};
}
@Override
public Function, ImmutableSet> finisher() {
return list -> {
ImmutableSet set = ImmutableSet.empty(hasher);
for (T entry : list) {
set = set.put(entry);
}
return set;
};
}
@Override
public Set characteristics() {
Set set = new HashSet<>();
set.add(Characteristics.UNORDERED);
return set;
}
};
}
@Nonnull
public static Collector> collector() {
return ImmutableSet.collectorUsingEquality();
}
@Nonnull
public static Collector> collectorUsingEquality() {
return ImmutableSet.collector(HashTable.equalityHasher());
}
@Nonnull
public static Collector> collectorUsingIdentity() {
return ImmutableSet.collector(HashTable.identityHasher());
}
}