From b63602eeec6d4f70853b5e8691425cd6b78876c1 Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Mon, 25 Apr 2016 07:51:35 +0300 Subject: [PATCH 01/11] BitSet interface #1271 --- .../java/javaslang/collection/BitSet.java | 743 ++++++++++++++++++ .../java/javaslang/collection/BitSetTest.java | 16 + 2 files changed, 759 insertions(+) create mode 100644 javaslang/src/main/java/javaslang/collection/BitSet.java create mode 100644 javaslang/src/test/java/javaslang/collection/BitSetTest.java diff --git a/javaslang/src/main/java/javaslang/collection/BitSet.java b/javaslang/src/main/java/javaslang/collection/BitSet.java new file mode 100644 index 0000000000..b43fcf8716 --- /dev/null +++ b/javaslang/src/main/java/javaslang/collection/BitSet.java @@ -0,0 +1,743 @@ +/* / \____ _ _ ____ ______ / \ ____ __ _______ + * / / \/ \ / \/ \ / /\__\/ // \/ \ // /\__\ JΛVΛSLΛNG + * _/ / /\ \ \/ / /\ \\__\\ \ // /\ \ /\\/ \ /__\ \ Copyright 2014-2016 Javaslang, http://javaslang.io + * /___/\_/ \_/\____/\_/ \_/\__\/__/\__\_/ \_// \__/\_____/ Licensed under the Apache License, Version 2.0 + */ +package javaslang.collection; + +import javaslang.Tuple2; +import javaslang.Tuple3; +import javaslang.control.Option; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Objects; +import java.util.function.*; +import java.util.stream.Collector; + +/** + * An immutable {@code BitSet} implementation. + * + * @author Ruslan Sennov + * @since 2.1.0 + */ +public interface BitSet extends SortedSet { + + /** + * Returns a {@link java.util.stream.Collector} which may be used in conjunction with + * {@link java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a {@link javaslang.collection.BitSet}. + *

+ * The natural comparator is used to compare TreeSet elements. + * + * @return A javaslang.collection.List Collector. + */ + static Collector, BitSet> collector() { + final BinaryOperator> combiner = (left, right) -> { + left.addAll(right); + return left; + }; + return Collector.of(ArrayList::new, ArrayList::add, combiner, BitSet::ofAll); + } + + static BitSet empty() { + return BitSetModule.EMPTY; + } + + static BitSet of(Integer value) { + if(value < Long.SIZE) { + return new BitSetModule.BitSet1(value); + } + if(value < 2 * Long.SIZE) { + return new BitSetModule.BitSet2(0L, value); + } + return empty().add(value); + } + + static BitSet of(Integer... values) { + if(values.length == 0) { + return empty(); + } + if(values.length == 1) { + return of(values[0]); + } + return empty().addAll(Iterator.of(values)); + } + + /** + * Returns a BitSet containing {@code n} values of a given Function {@code f} + * over a range of integer values from 0 to {@code n - 1}. + * + * @param n The number of elements in the BitSet + * @param f The Function computing element values + * @return A BitSet consisting of elements {@code f(0),f(1), ..., f(n - 1)} + * @throws NullPointerException if {@code f} are null + */ + static BitSet tabulate(int n, Function f) { + Objects.requireNonNull(f, "f is null"); + return Collections.tabulate(n, f, BitSet.empty(), BitSet::of); + } + + /** + * Returns a BitSet containing {@code n} values supplied by a given Supplier {@code s}. + * + * @param n The number of elements in the BitSet + * @param s The Supplier computing element values + * @return A BitSet of size {@code n}, where each element contains the result supplied by {@code s}. + * @throws NullPointerException if {@code s} are null + */ + static BitSet fill(int n, Supplier s) { + Objects.requireNonNull(s, "s is null"); + return Collections.fill(n, s, BitSet.empty(), BitSet::of); + } + + static BitSet ofAll(Iterable values) { + Objects.requireNonNull(values, "values is null"); + return Iterator.ofAll(values).foldLeft(BitSet.empty(), BitSet::add); + } + + /** + * Creates a BitSet based on the elements of an int array. + * + * @param array an int array + * @return A new BitSet of Integer values + */ + static BitSet ofAll(int[] array) { + Objects.requireNonNull(array, "array is null"); + return BitSet.ofAll(Iterator.ofAll(array)); + } + + /** + * Creates a BitSet of int numbers starting from {@code from}, extending to {@code toExclusive - 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} + */ + static BitSet range(int from, int toExclusive) { + return BitSet.ofAll(Iterator.range(from, toExclusive)); + } + + /** + * Creates a BitSet of int numbers starting from {@code from}, extending to {@code toExclusive - 1}, + * with {@code step}. + * + * @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 + */ + static BitSet rangeBy(int from, int toExclusive, int step) { + return BitSet.ofAll(Iterator.rangeBy(from, toExclusive, step)); + } + + /** + * Creates a BitSet of int numbers starting from {@code from}, extending to {@code toInclusive}. + * + * @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} + */ + static BitSet rangeClosed(int from, int toInclusive) { + return BitSet.ofAll(Iterator.rangeClosed(from, toInclusive)); + } + + /** + * Creates a BitSet of int numbers starting from {@code from}, extending to {@code toInclusive}, + * with {@code step}. + * + * @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 + */ + static BitSet rangeClosedBy(int from, int toInclusive, int step) { + return BitSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); + } + + @Override + BitSet add(Integer element); + + @Override + default BitSet addAll(Iterable elements) { + BitSet result = this; + for (Integer element : elements) { + result = result.add(element); + } + return result; + } + + @Override + BitSet diff(Set elements); + + @Override + BitSet distinct(); + + @Override + BitSet distinctBy(Comparator comparator); + + @Override + BitSet distinctBy(Function keyExtractor); + + @Override + BitSet drop(long n); + + @Override + BitSet dropRight(long n); + + @Override + BitSet dropUntil(Predicate predicate); + + @Override + BitSet dropWhile(Predicate predicate); + + @Override + BitSet filter(Predicate predicate); + + @Override + SortedSet flatMap(Function> mapper); + + @Override + U foldRight(U zero, BiFunction f); + + @Override + Map groupBy(Function classifier); + + @Override + Iterator grouped(long size); + + @Override + default boolean hasDefiniteSize() { + return true; + } + + @Override + Integer head(); + + @Override + BitSet init(); + + @Override + Option initOption(); + + @Override + default boolean isTraversableAgain() { + return true; + } + + @Override + Iterator iterator(); + + @Override + int length(); + + @Override + BitSet intersect(Set elements); + + @Override + SortedSet map(Function mapper); + + @Override + Tuple2 partition(Predicate predicate); + + @Override + BitSet peek(Consumer action); + + @Override + default String stringPrefix() { + return "BitSet"; + } + + @Override + default Comparator comparator() { + return Integer::compare; + } + + @Override + SortedSet flatMap(Comparator comparator, Function> mapper); + + @Override + SortedSet map(Comparator comparator, Function mapper); + + @Override + BitSet remove(Integer element); + + @Override + default BitSet removeAll(Iterable elements) { + BitSet result = this; + for (Integer element : elements) { + result = result.remove(element); + } + return result; + } + + @Override + BitSet replace(Integer currentElement, Integer newElement); + + @Override + BitSet replaceAll(Integer currentElement, Integer newElement); + + @Override + BitSet retainAll(Iterable elements); + + @Override + BitSet scan(Integer zero, BiFunction operation); + + @Override + Set scanLeft(U zero, BiFunction operation); + + @Override + Set scanRight(U zero, BiFunction operation); + + @Override + Iterator sliding(long size); + + @Override + Iterator sliding(long size, long step); + + @Override + Tuple2 span(Predicate predicate); + + @Override + BitSet tail(); + + @Override + Option tailOption(); + + @Override + BitSet take(long n); + + @Override + BitSet takeRight(long n); + + @Override + BitSet takeUntil(Predicate predicate); + + @Override + BitSet takeWhile(Predicate predicate); + + @Override + java.util.SortedSet toJavaSet(); + + @Override + BitSet union(Set elements); + + @Override + Tuple2, ? extends SortedSet> unzip(Function> unzipper); + + @Override + Tuple3, ? extends Set, ? extends Set> unzip3(Function> unzipper); + + @Override + SortedSet> zip(Iterable that); + + @Override + SortedSet> zipAll(Iterable that, Integer thisElem, U thatElem); + + @Override + SortedSet> zipWithIndex(); +} + +interface BitSetModule { + + BitSet EMPTY = new BitSet1(0); + + abstract class AbstractBitSet implements BitSet { + + abstract BitSet updateWord(int index, long word); + + abstract int nWords(); + + abstract long word(int index); + + BitSet fromBitMaskNoCopy(long[] elements) { + final int len = elements.length; + if (len == 0) { + return EMPTY; + } + if (len == 1) { + return new BitSet1(elements[0]); + } + if (len == 2) { + return new BitSet2(elements[0], elements[1]); + } + return new BitSetN(elements); + } + + long[] updateArray(long[] elements, int index, long word) { + int len = elements.length; + while (len > 0 && (elements[len - 1] == 0L || word == 0L && index == len - 1)) { + len--; + } + int newlen = len; + if (index >= newlen && word != 0L) { + newlen = index + 1; + } + long[] newelems = new long[newlen]; + System.arraycopy(elements, 0, newelems, 0, len); + if (index < newlen) { + newelems[index] = word; + } else { + if (word != 0L) { + throw new IndexOutOfBoundsException(); + } + } + return newelems; + } + + @Override + public BitSet add(Integer element) { + if (element < 0) { + throw new IllegalArgumentException("bitset element must be >= 0"); + } + if (contains(element)) { + return this; + } else { + final int index = element >> 6; + return updateWord(index, word(index) | (1L << element)); + } + } + + @Override + public SortedSet flatMap(Comparator comparator, Function> mapper) { + return null; + } + + @Override + public SortedSet map(Comparator comparator, Function mapper) { + return null; + } + + @Override + public boolean contains(Integer element) { + if (element < 0) { + throw new IllegalArgumentException("bitset element must be >= 0"); + } + final int index = element >> 6; + return (word(index) & (1L << element)) != 0; + } + + @Override + public BitSet diff(Set elements) { + return null; + } + + @Override + public BitSet distinct() { + return null; + } + + @Override + public BitSet distinctBy(Comparator comparator) { + return null; + } + + @Override + public BitSet distinctBy(Function keyExtractor) { + return null; + } + + @Override + public BitSet drop(long n) { + return null; + } + + @Override + public BitSet dropRight(long n) { + return null; + } + + @Override + public BitSet dropUntil(Predicate predicate) { + return null; + } + + @Override + public BitSet dropWhile(Predicate predicate) { + return null; + } + + @Override + public BitSet filter(Predicate predicate) { + return null; + } + + @Override + public SortedSet flatMap(Function> mapper) { + return null; + } + + @Override + public U foldRight(U zero, BiFunction f) { + return null; + } + + @Override + public Map groupBy(Function classifier) { + return null; + } + + @Override + public Iterator grouped(long size) { + return null; + } + + @Override + public Integer head() { + return null; + } + + @Override + public BitSet init() { + return null; + } + + @Override + public Option initOption() { + return null; + } + + @Override + public Iterator iterator() { + return null; + } + + @Override + public int length() { + return 0; + } + + @Override + public BitSet intersect(Set elements) { + return null; + } + + @Override + public SortedSet map(Function mapper) { + return null; + } + + @Override + public Tuple2 partition(Predicate predicate) { + return null; + } + + @Override + public BitSet peek(Consumer action) { + return null; + } + + @Override + public BitSet remove(Integer element) { + if (element < 0) { + throw new IllegalArgumentException("bitset element must be >= 0"); + } + if (contains(element)) { + final int idx = element >> 6; + return updateWord(idx, word(idx) & ~(1L << element)); + } else { + return this; + } + } + + @Override + public BitSet replace(Integer currentElement, Integer newElement) { + return null; + } + + @Override + public BitSet replaceAll(Integer currentElement, Integer newElement) { + return null; + } + + @Override + public BitSet retainAll(Iterable elements) { + return null; + } + + @Override + public BitSet scan(Integer zero, BiFunction operation) { + return null; + } + + @Override + public Set scanLeft(U zero, BiFunction operation) { + return null; + } + + @Override + public Set scanRight(U zero, BiFunction operation) { + return null; + } + + @Override + public Iterator sliding(long size) { + return null; + } + + @Override + public Iterator sliding(long size, long step) { + return null; + } + + @Override + public Tuple2 span(Predicate predicate) { + return null; + } + + @Override + public BitSet tail() { + return null; + } + + @Override + public Option tailOption() { + return null; + } + + @Override + public BitSet take(long n) { + return null; + } + + @Override + public BitSet takeRight(long n) { + return null; + } + + @Override + public BitSet takeUntil(Predicate predicate) { + return null; + } + + @Override + public BitSet takeWhile(Predicate predicate) { + return null; + } + + @Override + public java.util.SortedSet toJavaSet() { + return null; + } + + @Override + public BitSet union(Set elements) { + return null; + } + + @Override + public Tuple2, ? extends SortedSet> unzip(Function> unzipper) { + return null; + } + + @Override + public Tuple3, ? extends Set, ? extends Set> unzip3(Function> unzipper) { + return null; + } + + @Override + public SortedSet> zip(Iterable that) { + return null; + } + + @Override + public SortedSet> zipAll(Iterable that, Integer thisElem, U thatElem) { + return null; + } + + @Override + public SortedSet> zipWithIndex() { + return null; + } + } + + class BitSet1 extends AbstractBitSet { + + private final long elements; + + BitSet1(long elements) { + this.elements = elements; + } + + @Override + BitSet updateWord(int index, long word) { + if (index == 0) { + return new BitSet1(word); + } + if (index == 1) { + return new BitSet2(elements, word); + } + return fromBitMaskNoCopy(updateArray(new long[] { elements }, index, word)); + } + + @Override + int nWords() { + return 1; + } + + @Override + long word(int index) { + return index < 1 ? elements : 0L; + } + } + + class BitSet2 extends AbstractBitSet { + + private final long elements1, elements2; + + BitSet2(long elements1, long elements2) { + this.elements1 = elements1; + this.elements2 = elements2; + } + + @Override + BitSet updateWord(int index, long word) { + if (index == 0) { + return new BitSet2(word, elements1); + } + if (index == 1) { + return new BitSet2(elements1, word); + } + return fromBitMaskNoCopy(updateArray(new long[] { elements1, elements2 }, index, word)); + } + + @Override + int nWords() { + return 2; + } + + @Override + long word(int index) { + return index == 0 ? elements1 : index == 1 ? elements2 : 0L; + } + } + + class BitSetN extends AbstractBitSet { + + private final long[] elements; + + BitSetN(long[] elements) { + this.elements = elements; + } + + @Override + BitSet updateWord(int index, long word) { + return fromBitMaskNoCopy(updateArray(elements, index, word)); + } + + @Override + int nWords() { + return elements.length; + } + + @Override + long word(int index) { + return index < elements.length ? elements[index] : 0L; + } + } +} \ No newline at end of file diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java new file mode 100644 index 0000000000..ce36f58914 --- /dev/null +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -0,0 +1,16 @@ +package javaslang.collection; + +import org.junit.Test; + +public class BitSetTest { + + @Test + public void test1() { + BitSet bs = BitSet.empty(); + bs = bs.add(2); + bs = bs.add(4); + bs = bs.remove(2); + assert !bs.contains(2); + assert bs.contains(4); + } +} From a03ea19d074fff50970b3e9f8110f847392862d4 Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Fri, 29 Apr 2016 08:33:23 +0300 Subject: [PATCH 02/11] BitSet: first implementation --- .../java/javaslang/collection/BitSet.java | 773 ++++++++++-------- .../java/javaslang/collection/BitSetTest.java | 16 +- 2 files changed, 439 insertions(+), 350 deletions(-) diff --git a/javaslang/src/main/java/javaslang/collection/BitSet.java b/javaslang/src/main/java/javaslang/collection/BitSet.java index 2ac4c875df..d8ae4a31dc 100644 --- a/javaslang/src/main/java/javaslang/collection/BitSet.java +++ b/javaslang/src/main/java/javaslang/collection/BitSet.java @@ -5,6 +5,8 @@ */ package javaslang.collection; +import javaslang.Function1; +import javaslang.Tuple; import javaslang.Tuple2; import javaslang.Tuple3; import javaslang.control.Option; @@ -15,84 +17,128 @@ import java.util.function.*; import java.util.stream.Collector; +import static javaslang.collection.Comparators.naturalComparator; + /** * An immutable {@code BitSet} implementation. * * @author Ruslan Sennov * @since 2.1.0 */ -public interface BitSet extends SortedSet { +public abstract class BitSet implements SortedSet { + + private static final long serialVersionUID = 1L; + + public static class Builder { + + final static Builder DEFAULT = new Builder<>(i -> i, i -> i); + + final Function fromInt; + final Function toInt; + + Builder(Function fromInt, Function toInt) { + this.fromInt = fromInt; + this.toInt = toInt; + } + + public Collector, BitSet> collector() { + final BinaryOperator> combiner = (left, right) -> { + left.addAll(right); + return left; + }; + return Collector.of(ArrayList::new, ArrayList::add, combiner, this::ofAll); + } + + public BitSet empty() { + return new BitSetModule.BitSet1<>(this, 0L); + } + + public BitSet ofAll(Iterable values) { + Objects.requireNonNull(values, "values is null"); + return empty().addAll(values); + } + } + + public static Builder withRelations(Function fromInt, Function toInt) { + return new Builder<>(fromInt, toInt); + } + + public static > Builder withEnum(Class clz) { + final Function f1 = Function1.of(i -> { + for (T t : clz.getEnumConstants()) { + if (t.ordinal() == i) { + return t; + } + } + throw new RuntimeException("bad BitSet"); + }).memoized(); + final Function f2 = Enum::ordinal; + return new Builder<>(f1, f2); + } /** * Returns a {@link java.util.stream.Collector} which may be used in conjunction with * {@link java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a {@link javaslang.collection.BitSet}. - *

- * The natural comparator is used to compare TreeSet elements. * * @return A javaslang.collection.List Collector. */ - static Collector, BitSet> collector() { - final BinaryOperator> combiner = (left, right) -> { - left.addAll(right); - return left; - }; - return Collector.of(ArrayList::new, ArrayList::add, combiner, BitSet::ofAll); + public static Collector, BitSet> collector() { + return Builder.DEFAULT.collector(); } - static BitSet empty() { - return BitSetModule.EMPTY; + public static BitSet empty() { + return Builder.DEFAULT.empty(); } - static BitSet of(Integer value) { - if(value < Long.SIZE) { - return new BitSetModule.BitSet1(value); - } - if(value < 2 * Long.SIZE) { - return new BitSetModule.BitSet2(0L, value); + static BitSet of(Integer value) { + if(value < BitSetModule.BITS_PER_WORD) { + return new BitSetModule.BitSet1<>(Builder.DEFAULT, value); + } else if(value < 2 * BitSetModule.BITS_PER_WORD) { + return new BitSetModule.BitSet2<>(Builder.DEFAULT, 0L, value); + } else { + return empty().add(value); } - return empty().add(value); } - static BitSet of(Integer... values) { + static BitSet of(Integer... values) { if(values.length == 0) { return empty(); - } - if(values.length == 1) { + } else if(values.length == 1) { return of(values[0]); + } else { + return empty().addAll(Array.wrap(values)); } - return empty().addAll(Iterator.of(values)); } /** * Returns a BitSet containing {@code n} values of a given Function {@code f} * over a range of integer values from 0 to {@code n - 1}. * - * @param n The number of elements in the BitSet - * @param f The Function computing element values + * @param n The number of elements in the BitSet + * @param f The Function computing element values * @return A BitSet consisting of elements {@code f(0),f(1), ..., f(n - 1)} * @throws NullPointerException if {@code f} are null */ - static BitSet tabulate(int n, Function f) { + static BitSet tabulate(int n, Function f) { Objects.requireNonNull(f, "f is null"); - return Collections.tabulate(n, f, BitSet.empty(), BitSet::of); + return empty().addAll(Collections.tabulate(n, f)); } /** * Returns a BitSet containing {@code n} values supplied by a given Supplier {@code s}. * - * @param n The number of elements in the BitSet - * @param s The Supplier computing element values + * @param n The number of elements in the BitSet + * @param s The Supplier computing element values * @return A BitSet of size {@code n}, where each element contains the result supplied by {@code s}. * @throws NullPointerException if {@code s} are null */ - static BitSet fill(int n, Supplier s) { + static BitSet fill(int n, Supplier s) { Objects.requireNonNull(s, "s is null"); - return Collections.fill(n, s, BitSet.empty(), BitSet::of); + return empty().addAll(Collections.fill(n, s)); } - static BitSet ofAll(Iterable values) { - Objects.requireNonNull(values, "values is null"); - return Iterator.ofAll(values).foldLeft(BitSet.empty(), BitSet::add); + static BitSet ofAll(Iterable values) { + return Builder.DEFAULT.ofAll(values); } /** @@ -101,7 +147,7 @@ static BitSet ofAll(Iterable values) { * @param array an int array * @return A new BitSet of Integer values */ - static BitSet ofAll(int[] array) { + static BitSet ofAll(int[] array) { Objects.requireNonNull(array, "array is null"); return BitSet.ofAll(Iterator.ofAll(array)); } @@ -113,7 +159,7 @@ static BitSet ofAll(int[] array) { * @param toExclusive the last number + 1 * @return a range of int values as specified or the empty range if {@code from >= toExclusive} */ - static BitSet range(int from, int toExclusive) { + static BitSet range(int from, int toExclusive) { return BitSet.ofAll(Iterator.range(from, toExclusive)); } @@ -129,7 +175,7 @@ static BitSet range(int from, int toExclusive) { * {@code from <= toInclusive} and {@code step < 0} * @throws IllegalArgumentException if {@code step} is zero */ - static BitSet rangeBy(int from, int toExclusive, int step) { + static BitSet rangeBy(int from, int toExclusive, int step) { return BitSet.ofAll(Iterator.rangeBy(from, toExclusive, step)); } @@ -140,7 +186,7 @@ static BitSet rangeBy(int from, int toExclusive, int step) { * @param toInclusive the last number * @return a range of int values as specified or the empty range if {@code from > toInclusive} */ - static BitSet rangeClosed(int from, int toInclusive) { + static BitSet rangeClosed(int from, int toInclusive) { return BitSet.ofAll(Iterator.rangeClosed(from, toInclusive)); } @@ -156,355 +202,425 @@ static BitSet rangeClosed(int from, int toInclusive) { * {@code from < toInclusive} and {@code step < 0} * @throws IllegalArgumentException if {@code step} is zero */ - static BitSet rangeClosedBy(int from, int toInclusive, int step) { + static BitSet rangeClosedBy(int from, int toInclusive, int step) { return BitSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } - @Override - BitSet add(Integer element); + final Builder builder; - @Override - default BitSet addAll(Iterable elements) { - BitSet result = this; - for (Integer element : elements) { - result = result.add(element); - } - return result; + BitSet(Builder builder) { + this.builder = builder; } @Override - BitSet diff(Set elements); - - @Override - BitSet distinct(); + public abstract BitSet add(T element); @Override - BitSet distinctBy(Comparator comparator); + public abstract BitSet addAll(Iterable elements); @Override - BitSet distinctBy(Function keyExtractor); + public abstract BitSet diff(Set elements); @Override - BitSet drop(long n); + public BitSet distinct() { + return this; + } @Override - BitSet dropRight(long n); + public BitSet distinctBy(Comparator comparator) { + Objects.requireNonNull(comparator, "comparator is null"); + return builder.ofAll(iterator().distinctBy(comparator)); + } @Override - BitSet dropUntil(Predicate predicate); + public BitSet distinctBy(Function keyExtractor) { + Objects.requireNonNull(keyExtractor, "keyExtractor is null"); + return builder.ofAll(iterator().distinctBy(keyExtractor)); + } @Override - BitSet dropWhile(Predicate predicate); + public BitSet drop(long n) { + if (n <= 0) { + return this; + } else if (n >= length()) { + return builder.empty(); + } else { + return builder.ofAll(iterator().drop(n)); + } + } @Override - BitSet filter(Predicate predicate); + public BitSet dropRight(long n) { + if (n <= 0) { + return this; + } else if (n >= length()) { + return builder.empty(); + } else { + return builder.ofAll(iterator().dropRight(n)); + } + } @Override - SortedSet flatMap(Function> mapper); + public BitSet dropUntil(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + return dropWhile(predicate.negate()); + } @Override - U foldRight(U zero, BiFunction f); + public BitSet dropWhile(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + final BitSet bitSet = builder.ofAll(iterator().dropWhile(predicate)); + return (bitSet.length() == length()) ? this : bitSet; + } @Override - Map groupBy(Function classifier); + public BitSet filter(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + final BitSet bitSet = builder.ofAll(iterator().filter(predicate)); + return (bitSet.length() == length()) ? this : bitSet; + } @Override - Iterator grouped(long size); + public SortedSet flatMap(Comparator comparator, Function> mapper) { + Objects.requireNonNull(mapper, "mapper is null"); + return TreeSet.ofAll(comparator, iterator().flatMap(mapper)); + } @Override - default boolean hasDefiniteSize() { - return true; + public SortedSet flatMap(Function> mapper) { + Objects.requireNonNull(mapper, "mapper is null"); + return TreeSet.ofAll(naturalComparator(), iterator().flatMap(mapper)); } @Override - Integer head(); + public U foldRight(U zero, BiFunction f) { + Objects.requireNonNull(f, "f is null"); + return iterator().foldRight(zero, f); + } @Override - BitSet init(); + public Map> groupBy(Function classifier) { + Objects.requireNonNull(classifier, "classifier is null"); + return iterator().groupBy(classifier).map((key, iterator) -> Tuple.of(key, builder.ofAll(iterator))); + } @Override - Option initOption(); + public Iterator> grouped(long size) { + return sliding(size, size); + } @Override - default boolean isTraversableAgain() { + public boolean hasDefiniteSize() { return true; } @Override - Iterator iterator(); + public abstract BitSet init(); + + @Override + public Option> initOption() { + return isEmpty() ? Option.none() : Option.some(init()); + } @Override - int length(); + public boolean isTraversableAgain() { + return true; + } @Override - BitSet intersect(Set elements); + public abstract Iterator iterator(); @Override - SortedSet map(Function mapper); + public BitSet intersect(Set elements) { + Objects.requireNonNull(elements, "elements is null"); + if (isEmpty() || elements.isEmpty()) { + return builder.empty(); + } else { + int size = size(); + if (size <= elements.size()) { + return retainAll(elements); + } else { + BitSet results = builder.ofAll(elements).retainAll(this); + return (size == results.size()) ? this : results; + } + } + } @Override - Tuple2 partition(Predicate predicate); + public Tuple2, BitSet> partition(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + return iterator().partition(predicate).map(builder::ofAll, builder::ofAll); + } @Override - BitSet peek(Consumer action); + public BitSet peek(Consumer action) { + Objects.requireNonNull(action, "action is null"); + if (!isEmpty()) { + action.accept(head()); + } + return this; + } @Override - default String stringPrefix() { + public String stringPrefix() { return "BitSet"; } @Override - default Comparator comparator() { - return Integer::compare; + public Comparator comparator() { + return (t1, t2) -> Integer.compare(builder.toInt.apply(t1), builder.toInt.apply(t2)); } @Override - SortedSet flatMap(Comparator comparator, Function> mapper); + public SortedSet map(Comparator comparator, Function mapper) { + Objects.requireNonNull(mapper, "mapper is null"); + return TreeSet.ofAll(comparator, iterator().map(mapper)); + } @Override - SortedSet map(Comparator comparator, Function mapper); + public SortedSet map(Function mapper) { + return map(naturalComparator(), mapper); + } @Override - BitSet remove(Integer element); + public abstract BitSet remove(T element); @Override - default BitSet removeAll(Iterable elements) { - BitSet result = this; - for (Integer element : elements) { - result = result.remove(element); - } - return result; - } + public abstract BitSet removeAll(Iterable elements); @Override - BitSet replace(Integer currentElement, Integer newElement); + public abstract BitSet replace(T currentElement, T newElement); @Override - BitSet replaceAll(Integer currentElement, Integer newElement); + public BitSet replaceAll(T currentElement, T newElement) { + // a set has only one occurrence + return replace(currentElement, newElement); + } @Override - BitSet retainAll(Iterable elements); + public abstract BitSet retainAll(Iterable elements); @Override - BitSet scan(Integer zero, BiFunction operation); + public BitSet scan(T zero, BiFunction operation) { + Objects.requireNonNull(operation, "operation is null"); + return Collections.scanLeft(this, zero, operation, new java.util.ArrayList(), (arr, t) -> { + arr.add(t); + return arr; + }, builder::ofAll); + } @Override - Set scanLeft(U zero, BiFunction operation); + public Set scanLeft(U zero, BiFunction operation) { + return Collections.scanLeft(this, zero, operation, new java.util.ArrayList<>(), (c, u) -> { + c.add(u); + return c; + }, HashSet::ofAll); + } @Override - Set scanRight(U zero, BiFunction operation); + public Set scanRight(U zero, BiFunction operation) { + return Collections.scanRight(this, zero, operation, new java.util.ArrayList<>(), (c, u) -> { + c.add(u); + return c; + }, HashSet::ofAll); + } @Override - Iterator sliding(long size); + public Iterator> sliding(long size) { + return sliding(size, 1); + } @Override - Iterator sliding(long size, long step); + public Iterator> sliding(long size, long step) { + return iterator().sliding(size, step).map(builder::ofAll); + } @Override - Tuple2 span(Predicate predicate); + public Tuple2, BitSet> span(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + return iterator().span(predicate).map(builder::ofAll, builder::ofAll); + } @Override - BitSet tail(); + public abstract BitSet tail(); @Override - Option tailOption(); + public Option> tailOption() { + return isEmpty() ? Option.none() : Option.some(tail()); + } @Override - BitSet take(long n); + public BitSet take(long n) { + if (n <= 0) { + return builder.empty(); + } else if (n >= length()) { + return this; + } else { + return builder.ofAll(iterator().take(n)); + } + } @Override - BitSet takeRight(long n); + public abstract BitSet takeRight(long n); @Override - BitSet takeUntil(Predicate predicate); + public abstract BitSet takeUntil(Predicate predicate); @Override - BitSet takeWhile(Predicate predicate); + public abstract BitSet takeWhile(Predicate predicate); @Override - java.util.SortedSet toJavaSet(); + public java.util.SortedSet toJavaSet() { + return toJavaSet(() -> new java.util.TreeSet<>(comparator())); + } @Override - BitSet union(Set elements); + public abstract BitSet union(Set elements); + // TODO @Override - Tuple2, ? extends SortedSet> unzip(Function> unzipper); + public Tuple2, TreeSet> unzip( + Function> unzipper) { + Objects.requireNonNull(unzipper, "unzipper is null"); + return iterator().unzip(unzipper).map(i1 -> TreeSet.ofAll(naturalComparator(), i1), + i2 -> TreeSet.ofAll(naturalComparator(), i2)); + } + // TODO @Override - Tuple3, ? extends SortedSet, ? extends SortedSet> unzip3(Function> unzipper); + public Tuple3, TreeSet, TreeSet> unzip3( + Function> unzipper) { + Objects.requireNonNull(unzipper, "unzipper is null"); + return iterator().unzip3(unzipper).map( + i1 -> TreeSet.ofAll(naturalComparator(), i1), + i2 -> TreeSet.ofAll(naturalComparator(), i2), + i3 -> TreeSet.ofAll(naturalComparator(), i3)); + } @Override - SortedSet> zip(Iterable that); + public abstract SortedSet> zip(Iterable that); @Override - SortedSet> zipAll(Iterable that, Integer thisElem, U thatElem); + public abstract SortedSet> zipAll(Iterable that, T thisElem, U thatElem); @Override - SortedSet> zipWithIndex(); + public abstract SortedSet> zipWithIndex(); } interface BitSetModule { - BitSet EMPTY = new BitSet1(0); + int ADDRESS_BITS_PER_WORD = 6; + int BITS_PER_WORD = 64; - abstract class AbstractBitSet implements BitSet { + abstract class AbstractBitSet extends BitSet { + + private static final long serialVersionUID = 1L; + + AbstractBitSet(Builder builder) { + super(builder); + } - abstract BitSet updateWord(int index, long word); + abstract int getWordsNum(); - abstract int nWords(); + abstract long[] copyExpand(int wordsNum); - abstract long word(int index); + abstract long getWord(int index); - BitSet fromBitMaskNoCopy(long[] elements) { + BitSet fromBitMaskNoCopy(long[] elements) { final int len = elements.length; if (len == 0) { - return EMPTY; + return builder.empty(); } if (len == 1) { - return new BitSet1(elements[0]); + return new BitSet1<>(builder, elements[0]); } if (len == 2) { - return new BitSet2(elements[0], elements[1]); + return new BitSet2<>(builder, elements[0], elements[1]); } - return new BitSetN(elements); + return new BitSetN<>(builder, elements); } - long[] updateArray(long[] elements, int index, long word) { + private void setElement(long[] words, int element) { + final int index = element >> ADDRESS_BITS_PER_WORD; + words[index] |= (1L << element); + } + + private void unsetElement(long[] words, int element) { + final int index = element >> ADDRESS_BITS_PER_WORD; + words[index] &= ~(1L << element); + } + + long[] shrink(long[] elements) { int len = elements.length; - while (len > 0 && (elements[len - 1] == 0L || word == 0L && index == len - 1)) { - len--; - } int newlen = len; - if (index >= newlen && word != 0L) { - newlen = index + 1; + while (newlen > 0 && elements[newlen - 1] == 0) { + newlen--; } long[] newelems = new long[newlen]; System.arraycopy(elements, 0, newelems, 0, len); - if (index < newlen) { - newelems[index] = word; - } else { - if (word != 0L) { - throw new IndexOutOfBoundsException(); - } - } return newelems; } @Override - public BitSet add(Integer element) { - if (element < 0) { - throw new IllegalArgumentException("bitset element must be >= 0"); - } - if (contains(element)) { + public BitSet add(T t) { + if (contains(t)) { return this; } else { - final int index = element >> 6; - return updateWord(index, word(index) | (1L << element)); + final int element = builder.toInt.apply(t); + if (element < 0) { + throw new IllegalArgumentException("bitset element must be >= 0"); + } + final long[] copy = copyExpand(element >> ADDRESS_BITS_PER_WORD); + setElement(copy, element); + return fromBitMaskNoCopy(copy); } } @Override - public SortedSet flatMap(Comparator comparator, Function> mapper) { - return null; - } - - @Override - public SortedSet map(Comparator comparator, Function mapper) { - return null; + @SuppressWarnings("unchecked") + public BitSet addAll(Iterable elements) { + final Stream source = Stream.ofAll(elements).map(builder.toInt); + final long[] copy = copyExpand(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); } @Override - public boolean contains(Integer element) { + public boolean contains(T t) { + final int element = builder.toInt.apply(t); if (element < 0) { throw new IllegalArgumentException("bitset element must be >= 0"); } - final int index = element >> 6; - return (word(index) & (1L << element)) != 0; - } - - @Override - public BitSet diff(Set elements) { - return null; + final int index = element >> ADDRESS_BITS_PER_WORD; + return (getWord(index) & (1L << element)) != 0; } @Override - public BitSet distinct() { + public BitSet diff(Set elements) { return null; } @Override - public BitSet distinctBy(Comparator comparator) { + public T head() { return null; } @Override - public BitSet distinctBy(Function keyExtractor) { + public BitSet init() { return null; } @Override - public BitSet drop(long n) { - return null; - } - - @Override - public BitSet dropRight(long n) { - return null; - } - - @Override - public BitSet dropUntil(Predicate predicate) { - return null; - } - - @Override - public BitSet dropWhile(Predicate predicate) { - return null; - } - - @Override - public BitSet filter(Predicate predicate) { - return null; - } - - @Override - public SortedSet flatMap(Function> mapper) { - return null; - } - - @Override - public U foldRight(U zero, BiFunction f) { - return null; - } - - @Override - public Map groupBy(Function classifier) { - return null; - } - - @Override - public Iterator grouped(long size) { - return null; - } - - @Override - public Integer head() { - return null; - } - - @Override - public BitSet init() { - return null; - } - - @Override - public Option initOption() { - return null; - } - - @Override - public Iterator iterator() { - return null; + public Iterator iterator() { + return Stream.range(0, getWordsNum() << ADDRESS_BITS_PER_WORD) + .filter(i -> (getWord(i >> ADDRESS_BITS_PER_WORD) & (1L << i)) != 0) + .map(builder.fromInt) + .iterator(); } @Override @@ -513,231 +629,190 @@ public int length() { } @Override - public BitSet intersect(Set elements) { - return null; - } - - @Override - public SortedSet map(Function mapper) { - return null; - } - - @Override - public Tuple2 partition(Predicate predicate) { - return null; - } - - @Override - public BitSet peek(Consumer action) { - return null; - } - - @Override - public BitSet remove(Integer element) { - if (element < 0) { - throw new IllegalArgumentException("bitset element must be >= 0"); - } - if (contains(element)) { - final int idx = element >> 6; - return updateWord(idx, word(idx) & ~(1L << element)); + public BitSet remove(T t) { + if (contains(t)) { + final int element = builder.toInt.apply(t); + final long[] copy = copyExpand(getWordsNum()); + unsetElement(copy, element); + return fromBitMaskNoCopy(shrink(copy)); } else { return this; } } @Override - public BitSet replace(Integer currentElement, Integer newElement) { - return null; - } - - @Override - public BitSet replaceAll(Integer currentElement, Integer newElement) { - return null; - } - - @Override - public BitSet retainAll(Iterable elements) { - return null; - } - - @Override - public BitSet scan(Integer zero, BiFunction operation) { - return null; - } - - @Override - public Set scanLeft(U zero, BiFunction operation) { - return null; - } - - @Override - public Set scanRight(U zero, BiFunction operation) { - return null; - } - - @Override - public Iterator sliding(long size) { - return null; - } - - @Override - public Iterator sliding(long size, long step) { - return null; - } - - @Override - public Tuple2 span(Predicate predicate) { - return null; + @SuppressWarnings("unchecked") + public BitSet removeAll(Iterable elements) { + final Stream source = Stream.ofAll(elements).map(builder.toInt); + final long[] copy = copyExpand(getWordsNum()); + source.forEach(element -> { + unsetElement(copy, element); + }); + return fromBitMaskNoCopy(shrink(copy)); } @Override - public BitSet tail() { + public BitSet replace(T currentElement, T newElement) { return null; } @Override - public Option tailOption() { + public BitSet retainAll(Iterable elements) { return null; } @Override - public BitSet take(long n) { + public BitSet tail() { return null; } @Override - public BitSet takeRight(long n) { + public BitSet takeRight(long n) { return null; } @Override - public BitSet takeUntil(Predicate predicate) { + public BitSet takeUntil(Predicate predicate) { return null; } @Override - public BitSet takeWhile(Predicate predicate) { + public BitSet takeWhile(Predicate predicate) { return null; } @Override - public java.util.SortedSet toJavaSet() { + public BitSet union(Set elements) { return null; } @Override - public BitSet union(Set elements) { + public SortedSet> zip(Iterable that) { return null; } @Override - public Tuple2, ? extends SortedSet> unzip(Function> unzipper) { + public SortedSet> zipAll(Iterable that, T thisElem, U thatElem) { return null; } @Override - public Tuple3, ? extends SortedSet, ? extends SortedSet> unzip3(Function> unzipper) { - return null; - } - - @Override - public SortedSet> zip(Iterable that) { - return null; - } - - @Override - public SortedSet> zipAll(Iterable that, Integer thisElem, U thatElem) { - return null; - } - - @Override - public SortedSet> zipWithIndex() { + public SortedSet> zipWithIndex() { return null; } } - class BitSet1 extends AbstractBitSet { + class BitSet1 extends AbstractBitSet { + + private static final long serialVersionUID = 1L; private final long elements; - BitSet1(long elements) { + BitSet1(Builder builder, long elements) { + super(builder); this.elements = elements; } @Override - BitSet updateWord(int index, long word) { - if (index == 0) { - return new BitSet1(word); - } - if (index == 1) { - return new BitSet2(elements, word); - } - return fromBitMaskNoCopy(updateArray(new long[] { elements }, index, word)); + int getWordsNum() { + return 1; } @Override - int nWords() { - return 1; + long[] copyExpand(int wordsNum) { + if(wordsNum < 1) { + wordsNum = 1; + } + long[] arr = new long[wordsNum]; + arr[0] = elements; + return arr; } @Override - long word(int index) { - return index < 1 ? elements : 0L; + long getWord(int index) { + if (index == 0) { + return elements; + } else { + return 0L; + } } } - class BitSet2 extends AbstractBitSet { + class BitSet2 extends AbstractBitSet { + + private static final long serialVersionUID = 1L; private final long elements1, elements2; - BitSet2(long elements1, long elements2) { + BitSet2(Builder builder, long elements1, long elements2) { + super(builder); this.elements1 = elements1; this.elements2 = elements2; } @Override - BitSet updateWord(int index, long word) { - if (index == 0) { - return new BitSet2(word, elements1); - } - if (index == 1) { - return new BitSet2(elements1, word); - } - return fromBitMaskNoCopy(updateArray(new long[] { elements1, elements2 }, index, word)); + int getWordsNum() { + return 2; } @Override - int nWords() { - return 2; + long[] copyExpand(int wordsNum) { + if(wordsNum < 2) { + wordsNum = 2; + } + long[] arr = new long[wordsNum]; + arr[0] = elements1; + arr[1] = elements2; + return arr; } @Override - long word(int index) { - return index == 0 ? elements1 : index == 1 ? elements2 : 0L; + long getWord(int index) { + if (index == 0) { + return elements1; + } else { + if (index == 1) { + return elements2; + } else { + return 0L; + } + } } } - class BitSetN extends AbstractBitSet { + class BitSetN extends AbstractBitSet { + + private static final long serialVersionUID = 1L; private final long[] elements; - BitSetN(long[] elements) { + BitSetN(Builder builder, long[] elements) { + super(builder); this.elements = elements; } @Override - BitSet updateWord(int index, long word) { - return fromBitMaskNoCopy(updateArray(elements, index, word)); + int getWordsNum() { + return elements.length; } @Override - int nWords() { - return elements.length; + long[] copyExpand(int wordsNum) { + if(wordsNum < elements.length) { + wordsNum = elements.length; + } + long[] arr = new long[wordsNum]; + System.arraycopy(elements, 0, arr, 0, elements.length); + return arr; } @Override - long word(int index) { - return index < elements.length ? elements[index] : 0L; + long getWord(int index) { + if (index < elements.length) { + return elements[index]; + } else { + return 0L; + } } } } \ No newline at end of file diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java index ce36f58914..eaefa6342e 100644 --- a/javaslang/src/test/java/javaslang/collection/BitSetTest.java +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -4,13 +4,27 @@ public class BitSetTest { + private enum E { + V1, V2, V3 + } + @Test public void test1() { - BitSet bs = BitSet.empty(); + BitSet bs = BitSet.empty(); bs = bs.add(2); bs = bs.add(4); bs = bs.remove(2); assert !bs.contains(2); assert bs.contains(4); } + + @Test + public void test2() { + BitSet bs = BitSet.withEnum(E.class).empty(); + bs = bs.add(E.V2); + bs = bs.add(E.V3); + bs = bs.remove(E.V2); + assert !bs.contains(E.V2); + assert bs.contains(E.V3); + } } From 100ef3968effea0500f1c582e1f86658e887616a Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Sat, 30 Apr 2016 08:16:17 +0300 Subject: [PATCH 03/11] BitSet: more methods --- .../java/javaslang/collection/BitSet.java | 248 ++++++++++-------- .../java/javaslang/collection/BitSetTest.java | 34 ++- 2 files changed, 174 insertions(+), 108 deletions(-) diff --git a/javaslang/src/main/java/javaslang/collection/BitSet.java b/javaslang/src/main/java/javaslang/collection/BitSet.java index d8ae4a31dc..26c0e2593c 100644 --- a/javaslang/src/main/java/javaslang/collection/BitSet.java +++ b/javaslang/src/main/java/javaslang/collection/BitSet.java @@ -13,6 +13,7 @@ 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; @@ -53,10 +54,43 @@ public BitSet empty() { return new BitSetModule.BitSet1<>(this, 0L); } + public BitSet of(T t) { + final int value = toInt.apply(t); + if(value < BitSetModule.BITS_PER_WORD) { + return new BitSetModule.BitSet1<>(this, value); + } else if(value < 2 * BitSetModule.BITS_PER_WORD) { + return new BitSetModule.BitSet2<>(this, 0L, value); + } else { + return empty().add(t); + } + } + + @SuppressWarnings("varargs") + @SafeVarargs + public final BitSet of(T... values) { + if(values.length == 0) { + return empty(); + } else if(values.length == 1) { + return of(values[0]); + } else { + return empty().addAll(Array.wrap(values)); + } + } + public BitSet ofAll(Iterable values) { Objects.requireNonNull(values, "values is null"); return empty().addAll(values); } + + public BitSet tabulate(int n, Function f) { + Objects.requireNonNull(f, "f is null"); + return empty().addAll(Collections.tabulate(n, f)); + } + + public BitSet fill(int n, Supplier s) { + Objects.requireNonNull(s, "s is null"); + return empty().addAll(Collections.fill(n, s)); + } } public static Builder withRelations(Function fromInt, Function toInt) { @@ -64,16 +98,9 @@ public static Builder withRelations(Function fromInt, Functio } public static > Builder withEnum(Class clz) { - final Function f1 = Function1.of(i -> { - for (T t : clz.getEnumConstants()) { - if (t.ordinal() == i) { - return t; - } - } - throw new RuntimeException("bad BitSet"); - }).memoized(); - final Function f2 = Enum::ordinal; - return new Builder<>(f1, f2); + final Function fromInt = i -> clz.getEnumConstants()[i]; + final Function toInt = Enum::ordinal; + return new Builder<>(fromInt, toInt); } /** @@ -91,23 +118,11 @@ public static BitSet empty() { } static BitSet of(Integer value) { - if(value < BitSetModule.BITS_PER_WORD) { - return new BitSetModule.BitSet1<>(Builder.DEFAULT, value); - } else if(value < 2 * BitSetModule.BITS_PER_WORD) { - return new BitSetModule.BitSet2<>(Builder.DEFAULT, 0L, value); - } else { - return empty().add(value); - } + return Builder.DEFAULT.of(value); } static BitSet of(Integer... values) { - if(values.length == 0) { - return empty(); - } else if(values.length == 1) { - return of(values[0]); - } else { - return empty().addAll(Array.wrap(values)); - } + return Builder.DEFAULT.of(values); } /** @@ -120,8 +135,7 @@ static BitSet of(Integer... values) { * @throws NullPointerException if {@code f} are null */ static BitSet tabulate(int n, Function f) { - Objects.requireNonNull(f, "f is null"); - return empty().addAll(Collections.tabulate(n, f)); + return Builder.DEFAULT.tabulate(n, f); } /** @@ -133,8 +147,7 @@ static BitSet tabulate(int n, Function f) { * @throws NullPointerException if {@code s} are null */ static BitSet fill(int n, Supplier s) { - Objects.requireNonNull(s, "s is null"); - return empty().addAll(Collections.fill(n, s)); + return Builder.DEFAULT.fill(n, s); } static BitSet ofAll(Iterable values) { @@ -219,7 +232,9 @@ static BitSet rangeClosedBy(int from, int toInclusive, int step) { public abstract BitSet addAll(Iterable elements); @Override - public abstract BitSet diff(Set elements); + public BitSet diff(Set elements) { + return removeAll(elements); + } @Override public BitSet distinct() { @@ -389,7 +404,13 @@ public SortedSet map(Function mapper) { public abstract BitSet removeAll(Iterable elements); @Override - public abstract BitSet replace(T currentElement, T newElement); + public BitSet replace(T currentElement, T newElement) { + if (contains(currentElement)) { + return remove(currentElement).add(newElement); + } else { + return this; + } + } @Override public BitSet replaceAll(T currentElement, T newElement) { @@ -398,7 +419,9 @@ public BitSet replaceAll(T currentElement, T newElement) { } @Override - public abstract BitSet retainAll(Iterable elements); + public BitSet retainAll(Iterable elements) { + return Collections.retainAll(this, elements); + } @Override public BitSet scan(T zero, BiFunction operation) { @@ -442,7 +465,9 @@ public Tuple2, BitSet> span(Predicate predicate) { } @Override - public abstract BitSet tail(); + public BitSet tail() { + return remove(head()); + } @Override public Option> tailOption() { @@ -461,13 +486,29 @@ public BitSet take(long n) { } @Override - public abstract BitSet takeRight(long n); + public BitSet takeRight(long n) { + if (n <= 0) { + return builder.empty(); + } else if (n >= length()) { + return this; + } else { + return builder.ofAll(iterator().takeRight(n)); + } + } @Override - public abstract BitSet takeUntil(Predicate predicate); + public BitSet takeUntil(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + final BitSet result = takeWhile(predicate.negate()); + return (result.length() == length()) ? this : result; + } @Override - public abstract BitSet takeWhile(Predicate predicate); + public BitSet takeWhile(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + final BitSet result = builder.ofAll(iterator().takeWhile(predicate)); + return (result.length() == length()) ? this : result; + } @Override public java.util.SortedSet toJavaSet() { @@ -475,7 +516,10 @@ public java.util.SortedSet toJavaSet() { } @Override - public abstract BitSet union(Set elements); + public BitSet union(Set elements) { + Objects.requireNonNull(elements, "elements is null"); + return addAll(elements); + } // TODO @Override @@ -497,14 +541,29 @@ public Tuple3, TreeSet, TreeSet> unzip3( i3 -> TreeSet.ofAll(naturalComparator(), i3)); } + // TODO @Override - public abstract SortedSet> zip(Iterable that); + public TreeSet> zip(Iterable that) { + Objects.requireNonNull(that, "that is null"); + final Comparator> tuple2Comparator = Tuple2.comparator(comparator(), naturalComparator()); + return TreeSet.ofAll(tuple2Comparator, iterator().zip(that)); + } + // TODO @Override - public abstract SortedSet> zipAll(Iterable that, T thisElem, U thatElem); + public TreeSet> zipAll(Iterable that, T thisElem, U thatElem) { + Objects.requireNonNull(that, "that is null"); + final Comparator> tuple2Comparator = Tuple2.comparator(comparator(), naturalComparator()); + return TreeSet.ofAll(tuple2Comparator, iterator().zipAll(that, thisElem, thatElem)); + } + // TODO @Override - public abstract SortedSet> zipWithIndex(); + public TreeSet> zipWithIndex() { + final Comparator component1Comparator = comparator(); + final Comparator> tuple2Comparator = (t1, t2) -> component1Comparator.compare(t1._1, t2._1); + return TreeSet.ofAll(tuple2Comparator, iterator().zipWithIndex()); + } } interface BitSetModule { @@ -551,13 +610,12 @@ private void unsetElement(long[] words, int element) { } long[] shrink(long[] elements) { - int len = elements.length; - int newlen = len; + int newlen = elements.length; while (newlen > 0 && elements[newlen - 1] == 0) { newlen--; } long[] newelems = new long[newlen]; - System.arraycopy(elements, 0, newelems, 0, len); + System.arraycopy(elements, 0, newelems, 0, newlen); return newelems; } @@ -570,7 +628,7 @@ public BitSet add(T t) { if (element < 0) { throw new IllegalArgumentException("bitset element must be >= 0"); } - final long[] copy = copyExpand(element >> ADDRESS_BITS_PER_WORD); + final long[] copy = copyExpand(1 + (element >> ADDRESS_BITS_PER_WORD)); setElement(copy, element); return fromBitMaskNoCopy(copy); } @@ -580,7 +638,7 @@ public BitSet add(T t) { @SuppressWarnings("unchecked") public BitSet addAll(Iterable elements) { final Stream source = Stream.ofAll(elements).map(builder.toInt); - final long[] copy = copyExpand(source.max().getOrElse(0) >> ADDRESS_BITS_PER_WORD); + 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"); @@ -600,19 +658,11 @@ public boolean contains(T t) { return (getWord(index) & (1L << element)) != 0; } - @Override - public BitSet diff(Set elements) { - return null; - } - - @Override - public T head() { - return null; - } - @Override public BitSet init() { - return null; + final long last = getWord(getWordsNum() - 1); + final int element = BITS_PER_WORD * (getWordsNum() - 1) + BITS_PER_WORD - Long.numberOfLeadingZeros(last) - 1; + return remove(builder.fromInt.apply(element)); } @Override @@ -625,7 +675,11 @@ public Iterator iterator() { @Override public int length() { - return 0; + int len = 0; + for (int i = 0; i < getWordsNum(); i++) { + len += Long.bitCount(getWord(i)); + } + return len; } @Override @@ -650,56 +704,6 @@ public BitSet removeAll(Iterable elements) { }); return fromBitMaskNoCopy(shrink(copy)); } - - @Override - public BitSet replace(T currentElement, T newElement) { - return null; - } - - @Override - public BitSet retainAll(Iterable elements) { - return null; - } - - @Override - public BitSet tail() { - return null; - } - - @Override - public BitSet takeRight(long n) { - return null; - } - - @Override - public BitSet takeUntil(Predicate predicate) { - return null; - } - - @Override - public BitSet takeWhile(Predicate predicate) { - return null; - } - - @Override - public BitSet union(Set elements) { - return null; - } - - @Override - public SortedSet> zip(Iterable that) { - return null; - } - - @Override - public SortedSet> zipAll(Iterable that, T thisElem, U thatElem) { - return null; - } - - @Override - public SortedSet> zipWithIndex() { - return null; - } } class BitSet1 extends AbstractBitSet { @@ -736,6 +740,14 @@ long getWord(int index) { return 0L; } } + + @Override + public T head() { + if (elements != 0) { + return builder.fromInt.apply(Long.numberOfTrailingZeros(elements)); + } + throw new NoSuchElementException("head of empty BitSet"); + } } class BitSet2 extends AbstractBitSet { @@ -778,6 +790,16 @@ long getWord(int index) { } } } + + @Override + public T head() { + if (elements1 != 0) { + return builder.fromInt.apply(Long.numberOfTrailingZeros(elements1)); + } else if (elements2 != 0) { + return builder.fromInt.apply(BITS_PER_WORD + Long.numberOfTrailingZeros(elements2)); + } + throw new NoSuchElementException("head of empty BitSet"); + } } class BitSetN extends AbstractBitSet { @@ -814,5 +836,17 @@ long getWord(int index) { return 0L; } } + + @Override + public T head() { + int offset = 0; + for (int i = 0; i < getWordsNum(); i++) { + if(elements[i] != 0) { + return builder.fromInt.apply(offset + Long.numberOfTrailingZeros(elements[i])); + } + offset += BITS_PER_WORD; + } + throw new NoSuchElementException("head of empty BitSet"); + } } -} \ No newline at end of file +} diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java index eaefa6342e..ace31a8c15 100644 --- a/javaslang/src/test/java/javaslang/collection/BitSetTest.java +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -11,20 +11,52 @@ private enum E { @Test public void test1() { BitSet bs = BitSet.empty(); + bs = bs.add(2); + assert bs.head() == 2; + bs = bs.add(4); + assert bs.head() == 2; + + bs = bs.add(70); + assert bs.head() == 2; + + bs = bs.add(300); + assert bs.head() == 2; + bs = bs.remove(2); + assert bs.head() == 4; assert !bs.contains(2); - assert bs.contains(4); + + bs = bs.remove(4); + assert bs.head() == 70; + assert !bs.contains(4); + + bs = bs.remove(70); + assert bs.head() == 300; + assert !bs.contains(70); + + assert bs.contains(300); } @Test public void test2() { BitSet bs = BitSet.withEnum(E.class).empty(); bs = bs.add(E.V2); + assert bs.head() == E.V2; bs = bs.add(E.V3); + assert bs.head() == E.V2; bs = bs.remove(E.V2); + assert bs.head() == E.V3; assert !bs.contains(E.V2); assert bs.contains(E.V3); } + + @Test + public void test3() { + BitSet bs = BitSet.empty(); + assert bs.add(1).add(2).init().toList().equals(List.of(1)); + assert bs.add(1).add(70).init().toList().equals(List.of(1)); + assert bs.add(1).add(700).init().toList().equals(List.of(1)); + } } From 0ac3b6aac819ef550c595df6e1756040e06a44ce Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Thu, 5 May 2016 08:04:31 +0300 Subject: [PATCH 04/11] BitSet: 432 tests done; 99 failed --- .../java/javaslang/collection/BitSet.java | 73 ++++++- .../java/javaslang/collection/BitSetTest.java | 200 +++++++++++++++++- 2 files changed, 264 insertions(+), 9 deletions(-) diff --git a/javaslang/src/main/java/javaslang/collection/BitSet.java b/javaslang/src/main/java/javaslang/collection/BitSet.java index 26c0e2593c..bde698b803 100644 --- a/javaslang/src/main/java/javaslang/collection/BitSet.java +++ b/javaslang/src/main/java/javaslang/collection/BitSet.java @@ -11,6 +11,7 @@ import javaslang.Tuple3; import javaslang.control.Option; +import java.io.Serializable; import java.util.ArrayList; import java.util.Comparator; import java.util.NoSuchElementException; @@ -30,14 +31,16 @@ public abstract class BitSet implements SortedSet { private static final long serialVersionUID = 1L; - public static class Builder { + public static class Builder implements Serializable { + + private static final long serialVersionUID = 1L; final static Builder DEFAULT = new Builder<>(i -> i, i -> i); final Function fromInt; final Function toInt; - Builder(Function fromInt, Function toInt) { + Builder(Function1 fromInt, Function1 toInt) { this.fromInt = fromInt; this.toInt = toInt; } @@ -57,9 +60,9 @@ public BitSet empty() { public BitSet of(T t) { final int value = toInt.apply(t); if(value < BitSetModule.BITS_PER_WORD) { - return new BitSetModule.BitSet1<>(this, value); + return new BitSetModule.BitSet1<>(this, 1L << value); } else if(value < 2 * BitSetModule.BITS_PER_WORD) { - return new BitSetModule.BitSet2<>(this, 0L, value); + return new BitSetModule.BitSet2<>(this, 0L, 1L << value); } else { return empty().add(t); } @@ -93,13 +96,13 @@ public BitSet fill(int n, Supplier s) { } } - public static Builder withRelations(Function fromInt, Function toInt) { + public static Builder withRelations(Function1 fromInt, Function1 toInt) { return new Builder<>(fromInt, toInt); } public static > Builder withEnum(Class clz) { - final Function fromInt = i -> clz.getEnumConstants()[i]; - final Function toInt = Enum::ordinal; + final Function1 fromInt = i -> clz.getEnumConstants()[i]; + final Function1 toInt = Enum::ordinal; return new Builder<>(fromInt, toInt); } @@ -381,6 +384,11 @@ public String stringPrefix() { return "BitSet"; } + @Override + public String toString() { + return mkString(stringPrefix() + "(", ", ", ")"); + } + @Override public Comparator comparator() { return (t1, t2) -> Integer.compare(builder.toInt.apply(t1), builder.toInt.apply(t2)); @@ -466,7 +474,11 @@ public Tuple2, BitSet> span(Predicate predicate) { @Override public BitSet tail() { - return remove(head()); + if (isEmpty()) { + throw new UnsupportedOperationException("tail of empty BitSet"); + } else { + return remove(head()); + } } @Override @@ -748,6 +760,18 @@ public T head() { } throw new NoSuchElementException("head of empty BitSet"); } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof BitSet1) { + final BitSet1 that = (BitSet1) o; + return this.elements == that.elements; + } else { + return false; + } + } } class BitSet2 extends AbstractBitSet { @@ -800,6 +824,18 @@ public T head() { } throw new NoSuchElementException("head of empty BitSet"); } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof BitSet2) { + final BitSet2 that = (BitSet2) o; + return this.elements1 == that.elements1 && this.elements2 == that.elements2; + } else { + return false; + } + } } class BitSetN extends AbstractBitSet { @@ -848,5 +884,26 @@ public T head() { } throw new NoSuchElementException("head of empty BitSet"); } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof BitSetN) { + final BitSetN that = (BitSetN) o; + if (this.elements.length != that.elements.length) { + return false; + } else { + for (int i = 0; i < this.elements.length; i++) { + if (this.elements[i] != that.elements[i]) { + return false; + } + } + return true; + } + } else { + return false; + } + } } } diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java index ace31a8c15..340aabd209 100644 --- a/javaslang/src/test/java/javaslang/collection/BitSetTest.java +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -2,12 +2,210 @@ import org.junit.Test; -public class BitSetTest { +import java.io.Serializable; +import java.util.ArrayList; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + +public class BitSetTest extends AbstractSortedSetTest { private enum E { V1, V2, V3 } + private static class Mapper implements Serializable { + + private static final long serialVersionUID = 1L; + + private final java.util.Map fromIntMap = new java.util.HashMap<>(); + private final java.util.Map toIntMap = new java.util.HashMap<>(); + private int nextValue = 0; + + synchronized T fromInt(Integer i) { + if (i < nextValue) { + return fromIntMap.get(i); + } else { + throw new RuntimeException(); + } + } + + synchronized Integer toInt(T value) { + Integer i = toIntMap.get(value); + if (i == null) { + if(value instanceof Integer) { + i = (Integer) value; + nextValue = Integer.MAX_VALUE; + } else { + i = nextValue++; + } + toIntMap.put(value, i); + fromIntMap.put(i, value); + } + return i; + } + } + + private BitSet.Builder bsBuilder() { + Mapper mapper = new Mapper<>(); + return BitSet.withRelations(mapper::fromInt, mapper::toInt); + } + + @Override + protected Collector, ? extends Traversable> collector() { + return this.bsBuilder().collector(); + } + + @Override + protected BitSet empty() { + return this.bsBuilder().empty(); + } + + @Override + protected BitSet of(T element) { + return this.bsBuilder().of(element); + } + + @Override + protected Set of(T... elements) { + return this.bsBuilder().of(elements); + } + + @Override + protected boolean useIsEqualToInsteadOfIsSameAs() { + return false; + } + + @Override + protected int getPeekNonNilPerformingAnAction() { + return 1; + } + + @Override + protected Traversable ofAll(Iterable elements) { + return this.bsBuilder().ofAll(elements); + } + + @Override + protected Traversable ofAll(boolean[] array) { + return null; + } + + @Override + protected Traversable ofAll(byte[] array) { + return null; + } + + @Override + protected Traversable ofAll(char[] array) { + return null; + } + + @Override + protected Traversable ofAll(double[] array) { + return null; + } + + @Override + protected Traversable ofAll(float[] array) { + return null; + } + + @Override + protected Traversable ofAll(int[] array) { + return null; + } + + @Override + protected Traversable ofAll(long[] array) { + return null; + } + + @Override + protected Traversable ofAll(short[] array) { + return null; + } + + @Override + protected Traversable tabulate(int n, Function f) { + return this.bsBuilder().tabulate(n, f); + } + + @Override + protected Traversable fill(int n, Supplier s) { + return this.bsBuilder().fill(n, s); + } + + @Override + protected Traversable range(char from, char toExclusive) { + return null; + } + + @Override + protected Traversable rangeBy(char from, char toExclusive, int step) { + return null; + } + + @Override + protected Traversable rangeBy(double from, double toExclusive, double step) { + return null; + } + + @Override + protected Traversable range(int from, int toExclusive) { + return null; + } + + @Override + protected Traversable rangeBy(int from, int toExclusive, int step) { + return null; + } + + @Override + protected Traversable range(long from, long toExclusive) { + return null; + } + + @Override + protected Traversable rangeBy(long from, long toExclusive, long step) { + return null; + } + + @Override + protected Traversable rangeClosed(char from, char toInclusive) { + return null; + } + + @Override + protected Traversable rangeClosedBy(char from, char toInclusive, int step) { + return null; + } + + @Override + protected Traversable rangeClosedBy(double from, double toInclusive, double step) { + return null; + } + + @Override + protected Traversable rangeClosed(int from, int toInclusive) { + return null; + } + + @Override + protected Traversable rangeClosedBy(int from, int toInclusive, int step) { + return null; + } + + @Override + protected Traversable rangeClosed(long from, long toInclusive) { + return null; + } + + @Override + protected Traversable rangeClosedBy(long from, long toInclusive, long step) { + return null; + } + @Test public void test1() { BitSet bs = BitSet.empty(); From 05bb6174a46216d55e5b86a11e960c36e371815e Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Fri, 6 May 2016 07:19:34 +0300 Subject: [PATCH 05/11] more factories --- .../java/javaslang/collection/BitSet.java | 345 +++++++++++------- .../java/javaslang/collection/BitSetTest.java | 101 +++-- 2 files changed, 267 insertions(+), 179 deletions(-) diff --git a/javaslang/src/main/java/javaslang/collection/BitSet.java b/javaslang/src/main/java/javaslang/collection/BitSet.java index bde698b803..4c970c2858 100644 --- a/javaslang/src/main/java/javaslang/collection/BitSet.java +++ b/javaslang/src/main/java/javaslang/collection/BitSet.java @@ -27,18 +27,18 @@ * @author Ruslan Sennov * @since 2.1.0 */ -public abstract class BitSet implements SortedSet { +public interface BitSet extends SortedSet { - private static final long serialVersionUID = 1L; + long serialVersionUID = 1L; - public static class Builder implements Serializable { + class Builder implements Serializable { private static final long serialVersionUID = 1L; final static Builder DEFAULT = new Builder<>(i -> i, i -> i); - final Function fromInt; - final Function toInt; + final Function1 fromInt; + final Function1 toInt; Builder(Function1 fromInt, Function1 toInt) { this.fromInt = fromInt; @@ -96,27 +96,43 @@ public BitSet fill(int n, Supplier s) { } } - public static Builder withRelations(Function1 fromInt, Function1 toInt) { + static Builder withRelations(Function1 fromInt, Function1 toInt) { return new Builder<>(fromInt, toInt); } - public static > Builder withEnum(Class clz) { + static > Builder withEnum(Class clz) { final Function1 fromInt = i -> clz.getEnumConstants()[i]; final Function1 toInt = Enum::ordinal; return new Builder<>(fromInt, toInt); } + static Builder withCharacters() { + return new Builder<>(i -> (char) i.intValue(), c -> (int) c); + } + + static Builder withBytes() { + return new Builder<>(Integer::byteValue, Byte::intValue); + } + + static Builder withLongs() { + return new Builder<>(Integer::longValue, Long::intValue); + } + + static Builder withShorts() { + return new Builder<>(Integer::shortValue, Short::intValue); + } + /** * Returns a {@link java.util.stream.Collector} which may be used in conjunction with * {@link java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a {@link javaslang.collection.BitSet}. * * @return A javaslang.collection.List Collector. */ - public static Collector, BitSet> collector() { + static Collector, BitSet> collector() { return Builder.DEFAULT.collector(); } - public static BitSet empty() { + static BitSet empty() { return Builder.DEFAULT.empty(); } @@ -157,6 +173,39 @@ static BitSet ofAll(Iterable values) { return Builder.DEFAULT.ofAll(values); } + /** + * Creates a BitSet based on the elements of a boolean array. + * + * @param array a boolean array + * @return A new BitSet of Boolean values + */ + static BitSet ofAll(boolean[] array) { + Objects.requireNonNull(array, "array is null"); + return BitSet.withRelations(i -> i != 0, b -> b ? 1 : 0).ofAll(Iterator.ofAll(array)); + } + + /** + * Creates a BitSet based on the elements of a byte array. + * + * @param array a byte array + * @return A new BitSet of Byte values + */ + static BitSet ofAll(byte[] array) { + Objects.requireNonNull(array, "array is null"); + return BitSet.withBytes().ofAll(Iterator.ofAll(array)); + } + + /** + * Creates a BitSet based on the elements of a char array. + * + * @param array a char array + * @return A new BitSet of Character values + */ + static BitSet ofAll(char[] array) { + Objects.requireNonNull(array, "array is null"); + return BitSet.withCharacters().ofAll(Iterator.ofAll(array)); + } + /** * Creates a BitSet based on the elements of an int array. * @@ -168,6 +217,28 @@ static BitSet ofAll(int[] array) { return BitSet.ofAll(Iterator.ofAll(array)); } + /** + * Creates a BitSet based on the elements of a long array. + * + * @param array a long array + * @return A new BitSet of Long values + */ + static BitSet ofAll(long[] array) { + Objects.requireNonNull(array, "array is null"); + return BitSet.withLongs().ofAll(Iterator.ofAll(array)); + } + + /** + * Creates a BitSet based on the elements of a short array. + * + * @param array a short array + * @return A new BitSet of Short values + */ + static BitSet ofAll(short[] array) { + Objects.requireNonNull(array, "array is null"); + return BitSet.withShorts().ofAll(Iterator.ofAll(array)); + } + /** * Creates a BitSet of int numbers starting from {@code from}, extending to {@code toExclusive - 1}. * @@ -206,6 +277,14 @@ static BitSet rangeClosed(int from, int toInclusive) { return BitSet.ofAll(Iterator.rangeClosed(from, toInclusive)); } + static BitSet rangeClosed(char from, char toInclusive) { + return BitSet.withCharacters().ofAll(Iterator.rangeClosed(from, toInclusive)); + } + + static BitSet rangeClosed(long from, long toInclusive) { + return BitSet.withLongs().ofAll(Iterator.rangeClosed(from, toInclusive)); + } + /** * Creates a BitSet of int numbers starting from {@code from}, extending to {@code toInclusive}, * with {@code step}. @@ -222,156 +301,160 @@ static BitSet rangeClosedBy(int from, int toInclusive, int step) { return BitSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } - final Builder builder; + static BitSet rangeClosedBy(char from, char toInclusive, int step) { + return BitSet.withCharacters().ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); + } - BitSet(Builder builder) { - this.builder = builder; + static BitSet rangeClosedBy(long from, long toInclusive, long step) { + return BitSet.withLongs().ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } + Builder builder(); + @Override - public abstract BitSet add(T element); + BitSet add(T element); @Override - public abstract BitSet addAll(Iterable elements); + BitSet addAll(Iterable elements); @Override - public BitSet diff(Set elements) { + default BitSet diff(Set elements) { return removeAll(elements); } @Override - public BitSet distinct() { + default BitSet distinct() { return this; } @Override - public BitSet distinctBy(Comparator comparator) { + default BitSet distinctBy(Comparator comparator) { Objects.requireNonNull(comparator, "comparator is null"); - return builder.ofAll(iterator().distinctBy(comparator)); + return builder().ofAll(iterator().distinctBy(comparator)); } @Override - public BitSet distinctBy(Function keyExtractor) { + default BitSet distinctBy(Function keyExtractor) { Objects.requireNonNull(keyExtractor, "keyExtractor is null"); - return builder.ofAll(iterator().distinctBy(keyExtractor)); + return builder().ofAll(iterator().distinctBy(keyExtractor)); } @Override - public BitSet drop(long n) { + default BitSet drop(long n) { if (n <= 0) { return this; } else if (n >= length()) { - return builder.empty(); + return builder().empty(); } else { - return builder.ofAll(iterator().drop(n)); + return builder().ofAll(iterator().drop(n)); } } @Override - public BitSet dropRight(long n) { + default BitSet dropRight(long n) { if (n <= 0) { return this; } else if (n >= length()) { - return builder.empty(); + return builder().empty(); } else { - return builder.ofAll(iterator().dropRight(n)); + return builder().ofAll(iterator().dropRight(n)); } } @Override - public BitSet dropUntil(Predicate predicate) { + default BitSet dropUntil(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); return dropWhile(predicate.negate()); } @Override - public BitSet dropWhile(Predicate predicate) { + default BitSet dropWhile(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - final BitSet bitSet = builder.ofAll(iterator().dropWhile(predicate)); + final BitSet bitSet = builder().ofAll(iterator().dropWhile(predicate)); return (bitSet.length() == length()) ? this : bitSet; } @Override - public BitSet filter(Predicate predicate) { + default BitSet filter(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - final BitSet bitSet = builder.ofAll(iterator().filter(predicate)); + final BitSet bitSet = builder().ofAll(iterator().filter(predicate)); return (bitSet.length() == length()) ? this : bitSet; } @Override - public SortedSet flatMap(Comparator comparator, Function> mapper) { + default SortedSet flatMap(Comparator comparator, Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return TreeSet.ofAll(comparator, iterator().flatMap(mapper)); } @Override - public SortedSet flatMap(Function> mapper) { + default SortedSet flatMap(Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return TreeSet.ofAll(naturalComparator(), iterator().flatMap(mapper)); } @Override - public U foldRight(U zero, BiFunction f) { + default U foldRight(U zero, BiFunction f) { Objects.requireNonNull(f, "f is null"); return iterator().foldRight(zero, f); } @Override - public Map> groupBy(Function classifier) { + default Map> groupBy(Function classifier) { Objects.requireNonNull(classifier, "classifier is null"); - return iterator().groupBy(classifier).map((key, iterator) -> Tuple.of(key, builder.ofAll(iterator))); + return iterator().groupBy(classifier).map((key, iterator) -> Tuple.of(key, builder().ofAll(iterator))); } @Override - public Iterator> grouped(long size) { + default Iterator> grouped(long size) { return sliding(size, size); } @Override - public boolean hasDefiniteSize() { + default boolean hasDefiniteSize() { return true; } @Override - public abstract BitSet init(); + BitSet init(); @Override - public Option> initOption() { + default Option> initOption() { return isEmpty() ? Option.none() : Option.some(init()); } @Override - public boolean isTraversableAgain() { + default boolean isTraversableAgain() { return true; } @Override - public abstract Iterator iterator(); + Iterator iterator(); @Override - public BitSet intersect(Set elements) { + default BitSet intersect(Set elements) { Objects.requireNonNull(elements, "elements is null"); if (isEmpty() || elements.isEmpty()) { - return builder.empty(); + return builder().empty(); } else { int size = size(); if (size <= elements.size()) { return retainAll(elements); } else { - BitSet results = builder.ofAll(elements).retainAll(this); + BitSet results = builder().ofAll(elements).retainAll(this); return (size == results.size()) ? this : results; } } } @Override - public Tuple2, BitSet> partition(Predicate predicate) { + default Tuple2, BitSet> partition(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - return iterator().partition(predicate).map(builder::ofAll, builder::ofAll); + return iterator().partition(predicate).map(builder()::ofAll, builder()::ofAll); } @Override - public BitSet peek(Consumer action) { + default BitSet peek(Consumer action) { Objects.requireNonNull(action, "action is null"); if (!isEmpty()) { action.accept(head()); @@ -380,39 +463,34 @@ public BitSet peek(Consumer action) { } @Override - public String stringPrefix() { + default String stringPrefix() { return "BitSet"; } @Override - public String toString() { - return mkString(stringPrefix() + "(", ", ", ")"); - } - - @Override - public Comparator comparator() { - return (t1, t2) -> Integer.compare(builder.toInt.apply(t1), builder.toInt.apply(t2)); + default Comparator comparator() { + return (t1, t2) -> Integer.compare(builder().toInt.apply(t1), builder().toInt.apply(t2)); } @Override - public SortedSet map(Comparator comparator, Function mapper) { + default SortedSet map(Comparator comparator, Function mapper) { Objects.requireNonNull(mapper, "mapper is null"); return TreeSet.ofAll(comparator, iterator().map(mapper)); } @Override - public SortedSet map(Function mapper) { + default SortedSet map(Function mapper) { return map(naturalComparator(), mapper); } @Override - public abstract BitSet remove(T element); + BitSet remove(T element); @Override - public abstract BitSet removeAll(Iterable elements); + BitSet removeAll(Iterable elements); @Override - public BitSet replace(T currentElement, T newElement) { + default BitSet replace(T currentElement, T newElement) { if (contains(currentElement)) { return remove(currentElement).add(newElement); } else { @@ -421,27 +499,27 @@ public BitSet replace(T currentElement, T newElement) { } @Override - public BitSet replaceAll(T currentElement, T newElement) { + default BitSet replaceAll(T currentElement, T newElement) { // a set has only one occurrence return replace(currentElement, newElement); } @Override - public BitSet retainAll(Iterable elements) { + default BitSet retainAll(Iterable elements) { return Collections.retainAll(this, elements); } @Override - public BitSet scan(T zero, BiFunction operation) { + default BitSet scan(T zero, BiFunction operation) { Objects.requireNonNull(operation, "operation is null"); return Collections.scanLeft(this, zero, operation, new java.util.ArrayList(), (arr, t) -> { arr.add(t); return arr; - }, builder::ofAll); + }, builder()::ofAll); } @Override - public Set scanLeft(U zero, BiFunction operation) { + default Set scanLeft(U zero, BiFunction operation) { return Collections.scanLeft(this, zero, operation, new java.util.ArrayList<>(), (c, u) -> { c.add(u); return c; @@ -449,7 +527,7 @@ public Set scanLeft(U zero, BiFunction } @Override - public Set scanRight(U zero, BiFunction operation) { + default Set scanRight(U zero, BiFunction operation) { return Collections.scanRight(this, zero, operation, new java.util.ArrayList<>(), (c, u) -> { c.add(u); return c; @@ -457,23 +535,23 @@ public Set scanRight(U zero, BiFunction> sliding(long size) { + default Iterator> sliding(long size) { return sliding(size, 1); } @Override - public Iterator> sliding(long size, long step) { - return iterator().sliding(size, step).map(builder::ofAll); + default Iterator> sliding(long size, long step) { + return iterator().sliding(size, step).map(builder()::ofAll); } @Override - public Tuple2, BitSet> span(Predicate predicate) { + default Tuple2, BitSet> span(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - return iterator().span(predicate).map(builder::ofAll, builder::ofAll); + return iterator().span(predicate).map(builder()::ofAll, builder()::ofAll); } @Override - public BitSet tail() { + default BitSet tail() { if (isEmpty()) { throw new UnsupportedOperationException("tail of empty BitSet"); } else { @@ -482,60 +560,60 @@ public BitSet tail() { } @Override - public Option> tailOption() { + default Option> tailOption() { return isEmpty() ? Option.none() : Option.some(tail()); } @Override - public BitSet take(long n) { + default BitSet take(long n) { if (n <= 0) { - return builder.empty(); + return builder().empty(); } else if (n >= length()) { return this; } else { - return builder.ofAll(iterator().take(n)); + return builder().ofAll(iterator().take(n)); } } @Override - public BitSet takeRight(long n) { + default BitSet takeRight(long n) { if (n <= 0) { - return builder.empty(); + return builder().empty(); } else if (n >= length()) { return this; } else { - return builder.ofAll(iterator().takeRight(n)); + return builder().ofAll(iterator().takeRight(n)); } } @Override - public BitSet takeUntil(Predicate predicate) { + default BitSet takeUntil(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); final BitSet result = takeWhile(predicate.negate()); return (result.length() == length()) ? this : result; } @Override - public BitSet takeWhile(Predicate predicate) { + default BitSet takeWhile(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - final BitSet result = builder.ofAll(iterator().takeWhile(predicate)); + final BitSet result = builder().ofAll(iterator().takeWhile(predicate)); return (result.length() == length()) ? this : result; } @Override - public java.util.SortedSet toJavaSet() { + default java.util.SortedSet toJavaSet() { return toJavaSet(() -> new java.util.TreeSet<>(comparator())); } @Override - public BitSet union(Set elements) { + default BitSet union(Set elements) { Objects.requireNonNull(elements, "elements is null"); return addAll(elements); } // TODO @Override - public Tuple2, TreeSet> unzip( + default Tuple2, TreeSet> unzip( Function> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); return iterator().unzip(unzipper).map(i1 -> TreeSet.ofAll(naturalComparator(), i1), @@ -544,7 +622,7 @@ public Tuple2, TreeSet> unzip( // TODO @Override - public Tuple3, TreeSet, TreeSet> unzip3( + default Tuple3, TreeSet, TreeSet> unzip3( Function> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); return iterator().unzip3(unzipper).map( @@ -555,7 +633,7 @@ public Tuple3, TreeSet, TreeSet> unzip3( // TODO @Override - public TreeSet> zip(Iterable that) { + default TreeSet> zip(Iterable that) { Objects.requireNonNull(that, "that is null"); final Comparator> tuple2Comparator = Tuple2.comparator(comparator(), naturalComparator()); return TreeSet.ofAll(tuple2Comparator, iterator().zip(that)); @@ -563,7 +641,7 @@ public TreeSet> zip(Iterable that) { // TODO @Override - public TreeSet> zipAll(Iterable that, T thisElem, U thatElem) { + default TreeSet> zipAll(Iterable that, T thisElem, U thatElem) { Objects.requireNonNull(that, "that is null"); final Comparator> tuple2Comparator = Tuple2.comparator(comparator(), naturalComparator()); return TreeSet.ofAll(tuple2Comparator, iterator().zipAll(that, thisElem, thatElem)); @@ -571,7 +649,7 @@ public TreeSet> zipAll(Iterable that, T thisElem, // TODO @Override - public TreeSet> zipWithIndex() { + default TreeSet> zipWithIndex() { final Comparator component1Comparator = comparator(); final Comparator> tuple2Comparator = (t1, t2) -> component1Comparator.compare(t1._1, t2._1); return TreeSet.ofAll(tuple2Comparator, iterator().zipWithIndex()); @@ -583,12 +661,18 @@ interface BitSetModule { int ADDRESS_BITS_PER_WORD = 6; int BITS_PER_WORD = 64; - abstract class AbstractBitSet extends BitSet { + abstract class AbstractBitSet implements BitSet { private static final long serialVersionUID = 1L; + Builder builder; + AbstractBitSet(Builder builder) { - super(builder); + this.builder = builder; + } + + public Builder builder() { + return builder; } abstract int getWordsNum(); @@ -672,9 +756,13 @@ public boolean contains(T t) { @Override public BitSet init() { - final long last = getWord(getWordsNum() - 1); - final int element = BITS_PER_WORD * (getWordsNum() - 1) + BITS_PER_WORD - Long.numberOfLeadingZeros(last) - 1; - return remove(builder.fromInt.apply(element)); + if (isEmpty()) { + throw new UnsupportedOperationException("init of empty TreeSet"); + } else { + final long last = getWord(getWordsNum() - 1); + final int element = BITS_PER_WORD * (getWordsNum() - 1) + BITS_PER_WORD - Long.numberOfLeadingZeros(last) - 1; + return remove(builder.fromInt.apply(element)); + } } @Override @@ -716,6 +804,28 @@ public BitSet removeAll(Iterable elements) { }); return fromBitMaskNoCopy(shrink(copy)); } + + @Override + public String toString() { + return mkString(stringPrefix() + "(", ", ", ")"); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof BitSet) { + final BitSet that = (BitSet) o; + return Collections.equals(this, that); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Collections.hash(this); + } } class BitSet1 extends AbstractBitSet { @@ -760,18 +870,6 @@ public T head() { } throw new NoSuchElementException("head of empty BitSet"); } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } else if (o instanceof BitSet1) { - final BitSet1 that = (BitSet1) o; - return this.elements == that.elements; - } else { - return false; - } - } } class BitSet2 extends AbstractBitSet { @@ -824,18 +922,6 @@ public T head() { } throw new NoSuchElementException("head of empty BitSet"); } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } else if (o instanceof BitSet2) { - final BitSet2 that = (BitSet2) o; - return this.elements1 == that.elements1 && this.elements2 == that.elements2; - } else { - return false; - } - } } class BitSetN extends AbstractBitSet { @@ -884,26 +970,5 @@ public T head() { } throw new NoSuchElementException("head of empty BitSet"); } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } else if (o instanceof BitSetN) { - final BitSetN that = (BitSetN) o; - if (this.elements.length != that.elements.length) { - return false; - } else { - for (int i = 0; i < this.elements.length; i++) { - if (this.elements[i] != that.elements[i]) { - return false; - } - } - return true; - } - } else { - return false; - } - } } } diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java index 340aabd209..692db8e4d8 100644 --- a/javaslang/src/test/java/javaslang/collection/BitSetTest.java +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -1,5 +1,7 @@ package javaslang.collection; +import org.assertj.core.api.Assertions; +import org.assertj.core.api.IterableAssert; import org.junit.Test; import java.io.Serializable; @@ -46,6 +48,22 @@ synchronized Integer toInt(T value) { } } + @Override + protected IterableAssert assertThat(Iterable actual) { + return new IterableAssert(actual) { + @Override + @SuppressWarnings("unchecked") + public IterableAssert isEqualTo(Object obj) { + if(obj instanceof BitSet || actual instanceof BitSet) { + Assertions.assertThat(List.ofAll(actual)).isEqualTo(List.ofAll((Iterable) obj)); + } else { + super.isEqualTo(obj); + } + return this; + } + }; + } + private BitSet.Builder bsBuilder() { Mapper mapper = new Mapper<>(); return BitSet.withRelations(mapper::fromInt, mapper::toInt); @@ -61,19 +79,24 @@ protected BitSet empty() { return this.bsBuilder().empty(); } + @Override + protected boolean emptyShouldBeSingleton() { + return false; + } + @Override protected BitSet of(T element) { return this.bsBuilder().of(element); } @Override - protected Set of(T... elements) { + protected BitSet of(T... elements) { return this.bsBuilder().of(elements); } @Override protected boolean useIsEqualToInsteadOfIsSameAs() { - return false; + return true; } @Override @@ -82,127 +105,127 @@ protected int getPeekNonNilPerformingAnAction() { } @Override - protected Traversable ofAll(Iterable elements) { + protected BitSet ofAll(Iterable elements) { return this.bsBuilder().ofAll(elements); } @Override - protected Traversable ofAll(boolean[] array) { - return null; + protected BitSet ofAll(boolean[] array) { + return BitSet.ofAll(array); } @Override - protected Traversable ofAll(byte[] array) { - return null; + protected BitSet ofAll(byte[] array) { + return BitSet.ofAll(array); } @Override - protected Traversable ofAll(char[] array) { - return null; + protected BitSet ofAll(char[] array) { + return BitSet.ofAll(array); } @Override - protected Traversable ofAll(double[] array) { + protected BitSet ofAll(double[] array) { return null; } @Override - protected Traversable ofAll(float[] array) { + protected BitSet ofAll(float[] array) { return null; } @Override - protected Traversable ofAll(int[] array) { - return null; + protected BitSet ofAll(int[] array) { + return BitSet.ofAll(array); } @Override - protected Traversable ofAll(long[] array) { - return null; + protected BitSet ofAll(long[] array) { + return BitSet.ofAll(array); } @Override - protected Traversable ofAll(short[] array) { - return null; + protected BitSet ofAll(short[] array) { + return BitSet.ofAll(array); } @Override - protected Traversable tabulate(int n, Function f) { + protected BitSet tabulate(int n, Function f) { return this.bsBuilder().tabulate(n, f); } @Override - protected Traversable fill(int n, Supplier s) { + protected BitSet fill(int n, Supplier s) { return this.bsBuilder().fill(n, s); } @Override - protected Traversable range(char from, char toExclusive) { + protected BitSet range(char from, char toExclusive) { return null; } @Override - protected Traversable rangeBy(char from, char toExclusive, int step) { + protected BitSet rangeBy(char from, char toExclusive, int step) { return null; } @Override - protected Traversable rangeBy(double from, double toExclusive, double step) { + protected BitSet rangeBy(double from, double toExclusive, double step) { return null; } @Override - protected Traversable range(int from, int toExclusive) { - return null; + protected BitSet range(int from, int toExclusive) { + return BitSet.range(from, toExclusive); } @Override - protected Traversable rangeBy(int from, int toExclusive, int step) { - return null; + protected BitSet rangeBy(int from, int toExclusive, int step) { + return BitSet.rangeBy(from, toExclusive, step); } @Override - protected Traversable range(long from, long toExclusive) { + protected BitSet range(long from, long toExclusive) { return null; } @Override - protected Traversable rangeBy(long from, long toExclusive, long step) { + protected BitSet rangeBy(long from, long toExclusive, long step) { return null; } @Override - protected Traversable rangeClosed(char from, char toInclusive) { - return null; + protected BitSet rangeClosed(char from, char toInclusive) { + return BitSet.rangeClosed(from, toInclusive); } @Override - protected Traversable rangeClosedBy(char from, char toInclusive, int step) { - return null; + protected BitSet rangeClosedBy(char from, char toInclusive, int step) { + return BitSet.rangeClosedBy(from, toInclusive, step); } @Override - protected Traversable rangeClosedBy(double from, double toInclusive, double step) { + protected BitSet rangeClosedBy(double from, double toInclusive, double step) { return null; } @Override - protected Traversable rangeClosed(int from, int toInclusive) { - return null; + protected BitSet rangeClosed(int from, int toInclusive) { + return null;//BitSet.rangeClosed(from, toInclusive); } @Override - protected Traversable rangeClosedBy(int from, int toInclusive, int step) { - return null; + protected BitSet rangeClosedBy(int from, int toInclusive, int step) { + return BitSet.rangeClosedBy(from, toInclusive, step); } @Override - protected Traversable rangeClosed(long from, long toInclusive) { + protected BitSet rangeClosed(long from, long toInclusive) { return null; } @Override - protected Traversable rangeClosedBy(long from, long toInclusive, long step) { + protected BitSet rangeClosedBy(long from, long toInclusive, long step) { return null; } From 2ad955c64b5eb8caf1bda5b310453e7c3c18b759 Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Wed, 11 May 2016 22:13:20 +0300 Subject: [PATCH 06/11] more tests --- .../java/javaslang/collection/BitSetTest.java | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java index 692db8e4d8..9ac1862d90 100644 --- a/javaslang/src/test/java/javaslang/collection/BitSetTest.java +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -1,7 +1,11 @@ package javaslang.collection; +import javaslang.Tuple; +import javaslang.Tuple2; +import javaslang.Tuple3; import org.assertj.core.api.Assertions; import org.assertj.core.api.IterableAssert; +import org.assertj.core.api.ObjectAssert; import org.junit.Test; import java.io.Serializable; @@ -55,7 +59,7 @@ protected IterableAssert assertThat(Iterable actual) { @SuppressWarnings("unchecked") public IterableAssert isEqualTo(Object obj) { if(obj instanceof BitSet || actual instanceof BitSet) { - Assertions.assertThat(List.ofAll(actual)).isEqualTo(List.ofAll((Iterable) obj)); + Assertions.assertThat(HashSet.ofAll(actual)).isEqualTo(HashSet.ofAll((Iterable) obj)); } else { super.isEqualTo(obj); } @@ -64,6 +68,30 @@ public IterableAssert isEqualTo(Object obj) { }; } + @Override + protected ObjectAssert assertThat(T actual) { + return new ObjectAssert(actual) { + @Override + public ObjectAssert isEqualTo(Object expected) { + if (actual instanceof Tuple2) { + final Tuple2 t1 = (Tuple2) actual; + final Tuple2 t2 = (Tuple2) expected; + assertThat((Iterable) t1._1).isEqualTo(t2._1); + assertThat((Iterable) t1._2).isEqualTo(t2._2); + return this; + } else if (actual instanceof Tuple3) { + final Tuple3 t1 = (Tuple3) actual; + final Tuple3 t2 = (Tuple3) expected; + assertThat((Iterable) t1._1).isEqualTo(t2._1); + assertThat((Iterable) t1._2).isEqualTo(t2._2); + return this; + } else { + return super.isEqualTo(expected); + } + } + }; + } + private BitSet.Builder bsBuilder() { Mapper mapper = new Mapper<>(); return BitSet.withRelations(mapper::fromInt, mapper::toInt); @@ -126,12 +154,12 @@ protected BitSet ofAll(char[] array) { @Override protected BitSet ofAll(double[] array) { - return null; + return this.bsBuilder().ofAll(Iterator.ofAll(array)); } @Override protected BitSet ofAll(float[] array) { - return null; + return this.bsBuilder().ofAll(Iterator.ofAll(array)); } @Override From b08b941e09889d9c04b4c45709ae006355fb6e91 Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Sat, 14 May 2016 07:43:25 +0300 Subject: [PATCH 07/11] BitSet: hidden builder; tests passed --- .../java/javaslang/collection/BitSet.java | 273 +++++++++++------- .../java/javaslang/collection/BitSetTest.java | 105 +++++-- 2 files changed, 239 insertions(+), 139 deletions(-) diff --git a/javaslang/src/main/java/javaslang/collection/BitSet.java b/javaslang/src/main/java/javaslang/collection/BitSet.java index 4c970c2858..df92e59248 100644 --- a/javaslang/src/main/java/javaslang/collection/BitSet.java +++ b/javaslang/src/main/java/javaslang/collection/BitSet.java @@ -250,6 +250,14 @@ static BitSet range(int from, int toExclusive) { return BitSet.ofAll(Iterator.range(from, toExclusive)); } + static BitSet range(char from, char toExclusive) { + return BitSet.withCharacters().ofAll(Iterator.range(from, toExclusive)); + } + + static BitSet range(long from, long toExclusive) { + return BitSet.withLongs().ofAll(Iterator.range(from, toExclusive)); + } + /** * Creates a BitSet of int numbers starting from {@code from}, extending to {@code toExclusive - 1}, * with {@code step}. @@ -266,6 +274,14 @@ static BitSet rangeBy(int from, int toExclusive, int step) { return BitSet.ofAll(Iterator.rangeBy(from, toExclusive, step)); } + static BitSet rangeBy(char from, char toExclusive, int step) { + return BitSet.withCharacters().ofAll(Iterator.rangeBy(from, toExclusive, step)); + } + + static BitSet rangeBy(long from, long toExclusive, long step) { + return BitSet.withLongs().ofAll(Iterator.rangeBy(from, toExclusive, step)); + } + /** * Creates a BitSet of int numbers starting from {@code from}, extending to {@code toInclusive}. * @@ -309,8 +325,6 @@ static BitSet rangeClosedBy(long from, long toInclusive, long step) { return BitSet.withLongs().ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } - Builder builder(); - @Override BitSet add(T element); @@ -328,38 +342,16 @@ default BitSet distinct() { } @Override - default BitSet distinctBy(Comparator comparator) { - Objects.requireNonNull(comparator, "comparator is null"); - return builder().ofAll(iterator().distinctBy(comparator)); - } + BitSet distinctBy(Comparator comparator); @Override - default BitSet distinctBy(Function keyExtractor) { - Objects.requireNonNull(keyExtractor, "keyExtractor is null"); - return builder().ofAll(iterator().distinctBy(keyExtractor)); - } + BitSet distinctBy(Function keyExtractor); @Override - default BitSet drop(long n) { - if (n <= 0) { - return this; - } else if (n >= length()) { - return builder().empty(); - } else { - return builder().ofAll(iterator().drop(n)); - } - } + BitSet drop(long n); @Override - default BitSet dropRight(long n) { - if (n <= 0) { - return this; - } else if (n >= length()) { - return builder().empty(); - } else { - return builder().ofAll(iterator().dropRight(n)); - } - } + BitSet dropRight(long n); @Override default BitSet dropUntil(Predicate predicate) { @@ -368,18 +360,10 @@ default BitSet dropUntil(Predicate predicate) { } @Override - default BitSet dropWhile(Predicate predicate) { - Objects.requireNonNull(predicate, "predicate is null"); - final BitSet bitSet = builder().ofAll(iterator().dropWhile(predicate)); - return (bitSet.length() == length()) ? this : bitSet; - } + BitSet dropWhile(Predicate predicate); @Override - default BitSet filter(Predicate predicate) { - Objects.requireNonNull(predicate, "predicate is null"); - final BitSet bitSet = builder().ofAll(iterator().filter(predicate)); - return (bitSet.length() == length()) ? this : bitSet; - } + BitSet filter(Predicate predicate); @Override default SortedSet flatMap(Comparator comparator, Function> mapper) { @@ -400,10 +384,7 @@ default U foldRight(U zero, BiFunction f) } @Override - default Map> groupBy(Function classifier) { - Objects.requireNonNull(classifier, "classifier is null"); - return iterator().groupBy(classifier).map((key, iterator) -> Tuple.of(key, builder().ofAll(iterator))); - } + Map> groupBy(Function classifier); @Override default Iterator> grouped(long size) { @@ -429,29 +410,10 @@ default boolean isTraversableAgain() { } @Override - Iterator iterator(); - - @Override - default BitSet intersect(Set elements) { - Objects.requireNonNull(elements, "elements is null"); - if (isEmpty() || elements.isEmpty()) { - return builder().empty(); - } else { - int size = size(); - if (size <= elements.size()) { - return retainAll(elements); - } else { - BitSet results = builder().ofAll(elements).retainAll(this); - return (size == results.size()) ? this : results; - } - } - } + BitSet intersect(Set elements); @Override - default Tuple2, BitSet> partition(Predicate predicate) { - Objects.requireNonNull(predicate, "predicate is null"); - return iterator().partition(predicate).map(builder()::ofAll, builder()::ofAll); - } + Tuple2, BitSet> partition(Predicate predicate); @Override default BitSet peek(Consumer action) { @@ -467,11 +429,6 @@ default String stringPrefix() { return "BitSet"; } - @Override - default Comparator comparator() { - return (t1, t2) -> Integer.compare(builder().toInt.apply(t1), builder().toInt.apply(t2)); - } - @Override default SortedSet map(Comparator comparator, Function mapper) { Objects.requireNonNull(mapper, "mapper is null"); @@ -510,13 +467,7 @@ default BitSet retainAll(Iterable elements) { } @Override - default BitSet scan(T zero, BiFunction operation) { - Objects.requireNonNull(operation, "operation is null"); - return Collections.scanLeft(this, zero, operation, new java.util.ArrayList(), (arr, t) -> { - arr.add(t); - return arr; - }, builder()::ofAll); - } + BitSet scan(T zero, BiFunction operation); @Override default Set scanLeft(U zero, BiFunction operation) { @@ -540,15 +491,10 @@ default Iterator> sliding(long size) { } @Override - default Iterator> sliding(long size, long step) { - return iterator().sliding(size, step).map(builder()::ofAll); - } + Iterator> sliding(long size, long step); @Override - default Tuple2, BitSet> span(Predicate predicate) { - Objects.requireNonNull(predicate, "predicate is null"); - return iterator().span(predicate).map(builder()::ofAll, builder()::ofAll); - } + Tuple2, BitSet> span(Predicate predicate); @Override default BitSet tail() { @@ -565,26 +511,10 @@ default Option> tailOption() { } @Override - default BitSet take(long n) { - if (n <= 0) { - return builder().empty(); - } else if (n >= length()) { - return this; - } else { - return builder().ofAll(iterator().take(n)); - } - } + BitSet take(long n); @Override - default BitSet takeRight(long n) { - if (n <= 0) { - return builder().empty(); - } else if (n >= length()) { - return this; - } else { - return builder().ofAll(iterator().takeRight(n)); - } - } + BitSet takeRight(long n); @Override default BitSet takeUntil(Predicate predicate) { @@ -594,11 +524,7 @@ default BitSet takeUntil(Predicate predicate) { } @Override - default BitSet takeWhile(Predicate predicate) { - Objects.requireNonNull(predicate, "predicate is null"); - final BitSet result = builder().ofAll(iterator().takeWhile(predicate)); - return (result.length() == length()) ? this : result; - } + BitSet takeWhile(Predicate predicate); @Override default java.util.SortedSet toJavaSet() { @@ -671,10 +597,6 @@ abstract class AbstractBitSet implements BitSet { this.builder = builder; } - public Builder builder() { - return builder; - } - abstract int getWordsNum(); abstract long[] copyExpand(int wordsNum); @@ -721,15 +643,120 @@ public BitSet add(T t) { return this; } else { final int element = builder.toInt.apply(t); - if (element < 0) { - throw new IllegalArgumentException("bitset element must be >= 0"); - } final long[] copy = copyExpand(1 + (element >> ADDRESS_BITS_PER_WORD)); setElement(copy, element); return fromBitMaskNoCopy(copy); } } + @Override + public BitSet distinctBy(Comparator comparator) { + Objects.requireNonNull(comparator, "comparator is null"); + return builder.ofAll(iterator().distinctBy(comparator)); + } + + @Override + public BitSet distinctBy(Function keyExtractor) { + Objects.requireNonNull(keyExtractor, "keyExtractor is null"); + return builder.ofAll(iterator().distinctBy(keyExtractor)); + } + + @Override + public BitSet drop(long n) { + if (n <= 0) { + return this; + } else if (n >= length()) { + return builder.empty(); + } else { + return builder.ofAll(iterator().drop(n)); + } + } + + @Override + public BitSet dropRight(long n) { + if (n <= 0) { + return this; + } else if (n >= length()) { + return builder.empty(); + } else { + return builder.ofAll(iterator().dropRight(n)); + } + } + + @Override + public BitSet dropWhile(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + final BitSet bitSet = builder.ofAll(iterator().dropWhile(predicate)); + return (bitSet.length() == length()) ? this : bitSet; + } + + @Override + public BitSet intersect(Set elements) { + Objects.requireNonNull(elements, "elements is null"); + if (isEmpty() || elements.isEmpty()) { + return builder.empty(); + } else { + int size = size(); + if (size <= elements.size()) { + return retainAll(elements); + } else { + BitSet results = builder.ofAll(elements).retainAll(this); + return (size == results.size()) ? this : results; + } + } + } + + @Override + public Iterator> sliding(long size, long step) { + return iterator().sliding(size, step).map(builder::ofAll); + } + + @Override + public Tuple2, BitSet> span(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + return iterator().span(predicate).map(builder::ofAll, builder::ofAll); + } + + @Override + public BitSet scan(T zero, BiFunction operation) { + Objects.requireNonNull(operation, "operation is null"); + return Collections.scanLeft(this, zero, operation, new java.util.ArrayList(), (arr, t) -> { + arr.add(t); + return arr; + }, builder::ofAll); + } + + @Override + public Tuple2, BitSet> partition(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + return iterator().partition(predicate).map(builder::ofAll, builder::ofAll); + } + + @Override + public BitSet filter(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + final BitSet bitSet = builder.ofAll(iterator().filter(predicate)); + return (bitSet.length() == length()) ? this : bitSet; + } + + @Override + public Map> groupBy(Function classifier) { + Objects.requireNonNull(classifier, "classifier is null"); + return iterator().groupBy(classifier).map((key, iterator) -> Tuple.of(key, builder.ofAll(iterator))); + } + + @Override + public Comparator comparator() { + return (t1, t2) -> Integer.compare(builder.toInt.apply(t1), builder.toInt.apply(t2)); + } + + @Override + public BitSet takeWhile(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate is null"); + final BitSet result = builder.ofAll(iterator().takeWhile(predicate)); + return (result.length() == length()) ? this : result; + } + @Override @SuppressWarnings("unchecked") public BitSet addAll(Iterable elements) { @@ -782,6 +809,28 @@ public int length() { return len; } + @Override + public BitSet take(long n) { + if (n <= 0) { + return builder.empty(); + } else if (n >= length()) { + return this; + } else { + return builder.ofAll(iterator().take(n)); + } + } + + @Override + public BitSet takeRight(long n) { + if (n <= 0) { + return builder.empty(); + } else if (n >= length()) { + return this; + } else { + return builder.ofAll(iterator().takeRight(n)); + } + } + @Override public BitSet remove(T t) { if (contains(t)) { diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java index 9ac1862d90..7ed3b6cf32 100644 --- a/javaslang/src/test/java/javaslang/collection/BitSetTest.java +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -16,6 +16,8 @@ public class BitSetTest extends AbstractSortedSetTest { + private final static int MAX_BIT = 1_000_000; + private enum E { V1, V2, V3 } @@ -39,12 +41,7 @@ synchronized T fromInt(Integer i) { synchronized Integer toInt(T value) { Integer i = toIntMap.get(value); if (i == null) { - if(value instanceof Integer) { - i = (Integer) value; - nextValue = Integer.MAX_VALUE; - } else { - i = nextValue++; - } + i = nextValue++; toIntMap.put(value, i); fromIntMap.put(i, value); } @@ -117,8 +114,10 @@ protected BitSet of(T element) { return this.bsBuilder().of(element); } + @SuppressWarnings("varargs") + @SafeVarargs @Override - protected BitSet of(T... elements) { + protected final BitSet of(T... elements) { return this.bsBuilder().of(elements); } @@ -189,37 +188,61 @@ protected BitSet fill(int n, Supplier s) { @Override protected BitSet range(char from, char toExclusive) { - return null; + return BitSet.range(from, toExclusive); } @Override protected BitSet rangeBy(char from, char toExclusive, int step) { - return null; + return BitSet.rangeBy(from, toExclusive, step); } @Override protected BitSet rangeBy(double from, double toExclusive, double step) { - return null; + return this.bsBuilder().ofAll(Iterator.rangeBy(from, toExclusive, step)); + } + + private static boolean badRange(int a, int b) { + return a < 0 || b < 0 || a > MAX_BIT || b > MAX_BIT; + } + + private static boolean badRange(long a, long b) { + return a < 0 || b < 0 || a > MAX_BIT || b > MAX_BIT; } @Override protected BitSet range(int from, int toExclusive) { - return BitSet.range(from, toExclusive); + if (badRange(from, toExclusive)) { + return this.bsBuilder().ofAll(Iterator.range(from, toExclusive)); + } else { + return BitSet.range(from, toExclusive); + } } @Override protected BitSet rangeBy(int from, int toExclusive, int step) { - return BitSet.rangeBy(from, toExclusive, step); + if (badRange(from, toExclusive)) { + return this.bsBuilder().ofAll(Iterator.rangeBy(from, toExclusive, step)); + } else { + return BitSet.rangeBy(from, toExclusive, step); + } } @Override protected BitSet range(long from, long toExclusive) { - return null; + if (badRange(from, toExclusive)) { + return this.bsBuilder().ofAll(Iterator.range(from, toExclusive)); + } else { + return BitSet.range(from, toExclusive); + } } @Override protected BitSet rangeBy(long from, long toExclusive, long step) { - return null; + if (badRange(from, toExclusive)) { + return this.bsBuilder().ofAll(Iterator.rangeBy(from, toExclusive, step)); + } else { + return BitSet.rangeBy(from, toExclusive, step); + } } @Override @@ -234,31 +257,49 @@ protected BitSet rangeClosedBy(char from, char toInclusive, int step) @Override protected BitSet rangeClosedBy(double from, double toInclusive, double step) { - return null; + return this.bsBuilder().ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } @Override protected BitSet rangeClosed(int from, int toInclusive) { - return null;//BitSet.rangeClosed(from, toInclusive); + if (badRange(from, toInclusive)) { + return this.bsBuilder().ofAll(Iterator.rangeClosed(from, toInclusive)); + } else { + return BitSet.rangeClosed(from, toInclusive); + } } @Override protected BitSet rangeClosedBy(int from, int toInclusive, int step) { - return BitSet.rangeClosedBy(from, toInclusive, step); + if (badRange(from, toInclusive)) { + return this.bsBuilder().ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); + } else { + return BitSet.rangeClosedBy(from, toInclusive, step); + } } @Override protected BitSet rangeClosed(long from, long toInclusive) { - return null; + if (badRange(from, toInclusive)) { + return this.bsBuilder().ofAll(Iterator.rangeClosed(from, toInclusive)); + } else { + return BitSet.rangeClosed(from, toInclusive); + } } @Override protected BitSet rangeClosedBy(long from, long toInclusive, long step) { - return null; + if (badRange(from, toInclusive)) { + return this.bsBuilder().ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); + } else { + return BitSet.rangeClosedBy(from, toInclusive, step); + } } + // BitSet specific + @Test - public void test1() { + public void testNative() { BitSet bs = BitSet.empty(); bs = bs.add(2); @@ -273,6 +314,9 @@ public void test1() { bs = bs.add(300); assert bs.head() == 2; + bs = bs.add(3000); + assert bs.head() == 2; + bs = bs.remove(2); assert bs.head() == 4; assert !bs.contains(2); @@ -289,7 +333,7 @@ public void test1() { } @Test - public void test2() { + public void testEnums() { BitSet bs = BitSet.withEnum(E.class).empty(); bs = bs.add(E.V2); assert bs.head() == E.V2; @@ -301,11 +345,18 @@ public void test2() { assert bs.contains(E.V3); } - @Test - public void test3() { - BitSet bs = BitSet.empty(); - assert bs.add(1).add(2).init().toList().equals(List.of(1)); - assert bs.add(1).add(70).init().toList().equals(List.of(1)); - assert bs.add(1).add(700).init().toList().equals(List.of(1)); + @Test(expected = IllegalArgumentException.class) + public void shouldThrowAddNegativeElement() { + BitSet.empty().add(-1); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldThrowAddNegativeElements() { + BitSet.empty().addAll(List.of(-1)); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldThrowContainsNegativeElements() { + BitSet.empty().contains(-1); } } From d361562f15a15f057d83b86e1abf1b14b02857b9 Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Sun, 15 May 2016 10:45:47 +0300 Subject: [PATCH 08/11] remove Builder from AbstractBitSet; +tests --- .../java/javaslang/collection/BitSet.java | 121 +++++++++--------- .../java/javaslang/collection/BitSetTest.java | 63 ++++++--- 2 files changed, 106 insertions(+), 78 deletions(-) diff --git a/javaslang/src/main/java/javaslang/collection/BitSet.java b/javaslang/src/main/java/javaslang/collection/BitSet.java index df92e59248..e2a1640764 100644 --- a/javaslang/src/main/java/javaslang/collection/BitSet.java +++ b/javaslang/src/main/java/javaslang/collection/BitSet.java @@ -31,9 +31,7 @@ public interface BitSet extends SortedSet { long serialVersionUID = 1L; - class Builder implements Serializable { - - private static final long serialVersionUID = 1L; + class Builder { final static Builder DEFAULT = new Builder<>(i -> i, i -> i); @@ -54,15 +52,15 @@ public Collector, BitSet> collector() { } public BitSet empty() { - return new BitSetModule.BitSet1<>(this, 0L); + return new BitSetModule.BitSet1<>(fromInt, toInt, 0L); } public BitSet of(T t) { final int value = toInt.apply(t); if(value < BitSetModule.BITS_PER_WORD) { - return new BitSetModule.BitSet1<>(this, 1L << value); + return new BitSetModule.BitSet1<>(fromInt, toInt, 1L << value); } else if(value < 2 * BitSetModule.BITS_PER_WORD) { - return new BitSetModule.BitSet2<>(this, 0L, 1L << value); + return new BitSetModule.BitSet2<>(fromInt, toInt, 0L, 1L << value); } else { return empty().add(t); } @@ -71,13 +69,7 @@ public BitSet of(T t) { @SuppressWarnings("varargs") @SafeVarargs public final BitSet of(T... values) { - if(values.length == 0) { - return empty(); - } else if(values.length == 1) { - return of(values[0]); - } else { - return empty().addAll(Array.wrap(values)); - } + return empty().addAll(Array.wrap(values)); } public BitSet ofAll(Iterable values) { @@ -373,8 +365,7 @@ default SortedSet flatMap(Comparator comparator, Function SortedSet flatMap(Function> mapper) { - Objects.requireNonNull(mapper, "mapper is null"); - return TreeSet.ofAll(naturalComparator(), iterator().flatMap(mapper)); + return flatMap(naturalComparator(), mapper); } @Override @@ -591,10 +582,12 @@ abstract class AbstractBitSet implements BitSet { private static final long serialVersionUID = 1L; - Builder builder; + final Function1 fromInt; + final Function1 toInt; - AbstractBitSet(Builder builder) { - this.builder = builder; + AbstractBitSet(Function1 fromInt, Function1 toInt) { + this.fromInt = fromInt; + this.toInt = toInt; } abstract int getWordsNum(); @@ -603,18 +596,26 @@ abstract class AbstractBitSet implements BitSet { abstract long getWord(int index); + BitSet createEmpty() { + return new BitSet1<>(fromInt, toInt, 0L); + } + + BitSet createFromAll(Iterable values) { + return createEmpty().addAll(values); + } + BitSet fromBitMaskNoCopy(long[] elements) { final int len = elements.length; if (len == 0) { - return builder.empty(); + return createEmpty(); } if (len == 1) { - return new BitSet1<>(builder, elements[0]); + return new BitSet1<>(fromInt, toInt, elements[0]); } if (len == 2) { - return new BitSet2<>(builder, elements[0], elements[1]); + return new BitSet2<>(fromInt, toInt, elements[0], elements[1]); } - return new BitSetN<>(builder, elements); + return new BitSetN<>(fromInt, toInt, elements); } private void setElement(long[] words, int element) { @@ -642,7 +643,7 @@ public BitSet add(T t) { if (contains(t)) { return this; } else { - final int element = builder.toInt.apply(t); + final int element = toInt.apply(t); final long[] copy = copyExpand(1 + (element >> ADDRESS_BITS_PER_WORD)); setElement(copy, element); return fromBitMaskNoCopy(copy); @@ -652,13 +653,13 @@ public BitSet add(T t) { @Override public BitSet distinctBy(Comparator comparator) { Objects.requireNonNull(comparator, "comparator is null"); - return builder.ofAll(iterator().distinctBy(comparator)); + return createFromAll(iterator().distinctBy(comparator)); } @Override public BitSet distinctBy(Function keyExtractor) { Objects.requireNonNull(keyExtractor, "keyExtractor is null"); - return builder.ofAll(iterator().distinctBy(keyExtractor)); + return createFromAll(iterator().distinctBy(keyExtractor)); } @Override @@ -666,9 +667,9 @@ public BitSet drop(long n) { if (n <= 0) { return this; } else if (n >= length()) { - return builder.empty(); + return createEmpty(); } else { - return builder.ofAll(iterator().drop(n)); + return createFromAll(iterator().drop(n)); } } @@ -677,16 +678,16 @@ public BitSet dropRight(long n) { if (n <= 0) { return this; } else if (n >= length()) { - return builder.empty(); + return createEmpty(); } else { - return builder.ofAll(iterator().dropRight(n)); + return createFromAll(iterator().dropRight(n)); } } @Override public BitSet dropWhile(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - final BitSet bitSet = builder.ofAll(iterator().dropWhile(predicate)); + final BitSet bitSet = createFromAll(iterator().dropWhile(predicate)); return (bitSet.length() == length()) ? this : bitSet; } @@ -694,13 +695,13 @@ public BitSet dropWhile(Predicate predicate) { public BitSet intersect(Set elements) { Objects.requireNonNull(elements, "elements is null"); if (isEmpty() || elements.isEmpty()) { - return builder.empty(); + return createEmpty(); } else { int size = size(); if (size <= elements.size()) { return retainAll(elements); } else { - BitSet results = builder.ofAll(elements).retainAll(this); + BitSet results = createFromAll(elements).retainAll(this); return (size == results.size()) ? this : results; } } @@ -708,13 +709,13 @@ public BitSet intersect(Set elements) { @Override public Iterator> sliding(long size, long step) { - return iterator().sliding(size, step).map(builder::ofAll); + return iterator().sliding(size, step).map(this::createFromAll); } @Override public Tuple2, BitSet> span(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - return iterator().span(predicate).map(builder::ofAll, builder::ofAll); + return iterator().span(predicate).map(this::createFromAll, this::createFromAll); } @Override @@ -723,44 +724,44 @@ public BitSet scan(T zero, BiFunction oper return Collections.scanLeft(this, zero, operation, new java.util.ArrayList(), (arr, t) -> { arr.add(t); return arr; - }, builder::ofAll); + }, this::createFromAll); } @Override public Tuple2, BitSet> partition(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - return iterator().partition(predicate).map(builder::ofAll, builder::ofAll); + return iterator().partition(predicate).map(this::createFromAll, this::createFromAll); } @Override public BitSet filter(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - final BitSet bitSet = builder.ofAll(iterator().filter(predicate)); + final BitSet bitSet = createFromAll(iterator().filter(predicate)); return (bitSet.length() == length()) ? this : bitSet; } @Override public Map> groupBy(Function classifier) { Objects.requireNonNull(classifier, "classifier is null"); - return iterator().groupBy(classifier).map((key, iterator) -> Tuple.of(key, builder.ofAll(iterator))); + return iterator().groupBy(classifier).map((key, iterator) -> Tuple.of(key, createFromAll(iterator))); } @Override public Comparator comparator() { - return (t1, t2) -> Integer.compare(builder.toInt.apply(t1), builder.toInt.apply(t2)); + return (t1, t2) -> Integer.compare(toInt.apply(t1), toInt.apply(t2)); } @Override public BitSet takeWhile(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - final BitSet result = builder.ofAll(iterator().takeWhile(predicate)); + final BitSet result = createFromAll(iterator().takeWhile(predicate)); return (result.length() == length()) ? this : result; } @Override @SuppressWarnings("unchecked") public BitSet addAll(Iterable elements) { - final Stream source = Stream.ofAll(elements).map(builder.toInt); + final Stream 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) { @@ -773,7 +774,7 @@ public BitSet addAll(Iterable elements) { @Override public boolean contains(T t) { - final int element = builder.toInt.apply(t); + final int element = toInt.apply(t); if (element < 0) { throw new IllegalArgumentException("bitset element must be >= 0"); } @@ -788,7 +789,7 @@ public BitSet init() { } else { final long last = getWord(getWordsNum() - 1); final int element = BITS_PER_WORD * (getWordsNum() - 1) + BITS_PER_WORD - Long.numberOfLeadingZeros(last) - 1; - return remove(builder.fromInt.apply(element)); + return remove(fromInt.apply(element)); } } @@ -796,7 +797,7 @@ public BitSet init() { public Iterator iterator() { return Stream.range(0, getWordsNum() << ADDRESS_BITS_PER_WORD) .filter(i -> (getWord(i >> ADDRESS_BITS_PER_WORD) & (1L << i)) != 0) - .map(builder.fromInt) + .map(fromInt) .iterator(); } @@ -812,29 +813,29 @@ public int length() { @Override public BitSet take(long n) { if (n <= 0) { - return builder.empty(); + return createEmpty(); } else if (n >= length()) { return this; } else { - return builder.ofAll(iterator().take(n)); + return createFromAll(iterator().take(n)); } } @Override public BitSet takeRight(long n) { if (n <= 0) { - return builder.empty(); + return createEmpty(); } else if (n >= length()) { return this; } else { - return builder.ofAll(iterator().takeRight(n)); + return createFromAll(iterator().takeRight(n)); } } @Override public BitSet remove(T t) { if (contains(t)) { - final int element = builder.toInt.apply(t); + final int element = toInt.apply(t); final long[] copy = copyExpand(getWordsNum()); unsetElement(copy, element); return fromBitMaskNoCopy(shrink(copy)); @@ -846,7 +847,7 @@ public BitSet remove(T t) { @Override @SuppressWarnings("unchecked") public BitSet removeAll(Iterable elements) { - final Stream source = Stream.ofAll(elements).map(builder.toInt); + final Stream source = Stream.ofAll(elements).map(toInt); final long[] copy = copyExpand(getWordsNum()); source.forEach(element -> { unsetElement(copy, element); @@ -883,8 +884,8 @@ class BitSet1 extends AbstractBitSet { private final long elements; - BitSet1(Builder builder, long elements) { - super(builder); + BitSet1(Function1 fromInt, Function1 toInt, long elements) { + super(fromInt, toInt); this.elements = elements; } @@ -915,7 +916,7 @@ long getWord(int index) { @Override public T head() { if (elements != 0) { - return builder.fromInt.apply(Long.numberOfTrailingZeros(elements)); + return fromInt.apply(Long.numberOfTrailingZeros(elements)); } throw new NoSuchElementException("head of empty BitSet"); } @@ -927,8 +928,8 @@ class BitSet2 extends AbstractBitSet { private final long elements1, elements2; - BitSet2(Builder builder, long elements1, long elements2) { - super(builder); + BitSet2(Function1 fromInt, Function1 toInt, long elements1, long elements2) { + super(fromInt, toInt); this.elements1 = elements1; this.elements2 = elements2; } @@ -965,9 +966,9 @@ long getWord(int index) { @Override public T head() { if (elements1 != 0) { - return builder.fromInt.apply(Long.numberOfTrailingZeros(elements1)); + return fromInt.apply(Long.numberOfTrailingZeros(elements1)); } else if (elements2 != 0) { - return builder.fromInt.apply(BITS_PER_WORD + Long.numberOfTrailingZeros(elements2)); + return fromInt.apply(BITS_PER_WORD + Long.numberOfTrailingZeros(elements2)); } throw new NoSuchElementException("head of empty BitSet"); } @@ -979,8 +980,8 @@ class BitSetN extends AbstractBitSet { private final long[] elements; - BitSetN(Builder builder, long[] elements) { - super(builder); + BitSetN(Function1 fromInt, Function1 toInt, long[] elements) { + super(fromInt, toInt); this.elements = elements; } @@ -1013,7 +1014,7 @@ public T head() { int offset = 0; for (int i = 0; i < getWordsNum(); i++) { if(elements[i] != 0) { - return builder.fromInt.apply(offset + Long.numberOfTrailingZeros(elements[i])); + return fromInt.apply(offset + Long.numberOfTrailingZeros(elements[i])); } offset += BITS_PER_WORD; } diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java index 7ed3b6cf32..213f6e1e16 100644 --- a/javaslang/src/test/java/javaslang/collection/BitSetTest.java +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -299,37 +299,64 @@ protected BitSet rangeClosedBy(long from, long toInclusive, long step) { // BitSet specific @Test - public void testNative() { + public void testBitSet1() { BitSet bs = BitSet.empty(); bs = bs.add(2); - assert bs.head() == 2; + assertThat(bs.head()).isEqualTo(2); bs = bs.add(4); - assert bs.head() == 2; + assertThat(bs.head()).isEqualTo(2); - bs = bs.add(70); - assert bs.head() == 2; + bs = bs.remove(2); + assertThat(bs.head()).isEqualTo(4); + assertThat(bs.contains(2)).isFalse(); + + bs = bs.remove(4); + assertThat(bs.isEmpty()).isTrue(); + } + + @Test + public void testBitSet2() { + BitSet bs = BitSet.empty(); - bs = bs.add(300); - assert bs.head() == 2; + bs = bs.add(2); + assertThat(bs.head()).isEqualTo(2); - bs = bs.add(3000); - assert bs.head() == 2; + bs = bs.add(70); + assertThat(bs.head()).isEqualTo(2); bs = bs.remove(2); - assert bs.head() == 4; - assert !bs.contains(2); - - bs = bs.remove(4); - assert bs.head() == 70; - assert !bs.contains(4); + assertThat(bs.head()).isEqualTo(70); + assertThat(bs.contains(2)).isFalse(); bs = bs.remove(70); - assert bs.head() == 300; - assert !bs.contains(70); + assertThat(bs.isEmpty()).isTrue(); + } + + @Test + public void testBitSetN() { + BitSet bs = BitSet.empty(); + + bs = bs.add(2); + assertThat(bs.head()).isEqualTo(2); - assert bs.contains(300); + bs = bs.add(700); + assertThat(bs.head()).isEqualTo(2); + + bs = bs.remove(2); + assertThat(bs.head()).isEqualTo(700); + assertThat(bs.contains(2)).isFalse(); + + bs = bs.remove(700); + assertThat(bs.isEmpty()).isTrue(); + } + + @Test + public void testFactories() { + assertThat(BitSet.of(7).contains(7)).isTrue(); // BitSet1 + assertThat(BitSet.of(77).contains(77)).isTrue(); // BitSet2 + assertThat(BitSet.of(777).contains(777)).isTrue(); // BitSetN } @Test From b747801038b9cd7c234c115fa441bf27015b1558 Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Mon, 16 May 2016 22:30:04 +0300 Subject: [PATCH 09/11] BitSet PR comments --- .../java/javaslang/collection/BitSet.java | 142 ++++++++++++------ .../java/javaslang/collection/BitSetTest.java | 46 ++++-- 2 files changed, 126 insertions(+), 62 deletions(-) diff --git a/javaslang/src/main/java/javaslang/collection/BitSet.java b/javaslang/src/main/java/javaslang/collection/BitSet.java index e2a1640764..fb75599c3a 100644 --- a/javaslang/src/main/java/javaslang/collection/BitSet.java +++ b/javaslang/src/main/java/javaslang/collection/BitSet.java @@ -92,8 +92,8 @@ static Builder withRelations(Function1 fromInt, Function1(fromInt, toInt); } - static > Builder withEnum(Class clz) { - final Function1 fromInt = i -> clz.getEnumConstants()[i]; + static > Builder withEnum(Class enumClass) { + final Function1 fromInt = i -> enumClass.getEnumConstants()[i]; final Function1 toInt = Enum::ordinal; return new Builder<>(fromInt, toInt); } @@ -118,7 +118,7 @@ static Builder withShorts() { * Returns a {@link java.util.stream.Collector} which may be used in conjunction with * {@link java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a {@link javaslang.collection.BitSet}. * - * @return A javaslang.collection.List Collector. + * @return A {@link javaslang.collection.BitSet} Collector. */ static Collector, BitSet> collector() { return Builder.DEFAULT.collector(); @@ -143,7 +143,7 @@ static BitSet of(Integer... values) { * @param n The number of elements in the BitSet * @param f The Function computing element values * @return A BitSet consisting of elements {@code f(0),f(1), ..., f(n - 1)} - * @throws NullPointerException if {@code f} are null + * @throws NullPointerException if {@code f} is null */ static BitSet tabulate(int n, Function f) { return Builder.DEFAULT.tabulate(n, f); @@ -155,7 +155,7 @@ static BitSet tabulate(int n, Function f) { * @param n The number of elements in the BitSet * @param s The Supplier computing element values * @return A BitSet of size {@code n}, where each element contains the result supplied by {@code s}. - * @throws NullPointerException if {@code s} are null + * @throws NullPointerException if {@code s} is null */ static BitSet fill(int n, Supplier s) { return Builder.DEFAULT.fill(n, s); @@ -169,7 +169,7 @@ static BitSet ofAll(Iterable values) { * Creates a BitSet based on the elements of a boolean array. * * @param array a boolean array - * @return A new BitSet of Boolean values + * @return A new BitSet of boolean values */ static BitSet ofAll(boolean[] array) { Objects.requireNonNull(array, "array is null"); @@ -180,7 +180,7 @@ static BitSet ofAll(boolean[] array) { * Creates a BitSet based on the elements of a byte array. * * @param array a byte array - * @return A new BitSet of Byte values + * @return A new BitSet of byte values */ static BitSet ofAll(byte[] array) { Objects.requireNonNull(array, "array is null"); @@ -191,7 +191,7 @@ static BitSet ofAll(byte[] array) { * Creates a BitSet based on the elements of a char array. * * @param array a char array - * @return A new BitSet of Character values + * @return A new BitSet of char values */ static BitSet ofAll(char[] array) { Objects.requireNonNull(array, "array is null"); @@ -202,7 +202,7 @@ static BitSet ofAll(char[] array) { * Creates a BitSet based on the elements of an int array. * * @param array an int array - * @return A new BitSet of Integer values + * @return A new BitSet of int values */ static BitSet ofAll(int[] array) { Objects.requireNonNull(array, "array is null"); @@ -213,7 +213,7 @@ static BitSet ofAll(int[] array) { * Creates a BitSet based on the elements of a long array. * * @param array a long array - * @return A new BitSet of Long values + * @return A new BitSet of long values */ static BitSet ofAll(long[] array) { Objects.requireNonNull(array, "array is null"); @@ -224,7 +224,7 @@ static BitSet ofAll(long[] array) { * Creates a BitSet based on the elements of a short array. * * @param array a short array - * @return A new BitSet of Short values + * @return A new BitSet of short values */ static BitSet ofAll(short[] array) { Objects.requireNonNull(array, "array is null"); @@ -492,7 +492,7 @@ default BitSet tail() { if (isEmpty()) { throw new UnsupportedOperationException("tail of empty BitSet"); } else { - return remove(head()); + return drop(1); } } @@ -510,8 +510,7 @@ default Option> tailOption() { @Override default BitSet takeUntil(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - final BitSet result = takeWhile(predicate.negate()); - return (result.length() == length()) ? this : result; + return takeWhile(predicate.negate()); } @Override @@ -608,14 +607,13 @@ BitSet fromBitMaskNoCopy(long[] elements) { final int len = elements.length; if (len == 0) { return createEmpty(); - } - if (len == 1) { + } else if (len == 1) { return new BitSet1<>(fromInt, toInt, elements[0]); - } - if (len == 2) { + } else if (len == 2) { return new BitSet2<>(fromInt, toInt, elements[0], elements[1]); + } else { + return new BitSetN<>(fromInt, toInt, elements); } - return new BitSetN<>(fromInt, toInt, elements); } private void setElement(long[] words, int element) { @@ -779,7 +777,7 @@ public boolean contains(T t) { throw new IllegalArgumentException("bitset element must be >= 0"); } final int index = element >> ADDRESS_BITS_PER_WORD; - return (getWord(index) & (1L << element)) != 0; + return index < getWordsNum() && (getWord(index) & (1L << element)) != 0; } @Override @@ -795,19 +793,7 @@ public BitSet init() { @Override public Iterator iterator() { - return Stream.range(0, getWordsNum() << ADDRESS_BITS_PER_WORD) - .filter(i -> (getWord(i >> ADDRESS_BITS_PER_WORD) & (1L << i)) != 0) - .map(fromInt) - .iterator(); - } - - @Override - public int length() { - int len = 0; - for (int i = 0; i < getWordsNum(); i++) { - len += Long.bitCount(getWord(i)); - } - return len; + return new BitSetIterator<>(this); } @Override @@ -878,15 +864,45 @@ public int hashCode() { } } + class BitSetIterator extends AbstractIterator { + + private final AbstractBitSet bitSet; + private long element; + private int index; + + BitSetIterator(AbstractBitSet bitSet) { + this.bitSet = bitSet; + this.element = bitSet.getWord(0); + this.index = 0; + } + + @Override + protected T getNext() { + int pos = Long.numberOfTrailingZeros(element); + element &= ~(1L << pos); + return bitSet.fromInt.apply(pos + (index << ADDRESS_BITS_PER_WORD)); + } + + @Override + public boolean hasNext() { + while (element == 0 && index < bitSet.getWordsNum() - 1) { + element = bitSet.getWord(++index); + } + return element != 0 && index < bitSet.getWordsNum(); + } + } + class BitSet1 extends AbstractBitSet { private static final long serialVersionUID = 1L; private final long elements; + private final int len; BitSet1(Function1 fromInt, Function1 toInt, long elements) { super(fromInt, toInt); this.elements = elements; + this.len = Long.bitCount(elements); } @Override @@ -909,16 +925,22 @@ long getWord(int index) { if (index == 0) { return elements; } else { - return 0L; + throw new IndexOutOfBoundsException(); } } @Override public T head() { - if (elements != 0) { + if (elements == 0) { + throw new NoSuchElementException("head of empty BitSet"); + } else { return fromInt.apply(Long.numberOfTrailingZeros(elements)); } - throw new NoSuchElementException("head of empty BitSet"); + } + + @Override + public int length() { + return len; } } @@ -927,11 +949,13 @@ class BitSet2 extends AbstractBitSet { private static final long serialVersionUID = 1L; private final long elements1, elements2; + private final int len; BitSet2(Function1 fromInt, Function1 toInt, long elements1, long elements2) { super(fromInt, toInt); this.elements1 = elements1; this.elements2 = elements2; + this.len = Long.bitCount(elements1) + Long.bitCount(elements2); } @Override @@ -954,23 +978,29 @@ long[] copyExpand(int wordsNum) { long getWord(int index) { if (index == 0) { return elements1; + } else if (index == 1) { + return elements2; } else { - if (index == 1) { - return elements2; - } else { - return 0L; - } + throw new IndexOutOfBoundsException(); } } @Override public T head() { - if (elements1 != 0) { + if (elements1 == 0) { + if (elements2 == 0) { + throw new NoSuchElementException("head of empty BitSet"); + } else { + return fromInt.apply(BITS_PER_WORD + Long.numberOfTrailingZeros(elements2)); + } + } else { return fromInt.apply(Long.numberOfTrailingZeros(elements1)); - } else if (elements2 != 0) { - return fromInt.apply(BITS_PER_WORD + Long.numberOfTrailingZeros(elements2)); } - throw new NoSuchElementException("head of empty BitSet"); + } + + @Override + public int length() { + return len; } } @@ -979,10 +1009,20 @@ class BitSetN extends AbstractBitSet { private static final long serialVersionUID = 1L; private final long[] elements; + private final int len; BitSetN(Function1 fromInt, Function1 toInt, long[] elements) { super(fromInt, toInt); this.elements = elements; + this.len = calcLength(elements); + } + + private static int calcLength(long[] elements) { + int len = 0; + for (int i = 0; i < elements.length; i++) { + len += Long.bitCount(elements[i]); + } + return len; } @Override @@ -1005,7 +1045,7 @@ long getWord(int index) { if (index < elements.length) { return elements[index]; } else { - return 0L; + throw new IndexOutOfBoundsException(); } } @@ -1013,12 +1053,18 @@ long getWord(int index) { public T head() { int offset = 0; for (int i = 0; i < getWordsNum(); i++) { - if(elements[i] != 0) { + if(elements[i] == 0) { + offset += BITS_PER_WORD; + } else { return fromInt.apply(offset + Long.numberOfTrailingZeros(elements[i])); } - offset += BITS_PER_WORD; } throw new NoSuchElementException("head of empty BitSet"); } + + @Override + public int length() { + return len; + } } } diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java index 213f6e1e16..f1978b2472 100644 --- a/javaslang/src/test/java/javaslang/collection/BitSetTest.java +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -1,6 +1,5 @@ package javaslang.collection; -import javaslang.Tuple; import javaslang.Tuple2; import javaslang.Tuple3; import org.assertj.core.api.Assertions; @@ -14,6 +13,9 @@ import java.util.function.Supplier; import java.util.stream.Collector; +import static javaslang.Serializables.deserialize; +import static javaslang.Serializables.serialize; + public class BitSetTest extends AbstractSortedSetTest { private final static int MAX_BIT = 1_000_000; @@ -81,6 +83,7 @@ public ObjectAssert isEqualTo(Object expected) { final Tuple3 t2 = (Tuple3) expected; assertThat((Iterable) t1._1).isEqualTo(t2._1); assertThat((Iterable) t1._2).isEqualTo(t2._2); + assertThat((Iterable) t1._3).isEqualTo(t2._3); return this; } else { return super.isEqualTo(expected); @@ -201,17 +204,17 @@ protected BitSet rangeBy(double from, double toExclusive, double step) { return this.bsBuilder().ofAll(Iterator.rangeBy(from, toExclusive, step)); } - private static boolean badRange(int a, int b) { + private static boolean isBadRange(int a, int b) { return a < 0 || b < 0 || a > MAX_BIT || b > MAX_BIT; } - private static boolean badRange(long a, long b) { + private static boolean isBadRange(long a, long b) { return a < 0 || b < 0 || a > MAX_BIT || b > MAX_BIT; } @Override protected BitSet range(int from, int toExclusive) { - if (badRange(from, toExclusive)) { + if (isBadRange(from, toExclusive)) { return this.bsBuilder().ofAll(Iterator.range(from, toExclusive)); } else { return BitSet.range(from, toExclusive); @@ -220,7 +223,7 @@ protected BitSet range(int from, int toExclusive) { @Override protected BitSet rangeBy(int from, int toExclusive, int step) { - if (badRange(from, toExclusive)) { + if (isBadRange(from, toExclusive)) { return this.bsBuilder().ofAll(Iterator.rangeBy(from, toExclusive, step)); } else { return BitSet.rangeBy(from, toExclusive, step); @@ -229,7 +232,7 @@ protected BitSet rangeBy(int from, int toExclusive, int step) { @Override protected BitSet range(long from, long toExclusive) { - if (badRange(from, toExclusive)) { + if (isBadRange(from, toExclusive)) { return this.bsBuilder().ofAll(Iterator.range(from, toExclusive)); } else { return BitSet.range(from, toExclusive); @@ -238,7 +241,7 @@ protected BitSet range(long from, long toExclusive) { @Override protected BitSet rangeBy(long from, long toExclusive, long step) { - if (badRange(from, toExclusive)) { + if (isBadRange(from, toExclusive)) { return this.bsBuilder().ofAll(Iterator.rangeBy(from, toExclusive, step)); } else { return BitSet.rangeBy(from, toExclusive, step); @@ -262,7 +265,7 @@ protected BitSet rangeClosedBy(double from, double toInclusive, double s @Override protected BitSet rangeClosed(int from, int toInclusive) { - if (badRange(from, toInclusive)) { + if (isBadRange(from, toInclusive)) { return this.bsBuilder().ofAll(Iterator.rangeClosed(from, toInclusive)); } else { return BitSet.rangeClosed(from, toInclusive); @@ -271,7 +274,7 @@ protected BitSet rangeClosed(int from, int toInclusive) { @Override protected BitSet rangeClosedBy(int from, int toInclusive, int step) { - if (badRange(from, toInclusive)) { + if (isBadRange(from, toInclusive)) { return this.bsBuilder().ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } else { return BitSet.rangeClosedBy(from, toInclusive, step); @@ -280,7 +283,7 @@ protected BitSet rangeClosedBy(int from, int toInclusive, int step) { @Override protected BitSet rangeClosed(long from, long toInclusive) { - if (badRange(from, toInclusive)) { + if (isBadRange(from, toInclusive)) { return this.bsBuilder().ofAll(Iterator.rangeClosed(from, toInclusive)); } else { return BitSet.rangeClosed(from, toInclusive); @@ -289,7 +292,7 @@ protected BitSet rangeClosed(long from, long toInclusive) { @Override protected BitSet rangeClosedBy(long from, long toInclusive, long step) { - if (badRange(from, toInclusive)) { + if (isBadRange(from, toInclusive)) { return this.bsBuilder().ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } else { return BitSet.rangeClosedBy(from, toInclusive, step); @@ -354,9 +357,9 @@ public void testBitSetN() { @Test public void testFactories() { - assertThat(BitSet.of(7).contains(7)).isTrue(); // BitSet1 - assertThat(BitSet.of(77).contains(77)).isTrue(); // BitSet2 - assertThat(BitSet.of(777).contains(777)).isTrue(); // BitSetN + assertThat(BitSet.of(7).contains(7)).isTrue(); // BitSet1, < 64 + assertThat(BitSet.of(77).contains(77)).isTrue(); // BitSet2, < 2*64 + assertThat(BitSet.of(777).contains(777)).isTrue(); // BitSetN, >= 2*64 } @Test @@ -386,4 +389,19 @@ public void shouldThrowAddNegativeElements() { public void shouldThrowContainsNegativeElements() { BitSet.empty().contains(-1); } + + @Test + public void shouldSerializeDeserializeNativeBitSet() { + final Object actual = deserialize(serialize(BitSet.of(1, 2, 3))); + final Object expected = BitSet.of(1, 2, 3); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void shouldSerializeDeserializeEnumBitSet() { + final Object actual = deserialize(serialize(BitSet.withEnum(E.class).of(E.V1, E.V2))); + final Object expected = BitSet.withEnum(E.class).of(E.V1, E.V2); + assertThat(actual).isEqualTo(expected); + } + } From 39626f5ec97b5be2d11762ef43b8392c5d723612 Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Tue, 17 May 2016 21:29:16 +0300 Subject: [PATCH 10/11] BitSetTest: comparison with java.util.BitSet --- .../java/javaslang/AbstractValueTest.java | 12 +++++ .../java/javaslang/collection/BitSetTest.java | 46 ++++++++++++++++++- .../collection/PriorityQueueTest.java | 12 ----- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/javaslang/src/test/java/javaslang/AbstractValueTest.java b/javaslang/src/test/java/javaslang/AbstractValueTest.java index 2e5918fd97..ae9dbd58eb 100644 --- a/javaslang/src/test/java/javaslang/AbstractValueTest.java +++ b/javaslang/src/test/java/javaslang/AbstractValueTest.java @@ -27,6 +27,18 @@ public abstract class AbstractValueTest { + protected Random getRandom(int seed) { + if (seed >= 0) { + return new Random(seed); + } else { + final Random random = new Random(); + seed = random.nextInt(); + System.out.println("using seed: " + seed); + random.setSeed(seed); + return random; + } + } + protected IterableAssert assertThat(Iterable actual) { return new IterableAssert(actual) { }; diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java index f1978b2472..47255c9ed3 100644 --- a/javaslang/src/test/java/javaslang/collection/BitSetTest.java +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -8,11 +8,13 @@ import org.junit.Test; import java.io.Serializable; -import java.util.ArrayList; +import java.util.*; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; +import java.util.stream.Collectors; +import static java.util.stream.Collectors.toList; import static javaslang.Serializables.deserialize; import static javaslang.Serializables.serialize; @@ -404,4 +406,46 @@ public void shouldSerializeDeserializeEnumBitSet() { assertThat(actual).isEqualTo(expected); } + @Test + public void shouldBehaveExactlyLikeAnotherBitSet() { + for (int i = 0; i < 10; i++) { + final Random random = getRandom(-1); + + final java.util.BitSet mutableBitSet = new java.util.BitSet(); + javaslang.collection.BitSet functionalBitSet = javaslang.collection.BitSet.empty(); + + final int size = 5_000; + for (int j = 0; j < size; j++) { + /* Insert */ + if (random.nextInt() % 3 == 0) { + assertMinimumsAreEqual(mutableBitSet, functionalBitSet); + + final int value = random.nextInt(size); + mutableBitSet.set(value); + functionalBitSet = functionalBitSet.add(value); + } + + assertMinimumsAreEqual(mutableBitSet, functionalBitSet); + + /* Delete */ + if (random.nextInt() % 5 == 0) { + if (!mutableBitSet.isEmpty()) { mutableBitSet.clear(mutableBitSet.nextSetBit(0)); } + if (!functionalBitSet.isEmpty()) { functionalBitSet = functionalBitSet.tail(); } + + assertMinimumsAreEqual(mutableBitSet, functionalBitSet); + } + } + + final Collection oldValues = mutableBitSet.stream().sorted().boxed().collect(toList()); + final Collection newValues = functionalBitSet.toJavaList(); + assertThat(oldValues).isEqualTo(newValues); + } + } + + private void assertMinimumsAreEqual(java.util.BitSet oldSet, BitSet newSet) { + assertThat(oldSet.isEmpty()).isEqualTo(newSet.isEmpty()); + if (!newSet.isEmpty()) { + assertThat(oldSet.nextSetBit(0)).isEqualTo(newSet.head()); + } + } } diff --git a/javaslang/src/test/java/javaslang/collection/PriorityQueueTest.java b/javaslang/src/test/java/javaslang/collection/PriorityQueueTest.java index 0bbd06c74e..634d5580df 100644 --- a/javaslang/src/test/java/javaslang/collection/PriorityQueueTest.java +++ b/javaslang/src/test/java/javaslang/collection/PriorityQueueTest.java @@ -258,18 +258,6 @@ public void shouldBehaveExactlyLikeAnotherPriorityQueue() { } } - private Random getRandom(int seed) { - if (seed >= 0) { - return new Random(seed); - } else { - final Random random = new Random(); - seed = random.nextInt(); - System.out.println("using seed: " + seed); - random.setSeed(seed); - return random; - } - } - private void assertMinimumsAreEqual(java.util.PriorityQueue oldQueue, PriorityQueue newQueue) { assertThat(oldQueue.isEmpty()).isEqualTo(newQueue.isEmpty()); if (!newQueue.isEmpty()) { From af641d36b8188bfd4b5d84ae360b3bb387ff6fbc Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Wed, 18 May 2016 07:46:22 +0300 Subject: [PATCH 11/11] relax types of BitSet conversion functions --- .../java/javaslang/collection/BitSet.java | 67 ++++++++++++------- .../java/javaslang/collection/BitSetTest.java | 2 +- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/javaslang/src/main/java/javaslang/collection/BitSet.java b/javaslang/src/main/java/javaslang/collection/BitSet.java index fb75599c3a..4610e66347 100644 --- a/javaslang/src/main/java/javaslang/collection/BitSet.java +++ b/javaslang/src/main/java/javaslang/collection/BitSet.java @@ -5,7 +5,6 @@ */ package javaslang.collection; -import javaslang.Function1; import javaslang.Tuple; import javaslang.Tuple2; import javaslang.Tuple3; @@ -33,12 +32,15 @@ public interface BitSet extends SortedSet { class Builder { - final static Builder DEFAULT = new Builder<>(i -> i, i -> i); + final static Builder DEFAULT = new Builder<>( + (Function & Serializable) i -> i, + (Function & Serializable) i -> i + ); - final Function1 fromInt; - final Function1 toInt; + final Function fromInt; + final Function toInt; - Builder(Function1 fromInt, Function1 toInt) { + Builder(Function fromInt, Function toInt) { this.fromInt = fromInt; this.toInt = toInt; } @@ -88,30 +90,47 @@ public BitSet fill(int n, Supplier s) { } } - static Builder withRelations(Function1 fromInt, Function1 toInt) { + /** + * Both functions should be serializable + * TODO javadoc + */ + static Builder withRelations(Function fromInt, Function toInt) { return new Builder<>(fromInt, toInt); } static > Builder withEnum(Class enumClass) { - final Function1 fromInt = i -> enumClass.getEnumConstants()[i]; - final Function1 toInt = Enum::ordinal; - return new Builder<>(fromInt, toInt); + return new Builder<>( + (Function & Serializable) i -> enumClass.getEnumConstants()[i], + (Function & Serializable) Enum::ordinal + ); } static Builder withCharacters() { - return new Builder<>(i -> (char) i.intValue(), c -> (int) c); + return new Builder<>( + (Function & Serializable) i -> (char) i.intValue(), + (Function & Serializable) c -> (int) c + ); } static Builder withBytes() { - return new Builder<>(Integer::byteValue, Byte::intValue); + return new Builder<>( + (Function & Serializable) Integer::byteValue, + (Function & Serializable) Byte::intValue + ); } static Builder withLongs() { - return new Builder<>(Integer::longValue, Long::intValue); + return new Builder<>( + (Function & Serializable) Integer::longValue, + (Function & Serializable) Long::intValue + ); } static Builder withShorts() { - return new Builder<>(Integer::shortValue, Short::intValue); + return new Builder<>( + (Function & Serializable) Integer::shortValue, + (Function & Serializable) Short::intValue + ); } /** @@ -173,7 +192,10 @@ static BitSet ofAll(Iterable values) { */ static BitSet ofAll(boolean[] array) { Objects.requireNonNull(array, "array is null"); - return BitSet.withRelations(i -> i != 0, b -> b ? 1 : 0).ofAll(Iterator.ofAll(array)); + return BitSet.withRelations( + (Function & Serializable) i -> i != 0, + (Function & Serializable) b -> b ? 1 : 0 + ).ofAll(Iterator.ofAll(array)); } /** @@ -527,7 +549,6 @@ default BitSet union(Set elements) { return addAll(elements); } - // TODO @Override default Tuple2, TreeSet> unzip( Function> unzipper) { @@ -536,7 +557,6 @@ default Tuple2, TreeSet> unzip( i2 -> TreeSet.ofAll(naturalComparator(), i2)); } - // TODO @Override default Tuple3, TreeSet, TreeSet> unzip3( Function> unzipper) { @@ -547,7 +567,6 @@ default Tuple3, TreeSet, TreeSet> unzip3( i3 -> TreeSet.ofAll(naturalComparator(), i3)); } - // TODO @Override default TreeSet> zip(Iterable that) { Objects.requireNonNull(that, "that is null"); @@ -555,7 +574,6 @@ default TreeSet> zip(Iterable that) { return TreeSet.ofAll(tuple2Comparator, iterator().zip(that)); } - // TODO @Override default TreeSet> zipAll(Iterable that, T thisElem, U thatElem) { Objects.requireNonNull(that, "that is null"); @@ -563,7 +581,6 @@ default TreeSet> zipAll(Iterable that, T thisElem, return TreeSet.ofAll(tuple2Comparator, iterator().zipAll(that, thisElem, thatElem)); } - // TODO @Override default TreeSet> zipWithIndex() { final Comparator component1Comparator = comparator(); @@ -581,10 +598,10 @@ abstract class AbstractBitSet implements BitSet { private static final long serialVersionUID = 1L; - final Function1 fromInt; - final Function1 toInt; + final Function fromInt; + final Function toInt; - AbstractBitSet(Function1 fromInt, Function1 toInt) { + AbstractBitSet(Function fromInt, Function toInt) { this.fromInt = fromInt; this.toInt = toInt; } @@ -899,7 +916,7 @@ class BitSet1 extends AbstractBitSet { private final long elements; private final int len; - BitSet1(Function1 fromInt, Function1 toInt, long elements) { + BitSet1(Function fromInt, Function toInt, long elements) { super(fromInt, toInt); this.elements = elements; this.len = Long.bitCount(elements); @@ -951,7 +968,7 @@ class BitSet2 extends AbstractBitSet { private final long elements1, elements2; private final int len; - BitSet2(Function1 fromInt, Function1 toInt, long elements1, long elements2) { + BitSet2(Function fromInt, Function toInt, long elements1, long elements2) { super(fromInt, toInt); this.elements1 = elements1; this.elements2 = elements2; @@ -1011,7 +1028,7 @@ class BitSetN extends AbstractBitSet { private final long[] elements; private final int len; - BitSetN(Function1 fromInt, Function1 toInt, long[] elements) { + BitSetN(Function fromInt, Function toInt, long[] elements) { super(fromInt, toInt); this.elements = elements; this.len = calcLength(elements); diff --git a/javaslang/src/test/java/javaslang/collection/BitSetTest.java b/javaslang/src/test/java/javaslang/collection/BitSetTest.java index 47255c9ed3..3c85a6885e 100644 --- a/javaslang/src/test/java/javaslang/collection/BitSetTest.java +++ b/javaslang/src/test/java/javaslang/collection/BitSetTest.java @@ -96,7 +96,7 @@ public ObjectAssert isEqualTo(Object expected) { private BitSet.Builder bsBuilder() { Mapper mapper = new Mapper<>(); - return BitSet.withRelations(mapper::fromInt, mapper::toInt); + return BitSet.withRelations((Function & Serializable) mapper::fromInt, (Function & Serializable) mapper::toInt); } @Override