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

com.shapesecurity.functional.data.ImmutableSet Maven / Gradle / Ivy

There is a newer version: 3.1.0
Show newest version
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());
    }
}