javaslang.collection.LinkedHashSet Maven / Gradle / Ivy
/* / \____ _ _ ____ ______ / \ ____ __ _______
* / / \/ \ / \/ \ / /\__\/ // \/ \ // /\__\ JΛVΛSLΛNG
* _/ / /\ \ \/ / /\ \\__\\ \ // /\ \ /\\/ \ /__\ \ Copyright 2014-2016 Javaslang, http://javaslang.io
* /___/\_/ \_/\____/\_/ \_/\__\/__/\__\_/ \_// \__/\_____/ Licensed under the Apache License, Version 2.0
*/
package javaslang.collection;
import javaslang.*;
import javaslang.control.Option;
import java.io.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.*;
import java.util.stream.Collector;
/**
* An immutable {@code HashSet} implementation.
*
* @param Component type
* @author Ruslan Sennov, Patryk Najda, Daniel Dietrich
* @since 2.0.0
*/
public final class LinkedHashSet implements Kind1, T>, Set, Serializable {
private static final long serialVersionUID = 1L;
private static final LinkedHashSet> EMPTY = new LinkedHashSet<>(LinkedHashMap.empty());
private final LinkedHashMap map;
private LinkedHashSet(LinkedHashMap map) {
this.map = map;
}
@SuppressWarnings("unchecked")
public static LinkedHashSet empty() {
return (LinkedHashSet) EMPTY;
}
/**
* Returns a {@link Collector} which may be used in conjunction with
* {@link java.util.stream.Stream#collect(Collector)} to obtain a {@link LinkedHashSet}.
*
* @param Component type of the LinkedHashSet.
* @return A javaslang.collection.LinkedHashSet Collector.
*/
public static Collector, LinkedHashSet> collector() {
final Supplier> supplier = ArrayList::new;
final BiConsumer, T> accumulator = ArrayList::add;
final BinaryOperator> combiner = (left, right) -> {
left.addAll(right);
return left;
};
final Function, LinkedHashSet> finisher = LinkedHashSet::ofAll;
return Collector.of(supplier, accumulator, combiner, finisher);
}
/**
* Narrows a widened {@code LinkedHashSet extends T>} to {@code LinkedHashSet}
* by performing a type safe-cast. This is eligible because immutable/read-only
* collections are covariant.
*
* @param linkedHashSet A {@code LinkedHashSet}.
* @param Component type of the {@code linkedHashSet}.
* @return the given {@code linkedHashSet} instance as narrowed type {@code LinkedHashSet}.
*/
@SuppressWarnings("unchecked")
public static LinkedHashSet narrow(LinkedHashSet extends T> linkedHashSet) {
return (LinkedHashSet) linkedHashSet;
}
/**
* Returns a singleton {@code LinkedHashSet}, i.e. a {@code LinkedHashSet} of one element.
*
* @param element An element.
* @param The component type
* @return A new LinkedHashSet instance containing the given element
*/
public static LinkedHashSet of(T element) {
return LinkedHashSet. empty().add(element);
}
/**
* Creates a LinkedHashSet of the given elements.
*
* LinkedHashSet.of(1, 2, 3, 4)
*
* @param Component type of the LinkedHashSet.
* @param elements Zero or more elements.
* @return A set containing the given elements.
* @throws NullPointerException if {@code elements} is null
*/
@SafeVarargs
public static LinkedHashSet of(T... elements) {
Objects.requireNonNull(elements, "elements is null");
LinkedHashMap map = LinkedHashMap.empty();
for (T element : elements) {
map = map.put(element, element);
}
return map.isEmpty() ? LinkedHashSet.empty() : new LinkedHashSet<>(map);
}
/**
* Returns a LinkedHashSet containing {@code n} values of a given Function {@code f}
* over a range of integer values from 0 to {@code n - 1}.
*
* @param Component type of the LinkedHashSet
* @param n The number of elements in the LinkedHashSet
* @param f The Function computing element values
* @return A LinkedHashSet consisting of elements {@code f(0),f(1), ..., f(n - 1)}
* @throws NullPointerException if {@code f} is null
*/
public static LinkedHashSet tabulate(int n, Function super Integer, ? extends T> f) {
Objects.requireNonNull(f, "f is null");
return Collections.tabulate(n, f, LinkedHashSet.empty(), LinkedHashSet::of);
}
/**
* Returns a LinkedHashSet containing {@code n} values supplied by a given Supplier {@code s}.
*
* @param Component type of the LinkedHashSet
* @param n The number of elements in the LinkedHashSet
* @param s The Supplier computing element values
* @return A LinkedHashSet of size {@code n}, where each element contains the result supplied by {@code s}.
* @throws NullPointerException if {@code s} is null
*/
public static LinkedHashSet fill(int n, Supplier extends T> s) {
Objects.requireNonNull(s, "s is null");
return Collections.fill(n, s, LinkedHashSet.empty(), LinkedHashSet::of);
}
/**
* Creates a LinkedHashSet of the given elements.
*
* @param elements Set elements
* @param The value type
* @return A new LinkedHashSet containing the given entries
*/
@SuppressWarnings("unchecked")
public static LinkedHashSet ofAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (elements instanceof LinkedHashSet) {
return (LinkedHashSet) elements;
} else {
final LinkedHashMap mao = addAll(LinkedHashMap.empty(), elements);
return mao.isEmpty() ? empty() : new LinkedHashSet<>(mao);
}
}
/**
* Creates a LinkedHashSet based on the elements of a boolean array.
*
* @param array a boolean array
* @return A new LinkedHashSet of Boolean values
*/
public static LinkedHashSet ofAll(boolean[] array) {
Objects.requireNonNull(array, "array is null");
return LinkedHashSet.ofAll(Iterator.ofAll(array));
}
/**
* Creates a LinkedHashSet based on the elements of a byte array.
*
* @param array a byte array
* @return A new LinkedHashSet of Byte values
*/
public static LinkedHashSet ofAll(byte[] array) {
Objects.requireNonNull(array, "array is null");
return LinkedHashSet.ofAll(Iterator.ofAll(array));
}
/**
* Creates a LinkedHashSet based on the elements of a char array.
*
* @param array a char array
* @return A new LinkedHashSet of Character values
*/
public static LinkedHashSet ofAll(char[] array) {
Objects.requireNonNull(array, "array is null");
return LinkedHashSet.ofAll(Iterator.ofAll(array));
}
/**
* Creates a LinkedHashSet based on the elements of a double array.
*
* @param array a double array
* @return A new LinkedHashSet of Double values
*/
public static LinkedHashSet ofAll(double[] array) {
Objects.requireNonNull(array, "array is null");
return LinkedHashSet.ofAll(Iterator.ofAll(array));
}
/**
* Creates a LinkedHashSet based on the elements of a float array.
*
* @param array a float array
* @return A new LinkedHashSet of Float values
*/
public static LinkedHashSet ofAll(float[] array) {
Objects.requireNonNull(array, "array is null");
return LinkedHashSet.ofAll(Iterator.ofAll(array));
}
/**
* Creates a LinkedHashSet based on the elements of an int array.
*
* @param array an int array
* @return A new LinkedHashSet of Integer values
*/
public static LinkedHashSet ofAll(int[] array) {
Objects.requireNonNull(array, "array is null");
return LinkedHashSet.ofAll(Iterator.ofAll(array));
}
/**
* Creates a LinkedHashSet based on the elements of a long array.
*
* @param array a long array
* @return A new LinkedHashSet of Long values
*/
public static LinkedHashSet ofAll(long[] array) {
Objects.requireNonNull(array, "array is null");
return LinkedHashSet.ofAll(Iterator.ofAll(array));
}
/**
* Creates a LinkedHashSet based on the elements of a short array.
*
* @param array a short array
* @return A new LinkedHashSet of Short values
*/
public static LinkedHashSet ofAll(short[] array) {
Objects.requireNonNull(array, "array is null");
return LinkedHashSet.ofAll(Iterator.ofAll(array));
}
/**
* Creates a LinkedHashSet of int numbers starting from {@code from}, extending to {@code toExclusive - 1}.
*
* Examples:
*
*
* LinkedHashSet.range(0, 0) // = LinkedHashSet()
* LinkedHashSet.range(2, 0) // = LinkedHashSet()
* LinkedHashSet.range(-2, 2) // = LinkedHashSet(-2, -1, 0, 1)
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @return a range of int values as specified or the empty range if {@code from >= toExclusive}
*/
public static LinkedHashSet range(int from, int toExclusive) {
return LinkedHashSet.ofAll(Iterator.range(from, toExclusive));
}
public static LinkedHashSet range(char from, char toExclusive) {
return LinkedHashSet.ofAll(Iterator.range(from, toExclusive));
}
/**
* Creates a LinkedHashSet of int numbers starting from {@code from}, extending to {@code toExclusive - 1},
* with {@code step}.
*
* Examples:
*
*
* LinkedHashSet.rangeBy(1, 3, 1) // = LinkedHashSet(1, 2)
* LinkedHashSet.rangeBy(1, 4, 2) // = LinkedHashSet(1, 3)
* LinkedHashSet.rangeBy(4, 1, -2) // = LinkedHashSet(4, 2)
* LinkedHashSet.rangeBy(4, 1, 2) // = LinkedHashSet()
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @param step the step
* @return a range of long values as specified or the empty range if
* {@code from >= toInclusive} and {@code step > 0} or
* {@code from <= toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
public static LinkedHashSet rangeBy(int from, int toExclusive, int step) {
return LinkedHashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
public static LinkedHashSet rangeBy(char from, char toExclusive, int step) {
return LinkedHashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
public static LinkedHashSet rangeBy(double from, double toExclusive, double step) {
return LinkedHashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
/**
* Creates a LinkedHashSet of long numbers starting from {@code from}, extending to {@code toExclusive - 1}.
*
* Examples:
*
*
* LinkedHashSet.range(0L, 0L) // = LinkedHashSet()
* LinkedHashSet.range(2L, 0L) // = LinkedHashSet()
* LinkedHashSet.range(-2L, 2L) // = LinkedHashSet(-2L, -1L, 0L, 1L)
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @return a range of long values as specified or the empty range if {@code from >= toExclusive}
*/
public static LinkedHashSet range(long from, long toExclusive) {
return LinkedHashSet.ofAll(Iterator.range(from, toExclusive));
}
/**
* Creates a LinkedHashSet of long numbers starting from {@code from}, extending to {@code toExclusive - 1},
* with {@code step}.
*
* Examples:
*
*
* LinkedHashSet.rangeBy(1L, 3L, 1L) // = LinkedHashSet(1L, 2L)
* LinkedHashSet.rangeBy(1L, 4L, 2L) // = LinkedHashSet(1L, 3L)
* LinkedHashSet.rangeBy(4L, 1L, -2L) // = LinkedHashSet(4L, 2L)
* LinkedHashSet.rangeBy(4L, 1L, 2L) // = LinkedHashSet()
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @param step the step
* @return a range of long values as specified or the empty range if
* {@code from >= toInclusive} and {@code step > 0} or
* {@code from <= toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
public static LinkedHashSet rangeBy(long from, long toExclusive, long step) {
return LinkedHashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
/**
* Creates a LinkedHashSet of int numbers starting from {@code from}, extending to {@code toInclusive}.
*
* Examples:
*
*
* LinkedHashSet.rangeClosed(0, 0) // = LinkedHashSet(0)
* LinkedHashSet.rangeClosed(2, 0) // = LinkedHashSet()
* LinkedHashSet.rangeClosed(-2, 2) // = LinkedHashSet(-2, -1, 0, 1, 2)
*
*
*
* @param from the first number
* @param toInclusive the last number
* @return a range of int values as specified or the empty range if {@code from > toInclusive}
*/
public static LinkedHashSet rangeClosed(int from, int toInclusive) {
return LinkedHashSet.ofAll(Iterator.rangeClosed(from, toInclusive));
}
public static LinkedHashSet rangeClosed(char from, char toInclusive) {
return LinkedHashSet.ofAll(Iterator.rangeClosed(from, toInclusive));
}
/**
* Creates a LinkedHashSet of int numbers starting from {@code from}, extending to {@code toInclusive},
* with {@code step}.
*
* Examples:
*
*
* LinkedHashSet.rangeClosedBy(1, 3, 1) // = LinkedHashSet(1, 2, 3)
* LinkedHashSet.rangeClosedBy(1, 4, 2) // = LinkedHashSet(1, 3)
* LinkedHashSet.rangeClosedBy(4, 1, -2) // = LinkedHashSet(4, 2)
* LinkedHashSet.rangeClosedBy(4, 1, 2) // = LinkedHashSet()
*
*
*
* @param from the first number
* @param toInclusive the last number
* @param step the step
* @return a range of int values as specified or the empty range if
* {@code from > toInclusive} and {@code step > 0} or
* {@code from < toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
public static LinkedHashSet rangeClosedBy(int from, int toInclusive, int step) {
return LinkedHashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
public static LinkedHashSet rangeClosedBy(char from, char toInclusive, int step) {
return LinkedHashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
public static LinkedHashSet rangeClosedBy(double from, double toInclusive, double step) {
return LinkedHashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
/**
* Creates a LinkedHashSet of long numbers starting from {@code from}, extending to {@code toInclusive}.
*
* Examples:
*
*
* LinkedHashSet.rangeClosed(0L, 0L) // = LinkedHashSet(0L)
* LinkedHashSet.rangeClosed(2L, 0L) // = LinkedHashSet()
* LinkedHashSet.rangeClosed(-2L, 2L) // = LinkedHashSet(-2L, -1L, 0L, 1L, 2L)
*
*
*
* @param from the first number
* @param toInclusive the last number
* @return a range of long values as specified or the empty range if {@code from > toInclusive}
*/
public static LinkedHashSet rangeClosed(long from, long toInclusive) {
return LinkedHashSet.ofAll(Iterator.rangeClosed(from, toInclusive));
}
/**
* Creates a LinkedHashSet of long numbers starting from {@code from}, extending to {@code toInclusive},
* with {@code step}.
*
* Examples:
*
*
* LinkedHashSet.rangeClosedBy(1L, 3L, 1L) // = LinkedHashSet(1L, 2L, 3L)
* LinkedHashSet.rangeClosedBy(1L, 4L, 2L) // = LinkedHashSet(1L, 3L)
* LinkedHashSet.rangeClosedBy(4L, 1L, -2L) // = LinkedHashSet(4L, 2L)
* LinkedHashSet.rangeClosedBy(4L, 1L, 2L) // = LinkedHashSet()
*
*
*
* @param from the first number
* @param toInclusive the last number
* @param step the step
* @return a range of int values as specified or the empty range if
* {@code from > toInclusive} and {@code step > 0} or
* {@code from < toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
public static LinkedHashSet rangeClosedBy(long from, long toInclusive, long step) {
return LinkedHashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
@Override
public LinkedHashSet add(T element) {
return new LinkedHashSet<>(map.put(element, element));
}
@Override
public LinkedHashSet addAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
final LinkedHashMap that = addAll(map, elements);
if (that.size() == map.size()) {
return this;
} else {
return new LinkedHashSet<>(that);
}
}
@Override
public boolean contains(T element) {
return map.get(element).isDefined();
}
@Override
public LinkedHashSet diff(Set extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (isEmpty() || elements.isEmpty()) {
return this;
} else {
return removeAll(elements);
}
}
@Override
public LinkedHashSet distinct() {
return this;
}
@Override
public LinkedHashSet distinctBy(Comparator super T> comparator) {
Objects.requireNonNull(comparator, "comparator is null");
return LinkedHashSet.ofAll(iterator().distinctBy(comparator));
}
@Override
public LinkedHashSet distinctBy(Function super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor, "keyExtractor is null");
return LinkedHashSet.ofAll(iterator().distinctBy(keyExtractor));
}
@Override
public LinkedHashSet drop(long n) {
if (n <= 0) {
return this;
} else {
return LinkedHashSet.ofAll(iterator().drop(n));
}
}
@Override
public LinkedHashSet dropRight(long n) {
if (n <= 0) {
return this;
} else {
return LinkedHashSet.ofAll(iterator().dropRight(n));
}
}
@Override
public LinkedHashSet dropUntil(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return dropWhile(predicate.negate());
}
@Override
public LinkedHashSet dropWhile(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
final LinkedHashSet dropped = LinkedHashSet.ofAll(iterator().dropWhile(predicate));
return dropped.length() == length() ? this : dropped;
}
@Override
public LinkedHashSet filter(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
final LinkedHashSet filtered = LinkedHashSet.ofAll(iterator().filter(predicate));
return filtered.length() == length() ? this : filtered;
}
@Override
public LinkedHashSet flatMap(Function super T, ? extends Iterable extends U>> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
if (isEmpty()) {
return empty();
} else {
final LinkedHashMap that = foldLeft(LinkedHashMap.empty(),
(tree, t) -> addAll(tree, mapper.apply(t)));
return new LinkedHashSet<>(that);
}
}
@Override
public U foldRight(U zero, BiFunction super T, ? super U, ? extends U> f) {
Objects.requireNonNull(f, "f is null");
return iterator().foldRight(zero, f);
}
@Override
public Map> groupBy(Function super T, ? extends C> classifier) {
return foldLeft(HashMap.empty(), (map, t) -> {
final C key = classifier.apply(t);
final LinkedHashSet values = map.get(key).map(ts -> ts.add(t)).getOrElse(LinkedHashSet.of(t));
return map.put(key, values);
});
}
@Override
public Iterator> grouped(long size) {
return sliding(size, size);
}
@Override
public boolean hasDefiniteSize() {
return true;
}
@Override
public T head() {
if (map.isEmpty()) {
throw new NoSuchElementException("head of empty set");
}
return iterator().next();
}
@Override
public Option headOption() {
return iterator().headOption();
}
@Override
public LinkedHashSet init() {
if (map.isEmpty()) {
throw new UnsupportedOperationException("tail of empty set");
} else {
return new LinkedHashSet<>(map.init());
}
}
@Override
public Option> initOption() {
return isEmpty() ? Option.none() : Option.some(init());
}
@Override
public LinkedHashSet intersect(Set extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (isEmpty() || elements.isEmpty()) {
return empty();
} else {
return retainAll(elements);
}
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public boolean isTraversableAgain() {
return true;
}
@Override
public Iterator iterator() {
return map.iterator().map(t -> t._1);
}
@Override
public int length() {
return map.size();
}
@Override
public LinkedHashSet map(Function super T, ? extends U> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
if (isEmpty()) {
return empty();
} else {
final LinkedHashMap that = foldLeft(LinkedHashMap.empty(), (tree, t) -> {
final U u = mapper.apply(t);
return tree.put(u, u);
});
return new LinkedHashSet<>(that);
}
}
@Override
public String mkString(CharSequence prefix, CharSequence delimiter, CharSequence suffix) {
return iterator().mkString(prefix, delimiter, suffix);
}
@Override
public Tuple2, LinkedHashSet> partition(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
final Tuple2, Iterator> p = iterator().partition(predicate);
return Tuple.of(LinkedHashSet.ofAll(p._1), LinkedHashSet.ofAll(p._2));
}
@Override
public LinkedHashSet peek(Consumer super T> action) {
Objects.requireNonNull(action, "action is null");
if (!isEmpty()) {
action.accept(iterator().head());
}
return this;
}
@Override
public LinkedHashSet remove(T element) {
final LinkedHashMap newMap = map.remove(element);
return (newMap == map) ? this : new LinkedHashSet<>(newMap);
}
@Override
public LinkedHashSet removeAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
LinkedHashMap that = map;
for (T element : elements) {
that = that.remove(element);
}
return (that == map) ? this : new LinkedHashSet<>(that);
}
@Override
public LinkedHashSet replace(T currentElement, T newElement) {
if (!Objects.equals(currentElement, newElement) && contains(currentElement)) {
final Tuple2 currentPair = Tuple.of(currentElement, currentElement);
final Tuple2 newPair = Tuple.of(newElement, newElement);
final LinkedHashMap newMap = map.replace(currentPair, newPair);
return new LinkedHashSet<>(newMap);
} else {
return this;
}
}
@Override
public LinkedHashSet replaceAll(T currentElement, T newElement) {
return replace(currentElement, newElement);
}
@Override
public LinkedHashSet retainAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
final LinkedHashMap kept = addAll(LinkedHashMap.empty(), elements);
LinkedHashMap that = LinkedHashMap.empty();
for (T element : this) {
if (kept.containsKey(element)) {
that = that.put(element, element);
}
}
return that.isEmpty() ? empty() : that.size() == size() ? this : new LinkedHashSet<>(that);
}
@Override
public LinkedHashSet scan(T zero, BiFunction super T, ? super T, ? extends T> operation) {
return scanLeft(zero, operation);
}
@Override
public LinkedHashSet scanLeft(U zero, BiFunction super U, ? super T, ? extends U> operation) {
Objects.requireNonNull(operation, "operation is null");
return Collections.scanLeft(this, zero, operation, new java.util.ArrayList<>(), (c, u) -> {
c.add(u);
return c;
}, LinkedHashSet::ofAll);
}
@Override
public LinkedHashSet scanRight(U zero, BiFunction super T, ? super U, ? extends U> operation) {
Objects.requireNonNull(operation, "operation is null");
return Collections.scanRight(this, zero, operation, List.empty(), List::prepend, LinkedHashSet::ofAll);
}
@Override
public Iterator> sliding(long size) {
return sliding(size, 1);
}
@Override
public Iterator> sliding(long size, long step) {
return iterator().sliding(size, step).map(LinkedHashSet::ofAll);
}
@Override
public Tuple2, LinkedHashSet> span(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
final Tuple2, Iterator> t = iterator().span(predicate);
return Tuple.of(LinkedHashSet.ofAll(t._1), LinkedHashSet.ofAll(t._2));
}
@Override
public LinkedHashSet tail() {
if (map.isEmpty()) {
throw new UnsupportedOperationException("tail of empty set");
}
return remove(head());
}
@Override
public Option> tailOption() {
return isEmpty() ? Option.none() : Option.some(tail());
}
@Override
public LinkedHashSet take(long n) {
if (map.size() <= n) {
return this;
}
return LinkedHashSet.ofAll(() -> iterator().take(n));
}
@Override
public LinkedHashSet takeRight(long n) {
if (map.size() <= n) {
return this;
}
return LinkedHashSet.ofAll(() -> iterator().takeRight(n));
}
@Override
public LinkedHashSet takeUntil(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return takeWhile(predicate.negate());
}
@Override
public LinkedHashSet takeWhile(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
LinkedHashSet taken = LinkedHashSet.ofAll(iterator().takeWhile(predicate));
return taken.length() == length() ? this : taken;
}
/**
* Transforms this {@code LinkedHashSet}.
*
* @param f A transformation
* @param Type of transformation result
* @return An instance of type {@code U}
* @throws NullPointerException if {@code f} is null
*/
public U transform(Function super LinkedHashSet, ? extends U> f) {
Objects.requireNonNull(f, "f is null");
return f.apply(this);
}
@Override
public java.util.LinkedHashSet toJavaSet() {
return toJavaSet(java.util.LinkedHashSet::new);
}
@SuppressWarnings("unchecked")
@Override
public LinkedHashSet union(Set extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (isEmpty()) {
if (elements instanceof LinkedHashSet) {
return (LinkedHashSet) elements;
} else {
return LinkedHashSet.ofAll(elements);
}
} else if (elements.isEmpty()) {
return this;
} else {
final LinkedHashMap that = addAll(map, elements);
if (that.size() == map.size()) {
return this;
} else {
return new LinkedHashSet<>(that);
}
}
}
@Override
public Tuple2, LinkedHashSet> unzip(
Function super T, Tuple2 extends T1, ? extends T2>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
Tuple2, Iterator> t = iterator().unzip(unzipper);
return Tuple.of(LinkedHashSet.ofAll(t._1), LinkedHashSet.ofAll(t._2));
}
@Override
public Tuple3, LinkedHashSet, LinkedHashSet> unzip3(
Function super T, Tuple3 extends T1, ? extends T2, ? extends T3>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
Tuple3, Iterator, Iterator> t = iterator().unzip3(unzipper);
return Tuple.of(LinkedHashSet.ofAll(t._1), LinkedHashSet.ofAll(t._2), LinkedHashSet.ofAll(t._3));
}
@Override
public LinkedHashSet> zip(Iterable extends U> that) {
Objects.requireNonNull(that, "that is null");
return LinkedHashSet.ofAll(iterator().zip(that));
}
@Override
public LinkedHashSet> zipAll(Iterable extends U> that, T thisElem, U thatElem) {
Objects.requireNonNull(that, "that is null");
return LinkedHashSet.ofAll(iterator().zipAll(that, thisElem, thatElem));
}
@Override
public LinkedHashSet> zipWithIndex() {
return LinkedHashSet.ofAll(iterator().zipWithIndex());
}
// -- Object
@Override
public int hashCode() {
return map.hashCode();
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof LinkedHashSet) {
final LinkedHashSet> that = (LinkedHashSet>) o;
return this.map.equals(that.map);
} else {
return false;
}
}
@Override
public String stringPrefix() {
return "LinkedHashSet";
}
@Override
public String toString() {
return mkString(stringPrefix() + "(", ", ", ")");
}
private static LinkedHashMap addAll(LinkedHashMap initial,
Iterable extends T> additional) {
LinkedHashMap that = initial;
for (T t : additional) {
that = that.put(t, t);
}
return that;
}
// -- Serialization
/**
* {@code writeReplace} method for the serialization proxy pattern.
*
* The presence of this method causes the serialization system to emit a SerializationProxy instance instead of
* an instance of the enclosing class.
*
* @return A SerialiationProxy for this enclosing class.
*/
private Object writeReplace() {
return new SerializationProxy<>(this.map);
}
/**
* {@code readObject} method for the serialization proxy pattern.
*
* Guarantees that the serialization system will never generate a serialized instance of the enclosing class.
*
* @param stream An object serialization stream.
* @throws InvalidObjectException This method will throw with the message "Proxy required".
*/
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("Proxy required");
}
/**
* A serialization proxy which, in this context, is used to deserialize immutable, linked Lists with final
* instance fields.
*
* @param The component type of the underlying list.
*/
// DEV NOTE: The serialization proxy pattern is not compatible with non-final, i.e. extendable,
// classes. Also, it may not be compatible with circular object graphs.
private static final class SerializationProxy implements Serializable {
private static final long serialVersionUID = 1L;
// the instance to be serialized/deserialized
private transient LinkedHashMap map;
/**
* Constructor for the case of serialization, called by {@link LinkedHashSet#writeReplace()}.
*
* The constructor of a SerializationProxy takes an argument that concisely represents the logical state of
* an instance of the enclosing class.
*
* @param map a Cons
*/
SerializationProxy(LinkedHashMap map) {
this.map = map;
}
/**
* Write an object to a serialization stream.
*
* @param s An object serialization stream.
* @throws IOException If an error occurs writing to the stream.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeInt(map.size());
for (Tuple2 e : map) {
s.writeObject(e._1);
}
}
/**
* Read an object from a deserialization stream.
*
* @param s An object deserialization stream.
* @throws ClassNotFoundException If the object's class read from the stream cannot be found.
* @throws InvalidObjectException If the stream contains no list elements.
* @throws IOException If an error occurs reading from the stream.
*/
private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
s.defaultReadObject();
final int size = s.readInt();
if (size < 0) {
throw new InvalidObjectException("No elements");
}
LinkedHashMap temp = LinkedHashMap.empty();
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked")
final T element = (T) s.readObject();
temp = temp.put(element, element);
}
map = temp;
}
/**
* {@code readResolve} method for the serialization proxy pattern.
*
* Returns a logically equivalent instance of the enclosing class. The presence of this method causes the
* serialization system to translate the serialization proxy back into an instance of the enclosing class
* upon deserialization.
*
* @return A deserialized instance of the enclosing class.
*/
private Object readResolve() {
return map.isEmpty() ? LinkedHashSet.empty() : new LinkedHashSet<>(map);
}
}
}