Skip to content

Commit

Permalink
Ensures that Traversable modifications return the same instance if po…
Browse files Browse the repository at this point in the history
…ssible (#1801)

* Fixed Map and Multimap tests

* Unit tests finished. Next step: fixing code...

* Phase 1 completed

* Phase 2 completed

* Phase 3 completed
  • Loading branch information
danieldietrich authored Feb 10, 2017
1 parent 515b6ae commit 5c27580
Show file tree
Hide file tree
Showing 44 changed files with 1,110 additions and 571 deletions.
35 changes: 26 additions & 9 deletions javaslang/src/main/java/javaslang/collection/AbstractMultimap.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,19 +177,20 @@ public M distinct() {
@Override
public M distinctBy(Comparator<? super Tuple2<K, V>> comparator) {
Objects.requireNonNull(comparator, "comparator is null");
return (M) createFromEntries(iterator().distinctBy(comparator));
return (M) (isEmpty() ? this : createFromEntries(iterator().distinctBy(comparator)));
}

@SuppressWarnings("unchecked")
@Override
public <U> Multimap<K, V> distinctBy(Function<? super Tuple2<K, V>, ? extends U> keyExtractor) {
public <U> M distinctBy(Function<? super Tuple2<K, V>, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor, "keyExtractor is null");
return createFromEntries(iterator().distinctBy(keyExtractor));
return (M) (isEmpty() ? this : createFromEntries(iterator().distinctBy(keyExtractor)));
}

@Override
@SuppressWarnings("unchecked")
public M drop(int n) {
if (n <= 0) {
if (n <= 0 || isEmpty()) {
return (M) this;
} else if (n >= length()) {
return (M) this.emptyInstance();
Expand All @@ -201,7 +202,7 @@ public M drop(int n) {
@Override
@SuppressWarnings("unchecked")
public M dropRight(int n) {
if (n <= 0) {
if (n <= 0 || isEmpty()) {
return (M) this;
} else if (n >= length()) {
return (M) this.emptyInstance();
Expand All @@ -220,14 +221,18 @@ public M dropUntil(Predicate<? super Tuple2<K, V>> predicate) {
@Override
public M dropWhile(Predicate<? super Tuple2<K, V>> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return (M) createFromEntries(iterator().dropWhile(predicate));
return (M) (isEmpty() ? this : createFromEntries(iterator().dropWhile(predicate)));
}

@SuppressWarnings("unchecked")
@Override
public M filter(Predicate<? super Tuple2<K, V>> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return (M) createFromEntries(iterator().filter(predicate));
if (isEmpty()) {
return (M) this;
} else {
return (M) createFromEntries(iterator().filter(predicate));
}
}

@Override
Expand Down Expand Up @@ -442,13 +447,25 @@ public M tail() {
@Override
@SuppressWarnings("unchecked")
public M take(int n) {
return (M) (size() <= n ? this : createFromEntries(iterator().take(n)));
if (isEmpty() || n >= length()) {
return (M) this;
} else if (n <= 0) {
return (M) this.emptyInstance();
} else {
return (M) createFromEntries(iterator().take(n));
}
}

@Override
@SuppressWarnings("unchecked")
public M takeRight(int n) {
return (M) (size() <= n ? this : createFromEntries(iterator().takeRight(n)));
if (isEmpty() || n >= length()) {
return (M) this;
} else if (n <= 0) {
return (M) this.emptyInstance();
} else {
return (M) createFromEntries(iterator().takeRight(n));
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,12 @@ public Q enqueue(T... elements) {
@SuppressWarnings("unchecked")
public Q enqueueAll(Iterable<? extends T> elements) {
Objects.requireNonNull(elements, "elements is null");

return List.ofAll(elements).foldLeft((Q) this, AbstractsQueue<T, Q>::enqueue);
// TODO: With #1716 we should generate all these methods directly in Queue & PriorityQueue and check `elements instanceof <type>`
if (isEmpty() && getClass().isAssignableFrom(elements.getClass())) {
return (Q) elements;
} else {
return List.ofAll(elements).foldLeft((Q) this, AbstractsQueue<T, Q>::enqueue);
}
}

/**
Expand Down
19 changes: 15 additions & 4 deletions javaslang/src/main/java/javaslang/collection/Array.java
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,11 @@ public Array<T> append(T element) {
@Override
public Array<T> appendAll(Iterable<? extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (isEmpty() && elements instanceof Array) {
@SuppressWarnings("unchecked")
final Array<T> array = (Array<T>) elements;
return array;
}
final Object[] source = toArray(elements);
if (source.length == 0) {
return this;
Expand Down Expand Up @@ -809,6 +814,11 @@ public Array<T> insertAll(int index, Iterable<? extends T> elements) {
if (index < 0 || index > length()) {
throw new IndexOutOfBoundsException("insert(" + index + ", e) on Array of length " + length());
}
if (isEmpty() && elements instanceof Array) {
@SuppressWarnings("unchecked")
final Array<T> array = (Array<T>) elements;
return array;
}
final Object[] list = toArray(elements);
if (list.length == 0) {
return this;
Expand Down Expand Up @@ -1194,9 +1204,7 @@ public Tuple2<Array<T>, Array<T>> span(Predicate<? super T> predicate) {

@Override
public Array<T> subSequence(int beginIndex) {
if (beginIndex < 0) {
throw new IndexOutOfBoundsException("subSequence(" + beginIndex + ")");
} else if (beginIndex > length()) {
if (beginIndex < 0 || beginIndex > length()) {
throw new IndexOutOfBoundsException("subSequence(" + beginIndex + ")");
} else {
return drop(beginIndex);
Expand All @@ -1206,9 +1214,11 @@ public Array<T> subSequence(int beginIndex) {
@Override
public Array<T> subSequence(int beginIndex, int endIndex) {
if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
throw new IndexOutOfBoundsException("subSequence(" + beginIndex + ", " + endIndex + ") on List of length " + length());
throw new IndexOutOfBoundsException("subSequence(" + beginIndex + ", " + endIndex + ") on Array of length " + length());
} else if (beginIndex == endIndex) {
return empty();
} else if (beginIndex == 0 && endIndex == length()) {
return this;
} else {
final Object[] arr = new Object[endIndex - beginIndex];
System.arraycopy(delegate, beginIndex, arr, 0, arr.length);
Expand Down Expand Up @@ -1287,6 +1297,7 @@ public <U> U transform(Function<? super Array<T>, ? extends U> f) {
return f.apply(this);
}

@SuppressWarnings("deprecation")
@Override
public <U> Array<U> unit(Iterable<? extends U> iterable) {
return ofAll(iterable);
Expand Down
63 changes: 39 additions & 24 deletions javaslang/src/main/java/javaslang/collection/BitSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ default java.util.SortedSet<T> toJavaSet() {
@Override
default BitSet<T> union(Set<? extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
return addAll(elements);
return elements.isEmpty() ? this : addAll(elements);
}

@Override
Expand Down Expand Up @@ -663,18 +663,18 @@ BitSet<T> addElement(int element) {
@Override
public BitSet<T> distinctBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator, "comparator is null");
return createFromAll(iterator().distinctBy(comparator));
return isEmpty() ? this : createFromAll(iterator().distinctBy(comparator));
}

@Override
public <U> BitSet<T> distinctBy(Function<? super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor, "keyExtractor is null");
return createFromAll(iterator().distinctBy(keyExtractor));
return isEmpty() ? this : createFromAll(iterator().distinctBy(keyExtractor));
}

@Override
public BitSet<T> drop(int n) {
if (n <= 0) {
if (n <= 0 || isEmpty()) {
return this;
} else if (n >= length()) {
return createEmpty();
Expand All @@ -685,7 +685,7 @@ public BitSet<T> drop(int n) {

@Override
public BitSet<T> dropRight(int n) {
if (n <= 0) {
if (n <= 0 || isEmpty()) {
return this;
} else if (n >= length()) {
return createEmpty();
Expand All @@ -704,7 +704,9 @@ public BitSet<T> dropWhile(Predicate<? super T> predicate) {
@Override
public BitSet<T> intersect(Set<? extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (isEmpty() || elements.isEmpty()) {
if (isEmpty()) {
return this;
} else if (elements.isEmpty()) {
return createEmpty();
} else {
final int size = size();
Expand Down Expand Up @@ -772,14 +774,19 @@ public BitSet<T> takeWhile(Predicate<? super T> predicate) {
@SuppressWarnings("unchecked")
public BitSet<T> addAll(Iterable<? extends T> elements) {
final Stream<Integer> source = Stream.ofAll(elements).map(toInt);
final long[] copy = copyExpand(1 + (source.max().getOrElse(0) >> ADDRESS_BITS_PER_WORD));
source.forEach(element -> {
if (element < 0) {
throw new IllegalArgumentException("bitset element must be >= 0");
}
setElement(copy, element);
});
return fromBitMaskNoCopy(copy);
if (source.isEmpty()) {
return this;
} else {
final long[] copy = copyExpand(1 + (source.max().getOrElse(0) >> ADDRESS_BITS_PER_WORD));
source.forEach(element -> {
if (element < 0) {
throw new IllegalArgumentException("bitset element must be >= 0");
}
setElement(copy, element);
});
final BitSet<T> bitSet = fromBitMaskNoCopy(copy);
return (bitSet.length() == length()) ? this : bitSet;
}
}

@Override
Expand Down Expand Up @@ -810,21 +817,21 @@ public Iterator<T> iterator() {

@Override
public BitSet<T> take(int n) {
if (n <= 0) {
return createEmpty();
} else if (n >= length()) {
if (isEmpty() || n >= length()) {
return this;
} else if (n <= 0) {
return createEmpty();
} else {
return createFromAll(iterator().take(n));
}
}

@Override
public BitSet<T> takeRight(int n) {
if (n <= 0) {
return createEmpty();
} else if (n >= length()) {
if (isEmpty() || n >= length()) {
return this;
} else if (n <= 0) {
return createEmpty();
} else {
return createFromAll(iterator().takeRight(n));
}
Expand All @@ -844,10 +851,18 @@ public BitSet<T> remove(T t) {

@Override
public BitSet<T> removeAll(Iterable<? extends T> elements) {
final Stream<Integer> source = Stream.ofAll(elements).map(toInt);
final long[] copy = copyExpand(getWordsNum());
source.forEach(element -> unsetElement(copy, element));
return fromBitMaskNoCopy(shrink(copy));
if (isEmpty()) {
return this;
} else {
final Stream<Integer> source = Stream.ofAll(elements).map(toInt);
if (source.isEmpty()) {
return this;
} else {
final long[] copy = copyExpand(getWordsNum());
source.forEach(element -> unsetElement(copy, element));
return fromBitMaskNoCopy(shrink(copy));
}
}
}

@Override
Expand Down
1 change: 1 addition & 0 deletions javaslang/src/main/java/javaslang/collection/CharSeq.java
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,7 @@ public <U> U transform(Function<? super CharSeq, ? extends U> f) {
return f.apply(this);
}

@SuppressWarnings("deprecation")
@Override
public <U> IndexedSeq<U> unit(Iterable<? extends U> iterable) {
return Vector.ofAll(iterable);
Expand Down
30 changes: 23 additions & 7 deletions javaslang/src/main/java/javaslang/collection/Collections.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,26 +136,42 @@ static <K, V, K2, U extends Map<K2, V>> U mapKeys(Map<K, V> source, U zero, Func
@SuppressWarnings("unchecked")
static <C extends Traversable<T>, T> C removeAll(C source, Iterable<? extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
final Set<T> removed = HashSet.ofAll(elements);
return (C) source.filter(e -> !removed.contains(e));
if (source.isEmpty()) {
return source;
} else {
final Set<T> removed = HashSet.ofAll(elements);
return removed.isEmpty() ? source : (C) source.filter(e -> !removed.contains(e));
}
}

@SuppressWarnings("unchecked")
static <C extends Traversable<T>, T> C removeAll(C source, Predicate<? super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return (C) source.filter(predicate.negate());
if (source.isEmpty()) {
return source;
} else {
return (C) source.filter(predicate.negate());
}
}

@SuppressWarnings("unchecked")
static <C extends Traversable<T>, T> C removeAll(C source, T element) {
Objects.requireNonNull(element, "element is null");
return removeAll(source, List.of(element));
if (source.isEmpty()) {
return source;
} else {
return (C) source.filter(e -> !Objects.equals(e, element));
}
}

@SuppressWarnings("unchecked")
static <C extends Traversable<T>, T> C retainAll(C source, Iterable<? extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
final Set<T> removed = HashSet.ofAll(elements);
return (C) source.filter(removed::contains);
if (source.isEmpty()) {
return source;
} else {
final Set<T> retained = HashSet.ofAll(elements);
return (C) source.filter(retained::contains);
}
}

static <T> Iterator<T> reverseIterator(Iterable<T> iterable) {
Expand Down
12 changes: 10 additions & 2 deletions javaslang/src/main/java/javaslang/collection/HashSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,11 @@ public HashSet<T> add(T element) {
@Override
public HashSet<T> addAll(Iterable<? extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (isEmpty() && elements instanceof HashSet) {
@SuppressWarnings("unchecked")
final HashSet<T> set = (HashSet<T>) elements;
return set;
}
final HashArrayMappedTrie<T, T> that = addAll(tree, elements);
if (that.size() == tree.size()) {
return this;
Expand Down Expand Up @@ -772,10 +777,13 @@ public Option<HashSet<T>> tailOption() {

@Override
public HashSet<T> take(int n) {
if (tree.size() <= n) {
if (n >= size() || isEmpty()) {
return this;
} else if (n <= 0) {
return empty();
} else {
return ofAll(() -> iterator().take(n));
}
return HashSet.ofAll(() -> iterator().take(n));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ default boolean startsWith(Iterable<? extends T> that, int offset) {
@Override
IndexedSeq<T> takeWhile(Predicate<? super T> predicate);

@SuppressWarnings("deprecation")
@Override
<U> IndexedSeq<U> unit(Iterable<? extends U> iterable);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ default int segmentLength(Predicate<? super T> predicate, int from) {
@Override
LinearSeq<T> takeWhile(Predicate<? super T> predicate);

@SuppressWarnings("deprecation")
@Override
<U> LinearSeq<U> unit(Iterable<? extends U> iterable);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,11 @@ public LinkedHashSet<T> add(T element) {
@Override
public LinkedHashSet<T> addAll(Iterable<? extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (isEmpty() && elements instanceof LinkedHashSet) {
@SuppressWarnings("unchecked")
final LinkedHashSet<T> set = (LinkedHashSet<T>) elements;
return set;
}
final LinkedHashMap<T, Object> that = addAll(map, elements);
if (that.size() == map.size()) {
return this;
Expand Down
Loading

0 comments on commit 5c27580

Please sign in to comment.