├── .gitignore ├── .travis.yml ├── License.txt ├── Readme.md ├── pom.xml └── src ├── main └── java │ ├── module-info.java │ └── org │ └── paumard │ ├── spliterators │ ├── AccumulatingEntriesSpliterator.java │ ├── AccumulatingSpliterator.java │ ├── CrossProductOrderedSpliterator.java │ ├── CyclingSpliterator.java │ ├── FilteringAllMaxSpliterator.java │ ├── FilteringMaxKeysSpliterator.java │ ├── FilteringMaxValuesSpliterator.java │ ├── GatingSpliterator.java │ ├── GroupingOnGatingSpliterator.java │ ├── GroupingOnSplittingSpliterator.java │ ├── GroupingSpliterator.java │ ├── InterruptingSpliterator.java │ ├── RepeatingSpliterator.java │ ├── RollingOfDoubleSpliterator.java │ ├── RollingOfIntSpliterator.java │ ├── RollingOfLongSpliterator.java │ ├── RollingSpliterator.java │ ├── TraversingSpliterator.java │ ├── ValidatingSpliterator.java │ ├── WeavingSpliterator.java │ └── ZippingSpliterator.java │ └── streams │ └── StreamsUtils.java └── test └── java └── org └── paumard └── spliterators ├── AccumulatingEntriesSpliteratorTest.java ├── AccumulatingSpliteratorTest.java ├── CrossProductNaturalyOrderedSpliteratorTest.java ├── CrossProductNoDoublesSpliteratorTest.java ├── CrossProductSpliteratorTest.java ├── CyclingSpliteratorTest.java ├── FilteringAllMaxSpliteratorTest.java ├── FilteringMaxKeysSpliteratorTest.java ├── FilteringMaxValuesSpliteratorTest.java ├── GatingSpliteratorTest.java ├── GroupingOnGatingClosedClosedSpliteratorTest.java ├── GroupingOnGatingClosedOpenedSpliteratorTest.java ├── GroupingOnGatingOpenedClosedSpliteratorTest.java ├── GroupingOnGatingSpliteratorTest.java ├── GroupingOnSplittingNonIncludedSpliteratorTest.java ├── GroupingOnSplittingSpliteratorTest.java ├── GroupingSpliteratorTest.java ├── InterruptingSpliteratorTest.java ├── RepeatingSpliteratorTest.java ├── RollingSpliteratorTest.java ├── ShiftingWindowAveragingDoubleTest.java ├── ShiftingWindowAveragingIntTest.java ├── ShiftingWindowAveragingLongTest.java ├── ShiftingWindowCollectTest.java ├── ShiftingWindowSummarizingDoubleTest.java ├── ShiftingWindowSummarizingIntTest.java ├── ShiftingWindowSummarizingLongTest.java ├── TraversingSpliteratorTest.java ├── ValidatingSpliteratorTest.java ├── WeavingSpliteratorTest.java ├── ZippingSpliteratorTest.java └── util └── TryAdvanceCheckingSpliterator.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.iml 3 | .classpath 4 | .project 5 | .settings/ 6 | bin/ 7 | .idea/ 8 | notes-to-self.txt -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | install: 3 | - mvn install -DskipTests=true -Dgpg.skip=true -B -V 4 | jdk: 5 | - oraclejdk9 6 | after_success: 7 | - mvn clean test jacoco:report coveralls:report -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | org.paumard::streams-utils 9 | 10 | 11 | Streams Utils is a set of operations written on Java 8 Streams. It allows several basic operations that 12 | are not available in the Java 8 JDK, and that have proven to be very useful in some cases. 13 | 14 | 15 | http://github.com/JosePaumard/streams-utils 16 | 17 | org.paumard 18 | streams-utils 19 | 2.1.1 20 | 21 | 22 | 9 23 | 9 24 | UTF-8 25 | 6.10 26 | 3.8.0 27 | 0.8.2 28 | 4.3.0 29 | 30 | 31 | 2015 32 | 33 | 34 | 35 | The Apache Software License, Version 2.0 36 | http://www.apache.org/licenses/LICENSE-2.0.txt 37 | 38 | 39 | 40 | 41 | 3.5.0 42 | 43 | 44 | 45 | scm:git:https://github.com/JosePaumard/streams-utils.git 46 | scm:git:git@github.com:JosePaumard/streams-utils.git 47 | https://github.com/JosePaumard/streams-utils 48 | 49 | 50 | 51 | 52 | jose-paumard 53 | José Paumard 54 | Jose.Paumard@gmail.com 55 | Very independant 56 | http://blog.paumard.org 57 | 58 | owner 59 | developer 60 | 61 | +1 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.testng 69 | testng 70 | ${testng.version} 71 | test 72 | 73 | 74 | 75 | org.assertj 76 | assertj-core 77 | ${assertj.version} 78 | test 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | org.jacoco 87 | jacoco-maven-plugin 88 | ${jacoco-maven-plugin.version} 89 | 90 | 91 | prepare-agent 92 | 93 | prepare-agent 94 | 95 | 96 | 97 | 98 | 99 | 100 | org.eluder.coveralls 101 | coveralls-maven-plugin 102 | ${coveralls-maven-plugin.version} 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | release 111 | 112 | 113 | 114 | org.apache.maven.plugins 115 | maven-javadoc-plugin 116 | 117 | 118 | attach-javadocs 119 | 120 | jar 121 | 122 | 123 | 124 | 125 | 126 | org.apache.maven.plugins 127 | maven-source-plugin 128 | 3.0.0 129 | 130 | 131 | attach-sources 132 | 133 | jar-no-fork 134 | 135 | 136 | 137 | 138 | 139 | org.apache.maven.plugins 140 | maven-gpg-plugin 141 | 1.5 142 | 143 | 144 | sign-artifacts 145 | verify 146 | 147 | sign 148 | 149 | 150 | 151 | 152 | 153 | org.sonatype.plugins 154 | nexus-staging-maven-plugin 155 | 1.6.3 156 | true 157 | 158 | ossrh 159 | https://oss.sonatype.org/ 160 | true 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | ossrh 172 | https://oss.sonatype.org/content/repositories/snapshots 173 | 174 | 175 | ossrh 176 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module org.paumard.streams.utils { 2 | 3 | exports org.paumard.streams; 4 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/AccumulatingEntriesSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Map; 22 | import java.util.Objects; 23 | import java.util.Spliterator; 24 | import java.util.concurrent.atomic.AtomicReference; 25 | import java.util.function.BinaryOperator; 26 | import java.util.function.Consumer; 27 | 28 | /** 29 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 30 | *

31 | * Created by José 32 | */ 33 | public class AccumulatingEntriesSpliterator implements Spliterator> { 34 | 35 | private BinaryOperator operator; 36 | private final Spliterator> spliterator; 37 | private AtomicReference accumulator; 38 | 39 | public static AccumulatingEntriesSpliterator of(Spliterator> spliterator, BinaryOperator operator) { 40 | 41 | Objects.requireNonNull(spliterator); 42 | Objects.requireNonNull(operator); 43 | 44 | if ((spliterator.characteristics() & Spliterator.ORDERED) == 0) { 45 | throw new IllegalArgumentException(("Why would you try to accumulate a non-ORDERED spliterator?")); 46 | } 47 | 48 | return new AccumulatingEntriesSpliterator<>(spliterator, operator); 49 | } 50 | 51 | private AccumulatingEntriesSpliterator(Spliterator> spliterator, BinaryOperator operator) { 52 | this.spliterator = spliterator; 53 | this.operator = operator; 54 | } 55 | 56 | @Override 57 | public boolean tryAdvance(Consumer> action) { 58 | boolean hasMore = spliterator.tryAdvance( 59 | entry -> { 60 | if (accumulator == null) { 61 | accumulator = new AtomicReference<>(entry.getValue()); 62 | action.accept(entry); 63 | } else { 64 | entry.setValue(accumulator.accumulateAndGet(entry.getValue(), operator)); 65 | action.accept(entry); 66 | } 67 | } 68 | ); 69 | 70 | return hasMore; 71 | } 72 | 73 | @Override 74 | public Spliterator> trySplit() { 75 | Spliterator> splitSpliterator = spliterator.trySplit(); 76 | return splitSpliterator == null ? null : new AccumulatingEntriesSpliterator<>(splitSpliterator, operator); 77 | } 78 | 79 | @Override 80 | public long estimateSize() { 81 | return spliterator.estimateSize(); 82 | } 83 | 84 | @Override 85 | public int characteristics() { 86 | return this.spliterator.characteristics(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/AccumulatingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.concurrent.atomic.AtomicReference; 24 | import java.util.function.BinaryOperator; 25 | import java.util.function.Consumer; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | *

30 | * Created by José 31 | */ 32 | public class AccumulatingSpliterator implements Spliterator { 33 | 34 | private BinaryOperator operator; 35 | private final Spliterator spliterator; 36 | private AtomicReference accumulator; 37 | 38 | public static AccumulatingSpliterator of(Spliterator spliterator, BinaryOperator operator) { 39 | 40 | Objects.requireNonNull(spliterator); 41 | Objects.requireNonNull(operator); 42 | 43 | if ((spliterator.characteristics() & Spliterator.ORDERED) == 0) { 44 | throw new IllegalArgumentException(("Why would you try to accumulate a non-ORDERED spliterator?")); 45 | } 46 | 47 | return new AccumulatingSpliterator<>(spliterator, operator); 48 | } 49 | 50 | private AccumulatingSpliterator(Spliterator spliterator, BinaryOperator operator) { 51 | this.spliterator = spliterator; 52 | this.operator = operator; 53 | } 54 | 55 | @Override 56 | public boolean tryAdvance(Consumer action) { 57 | boolean hasMore = spliterator.tryAdvance( 58 | e -> { 59 | if (accumulator == null) { 60 | accumulator = new AtomicReference<>(e); 61 | action.accept(e); 62 | } else { 63 | action.accept(accumulator.accumulateAndGet(e, operator)); 64 | } 65 | } 66 | ); 67 | 68 | return hasMore; 69 | } 70 | 71 | @Override 72 | public Spliterator trySplit() { 73 | Spliterator splitSpliterator = spliterator.trySplit(); 74 | return splitSpliterator == null ? null : new AccumulatingSpliterator<>(splitSpliterator, operator); 75 | } 76 | 77 | @Override 78 | public long estimateSize() { 79 | return spliterator.estimateSize(); 80 | } 81 | 82 | @Override 83 | public int characteristics() { 84 | return this.spliterator.characteristics(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/CrossProductOrderedSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import java.util.*; 20 | import java.util.function.BiConsumer; 21 | import java.util.function.Consumer; 22 | import java.util.function.Function; 23 | import java.util.function.UnaryOperator; 24 | import java.util.stream.Collectors; 25 | import java.util.stream.Stream; 26 | 27 | /** 28 | * Created by José 29 | */ 30 | public class CrossProductOrderedSpliterator implements Spliterator> { 31 | 32 | private Spliterator spliterator; 33 | private List buffer = new ArrayList<>(); 34 | private UnaryOperator estimateSize; 35 | 36 | private final Function>, BiConsumer> function; 37 | private boolean hasMore = true; 38 | private Iterator> iterator; 39 | private boolean consumingIterator = false; 40 | 41 | public static CrossProductOrderedSpliterator ordered(Spliterator spliterator, Comparator comparator) { 42 | return new CrossProductOrderedSpliterator<>( 43 | spliterator, 44 | a -> (e1, e2) -> { 45 | int compare = comparator.compare(e2, e1); 46 | if (compare > 0) { 47 | a.accept(new AbstractMap.SimpleImmutableEntry<>(e1, e2)); 48 | } else if (compare < 0) { 49 | a.accept(new AbstractMap.SimpleImmutableEntry<>(e2, e1)); 50 | } 51 | }, 52 | estimateSize -> (estimateSize == Long.MAX_VALUE) || (estimateSize * (estimateSize - 1) / 2 < estimateSize) ? 53 | Long.MAX_VALUE : estimateSize * (estimateSize - 1) / 2); 54 | } 55 | 56 | public static CrossProductOrderedSpliterator noDoubles(Spliterator spliterator) { 57 | return new CrossProductOrderedSpliterator<>( 58 | spliterator, 59 | a -> (e1, e2) -> { 60 | if (!e1.equals(e2)) { 61 | a.accept(new AbstractMap.SimpleImmutableEntry<>(e1, e2)); 62 | a.accept(new AbstractMap.SimpleImmutableEntry<>(e2, e1)); 63 | } 64 | }, 65 | estimateSize -> (estimateSize == Long.MAX_VALUE) || (estimateSize * (estimateSize - 1) < estimateSize) ? 66 | Long.MAX_VALUE : (estimateSize * (estimateSize - 1))); 67 | } 68 | 69 | public static CrossProductOrderedSpliterator of(Spliterator spliterator) { 70 | return new CrossProductOrderedSpliterator<>( 71 | spliterator, 72 | a -> (e1, e2) -> { 73 | if (e1.equals(e2)) { 74 | a.accept(new AbstractMap.SimpleImmutableEntry<>(e1, e2)); 75 | } else { 76 | a.accept(new AbstractMap.SimpleImmutableEntry<>(e1, e2)); 77 | a.accept(new AbstractMap.SimpleImmutableEntry<>(e2, e1)); 78 | } 79 | }, 80 | estimateSize -> (estimateSize == Long.MAX_VALUE) || (estimateSize * estimateSize < estimateSize) ? 81 | Long.MAX_VALUE : estimateSize * estimateSize 82 | ); 83 | } 84 | 85 | private CrossProductOrderedSpliterator( 86 | Spliterator spliterator, 87 | Function>, BiConsumer> function, 88 | UnaryOperator estimateSize) { 89 | 90 | this.spliterator = spliterator; 91 | this.function = function; 92 | this.estimateSize = estimateSize; 93 | } 94 | 95 | @Override 96 | public boolean tryAdvance(Consumer> action) { 97 | 98 | Stream.Builder> builder = Stream.builder(); 99 | if (consumingIterator) { 100 | if (iterator.hasNext()) { 101 | action.accept(iterator.next()); 102 | return true; 103 | } else { 104 | consumingIterator = false; 105 | } 106 | } 107 | if (hasMore) { 108 | fillBuilder(builder); 109 | consumingIterator = true; 110 | } 111 | 112 | List> entryList = builder.build().collect(Collectors.toList()); 113 | while (entryList.isEmpty() && hasMore) { 114 | builder = Stream.builder(); 115 | fillBuilder(builder); 116 | entryList = builder.build().collect(Collectors.toList()); 117 | } 118 | iterator = entryList.iterator(); 119 | if (iterator.hasNext()) { 120 | action.accept(iterator.next()); 121 | return true; 122 | } 123 | 124 | return false; 125 | } 126 | 127 | private void fillBuilder(Stream.Builder> builder) { 128 | BiConsumer biConsumer = function.apply(builder::add); 129 | hasMore = spliterator.tryAdvance( 130 | e1 -> { 131 | buffer.add(e1); 132 | buffer.forEach(e2 -> biConsumer.accept(e1, e2)); 133 | } 134 | ); 135 | } 136 | 137 | @Override 138 | public Spliterator> trySplit() { 139 | return null; 140 | } 141 | 142 | @Override 143 | public long estimateSize() { 144 | long estimateSize = this.spliterator.estimateSize(); 145 | return this.estimateSize.apply(estimateSize); 146 | } 147 | 148 | @Override 149 | public int characteristics() { 150 | return this.spliterator.characteristics() & ~Spliterator.SORTED; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/CyclingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import java.util.List; 20 | import java.util.Objects; 21 | import java.util.Spliterator; 22 | import java.util.function.Consumer; 23 | import java.util.stream.Stream; 24 | import java.util.stream.StreamSupport; 25 | 26 | import static java.util.stream.Collectors.toList; 27 | 28 | /** 29 | * Created by José 30 | */ 31 | public class CyclingSpliterator implements Spliterator> { 32 | 33 | private final List list; 34 | 35 | public static CyclingSpliterator of(Spliterator spliterator) { 36 | Objects.requireNonNull(spliterator); 37 | return new CyclingSpliterator<>(spliterator); 38 | } 39 | 40 | private CyclingSpliterator(List list) { 41 | this.list = list; 42 | } 43 | 44 | private CyclingSpliterator(Spliterator spliterator) { 45 | this.list = StreamSupport.stream(spliterator, false).collect(toList()); 46 | } 47 | 48 | @Override 49 | public boolean tryAdvance(Consumer> action) { 50 | action.accept(list.stream()); 51 | return true; 52 | } 53 | 54 | @Override 55 | public Spliterator> trySplit() { 56 | return new CyclingSpliterator<>(list); 57 | } 58 | 59 | @Override 60 | public long estimateSize() { 61 | return Long.MAX_VALUE; 62 | } 63 | 64 | @Override 65 | public int characteristics() { 66 | return Spliterator.ORDERED; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/FilteringAllMaxSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.*; 22 | import java.util.function.Consumer; 23 | import java.util.stream.Collectors; 24 | import java.util.stream.Stream; 25 | 26 | /** 27 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 28 | * 29 | * @author José 30 | */ 31 | public class FilteringAllMaxSpliterator implements Spliterator { 32 | 33 | private final Spliterator spliterator; 34 | private final Comparator comparator; 35 | 36 | private Stream.Builder builder = Stream.builder(); 37 | private E currentMax; 38 | private boolean hasMore = true; 39 | private boolean maxesBuilt = false; 40 | private Iterator maxes; 41 | 42 | public static FilteringAllMaxSpliterator of( 43 | Spliterator spliterator, 44 | Comparator comparator) { 45 | Objects.requireNonNull(spliterator); 46 | Objects.requireNonNull(comparator); 47 | 48 | return new FilteringAllMaxSpliterator<>(spliterator, comparator); 49 | } 50 | 51 | private FilteringAllMaxSpliterator( 52 | Spliterator spliterator, 53 | Comparator comparator) { 54 | this.spliterator = spliterator; 55 | this.comparator = comparator; 56 | } 57 | 58 | @Override 59 | public boolean tryAdvance(Consumer action) { 60 | 61 | while (hasMore) { 62 | hasMore = spliterator.tryAdvance(e -> { 63 | if (currentMax == null) { 64 | currentMax = e; 65 | builder.add(e); 66 | } else if (comparator.compare(currentMax, e) == 0) { 67 | builder.add(e); 68 | } else if (comparator.compare(currentMax, e) < 0) { 69 | currentMax = e; 70 | builder = Stream.builder(); 71 | builder.add(e); 72 | } 73 | }); 74 | } 75 | 76 | if (!maxesBuilt) { 77 | maxes = builder.build().collect(Collectors.toList()).iterator(); 78 | maxesBuilt = true; 79 | } 80 | if (maxesBuilt && maxes.hasNext()) { 81 | action.accept(maxes.next()); 82 | return true; 83 | } 84 | 85 | return false; 86 | } 87 | 88 | @Override 89 | public Spliterator trySplit() { 90 | return null; 91 | } 92 | 93 | @Override 94 | public long estimateSize() { 95 | return 0L; 96 | } 97 | 98 | @Override 99 | public int characteristics() { 100 | return spliterator.characteristics() & ~Spliterator.SIZED & ~Spliterator.SUBSIZED; 101 | } 102 | 103 | @Override 104 | public Comparator getComparator() { 105 | return this.spliterator.getComparator(); 106 | } 107 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/FilteringMaxKeysSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.lang.reflect.Array; 22 | import java.util.*; 23 | import java.util.function.Consumer; 24 | import java.util.stream.Collectors; 25 | import java.util.stream.Stream; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class FilteringMaxKeysSpliterator implements Spliterator { 33 | 34 | private final Spliterator spliterator; 35 | private final Comparator comparator; 36 | private final int numberOfMaxes; 37 | private boolean hasMore = true; 38 | private Iterator maxes; 39 | private boolean maxesBuilt = false; 40 | 41 | public static FilteringMaxKeysSpliterator of( 42 | Spliterator spliterator, 43 | int numberOfMaxes, 44 | Comparator comparator) { 45 | Objects.requireNonNull(spliterator); 46 | Objects.requireNonNull(comparator); 47 | if (numberOfMaxes < 2) { 48 | throw new IllegalArgumentException("numberOfMaxes should not be less than 2?"); 49 | } 50 | 51 | return new FilteringMaxKeysSpliterator<>(spliterator, numberOfMaxes, comparator); 52 | } 53 | 54 | private FilteringMaxKeysSpliterator( 55 | Spliterator spliterator, 56 | int numberOfMaxes, 57 | Comparator comparator) { 58 | this.spliterator = spliterator; 59 | this.numberOfMaxes = numberOfMaxes; 60 | this.comparator = comparator; 61 | } 62 | 63 | @Override 64 | public boolean tryAdvance(Consumer action) { 65 | 66 | InsertionTab insertionTab = new InsertionTab<>(this.numberOfMaxes, this.comparator); 67 | while (hasMore) { 68 | hasMore = spliterator.tryAdvance(insertionTab); 69 | } 70 | 71 | if (!maxesBuilt) { 72 | maxes = insertionTab.getResult().collect(Collectors.toList()).iterator(); 73 | maxesBuilt = true; 74 | } 75 | if (maxesBuilt && maxes.hasNext()) { 76 | action.accept(maxes.next()); 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | @Override 84 | public Spliterator trySplit() { 85 | return null; 86 | } 87 | 88 | @Override 89 | public long estimateSize() { 90 | return 0L; 91 | } 92 | 93 | @Override 94 | public int characteristics() { 95 | return spliterator.characteristics() & ~Spliterator.SIZED & ~Spliterator.SUBSIZED; 96 | } 97 | 98 | @Override 99 | public Comparator getComparator() { 100 | return this.spliterator.getComparator(); 101 | } 102 | 103 | private static class InsertionTab implements Consumer { 104 | 105 | private final T[] tab; 106 | private int currentIndex; 107 | private final Comparator comparator; 108 | 109 | @SuppressWarnings("unchecked") 110 | public InsertionTab(int maxN, Comparator comparator) { 111 | this.comparator = comparator; 112 | this.tab = (T[]) Array.newInstance(Object.class, maxN); 113 | this.currentIndex = 0; 114 | } 115 | 116 | public void accept(T t) { 117 | if (currentIndex < tab.length) { 118 | insertInDecreasingOrder(tab, t, currentIndex); 119 | currentIndex++; 120 | return; 121 | } 122 | if (tab[tab.length - 1] == null || comparator.compare(tab[tab.length - 1], t) < 0) { 123 | insertInDecreasingOrder(tab, t, tab.length - 1); 124 | } 125 | } 126 | 127 | private void insertInDecreasingOrder(T[] tab, T t, int maxIndex) { 128 | int index = 0; 129 | while(index < maxIndex) { 130 | if (comparator.compare(tab[index], t) > 0) { 131 | index++; 132 | } else if (comparator.compare(tab[index], t) < 0){ 133 | for (int i = maxIndex ; i > index ; i--) { 134 | tab[i] = tab[i - 1]; 135 | } 136 | break; 137 | } else { 138 | break; 139 | } 140 | } 141 | tab[index] = t; 142 | } 143 | 144 | private Stream getResult() { 145 | return StreamsUtils.interrupt(Arrays.stream(tab), Objects::isNull); 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/FilteringMaxValuesSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.lang.reflect.Array; 22 | import java.util.*; 23 | import java.util.function.Consumer; 24 | import java.util.stream.Collectors; 25 | import java.util.stream.Stream; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class FilteringMaxValuesSpliterator implements Spliterator { 33 | 34 | private final Spliterator spliterator; 35 | private final Comparator comparator; 36 | private final int numberOfMaxes; 37 | private boolean hasMore = true; 38 | private boolean maxesBuilt = false; 39 | private Iterator maxes; 40 | 41 | public static FilteringMaxValuesSpliterator of( 42 | Spliterator spliterator, 43 | int numberOfMaxes, 44 | Comparator comparator) { 45 | Objects.requireNonNull(spliterator); 46 | Objects.requireNonNull(comparator); 47 | if (numberOfMaxes < 2) { 48 | throw new IllegalArgumentException("numberOfMaxes should not be less than 2"); 49 | } 50 | 51 | return new FilteringMaxValuesSpliterator<>(spliterator, numberOfMaxes, comparator); 52 | } 53 | 54 | private FilteringMaxValuesSpliterator( 55 | Spliterator spliterator, 56 | int numberOfMaxes, 57 | Comparator comparator) { 58 | this.spliterator = spliterator; 59 | this.numberOfMaxes = numberOfMaxes; 60 | this.comparator = comparator; 61 | } 62 | 63 | @Override 64 | public boolean tryAdvance(Consumer action) { 65 | 66 | InsertionTab insertionTab = new InsertionTab<>(this.numberOfMaxes, this.comparator); 67 | while (hasMore) { 68 | hasMore = spliterator.tryAdvance(insertionTab); 69 | } 70 | 71 | if (!maxesBuilt) { 72 | maxes = insertionTab.getResult().collect(Collectors.toList()).iterator(); 73 | maxesBuilt = true; 74 | } 75 | if (maxesBuilt && maxes.hasNext()) { 76 | action.accept(maxes.next()); 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | @Override 84 | public Spliterator trySplit() { 85 | return null; 86 | } 87 | 88 | @Override 89 | public long estimateSize() { 90 | return 0L; 91 | } 92 | 93 | @Override 94 | public int characteristics() { 95 | return spliterator.characteristics() & ~Spliterator.SIZED & ~Spliterator.SUBSIZED; 96 | } 97 | 98 | @Override 99 | public Comparator getComparator() { 100 | return this.spliterator.getComparator(); 101 | } 102 | 103 | private static class InsertionTab implements Consumer { 104 | 105 | private final T[] tab; 106 | private final Map> map; 107 | private int currentIndex; 108 | private final Comparator comparator; 109 | 110 | @SuppressWarnings("unchecked") 111 | public InsertionTab(int maxN, Comparator comparator) { 112 | this.comparator = comparator; 113 | this.map = new TreeMap<>(comparator.reversed()); 114 | this.tab = (T[]) Array.newInstance(Object.class, maxN); 115 | this.currentIndex = 0; 116 | } 117 | 118 | public void accept(T t) { 119 | if (currentIndex < tab.length) { 120 | insertInDecreasingOrder(tab, t, currentIndex); 121 | addToResults(map, t); 122 | currentIndex++; 123 | return; 124 | } 125 | int compare = comparator.compare(tab[tab.length - 1], t); 126 | if (compare < 0) { 127 | addToResults(map, t); 128 | if (comparator.compare(tab[tab.length - 1], tab[tab.length - 2]) != 0) { 129 | removeFromResults(map, tab[tab.length - 1]); 130 | } 131 | insertInDecreasingOrder(tab, t, tab.length - 1); 132 | } else if (compare > 0) { 133 | removeFromResults(map, t); 134 | } else if (compare == 0) { 135 | map.get(t).add(t); 136 | } 137 | } 138 | 139 | private void insertInDecreasingOrder(T[] tab, T t, int maxIndex) { 140 | int index = 0; 141 | while(index < maxIndex) { 142 | if (comparator.compare(tab[index], t) > 0) { 143 | index++; 144 | } else { 145 | for (int i = maxIndex ; i > index ; i--) { 146 | tab[i] = tab[i - 1]; 147 | } 148 | break; 149 | } 150 | } 151 | tab[index] = t; 152 | } 153 | 154 | private void removeFromResults(Map> map, T key) { 155 | map.remove(key); 156 | } 157 | 158 | private void addToResults(Map> map, T t) { 159 | map.computeIfAbsent(t, key -> Stream.builder()).add(t); 160 | } 161 | 162 | private Stream getResult() { 163 | return map.entrySet().stream().flatMap(entry -> entry.getValue().build()); 164 | } 165 | } 166 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/GatingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Comparator; 22 | import java.util.Objects; 23 | import java.util.Spliterator; 24 | import java.util.function.Consumer; 25 | import java.util.function.Predicate; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class GatingSpliterator implements Spliterator { 33 | 34 | private final Spliterator spliterator; 35 | private final Predicate gate; 36 | private boolean gateIsOpenned = false; 37 | 38 | public static GatingSpliterator of(Spliterator spliterator, Predicate gate) { 39 | Objects.requireNonNull(spliterator); 40 | Objects.requireNonNull(gate); 41 | 42 | return new GatingSpliterator<>(spliterator, gate); 43 | } 44 | 45 | private GatingSpliterator(Spliterator spliterator, Predicate gate) { 46 | this.spliterator = spliterator; 47 | this.gate = gate; 48 | } 49 | 50 | @Override 51 | public boolean tryAdvance(Consumer action) { 52 | 53 | boolean hasMore = false; 54 | if (!gateIsOpenned) { 55 | hasMore = spliterator.tryAdvance(e -> { 56 | if (gate.test(e)) { 57 | gateIsOpenned = true; 58 | action.accept(e); 59 | } 60 | }); 61 | if (hasMore && gateIsOpenned) { 62 | return true; 63 | } 64 | } 65 | while (!gateIsOpenned && hasMore) { 66 | hasMore = spliterator.tryAdvance(e -> { 67 | if (gate.test(e)) { 68 | gateIsOpenned = true; 69 | action.accept(e); 70 | } 71 | }); 72 | if (hasMore && gateIsOpenned) { 73 | return true; 74 | } 75 | } 76 | if (gateIsOpenned) { 77 | hasMore = spliterator.tryAdvance(action); 78 | } 79 | 80 | return hasMore; 81 | } 82 | 83 | @Override 84 | public Spliterator trySplit() { 85 | Spliterator split = this.spliterator.trySplit(); 86 | return split == null ? null : new GatingSpliterator<>(split, gate); 87 | } 88 | 89 | @Override 90 | public long estimateSize() { 91 | return 0L; 92 | } 93 | 94 | @Override 95 | public int characteristics() { 96 | return this.spliterator.characteristics() & ~Spliterator.SIZED & ~Spliterator.SUBSIZED; 97 | } 98 | 99 | @Override 100 | public Comparator getComparator() { 101 | return this.spliterator.getComparator(); 102 | } 103 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/GroupingOnGatingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.function.Consumer; 24 | import java.util.function.Predicate; 25 | import java.util.stream.Stream; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class GroupingOnGatingSpliterator implements Spliterator> { 33 | 34 | private final Spliterator spliterator; 35 | private final Predicate open; 36 | private final Predicate close; 37 | private final boolean openingElementIncluded; 38 | private final boolean closingElementIncluded; 39 | 40 | private Stream.Builder builder = Stream.builder(); 41 | private boolean gateOpen = false; 42 | private boolean groupReady = false; 43 | private boolean builderEmpty = true; 44 | 45 | public static GroupingOnGatingSpliterator of( 46 | Spliterator spliterator, 47 | Predicate open, boolean openingElementIncluded, 48 | Predicate close, boolean closingElementIncluded) { 49 | Objects.requireNonNull(spliterator); 50 | Objects.requireNonNull(open); 51 | Objects.requireNonNull(close); 52 | 53 | if ((spliterator.characteristics() & Spliterator.ORDERED) == 0) { 54 | throw new IllegalArgumentException("Why would you build a grouping on gating spliterator on a non-ordered spliterator?"); 55 | } 56 | 57 | return new GroupingOnGatingSpliterator(spliterator, open, openingElementIncluded, close, closingElementIncluded); 58 | } 59 | 60 | private GroupingOnGatingSpliterator( 61 | Spliterator spliterator, 62 | Predicate open, boolean openingElementIncluded, 63 | Predicate close, boolean closingElementIncluded) { 64 | this.spliterator = spliterator; 65 | this.open = open; 66 | this.openingElementIncluded = openingElementIncluded; 67 | this.close = close; 68 | this.closingElementIncluded = closingElementIncluded; 69 | } 70 | 71 | @Override 72 | public boolean tryAdvance(Consumer> action) { 73 | 74 | boolean hasMore = true; 75 | while (hasMore && !groupReady) { 76 | hasMore = spliterator.tryAdvance(e -> { 77 | if (gateOpen && !close.test(e)) { 78 | builder.add(e); 79 | builderEmpty = false; 80 | } 81 | if (!gateOpen && open.test(e)) { 82 | gateOpen = true; 83 | if (openingElementIncluded) { 84 | builder.add(e); 85 | builderEmpty = false; 86 | } 87 | } 88 | if (gateOpen && close.test(e)) { 89 | if (closingElementIncluded) { 90 | builder.add(e); 91 | builderEmpty = false; 92 | } 93 | gateOpen = false; 94 | groupReady = true; 95 | } 96 | }); 97 | } 98 | 99 | if ((groupReady || !hasMore) && !builderEmpty) { 100 | action.accept(builder.build()); 101 | builder = Stream.builder(); 102 | builderEmpty = true; 103 | groupReady = false; 104 | } 105 | 106 | 107 | return hasMore; 108 | } 109 | 110 | @Override 111 | public Spliterator> trySplit() { 112 | Spliterator splitSpliterator = this.spliterator.trySplit(); 113 | return splitSpliterator == null ? null : new GroupingOnGatingSpliterator<>(splitSpliterator, open, openingElementIncluded, close, closingElementIncluded); 114 | } 115 | 116 | @Override 117 | public long estimateSize() { 118 | return 0L; 119 | } 120 | 121 | @Override 122 | public int characteristics() { 123 | // this spliterator is already ordered 124 | return spliterator.characteristics() & ~Spliterator.SORTED & ~Spliterator.SIZED & ~Spliterator.SUBSIZED; 125 | } 126 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/GroupingOnSplittingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.function.Consumer; 24 | import java.util.function.Predicate; 25 | import java.util.stream.Stream; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class GroupingOnSplittingSpliterator implements Spliterator> { 33 | 34 | private final Spliterator spliterator; 35 | private final Predicate splitter; 36 | private final boolean included; 37 | 38 | private Stream.Builder currentBuidler = Stream.builder(); 39 | private Stream.Builder nextBuilder = Stream.builder(); 40 | private boolean gateOpen = false; 41 | private boolean groupReady = false; 42 | private boolean builderReady = true; 43 | private boolean hasMore = true; 44 | 45 | public static GroupingOnSplittingSpliterator of( 46 | Spliterator spliterator, 47 | Predicate splitter, boolean included) { 48 | Objects.requireNonNull(spliterator); 49 | Objects.requireNonNull(splitter); 50 | 51 | if ((spliterator.characteristics() & Spliterator.ORDERED) == 0) { 52 | throw new IllegalArgumentException("Why would you build a grouping on gating spliterator on a non-ordered spliterator?"); 53 | } 54 | 55 | return new GroupingOnSplittingSpliterator(spliterator, splitter, included); 56 | } 57 | 58 | private GroupingOnSplittingSpliterator( 59 | Spliterator spliterator, 60 | Predicate splitter, boolean included) { 61 | this.spliterator = spliterator; 62 | this.splitter = splitter; 63 | this.included = included; 64 | } 65 | 66 | @Override 67 | public boolean tryAdvance(Consumer> action) { 68 | if (!hasMore) { 69 | return false; 70 | } 71 | hasMore = true; 72 | while (hasMore && !groupReady) { 73 | hasMore = spliterator.tryAdvance(e -> { 74 | if (gateOpen && splitter.test(e)) { 75 | if (included) { 76 | nextBuilder.add(e); 77 | } 78 | groupReady = true; 79 | } 80 | if (gateOpen && !splitter.test(e)) { 81 | currentBuidler.add(e); 82 | builderReady = false; 83 | } 84 | if (!gateOpen && splitter.test(e)) { 85 | gateOpen = true; 86 | if (included) { 87 | currentBuidler.add(e); 88 | } 89 | builderReady = false; 90 | } 91 | }); 92 | } 93 | 94 | if ((groupReady || !hasMore) && !builderReady) { 95 | action.accept(currentBuidler.build()); 96 | currentBuidler = nextBuilder; 97 | groupReady = false; 98 | if (hasMore) { 99 | nextBuilder = Stream.builder(); 100 | } 101 | } 102 | 103 | return true; 104 | } 105 | 106 | @Override 107 | public Spliterator> trySplit() { 108 | Spliterator splitSpliterator = this.spliterator.trySplit(); 109 | return splitSpliterator == null ? null : new GroupingOnSplittingSpliterator<>(splitSpliterator, splitter, included); 110 | } 111 | 112 | @Override 113 | public long estimateSize() { 114 | return 0L; 115 | } 116 | 117 | @Override 118 | public int characteristics() { 119 | // this spliterator is already ordered 120 | return spliterator.characteristics() & ~Spliterator.SORTED & ~Spliterator.SIZED & ~Spliterator.SUBSIZED; 121 | } 122 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/GroupingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.function.Consumer; 24 | import java.util.stream.Stream; 25 | 26 | /** 27 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 28 | * 29 | * @author José 30 | */ 31 | public class GroupingSpliterator implements Spliterator> { 32 | 33 | private final long grouping; 34 | private final Spliterator spliterator; 35 | private Stream.Builder builder = Stream.builder(); 36 | private boolean firstGroup = true; 37 | private boolean lastBuilderHasBeenConsumed = false; 38 | 39 | public static GroupingSpliterator of(Spliterator spliterator, long grouping) { 40 | Objects.requireNonNull(spliterator); 41 | if (grouping < 2) { 42 | throw new IllegalArgumentException("Why would you build a grouping spliterator with a grouping factor of less than 2?"); 43 | } 44 | if ((spliterator.characteristics() & Spliterator.ORDERED) == 0) { 45 | throw new IllegalArgumentException("Why would you build a grouping spliterator on a non-ordered spliterator?"); 46 | } 47 | 48 | return new GroupingSpliterator<>(spliterator, grouping); 49 | } 50 | 51 | private GroupingSpliterator(Spliterator spliterator, long grouping) { 52 | this.spliterator = spliterator; 53 | this.grouping = grouping; 54 | } 55 | 56 | @Override 57 | public boolean tryAdvance(Consumer> action) { 58 | if (lastBuilderHasBeenConsumed) { 59 | return false; 60 | } 61 | boolean moreElements = true; 62 | if (firstGroup) { 63 | moreElements = spliterator.tryAdvance(builder::add); 64 | firstGroup = false; 65 | } 66 | if (!moreElements) { 67 | action.accept(builder.build()); 68 | lastBuilderHasBeenConsumed = true; 69 | return true; 70 | } 71 | for (int i = 1; i < grouping && moreElements; i++) { 72 | if (!spliterator.tryAdvance(builder::add)) { 73 | moreElements = false; 74 | } 75 | } 76 | Stream subStream = builder.build(); 77 | action.accept(subStream); 78 | if (moreElements) { 79 | builder = Stream.builder(); 80 | moreElements = spliterator.tryAdvance(builder::add); 81 | } 82 | 83 | if (!moreElements) { 84 | lastBuilderHasBeenConsumed = true; 85 | } 86 | 87 | return true; 88 | } 89 | 90 | @Override 91 | public Spliterator> trySplit() { 92 | Spliterator splitSpliterator = this.spliterator.trySplit(); 93 | return splitSpliterator == null ? null : new GroupingSpliterator<>(splitSpliterator, grouping); 94 | } 95 | 96 | @Override 97 | public long estimateSize() { 98 | long estimateSize = spliterator.estimateSize(); 99 | return estimateSize == Long.MAX_VALUE ? Long.MAX_VALUE : estimateSize / grouping; 100 | } 101 | 102 | @Override 103 | public int characteristics() { 104 | // this spliterator is already ordered 105 | return spliterator.characteristics() & ~Spliterator.SORTED; 106 | } 107 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/InterruptingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Comparator; 22 | import java.util.Objects; 23 | import java.util.Spliterator; 24 | import java.util.function.Consumer; 25 | import java.util.function.Predicate; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class InterruptingSpliterator implements Spliterator { 33 | 34 | private final Spliterator spliterator; 35 | private final Predicate interruptor; 36 | private boolean hasBeenInterrupted = false; 37 | 38 | public static InterruptingSpliterator of(Spliterator spliterator, Predicate interruptor) { 39 | Objects.requireNonNull(spliterator); 40 | Objects.requireNonNull(interruptor); 41 | 42 | return new InterruptingSpliterator(spliterator, interruptor); 43 | } 44 | 45 | private InterruptingSpliterator(Spliterator spliterator, Predicate interruptor) { 46 | this.spliterator = spliterator; 47 | this.interruptor = interruptor; 48 | } 49 | 50 | @Override 51 | public boolean tryAdvance(Consumer action) { 52 | 53 | boolean hasMore = spliterator.tryAdvance(e -> { 54 | if (interruptor.test(e)) { 55 | hasBeenInterrupted = true; 56 | } else { 57 | action.accept(e); 58 | } 59 | }); 60 | 61 | return hasMore && !hasBeenInterrupted; 62 | } 63 | 64 | @Override 65 | public Spliterator trySplit() { 66 | Spliterator split = this.spliterator.trySplit(); 67 | return split == null ? null : new InterruptingSpliterator<>(split, interruptor); 68 | } 69 | 70 | @Override 71 | public long estimateSize() { 72 | return 0; 73 | } 74 | 75 | @Override 76 | public int characteristics() { 77 | return this.spliterator.characteristics() & ~Spliterator.SIZED & ~Spliterator.SUBSIZED; 78 | } 79 | 80 | @Override 81 | public Comparator getComparator() { 82 | return this.spliterator.getComparator(); 83 | } 84 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/RepeatingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.function.Consumer; 24 | import java.util.stream.IntStream; 25 | 26 | /** 27 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 28 | * 29 | * Created by José 30 | */ 31 | public class RepeatingSpliterator implements Spliterator { 32 | 33 | private final int repeating; 34 | private int currentRepeat = 0; 35 | private final Spliterator spliterator; 36 | private E currentValue; 37 | 38 | public static RepeatingSpliterator of(Spliterator spliterator, int repeating) { 39 | Objects.requireNonNull(spliterator); 40 | if (repeating <= 1) { 41 | throw new IllegalArgumentException (("Why would you build a repeating spliterator with a repeating factor of less than 2?")); 42 | } 43 | if ((spliterator.characteristics() & Spliterator.SIZED) == 0) { 44 | throw new IllegalArgumentException (("Why would you try to repeat a non-SIZED spliterator?")); 45 | } 46 | 47 | return new RepeatingSpliterator<>(spliterator, repeating); 48 | } 49 | 50 | private RepeatingSpliterator(Spliterator spliterator, int repeating) { 51 | this.spliterator = spliterator; 52 | this.repeating = repeating; 53 | } 54 | 55 | @Override 56 | public boolean tryAdvance(Consumer action) { 57 | if (currentRepeat > 0) { 58 | currentRepeat--; 59 | action.accept(currentValue); 60 | return true; 61 | } else if (spliterator.tryAdvance(e -> { currentValue = e; })) { 62 | currentRepeat = repeating - 1; 63 | action.accept(currentValue); 64 | return true; 65 | } else { 66 | return false; 67 | } 68 | } 69 | 70 | @Override 71 | public Spliterator trySplit() { 72 | Spliterator splitSpliterator = spliterator.trySplit(); 73 | return splitSpliterator == null ? null : new RepeatingSpliterator<>(splitSpliterator, repeating); 74 | } 75 | 76 | @Override 77 | public long estimateSize() { 78 | long estimateSize = spliterator.estimateSize(); 79 | return (estimateSize == Long.MAX_VALUE) || (estimateSize*repeating < estimateSize) ? Long.MAX_VALUE : estimateSize*repeating; 80 | } 81 | 82 | @Override 83 | public int characteristics() { 84 | return this.spliterator.characteristics() & ~Spliterator.SORTED | Spliterator.ORDERED; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/RollingOfDoubleSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.concurrent.atomic.AtomicInteger; 24 | import java.util.function.Consumer; 25 | import java.util.stream.DoubleStream; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class RollingOfDoubleSpliterator implements Spliterator { 33 | 34 | private final int grouping ; 35 | private final OfDouble spliterator ; 36 | private final double [] buffer ; 37 | private final AtomicInteger bufferWriteIndex = new AtomicInteger(0) ; 38 | private final AtomicInteger bufferReadIndex = new AtomicInteger(0) ; 39 | 40 | public static RollingOfDoubleSpliterator of(OfDouble spliterator, int grouping) { 41 | Objects.requireNonNull(spliterator); 42 | if (grouping < 2) { 43 | throw new IllegalArgumentException ("Why would you be creating a rolling spliterator with a grouping factor of less than 2?"); 44 | } 45 | if ((spliterator.characteristics() & Spliterator.ORDERED) == 0) { 46 | throw new IllegalArgumentException ("Why would you create a rolling spliterator on a non-ordered spliterator?"); 47 | } 48 | 49 | return new RollingOfDoubleSpliterator(spliterator, grouping); 50 | } 51 | 52 | private RollingOfDoubleSpliterator(OfDouble spliterator, int grouping) { 53 | this.spliterator = spliterator ; 54 | this.grouping = grouping ; 55 | this.buffer = new double[grouping + 1] ; 56 | } 57 | 58 | 59 | @Override 60 | public boolean tryAdvance(Consumer action) { 61 | boolean finished = false ; 62 | 63 | if (bufferWriteIndex.get() == bufferReadIndex.get()) { 64 | for (int i = 0 ; i < grouping ; i++) { 65 | if (!advanceSpliterator()) { 66 | finished = true ; 67 | } 68 | } 69 | } 70 | if (!advanceSpliterator()) { 71 | finished = true ; 72 | } 73 | 74 | DoubleStream subStream = buildSubstream() ; 75 | action.accept(subStream) ; 76 | return !finished ; 77 | } 78 | 79 | private boolean advanceSpliterator() { 80 | return spliterator.tryAdvance( 81 | (double element) -> { 82 | buffer[bufferWriteIndex.get() % buffer.length] = element ; 83 | bufferWriteIndex.incrementAndGet() ; 84 | }); 85 | } 86 | 87 | @Override 88 | public Spliterator trySplit() { 89 | OfDouble splitSpliterator = spliterator.trySplit(); 90 | return splitSpliterator == null ? null : new RollingOfDoubleSpliterator(splitSpliterator, grouping) ; 91 | } 92 | 93 | private DoubleStream buildSubstream() { 94 | 95 | DoubleStream.Builder subBuilder = DoubleStream.builder() ; 96 | for (int i = 0 ; i < grouping ; i++) { 97 | subBuilder.add(buffer[(i + bufferReadIndex.get()) % buffer.length]) ; 98 | } 99 | bufferReadIndex.incrementAndGet() ; 100 | return subBuilder.build() ; 101 | } 102 | 103 | @Override 104 | public long estimateSize() { 105 | long estimateSize = spliterator.estimateSize(); 106 | return estimateSize == Long.MAX_VALUE ? Long.MAX_VALUE : estimateSize - grouping + 1; 107 | } 108 | 109 | @Override 110 | public int characteristics() { 111 | // this spliterator is already ordered 112 | return spliterator.characteristics() & ~Spliterator.SORTED; 113 | } 114 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/RollingOfIntSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.concurrent.atomic.AtomicInteger; 24 | import java.util.function.Consumer; 25 | import java.util.stream.IntStream; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class RollingOfIntSpliterator implements Spliterator { 33 | 34 | private final int grouping ; 35 | private final Spliterator.OfInt spliterator ; 36 | private final int [] buffer ; 37 | private final AtomicInteger bufferWriteIndex = new AtomicInteger(0) ; 38 | private final AtomicInteger bufferReadIndex = new AtomicInteger(0) ; 39 | 40 | public static RollingOfIntSpliterator of(Spliterator.OfInt spliterator, int grouping) { 41 | Objects.requireNonNull(spliterator); 42 | if (grouping < 2) { 43 | throw new IllegalArgumentException ("Why would you be creating a rolling spliterator with a grouping factor of less than 2?"); 44 | } 45 | if ((spliterator.characteristics() & Spliterator.ORDERED) == 0) { 46 | throw new IllegalArgumentException ("Why would you create a rolling spliterator on a non-ordered spliterator?"); 47 | } 48 | 49 | return new RollingOfIntSpliterator(spliterator, grouping); 50 | } 51 | 52 | private RollingOfIntSpliterator(Spliterator.OfInt spliterator, int grouping) { 53 | this.spliterator = spliterator ; 54 | this.grouping = grouping ; 55 | this.buffer = new int[grouping + 1] ; 56 | } 57 | 58 | 59 | @Override 60 | public boolean tryAdvance(Consumer action) { 61 | boolean finished = false ; 62 | 63 | if (bufferWriteIndex.get() == bufferReadIndex.get()) { 64 | for (int i = 0 ; i < grouping ; i++) { 65 | if (!advanceSpliterator()) { 66 | finished = true ; 67 | } 68 | } 69 | } 70 | if (!advanceSpliterator()) { 71 | finished = true ; 72 | } 73 | 74 | IntStream subStream = buildSubstream() ; 75 | action.accept(subStream) ; 76 | return !finished ; 77 | } 78 | 79 | private boolean advanceSpliterator() { 80 | return spliterator.tryAdvance( 81 | (int element) -> { 82 | buffer[bufferWriteIndex.get() % buffer.length] = element ; 83 | bufferWriteIndex.incrementAndGet() ; 84 | }); 85 | } 86 | 87 | @Override 88 | public Spliterator trySplit() { 89 | Spliterator.OfInt splitSpliterator = spliterator.trySplit(); 90 | return splitSpliterator == null ? null : new RollingOfIntSpliterator(splitSpliterator, grouping) ; 91 | } 92 | 93 | private IntStream buildSubstream() { 94 | 95 | IntStream.Builder subBuilder = IntStream.builder() ; 96 | for (int i = 0 ; i < grouping ; i++) { 97 | subBuilder.add(buffer[(i + bufferReadIndex.get()) % buffer.length]) ; 98 | } 99 | bufferReadIndex.incrementAndGet() ; 100 | return subBuilder.build() ; 101 | } 102 | 103 | @Override 104 | public long estimateSize() { 105 | long estimateSize = spliterator.estimateSize(); 106 | return estimateSize == Long.MAX_VALUE ? Long.MAX_VALUE : estimateSize - grouping + 1; 107 | } 108 | 109 | @Override 110 | public int characteristics() { 111 | // this spliterator is already ordered 112 | return spliterator.characteristics(); 113 | } 114 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/RollingOfLongSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.concurrent.atomic.AtomicInteger; 24 | import java.util.function.Consumer; 25 | import java.util.stream.LongStream; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class RollingOfLongSpliterator implements Spliterator { 33 | 34 | private final int grouping ; 35 | private final OfLong spliterator ; 36 | private final long [] buffer ; 37 | private final AtomicInteger bufferWriteIndex = new AtomicInteger(0) ; 38 | private final AtomicInteger bufferReadIndex = new AtomicInteger(0) ; 39 | 40 | public static RollingOfLongSpliterator of(OfLong spliterator, int grouping) { 41 | Objects.requireNonNull(spliterator); 42 | if (grouping < 2) { 43 | throw new IllegalArgumentException ("Why would you be creating a rolling spliterator with a grouping factor of less than 2?"); 44 | } 45 | if ((spliterator.characteristics() & Spliterator.ORDERED) == 0) { 46 | throw new IllegalArgumentException ("Why would you create a rolling spliterator on a non-ordered spliterator?"); 47 | } 48 | 49 | return new RollingOfLongSpliterator(spliterator, grouping); 50 | } 51 | 52 | private RollingOfLongSpliterator(OfLong spliterator, int grouping) { 53 | this.spliterator = spliterator ; 54 | this.grouping = grouping ; 55 | this.buffer = new long[grouping + 1] ; 56 | } 57 | 58 | 59 | @Override 60 | public boolean tryAdvance(Consumer action) { 61 | boolean finished = false ; 62 | 63 | if (bufferWriteIndex.get() == bufferReadIndex.get()) { 64 | for (int i = 0 ; i < grouping ; i++) { 65 | if (!advanceSpliterator()) { 66 | finished = true ; 67 | } 68 | } 69 | } 70 | if (!advanceSpliterator()) { 71 | finished = true ; 72 | } 73 | 74 | LongStream subStream = buildSubstream() ; 75 | action.accept(subStream) ; 76 | return !finished ; 77 | } 78 | 79 | private boolean advanceSpliterator() { 80 | return spliterator.tryAdvance( 81 | (long element) -> { 82 | buffer[bufferWriteIndex.get() % buffer.length] = element ; 83 | bufferWriteIndex.incrementAndGet() ; 84 | }); 85 | } 86 | 87 | @Override 88 | public Spliterator trySplit() { 89 | OfLong splitSpliterator = spliterator.trySplit(); 90 | return splitSpliterator == null ? null : new RollingOfLongSpliterator(splitSpliterator, grouping) ; 91 | } 92 | 93 | private LongStream buildSubstream() { 94 | 95 | LongStream.Builder subBuilder = LongStream.builder() ; 96 | for (int i = 0 ; i < grouping ; i++) { 97 | subBuilder.add(buffer[(i + bufferReadIndex.get()) % buffer.length]) ; 98 | } 99 | bufferReadIndex.incrementAndGet() ; 100 | return subBuilder.build() ; 101 | } 102 | 103 | @Override 104 | public long estimateSize() { 105 | long estimateSize = spliterator.estimateSize(); 106 | return estimateSize == Long.MAX_VALUE ? Long.MAX_VALUE : estimateSize - grouping + 1; 107 | } 108 | 109 | @Override 110 | public int characteristics() { 111 | // this spliterator is already ordered 112 | return spliterator.characteristics(); 113 | } 114 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/RollingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.concurrent.atomic.AtomicInteger; 24 | import java.util.function.Consumer; 25 | import java.util.stream.Stream; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class RollingSpliterator implements Spliterator> { 33 | 34 | private final int grouping; 35 | private final Spliterator spliterator; 36 | private final Object[] buffer; // we cant create arrays of E 37 | private final AtomicInteger bufferWriteIndex = new AtomicInteger(0); 38 | private final AtomicInteger bufferReadIndex = new AtomicInteger(0); 39 | private boolean lastBufferSent = false; 40 | 41 | public static RollingSpliterator of(Spliterator spliterator, int grouping) { 42 | Objects.requireNonNull(spliterator); 43 | if (grouping < 2) { 44 | throw new IllegalArgumentException("Why would you be creating a rolling spliterator with a grouping factor of less than 2?"); 45 | } 46 | if ((spliterator.characteristics() & Spliterator.ORDERED) == 0) { 47 | throw new IllegalArgumentException("Why would you create a rolling spliterator on a non-ordered spliterator?"); 48 | } 49 | 50 | return new RollingSpliterator<>(spliterator, grouping); 51 | } 52 | 53 | private RollingSpliterator(Spliterator spliterator, int grouping) { 54 | this.spliterator = spliterator; 55 | this.grouping = grouping; 56 | this.buffer = new Object[grouping + 1]; 57 | } 58 | 59 | @Override 60 | public boolean tryAdvance(Consumer> action) { 61 | boolean hasMore = true; 62 | 63 | if ((bufferWriteIndex.get() == bufferReadIndex.get()) && hasMore) { 64 | for (int i = 0; i < grouping; i++) { 65 | if (!advance(this.spliterator)) { 66 | hasMore = false; 67 | } 68 | } 69 | } 70 | if (!advance(spliterator)) { 71 | hasMore = false; 72 | } 73 | 74 | if (hasMore) { 75 | Stream subStream = buildSubstream(); 76 | action.accept(subStream); 77 | return true; 78 | } else if (!lastBufferSent) { 79 | Stream subStream = buildSubstream(); 80 | action.accept(subStream); 81 | lastBufferSent = true; 82 | return true; 83 | } else { 84 | return false; 85 | } 86 | } 87 | 88 | private boolean advance(Spliterator spliterator) { 89 | return spliterator.tryAdvance( 90 | element -> { 91 | buffer[bufferWriteIndex.get() % buffer.length] = element; 92 | bufferWriteIndex.incrementAndGet(); 93 | }); 94 | } 95 | 96 | @Override 97 | public Spliterator> trySplit() { 98 | Spliterator splitSpliterator = spliterator.trySplit(); 99 | return splitSpliterator == null ? null : new RollingSpliterator<>(splitSpliterator, grouping); 100 | } 101 | 102 | @SuppressWarnings("unchecked") 103 | private Stream buildSubstream() { 104 | 105 | Stream.Builder subBuilder = Stream.builder(); 106 | for (int i = 0; i < grouping; i++) { 107 | subBuilder.add((E) buffer[(i + bufferReadIndex.get()) % buffer.length]); 108 | } 109 | bufferReadIndex.incrementAndGet(); 110 | return subBuilder.build(); 111 | } 112 | 113 | @Override 114 | public long estimateSize() { 115 | long estimateSize = spliterator.estimateSize(); 116 | return estimateSize == Long.MAX_VALUE ? Long.MAX_VALUE : estimateSize - grouping + 1; 117 | } 118 | 119 | @Override 120 | public int characteristics() { 121 | // this spliterator is already ordered 122 | return spliterator.characteristics() & ~Spliterator.SORTED; 123 | } 124 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/TraversingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.concurrent.atomic.AtomicBoolean; 24 | import java.util.function.Consumer; 25 | import java.util.stream.Stream; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * Created by José 31 | */ 32 | public class TraversingSpliterator implements Spliterator> { 33 | 34 | private final Spliterator[] spliterators; 35 | private final AtomicBoolean firstGroup = new AtomicBoolean(true); 36 | 37 | @SafeVarargs 38 | public static TraversingSpliterator of(Spliterator... spliterators) { 39 | Objects.requireNonNull(spliterators); 40 | if (spliterators.length < 2) { 41 | throw new IllegalArgumentException ("Why would you want to traverse less than two streams?"); 42 | } 43 | if (Stream.of(spliterators).mapToInt(Spliterator::characteristics).reduce(Spliterator.ORDERED, (i1, i2) -> i1 & i2) == 0) { 44 | throw new IllegalArgumentException ("Why would you want to traverse non ordered spliterators?"); 45 | } 46 | 47 | return new TraversingSpliterator<>(spliterators); 48 | } 49 | 50 | @SafeVarargs 51 | private TraversingSpliterator(Spliterator... spliterators) { 52 | this.spliterators = spliterators; 53 | } 54 | 55 | @Override 56 | public boolean tryAdvance(Consumer> action) { 57 | Stream.Builder builder = Stream.builder(); 58 | boolean hasMore = true; 59 | for (Spliterator spliterator : spliterators) { 60 | hasMore &= spliterator.tryAdvance(builder::add); 61 | } 62 | if (hasMore) { 63 | action.accept(builder.build()); 64 | firstGroup.getAndSet(false); 65 | } 66 | if (!hasMore && firstGroup.getAndSet(false)) 67 | action.accept(Stream.empty()); 68 | return hasMore; 69 | } 70 | 71 | 72 | @Override 73 | public Spliterator> trySplit() { 74 | @SuppressWarnings("unchecked") 75 | TraversingSpliterator[] spliterators = 76 | Stream.of(this.spliterators).map(Spliterator::trySplit).toArray(TraversingSpliterator[]::new); 77 | return new TraversingSpliterator<>((Spliterator[]) spliterators); 78 | } 79 | 80 | @Override 81 | public long estimateSize() { 82 | return Stream.of(spliterators).mapToLong(Spliterator::estimateSize).min().getAsLong(); 83 | } 84 | 85 | @Override 86 | public int characteristics() { 87 | return Stream.of(spliterators) 88 | .mapToInt(Spliterator::characteristics) 89 | .reduce(0xFFFFFFFF, (i1, i2) -> i1 & i2) 90 | & ~Spliterator.SORTED; 91 | } 92 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/ValidatingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.function.Consumer; 24 | import java.util.function.Function; 25 | import java.util.function.Predicate; 26 | 27 | /** 28 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 29 | * 30 | * @author José 31 | */ 32 | public class ValidatingSpliterator implements Spliterator { 33 | 34 | private final Spliterator spliterator; 35 | private final Function transformIfValid, transformIfNotValid; 36 | private final Predicate validator; 37 | 38 | public static class Builder { 39 | 40 | private Spliterator spliterator; 41 | private Function transformIfValid, transformIfNotValid; 42 | private Predicate validator; 43 | 44 | public Builder() { 45 | } 46 | 47 | public Builder with(Spliterator spliterator) { 48 | this.spliterator = Objects.requireNonNull(spliterator); 49 | return this; 50 | } 51 | 52 | public Builder validatedBy(Predicate validator) { 53 | this.validator = Objects.requireNonNull(validator); 54 | return this; 55 | } 56 | 57 | public Builder withValidFunction(Function validFunction) { 58 | this.transformIfValid = Objects.requireNonNull(validFunction); 59 | return this; 60 | } 61 | 62 | public Builder withNotValidFunction(Function notValidFunction) { 63 | this.transformIfNotValid = Objects.requireNonNull(notValidFunction); 64 | return this; 65 | } 66 | 67 | public ValidatingSpliterator build() { 68 | return new ValidatingSpliterator<>(spliterator, validator, transformIfValid, transformIfNotValid); 69 | } 70 | } 71 | 72 | ValidatingSpliterator( 73 | Spliterator spliterator, Predicate validator, 74 | Function transformIfValid, Function transformIfNotValid) { 75 | this.spliterator = Objects.requireNonNull(spliterator, "spliterator"); 76 | this.validator = Objects.requireNonNull(validator, "validator"); 77 | this.transformIfValid = Objects.requireNonNull(transformIfValid, "validFunction"); 78 | this.transformIfNotValid = Objects.requireNonNull(transformIfNotValid, "notValidFunction"); 79 | } 80 | 81 | @Override 82 | public boolean tryAdvance(Consumer action) { 83 | 84 | return this.spliterator.tryAdvance( 85 | e -> { 86 | if (validator.test(e)) { 87 | action.accept(transformIfValid.apply(e)); 88 | } else { 89 | action.accept(transformIfNotValid.apply(e)); 90 | } 91 | } 92 | ); 93 | } 94 | 95 | @Override 96 | public Spliterator trySplit() { 97 | Spliterator split = this.spliterator.trySplit(); 98 | return split == null ? null : new ValidatingSpliterator<>(split, validator, transformIfValid, transformIfNotValid); 99 | } 100 | 101 | @Override 102 | public long estimateSize() { 103 | return spliterator.estimateSize(); 104 | } 105 | 106 | @Override 107 | public int characteristics() { 108 | return this.spliterator.characteristics() & ~Spliterator.SORTED; 109 | } 110 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/WeavingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.ArrayDeque; 22 | import java.util.Deque; 23 | import java.util.Objects; 24 | import java.util.Spliterator; 25 | import java.util.function.Consumer; 26 | import java.util.stream.Stream; 27 | 28 | import static java.util.stream.Collectors.toList; 29 | import static org.paumard.streams.StreamsUtils.roll; 30 | 31 | /** 32 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 33 | * 34 | * @author José 35 | */ 36 | public class WeavingSpliterator implements Spliterator { 37 | 38 | private final Spliterator[] spliterators; 39 | private final ArrayDeque elements = new ArrayDeque<>(); 40 | private boolean firstGroup = true; 41 | private boolean moreElements; 42 | 43 | @SafeVarargs 44 | public static WeavingSpliterator of(Spliterator... spliterators) { 45 | Objects.requireNonNull(spliterators); 46 | if (spliterators.length < 2) { 47 | throw new IllegalArgumentException("Why would you weave less than 2 spliterators?"); 48 | } 49 | if (Stream.of(spliterators).mapToInt(Spliterator::characteristics).reduce(Spliterator.ORDERED, (i1, i2) -> i1 & i2) == 0) { 50 | throw new IllegalArgumentException("Why would you want to weave non ordered spliterators?"); 51 | } 52 | 53 | return new WeavingSpliterator<>(spliterators); 54 | } 55 | 56 | @SafeVarargs 57 | private WeavingSpliterator(Spliterator... spliterators) { 58 | this.spliterators = spliterators; 59 | } 60 | 61 | private void consumeOneElementOnEachSpliterator() { 62 | Deque elementsWave = new ArrayDeque<>(); 63 | moreElements = true; 64 | for (int i = 0; i < spliterators.length && moreElements; i++) { 65 | moreElements = spliterators[i].tryAdvance(elementsWave::addLast); 66 | } 67 | if (moreElements) { 68 | elements.addAll(elementsWave); 69 | } 70 | } 71 | 72 | @Override 73 | public boolean tryAdvance(Consumer action) { 74 | if (firstGroup) { 75 | consumeOneElementOnEachSpliterator(); 76 | firstGroup = false; 77 | } 78 | if (!elements.isEmpty() && moreElements) { 79 | action.accept(elements.pop()); 80 | return moreElements; 81 | } 82 | if (moreElements) { 83 | consumeOneElementOnEachSpliterator(); 84 | } 85 | if (!elements.isEmpty() && moreElements) { 86 | action.accept(elements.pop()); 87 | return moreElements; 88 | } 89 | return false; 90 | } 91 | 92 | @SuppressWarnings("unchecked") 93 | @Override 94 | public Spliterator trySplit() { 95 | WeavingSpliterator[] splitSpliterators = Stream.of(spliterators).map(Spliterator::trySplit).toArray(WeavingSpliterator[]::new); 96 | return Stream.of(splitSpliterators).noneMatch(Objects::isNull) ? new WeavingSpliterator<>(splitSpliterators) : null; 97 | } 98 | 99 | @Override 100 | public long estimateSize() { 101 | return hasMaxValueSize() ? Long.MAX_VALUE : Stream.of(spliterators).mapToLong(Spliterator::estimateSize).min().getAsLong()*spliterators.length; 102 | } 103 | 104 | private boolean hasMaxValueSize() { 105 | return Stream.of(spliterators).mapToLong(Spliterator::estimateSize).anyMatch(l -> l == Long.MAX_VALUE); 106 | } 107 | 108 | @Override 109 | public int characteristics() { 110 | return Stream.of(spliterators) 111 | .mapToInt(Spliterator::characteristics) 112 | .reduce(0xFFFFFFFF, (i1, i2) -> i1 & i2) 113 | & ~Spliterator.SORTED; 114 | } 115 | } -------------------------------------------------------------------------------- /src/main/java/org/paumard/spliterators/ZippingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.streams.StreamsUtils; 20 | 21 | import java.util.Objects; 22 | import java.util.Spliterator; 23 | import java.util.function.*; 24 | 25 | /** 26 | * See the documentation and patterns to be used in this class in the {@link StreamsUtils} factory class. 27 | * 28 | * @author José 29 | */ 30 | public class ZippingSpliterator implements Spliterator { 31 | 32 | private final Spliterator spliterator1; 33 | private final Spliterator spliterator2; 34 | private final BiFunction zipper; 35 | 36 | public static class Builder { 37 | 38 | private Spliterator spliterator1; 39 | private Spliterator spliterator2; 40 | private BiFunction zipper; 41 | 42 | public Builder() { 43 | } 44 | 45 | public Builder with(Spliterator spliterator) { 46 | this.spliterator1 = Objects.requireNonNull(spliterator); 47 | return this; 48 | } 49 | 50 | public Builder and(Spliterator spliterator) { 51 | this.spliterator2 = Objects.requireNonNull(spliterator); 52 | return this; 53 | } 54 | 55 | public Builder mergedBy(BiFunction zipper) { 56 | this.zipper = Objects.requireNonNull(zipper); 57 | return this; 58 | } 59 | 60 | public ZippingSpliterator build() { 61 | return new ZippingSpliterator<>(spliterator1, spliterator2, zipper); 62 | } 63 | } 64 | 65 | ZippingSpliterator( 66 | Spliterator spliterator1, Spliterator spliterator2, 67 | BiFunction zipper) { 68 | this.spliterator1 = Objects.requireNonNull(spliterator1, "spliterator1"); 69 | this.spliterator2 = Objects.requireNonNull(spliterator2, "spliterator2"); 70 | this.zipper = Objects.requireNonNull(zipper, "zipper"); 71 | } 72 | 73 | private static class Wrapper { 74 | 75 | private E e; 76 | 77 | public E get() { 78 | return this.e; 79 | } 80 | 81 | public void set(E e) { 82 | this.e = e; 83 | } 84 | 85 | static Wrapper empty() { 86 | return new Wrapper<>(); 87 | } 88 | } 89 | 90 | @Override 91 | public boolean tryAdvance(Consumer action) { 92 | 93 | Wrapper wrapper1 = Wrapper.empty(); 94 | boolean advanced1 = spliterator1.tryAdvance(wrapper1::set); 95 | if (advanced1) { 96 | Wrapper wrapper2 = Wrapper.empty(); 97 | boolean advanced2 = spliterator2.tryAdvance(wrapper2::set); 98 | 99 | if (advanced2) { 100 | action.accept(Objects.requireNonNull(zipper.apply(wrapper1.get(), wrapper2.get()))); 101 | return true; 102 | } else { 103 | return false; 104 | } 105 | } else { 106 | return false; 107 | } 108 | } 109 | 110 | @Override 111 | public Spliterator trySplit() { 112 | Spliterator splitedSpliterator1 = spliterator1.trySplit(); 113 | Spliterator splitedSpliterator2 = spliterator2.trySplit(); 114 | 115 | return splitedSpliterator1 == null || splitedSpliterator2 == null ? null : 116 | new ZippingSpliterator<>(splitedSpliterator1, splitedSpliterator2, zipper); 117 | } 118 | 119 | @Override 120 | public long estimateSize() { 121 | return Long.min(spliterator1.estimateSize(), spliterator2.estimateSize()); 122 | } 123 | 124 | @Override 125 | public int characteristics() { 126 | return this.spliterator1.characteristics() & this.spliterator2.characteristics() & ~Spliterator.SORTED; 127 | } 128 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/AccumulatingEntriesSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.AbstractMap; 24 | import java.util.Arrays; 25 | import java.util.List; 26 | import java.util.Map; 27 | import java.util.concurrent.atomic.AtomicBoolean; 28 | import java.util.stream.Stream; 29 | import java.util.stream.StreamSupport; 30 | 31 | import static java.util.stream.Collectors.toList; 32 | import static org.assertj.core.api.Assertions.*; 33 | 34 | /** 35 | * Created by José 36 | */ 37 | public class AccumulatingEntriesSpliteratorTest { 38 | 39 | @Test 40 | public void should_accumulate_an_empty_entry_stream_into_an_empty_entry_stream() { 41 | // Given 42 | Stream> entries = 43 | Stream.of( 44 | new AbstractMap.SimpleEntry<>(1, "1"), 45 | new AbstractMap.SimpleEntry<>(2, "2") 46 | ); 47 | entries = entries.filter(e -> e.getValue().length() > 10); // trick to create an empty ordered stream 48 | 49 | // When 50 | Stream> accumulate = StreamsUtils.accumulateEntries(entries, String::concat); 51 | 52 | // Then 53 | assertThat(accumulate.count()).isEqualTo(0L); 54 | } 55 | 56 | @Test 57 | public void should_accumulate_a_singleton_entry_stream_into_the_same_entry_stream() { 58 | // Given 59 | Stream> entries = 60 | Stream.of( 61 | new AbstractMap.SimpleEntry<>(1, "1") 62 | ); 63 | 64 | // When 65 | Stream> accumulate = StreamsUtils.accumulateEntries(entries, String::concat); 66 | 67 | // Then 68 | assertThat(accumulate.collect(toList())).containsExactly(new AbstractMap.SimpleEntry<>(1, "1")); 69 | } 70 | 71 | @Test 72 | public void should_accumulate_an_entry_stream_into_the_correct_entry_stream() { 73 | // Given 74 | Stream> entries = 75 | Stream.of( 76 | new AbstractMap.SimpleEntry<>(1, "1"), 77 | new AbstractMap.SimpleEntry<>(2, "2"), 78 | new AbstractMap.SimpleEntry<>(3, "3"), 79 | new AbstractMap.SimpleEntry<>(4, "4") 80 | ); 81 | 82 | // When 83 | Stream> accumulate = StreamsUtils.accumulateEntries(entries, String::concat); 84 | 85 | // Then 86 | assertThat(accumulate.collect(toList())).containsExactly( 87 | new AbstractMap.SimpleEntry<>(1, "1"), 88 | new AbstractMap.SimpleEntry<>(2, "12"), 89 | new AbstractMap.SimpleEntry<>(3, "123"), 90 | new AbstractMap.SimpleEntry<>(4, "1234") 91 | ); 92 | } 93 | 94 | @Test 95 | public void should_conform_to_specified_trySplit_behavior() { 96 | // Given 97 | Stream> entries = 98 | Stream.of( 99 | new AbstractMap.SimpleEntry<>(1, "1"), 100 | new AbstractMap.SimpleEntry<>(2, "2"), 101 | new AbstractMap.SimpleEntry<>(3, "3") 102 | ); 103 | Stream> accumulatingStream = StreamsUtils.accumulateEntries(entries, String::concat); 104 | TryAdvanceCheckingSpliterator> spliterator = new TryAdvanceCheckingSpliterator<>(accumulatingStream.spliterator()); 105 | Stream> monitoredStream = StreamSupport.stream(spliterator, false); 106 | 107 | // When 108 | long count = monitoredStream.count(); 109 | 110 | // Then 111 | assertThat(count).isEqualTo(3L); 112 | } 113 | 114 | @Test 115 | public void should_correctly_count_the_elements_of_a_sized_stream() { 116 | // Given 117 | List> entries = Arrays.asList( 118 | new AbstractMap.SimpleEntry<>(1, "1"), 119 | new AbstractMap.SimpleEntry<>(2, "2"), 120 | new AbstractMap.SimpleEntry<>(3, "3"), 121 | new AbstractMap.SimpleEntry<>(4, "4") 122 | ); 123 | Stream> accumulatingStream = StreamsUtils.accumulateEntries(entries.stream(), String::concat); 124 | 125 | // When 126 | long count = accumulatingStream.count(); 127 | 128 | // Then 129 | assertThat(count).isEqualTo(4); 130 | } 131 | 132 | @Test 133 | public void should_not_build_an_accumulate_stream_on_a_non_ordered_stream() { 134 | // Given 135 | Map map = Map.of(1, "1", 2, "2"); 136 | Stream> entryStream = map.entrySet().stream(); 137 | 138 | // Then 139 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.accumulateEntries(entryStream, String::concat)); 140 | } 141 | 142 | @Test 143 | public void should_not_build_an_accumulate_stream_on_a_null_stream() { 144 | // When 145 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.accumulateEntries(null, Integer::sum)); 146 | } 147 | 148 | @Test 149 | public void should_not_build_an_accumulate_stream_on_a_null_operator() { 150 | // Given 151 | Stream> stream = Map.of(1, "1", 2, "2").entrySet().stream(); 152 | 153 | // Then 154 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.accumulateEntries(stream, null)); 155 | } 156 | 157 | @Test 158 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 159 | // Given 160 | AtomicBoolean b = new AtomicBoolean(false); 161 | Stream> entries = 162 | Stream.of( 163 | new AbstractMap.SimpleEntry<>(1, "1"), 164 | new AbstractMap.SimpleEntry<>(2, "2") 165 | ); 166 | Stream> stream = entries.onClose(() -> b.set(true)); 167 | 168 | // When 169 | StreamsUtils.accumulateEntries(stream, String::concat).close(); 170 | 171 | // Then 172 | assertThat(b.get()).isEqualTo(true); 173 | } 174 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/AccumulatingSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.Map; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.stream.Stream; 26 | import java.util.stream.StreamSupport; 27 | 28 | import static java.util.stream.Collectors.toList; 29 | import static org.assertj.core.api.Assertions.*; 30 | 31 | /** 32 | * Created by José 33 | */ 34 | public class AccumulatingSpliteratorTest { 35 | 36 | @Test 37 | public void should_accumulate_an_empty_stream_into_an_empty_stream() { 38 | // Given 39 | Stream strings = Stream.of("0", "0"); 40 | strings = strings.filter(s -> s.length() > 10); // trick to create an empty ordered stream 41 | 42 | // When 43 | Stream accumulate = StreamsUtils.accumulate(strings, String::concat); 44 | 45 | // Then 46 | assertThat(accumulate.count()).isEqualTo(0L); 47 | } 48 | 49 | @Test 50 | public void should_accumulate_a_singleton_stream_into_the_same_stream() { 51 | // Given 52 | Stream strings = Stream.of("one"); 53 | 54 | // When 55 | Stream accumulate = StreamsUtils.accumulate(strings, String::concat); 56 | 57 | // Then 58 | assertThat(accumulate.collect(toList())).containsExactly("one"); 59 | } 60 | 61 | @Test 62 | public void should_accumulate_a_stream_into_the_correct_stream() { 63 | // Given 64 | Stream integers = Stream.of(1, 1, 1, 1, 1); 65 | 66 | // When 67 | Stream accumulate = StreamsUtils.accumulate(integers, Integer::sum); 68 | 69 | // Then 70 | assertThat(accumulate.collect(toList())).containsExactly(1, 2, 3, 4, 5); 71 | } 72 | 73 | @Test 74 | public void should_conform_to_specified_trySplit_behavior() { 75 | // Given 76 | Stream strings = Stream.of("one", "two", "three"); 77 | Stream accumulatingStream = StreamsUtils.accumulate(strings, String::concat); 78 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(accumulatingStream.spliterator()); 79 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 80 | 81 | // When 82 | long count = monitoredStream.count(); 83 | 84 | // Then 85 | assertThat(count).isEqualTo(3L); 86 | } 87 | 88 | @Test 89 | public void should_correctly_count_the_elements_of_a_sized_stream() { 90 | // Given 91 | Stream integers = Stream.of(1, 1, 1, 1, 1); 92 | Stream accumulate = StreamsUtils.accumulate(integers, Integer::sum); 93 | 94 | // When 95 | long count = accumulate.count(); 96 | 97 | // Then 98 | assertThat(count).isEqualTo(5); 99 | } 100 | 101 | @Test 102 | public void should_not_build_an_accumulate_stream_on_a_non_ordered_stream() { 103 | // Given 104 | Map map = Map.of(1, "1", 2, "2"); 105 | Stream accumulate = map.keySet().stream(); 106 | 107 | // Then 108 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.accumulate(accumulate, Integer::sum)); 109 | } 110 | 111 | @Test 112 | public void should_not_build_an_accumulate_stream_on_a_null_stream() { 113 | // Then 114 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.accumulate(null, Integer::sum)); 115 | } 116 | 117 | @Test 118 | public void should_not_build_an_accumulate_stream_on_a_null_operator() { 119 | // Given 120 | Stream stream = Stream.of(1, 1, 1, 1, 1); 121 | 122 | // Then 123 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.accumulate(stream, null)); 124 | } 125 | 126 | @Test 127 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 128 | // Given 129 | AtomicBoolean b = new AtomicBoolean(false); 130 | Stream integers = Stream.of(1, 1, 1, 1, 1).onClose(() -> b.set(true)); 131 | 132 | // When 133 | StreamsUtils.accumulate(integers, Integer::sum).close(); 134 | 135 | // Then 136 | assertThat(b.get()).isEqualTo(true); 137 | } 138 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/CrossProductNoDoublesSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.stream.Collectors; 26 | import java.util.stream.Stream; 27 | import java.util.stream.StreamSupport; 28 | 29 | import static java.util.stream.Collectors.toList; 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 32 | 33 | /** 34 | * Created by José 35 | */ 36 | public class CrossProductNoDoublesSpliteratorTest { 37 | 38 | @Test 39 | public void should_cross_an_empty_stream_into_an_empty_stream() { 40 | // Given 41 | Stream strings = Stream.empty(); 42 | 43 | // When 44 | Stream> stream = StreamsUtils.crossProductNoDoubles(strings); 45 | long count = stream.count(); 46 | 47 | // Then 48 | assertThat(count).isEqualTo(0L); 49 | } 50 | 51 | @Test 52 | public void should_cross_a_singleton_stream_into_an_empty_stream() { 53 | // Given 54 | Stream strings = Stream.of("a"); 55 | 56 | // When 57 | Stream> stream = StreamsUtils.crossProductNoDoubles(strings); 58 | List> entries = stream.collect(toList()); 59 | 60 | // Then 61 | assertThat(entries.size()).isEqualTo(0); 62 | } 63 | 64 | @Test 65 | public void should_cross_a_non_empty_stream_into_a_stream_of_entries() { 66 | // Given 67 | Stream strings = Stream.of("a", "b", "c", "d"); 68 | 69 | 70 | // When 71 | Stream> stream = StreamsUtils.crossProductNoDoubles(strings); 72 | Comparator> comparator = 73 | Comparator., String>comparing(Map.Entry::getKey) 74 | .thenComparing(Map.Entry::getValue); 75 | Set> entries = 76 | stream.collect( 77 | Collectors.toCollection(() -> new TreeSet<>(comparator)) 78 | ); 79 | 80 | // Then 81 | assertThat(entries.size()).isEqualTo(12); 82 | Iterator> iterator = entries.iterator(); 83 | Map.Entry entry = iterator.next(); 84 | assertThat(entry.getKey()).isEqualTo("a"); 85 | assertThat(entry.getValue()).isEqualTo("b"); 86 | entry = iterator.next(); 87 | assertThat(entry.getKey()).isEqualTo("a"); 88 | assertThat(entry.getValue()).isEqualTo("c"); 89 | entry = iterator.next(); 90 | assertThat(entry.getKey()).isEqualTo("a"); 91 | assertThat(entry.getValue()).isEqualTo("d"); 92 | entry = iterator.next(); 93 | assertThat(entry.getKey()).isEqualTo("b"); 94 | assertThat(entry.getValue()).isEqualTo("a"); 95 | entry = iterator.next(); 96 | assertThat(entry.getKey()).isEqualTo("b"); 97 | assertThat(entry.getValue()).isEqualTo("c"); 98 | entry = iterator.next(); 99 | assertThat(entry.getKey()).isEqualTo("b"); 100 | assertThat(entry.getValue()).isEqualTo("d"); 101 | entry = iterator.next(); 102 | assertThat(entry.getKey()).isEqualTo("c"); 103 | assertThat(entry.getValue()).isEqualTo("a"); 104 | entry = iterator.next(); 105 | assertThat(entry.getKey()).isEqualTo("c"); 106 | assertThat(entry.getValue()).isEqualTo("b"); 107 | entry = iterator.next(); 108 | assertThat(entry.getKey()).isEqualTo("c"); 109 | assertThat(entry.getValue()).isEqualTo("d"); 110 | entry = iterator.next(); 111 | assertThat(entry.getKey()).isEqualTo("d"); 112 | assertThat(entry.getValue()).isEqualTo("a"); 113 | entry = iterator.next(); 114 | assertThat(entry.getKey()).isEqualTo("d"); 115 | assertThat(entry.getValue()).isEqualTo("b"); 116 | entry = iterator.next(); 117 | assertThat(entry.getKey()).isEqualTo("d"); 118 | assertThat(entry.getValue()).isEqualTo("c"); 119 | } 120 | 121 | @Test 122 | public void should_be_able_to_cross_product_no_doubles_a_sorted_stream_in_an_non_sorted_cross_product_stream() { 123 | // Given 124 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("one", "two", "three")); 125 | 126 | // When 127 | Stream> stream = StreamsUtils.crossProductNoDoubles(sortedSet.stream()); 128 | 129 | // Then 130 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 131 | } 132 | 133 | @Test 134 | public void should_conform_to_specified_trySplit_behavior() { 135 | // Given 136 | Stream strings = Stream.of("a", "d", "c", "b"); 137 | Stream> stream = StreamsUtils.crossProductNoDoubles(strings); 138 | TryAdvanceCheckingSpliterator> spliterator = new TryAdvanceCheckingSpliterator<>(stream.spliterator()); 139 | Stream> monitoredStream = StreamSupport.stream(spliterator, false); 140 | 141 | // When 142 | long count = monitoredStream.count(); 143 | 144 | // Then 145 | assertThat(count).isEqualTo(12L); 146 | } 147 | 148 | @Test 149 | public void should_correctly_count_the_elements_of_a_sized_stream() { 150 | // Given 151 | Stream strings = Stream.of("a", "d", "c", "b"); 152 | Stream> stream = StreamsUtils.crossProductNoDoubles(strings); 153 | 154 | // When 155 | long count = stream.count(); 156 | 157 | // Then 158 | assertThat(count).isEqualTo(12L); 159 | } 160 | 161 | @Test 162 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 163 | // Given 164 | AtomicBoolean b = new AtomicBoolean(false); 165 | Stream strings = Stream.of("a", "d", "c", "b").onClose(() -> b.set(true)); 166 | 167 | // When 168 | StreamsUtils.crossProductNoDoubles(strings).close(); 169 | 170 | // Then 171 | assertThat(b.get()).isEqualTo(true); 172 | } 173 | 174 | @Test 175 | public void should_not_build_a_crossing_spliterator_on_a_null_spliterator() { 176 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.crossProductNoDoubles(null)); 177 | } 178 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/CyclingSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.stream.IntStream; 25 | import java.util.stream.Stream; 26 | import java.util.stream.StreamSupport; 27 | 28 | import static java.util.function.Function.identity; 29 | import static java.util.stream.Collectors.toList; 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 32 | import static org.paumard.streams.StreamsUtils.cycle; 33 | import static org.paumard.streams.StreamsUtils.zip; 34 | 35 | /** 36 | * Created by José 37 | */ 38 | public class CyclingSpliteratorTest { 39 | 40 | @Test 41 | public void should_cycle_an_empty_stream_into_a_stream_of_streams() { 42 | // Given 43 | Stream strings = Stream.empty(); 44 | 45 | // When 46 | long n = StreamSupport.stream(CyclingSpliterator.of(strings.spliterator()), false).limit(10).count(); 47 | 48 | // Then 49 | assertThat(n).isEqualTo(10); 50 | } 51 | 52 | @Test 53 | public void should_cycle_an_empty_stream_into_a_stream_of_empty_streams() { 54 | // Given 55 | Stream strings = Stream.empty(); 56 | 57 | // When 58 | Stream stream = StreamSupport.stream(CyclingSpliterator.of(strings.spliterator()), false).limit(10).flatMap(identity()); 59 | // Then 60 | assertThat(stream.count()).isEqualTo(0); 61 | } 62 | 63 | @Test 64 | public void should_cycle_a_non_empty_stream_into_a_stream_of_streams() { 65 | // Given 66 | Stream strings = Stream.of("one", "two"); 67 | 68 | // When 69 | long n = StreamSupport.stream(CyclingSpliterator.of(strings.spliterator()), false).limit(10).count(); 70 | // Then 71 | assertThat(n).isEqualTo(10); 72 | } 73 | 74 | @Test 75 | public void should_cycle_a_non_empty_stream_into_a_stream_of_non_empty_streams() { 76 | // Given 77 | Stream strings = Stream.of("one", "two"); 78 | 79 | // When 80 | List list = StreamSupport.stream(CyclingSpliterator.of(strings.spliterator()), false).limit(3).flatMap(identity()).collect(toList()); 81 | // Then 82 | assertThat(list).containsExactly("one", "two", "one", "two", "one", "two"); 83 | } 84 | 85 | @Test 86 | public void should_be_able_to_cycle_a_sorted_stream_in_an_non_sorted_cycle_stream() { 87 | // Given 88 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("one", "two", "three")); 89 | 90 | // When 91 | Stream stream = StreamsUtils.cycle(sortedSet.stream()); 92 | 93 | // Then 94 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 95 | } 96 | 97 | @Test 98 | public void should_not_build_a_cycling_spliterator_on_a_null_spliterator() { 99 | // Then 100 | assertThatNullPointerException().isThrownBy(() -> CyclingSpliterator.of(null)); 101 | } 102 | 103 | @Test 104 | public void should_conform_to_specified_trySplit_behavior() { 105 | // Given 106 | Stream strings = Stream.of("one", "two", "three"); 107 | Stream cyclingStream = StreamsUtils.cycle(strings).limit(2); 108 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(cyclingStream.spliterator()); 109 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 110 | 111 | // When 112 | long count = monitoredStream.count(); 113 | 114 | // Then 115 | assertThat(count).isEqualTo(2L); 116 | } 117 | 118 | @Test 119 | public void should_solve_fizzbuzz_correctly() { 120 | 121 | // When 122 | Stream fizzBuzz = 123 | zip( 124 | IntStream.range(0, 101).boxed(), 125 | zip( 126 | cycle(Stream.of("fizz", "", "")), 127 | cycle(Stream.of("buzz", "", "", "", "")), 128 | String::concat 129 | ), 130 | (i, string) -> string.isEmpty() ? i.toString() : string 131 | ); 132 | List fizzBuzzList = fizzBuzz.skip(1).limit(20).collect(toList()); 133 | 134 | // Then 135 | assertThat(fizzBuzzList).containsExactly( 136 | "1", "2", "fizz", "4", "buzz", "fizz", "7", "8", "fizz", 137 | "buzz", "11", "fizz", "13", "14", "fizzbuzz", "16", "17", "fizz", "19", 138 | "buzz"); 139 | } 140 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/FilteringAllMaxSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.stream.Stream; 26 | import java.util.stream.StreamSupport; 27 | 28 | import static java.util.stream.Collectors.toList; 29 | import static org.assertj.core.api.Assertions.assertThat; 30 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 31 | 32 | /** 33 | * Created by José 34 | */ 35 | public class FilteringAllMaxSpliteratorTest { 36 | 37 | @Test 38 | public void should_filter_an_empty_stream_into_an_empty_stream() { 39 | // Given 40 | Stream strings = Stream.empty(); 41 | Comparator comparator = Comparator.naturalOrder(); 42 | 43 | // When 44 | long n = StreamsUtils.filteringAllMax(strings, comparator).count(); 45 | // Then 46 | assertThat(n).isEqualTo(0L); 47 | } 48 | 49 | @Test 50 | public void should_filter_a_non_empty_stream_into_a_the_right_stream_when_several_maxes() { 51 | // Given 52 | Stream strings = Stream.of("1", "1", "2", "2", "3", "3"); 53 | Comparator comparator = Comparator.naturalOrder(); 54 | 55 | // When 56 | List list = StreamsUtils.filteringAllMax(strings, comparator).collect(toList()); 57 | 58 | // Then 59 | assertThat(list).containsExactly("3", "3"); 60 | } 61 | 62 | @Test 63 | public void should_filter_a_non_empty_stream_into_a_the_right_stream_when_one_max() { 64 | // Given 65 | Stream strings = Stream.of("4", "1", "1", "2", "2", "3", "3"); 66 | Comparator comparator = Comparator.naturalOrder(); 67 | 68 | // When 69 | List list = StreamsUtils.filteringAllMax(strings, comparator).collect(toList()); 70 | 71 | // Then 72 | assertThat(list).containsExactly("4"); 73 | } 74 | 75 | @Test 76 | public void should_be_able_to_filter_all_maxes_of_a_sorted_stream_in_an_sorted_filtered_stream() { 77 | // Given 78 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("one", "two", "three")); 79 | 80 | // When 81 | Stream stream = StreamsUtils.filteringAllMax(sortedSet.stream()); 82 | 83 | // Then 84 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(Spliterator.SORTED); 85 | } 86 | 87 | @Test 88 | public void should_conform_to_specified_trySplit_behavior() { 89 | // Given 90 | Stream strings = Arrays.asList("one", "two", "three").stream(); 91 | Stream testedStream = StreamsUtils.filteringAllMax(strings); 92 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 93 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 94 | 95 | // When 96 | long count = monitoredStream.count(); 97 | 98 | // Then 99 | assertThat(count).isEqualTo(1L); 100 | } 101 | 102 | @Test 103 | public void should_correctly_count_the_elements_of_a_sized_stream() { 104 | // Given 105 | Stream strings = Arrays.asList("one", "two", "three").stream(); 106 | Stream stream = StreamsUtils.filteringAllMax(strings); 107 | 108 | // When 109 | long count = stream.count(); 110 | 111 | // Then 112 | assertThat(count).isEqualTo(1L); 113 | } 114 | 115 | @Test 116 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 117 | // Given 118 | AtomicBoolean b = new AtomicBoolean(false); 119 | Stream strings = Stream.of("one", "two", "three").onClose(() -> b.set(true)); 120 | 121 | // When 122 | StreamsUtils.filteringAllMax(strings).close(); 123 | 124 | // Then 125 | assertThat(b.get()).isEqualTo(true); 126 | } 127 | 128 | @Test 129 | public void should_not_build_a_filtering_spliterator_on_a_null_stream() { 130 | // Given 131 | Comparator comparator = Comparator.naturalOrder(); 132 | 133 | // Then 134 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.filteringAllMax(null, comparator)); 135 | } 136 | 137 | @Test 138 | public void should_not_build_a_filtering_spliterator_on_a_null_comparator() { 139 | // Given 140 | Stream strings = Stream.of("1", "1", "2", "2", "3", "3"); 141 | 142 | // When 143 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.filteringAllMax(strings, null).collect(toList())); 144 | } 145 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/GatingSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.function.Predicate; 26 | import java.util.stream.Stream; 27 | import java.util.stream.StreamSupport; 28 | 29 | import static java.util.stream.Collectors.toList; 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | 32 | /** 33 | * Created by José 34 | */ 35 | public class GatingSpliteratorTest { 36 | 37 | @Test 38 | public void should_gate_empty_streams_into_an_empty_stream() { 39 | // Given 40 | Stream strings = Stream.empty(); 41 | Predicate validator = String::isEmpty; 42 | 43 | // When 44 | Stream gatingStream = StreamsUtils.gate(strings, validator); 45 | long count = gatingStream.count(); 46 | 47 | // Then 48 | assertThat(count).isEqualTo(0); 49 | } 50 | 51 | @Test 52 | public void should_gate_a_stream_correctly() { 53 | // Given 54 | Stream strings = Stream.of("", "", "", "", "one", "two", "three"); 55 | 56 | // When 57 | Stream gatingStream = StreamsUtils.gate(strings, s -> !s.isEmpty()); 58 | List list = gatingStream.collect(toList()); 59 | 60 | // Then 61 | assertThat(list.size()).isEqualTo(3); 62 | assertThat(list).containsExactly("one", "two", "three"); 63 | } 64 | 65 | @Test 66 | public void should_gate_a_stream_correctly_when_the_gate_opens_on_the_first_element() { 67 | // Given 68 | Stream strings = Stream.of("one", "two", "three"); 69 | 70 | // When 71 | Stream gatingStream = StreamsUtils.gate(strings, s -> !s.isEmpty()); 72 | List list = gatingStream.collect(toList()); 73 | 74 | // Then 75 | assertThat(list.size()).isEqualTo(3); 76 | assertThat(list).containsExactly("one", "two", "three"); 77 | } 78 | 79 | @Test 80 | public void should_gate_a_stream_correctly_when_the_gate_does_not_open() { 81 | // Given 82 | Stream strings = Stream.of("", "", "", ""); 83 | 84 | // When 85 | Stream gatingStream = StreamsUtils.gate(strings, s -> !s.isEmpty()); 86 | List list = gatingStream.collect(toList()); 87 | 88 | // Then 89 | assertThat(list.size()).isEqualTo(0); 90 | } 91 | 92 | @Test 93 | public void should_gate_a_sorted_stream_correctly_and_in_a_sorted_stream() { 94 | // Given 95 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("", "", "", "", "one", "two", "three")); 96 | 97 | // When 98 | Stream gatingStream = StreamsUtils.gate(sortedSet.stream(), s -> !s.isEmpty()); 99 | 100 | // Then 101 | assertThat(gatingStream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(Spliterator.SORTED); 102 | } 103 | 104 | @Test 105 | public void should_conform_to_specified_trySplit_behavior_with_a_normal_stream() { 106 | // Given 107 | Stream strings = Stream.of("", "", "", "", "one", "two", "three"); 108 | Stream testedStream = StreamsUtils.gate(strings, s -> !s.isEmpty()); 109 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 110 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 111 | 112 | // When 113 | long count = monitoredStream.count(); 114 | 115 | // Then 116 | assertThat(count).isEqualTo(3L); 117 | } 118 | 119 | @Test 120 | public void should_conform_to_specified_trySplit_behavior_with_a_fully_valid__stream() { 121 | // Given 122 | Stream strings = Stream.of("one", "two", "three"); 123 | Stream testedStream = StreamsUtils.gate(strings, s -> !s.isEmpty()); 124 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 125 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 126 | 127 | // When 128 | long count = monitoredStream.count(); 129 | 130 | // Then 131 | assertThat(count).isEqualTo(3L); 132 | } 133 | 134 | @Test 135 | public void should_conform_to_specified_trySplit_behavior_with_a_fully_invalid__stream() { 136 | // Given 137 | Stream strings = Stream.of("", "", ""); 138 | Stream testedStream = StreamsUtils.gate(strings, s -> !s.isEmpty()); 139 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 140 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 141 | 142 | // When 143 | long count = monitoredStream.count(); 144 | 145 | // Then 146 | assertThat(count).isEqualTo(0L); 147 | } 148 | 149 | @Test 150 | public void should_conform_to_specified_trySplit_behavior_with_an_empty_stream() { 151 | // Given 152 | Stream strings = Stream.empty(); 153 | Stream testedStream = StreamsUtils.gate(strings, s -> !s.isEmpty()); 154 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 155 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 156 | 157 | // When 158 | long count = monitoredStream.count(); 159 | 160 | // Then 161 | assertThat(count).isEqualTo(0L); 162 | } 163 | 164 | @Test 165 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 166 | // Given 167 | AtomicBoolean b = new AtomicBoolean(false); 168 | Stream strings = Stream.of("", "", "", "", "one", "two", "three").onClose(() -> b.set(true)); 169 | 170 | // When 171 | StreamsUtils.gate(strings, s -> !s.isEmpty()).close(); 172 | 173 | // Then 174 | assertThat(b.get()).isEqualTo(true); 175 | } 176 | 177 | @Test 178 | public void should_correctly_count_the_elements_of_a_sized_stream() { 179 | // Given 180 | Stream strings = Arrays.asList("", "", "", "one", "two", "three", "four").stream(); 181 | Stream stream = StreamsUtils.gate(strings, s -> !s.isEmpty()); 182 | 183 | // When 184 | long count = stream.count(); 185 | 186 | // Then 187 | assertThat(count).isEqualTo(4L); 188 | } 189 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/GroupingOnSplittingNonIncludedSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | 20 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 21 | import org.paumard.streams.StreamsUtils; 22 | import org.testng.annotations.Test; 23 | 24 | import java.util.Arrays; 25 | import java.util.List; 26 | import java.util.Spliterator; 27 | import java.util.concurrent.atomic.AtomicBoolean; 28 | import java.util.function.Function; 29 | import java.util.function.Predicate; 30 | import java.util.stream.Collectors; 31 | import java.util.stream.Stream; 32 | import java.util.stream.StreamSupport; 33 | 34 | import static org.assertj.core.api.Assertions.assertThat; 35 | 36 | public class GroupingOnSplittingNonIncludedSpliteratorTest { 37 | 38 | @Test 39 | public void should_group_an_empty_stream_into_an_empty_stream() { 40 | // Given 41 | // a trick to create an empty ORDERED stream 42 | Stream strings = Stream.of("one").filter(s -> s.isEmpty()); 43 | Predicate splitter = s -> s.startsWith("o"); 44 | Predicate close = s -> s.startsWith("c"); 45 | 46 | // When 47 | Stream> groupingOnSplittingStream = StreamsUtils.group(strings, splitter, false); 48 | long numberOfGroupedSteams = groupingOnSplittingStream.count(); 49 | 50 | // Then 51 | assertThat(numberOfGroupedSteams).isEqualTo(0); 52 | } 53 | 54 | @Test 55 | public void should_group_an_stream_without_splitter_into_an_empty_stream() { 56 | // Given 57 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9"); 58 | Predicate splitter = s -> s.startsWith("o"); 59 | 60 | // When 61 | Stream> groupingOnSplittingStream = StreamsUtils.group(strings, splitter, false); 62 | long numberOfGroupedSteams = groupingOnSplittingStream.count(); 63 | 64 | // Then 65 | assertThat(numberOfGroupedSteams).isEqualTo(0); 66 | } 67 | 68 | @Test 69 | public void should_group_a_non_empty_stream_with_correct_substreams_content() { 70 | // Given 71 | Stream strings = Stream.of("1", "o", "2", "3", "4", "5", "6", "o", "7", "8", "o", "9"); 72 | Predicate splitter = s -> s.startsWith("o"); 73 | 74 | // When 75 | Stream> groupingStream = StreamsUtils.group(strings, splitter, false); 76 | List> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList()); 77 | 78 | // When 79 | assertThat(collect.size()).isEqualTo(3); 80 | assertThat(collect.get(0)).containsExactly("2", "3", "4", "5", "6"); 81 | assertThat(collect.get(1)).containsExactly("7", "8"); 82 | assertThat(collect.get(2)).containsExactly("9"); 83 | } 84 | 85 | @Test 86 | public void should_group_a_non_empty_stream_with_correct_substreams_content_even_if_more_than_one_opener() { 87 | // Given 88 | Stream strings = Stream.of("1", "o", "o", "2", "3", "o", "4", "5", "6", "o", "7", "8", "9"); 89 | Predicate splitter = s -> s.startsWith("o"); 90 | 91 | // When 92 | Stream> groupingStream = StreamsUtils.group(strings, splitter, false); 93 | List> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList()); 94 | 95 | // When 96 | assertThat(collect.size()).isEqualTo(4); 97 | assertThat(collect.get(0)).isEmpty(); 98 | assertThat(collect.get(1)).containsExactly("2", "3"); 99 | assertThat(collect.get(2)).containsExactly("4", "5", "6"); 100 | assertThat(collect.get(3)).containsExactly("7", "8", "9"); 101 | } 102 | 103 | @Test 104 | public void should_group_a_non_empty_stream_with_correct_substreams_content_with_splitter_at_first_position() { 105 | // Given 106 | Stream strings = Stream.of("o", "1", "2", "3", "4", "5", "6", "7", "8", "9"); 107 | Predicate splitter = s -> s.startsWith("o"); 108 | 109 | // When 110 | Stream> groupingStream = StreamsUtils.group(strings, splitter, false); 111 | List> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList()); 112 | 113 | // When 114 | assertThat(collect.size()).isEqualTo(1); 115 | assertThat(collect.get(0)).containsExactly("1", "2", "3", "4", "5", "6", "7", "8", "9"); 116 | } 117 | 118 | @Test 119 | public void should_group_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 120 | // Given 121 | List strings = Arrays.asList("o", "1", "2", "3", "4", "5", "6", "7", "8", "9", "c"); 122 | Predicate splitter = s -> s.startsWith("o"); 123 | 124 | // When 125 | Stream> groupingStream = StreamsUtils.group(strings.stream(), splitter, false); 126 | 127 | // Then 128 | assertThat(groupingStream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 129 | } 130 | 131 | @Test 132 | public void should_correctly_count_the_elements_of_a_sized_stream() { 133 | // Given 134 | Stream strings = Stream.of("o", "1", "2", "3", "4", "5", "6", "7", "8", "9", "c"); 135 | Predicate splitter = s -> s.startsWith("o"); 136 | 137 | Stream> stream = StreamsUtils.group(strings, splitter, false); 138 | 139 | // When 140 | long count = stream.count(); 141 | 142 | // Then 143 | assertThat(count).isEqualTo(1L); 144 | } 145 | 146 | @Test 147 | public void should_conform_to_specified_trySplit_behavior() { 148 | // Given 149 | Stream strings = Stream.of("o", "1", "2", "3", "4", "5", "6", "7", "8", "9", "c"); 150 | Predicate splitter = s -> s.startsWith("o"); 151 | 152 | Stream> testedStream = StreamsUtils.group(strings, splitter, false); 153 | TryAdvanceCheckingSpliterator> spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 154 | Stream monitoredStream = StreamSupport.stream(spliterator, false).flatMap(Function.identity()); 155 | 156 | // When 157 | long count = monitoredStream.count(); 158 | 159 | // Then 160 | assertThat(count).isEqualTo(10L); 161 | } 162 | 163 | @Test 164 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 165 | // Given 166 | AtomicBoolean b = new AtomicBoolean(false); 167 | Stream strings = Stream.of("o", "1", "2", "3", "4", "5", "6", "7", "8", "9", "c").onClose(() -> b.set(true)); 168 | Predicate splitter = s -> s.startsWith("o"); 169 | 170 | // When 171 | StreamsUtils.group(strings, splitter, false).close(); 172 | 173 | // Then 174 | assertThat(b.get()).isEqualTo(true); 175 | } 176 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/GroupingSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | 20 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 21 | import org.paumard.streams.StreamsUtils; 22 | import org.testng.annotations.Test; 23 | 24 | import java.util.*; 25 | import java.util.concurrent.atomic.AtomicBoolean; 26 | import java.util.function.Function; 27 | import java.util.stream.Collectors; 28 | import java.util.stream.Stream; 29 | import java.util.stream.StreamSupport; 30 | 31 | import static org.assertj.core.api.Assertions.assertThat; 32 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 33 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 34 | 35 | public class GroupingSpliteratorTest { 36 | 37 | @Test 38 | public void should_group_an_empty_stream_into_a_stream_of_an_empty_stream() { 39 | // Given 40 | // a trick to create an empty ORDERED stream 41 | Stream strings = Stream.of("one").filter(s -> s.isEmpty()); 42 | int groupingFactor = 2; 43 | 44 | // When 45 | Stream> groupingStream = StreamsUtils.group(strings, groupingFactor); 46 | long numberOfGroupedSteams = groupingStream.count(); 47 | 48 | // Then 49 | assertThat(numberOfGroupedSteams).isEqualTo(1); 50 | } 51 | 52 | @Test 53 | public void should_group_a_non_empty_stream_with_correct_substreams_content() { 54 | // Given 55 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9"); 56 | int groupingFactor = 3; 57 | 58 | // When 59 | Stream> groupingStream = StreamsUtils.group(strings, groupingFactor); 60 | List> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList()); 61 | 62 | // When 63 | assertThat(collect.size()).isEqualTo(3); 64 | assertThat(collect.get(0)).containsExactly("1", "2", "3"); 65 | assertThat(collect.get(1)).containsExactly("4", "5", "6"); 66 | assertThat(collect.get(2)).containsExactly("7", "8", "9"); 67 | } 68 | 69 | @Test 70 | public void should_group_a_non_empty_stream_with_correct_substreams_content_even_if_last_stream_is_incomplete() { 71 | // Given 72 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 73 | int groupingFactor = 3; 74 | 75 | // When 76 | Stream> groupingStream = StreamsUtils.group(strings, groupingFactor); 77 | List> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList()); 78 | 79 | // When 80 | assertThat(collect.size()).isEqualTo(3); 81 | assertThat(collect.get(0)).containsExactly("1", "2", "3"); 82 | assertThat(collect.get(1)).containsExactly("4", "5", "6"); 83 | assertThat(collect.get(2)).containsExactly("7"); 84 | } 85 | 86 | @Test 87 | public void should_group_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 88 | // Given 89 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("o", "1", "2", "3", "4", "5", "6", "7", "8", "9", "c")); 90 | int groupingFactor = 3; 91 | 92 | // When 93 | Stream> groupingStream = StreamsUtils.group(sortedSet.stream(), groupingFactor); 94 | 95 | // Then 96 | assertThat(groupingStream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 97 | } 98 | 99 | @Test 100 | public void should_conform_to_specified_trySplit_behavior() { 101 | // Given 102 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 103 | int groupingFactor = 3; 104 | 105 | Stream> testedStream = StreamsUtils.group(strings, groupingFactor); 106 | TryAdvanceCheckingSpliterator> spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 107 | Stream monitoredStream = StreamSupport.stream(spliterator, false).flatMap(Function.identity()); 108 | 109 | // When 110 | long count = monitoredStream.count(); 111 | 112 | // Then 113 | assertThat(count).isEqualTo(7L); 114 | } 115 | 116 | @Test 117 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 118 | // Given 119 | AtomicBoolean b = new AtomicBoolean(false); 120 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7").onClose(() -> b.set(true)); 121 | int groupingFactor = 3; 122 | 123 | // When 124 | StreamsUtils.group(strings, groupingFactor).close(); 125 | 126 | // Then 127 | assertThat(b.get()).isEqualTo(true); 128 | } 129 | 130 | @Test 131 | public void should_correctly_count_the_elements_of_a_sized_stream() { 132 | // Given 133 | Stream strings = Stream.of("o", "1", "2", "3", "4", "5", "6", "7", "8", "9", "c"); 134 | int groupingFactor = 3; 135 | 136 | Stream> stream = StreamsUtils.group(strings, groupingFactor); 137 | 138 | // When 139 | long count = stream.count(); 140 | 141 | // Then 142 | assertThat(count).isEqualTo(3L); 143 | } 144 | 145 | @Test 146 | public void should_not_build_a_grouping_stream_on_a_non_ordered_stream() { 147 | // Given 148 | Stream strings = Set.of("1", "2", "3", "4", "5", "6", "7").stream(); 149 | 150 | // Then 151 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.group(strings, 3)); 152 | } 153 | 154 | @Test 155 | public void should_not_build_a_grouping_spliterator_on_a_null_spliterator() { 156 | 157 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.group(null, 3)); 158 | } 159 | 160 | @Test 161 | public void should_not_build_a_grouping_spliterator_with_a_grouping_factor_of_1() { 162 | // Given 163 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 164 | 165 | // Then 166 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.group(strings, 1)); 167 | } 168 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/InterruptingSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.function.Predicate; 26 | import java.util.stream.Stream; 27 | import java.util.stream.StreamSupport; 28 | 29 | import static java.util.stream.Collectors.toList; 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | 32 | /** 33 | * Created by José 34 | */ 35 | public class InterruptingSpliteratorTest { 36 | 37 | @Test 38 | public void should_interrupt_an_empty_streams_into_an_empty_stream() { 39 | // Given 40 | Stream strings = Stream.empty(); 41 | Predicate interruptor = String::isEmpty; 42 | 43 | // When 44 | Stream interruptStream = StreamsUtils.interrupt(strings, interruptor); 45 | long count = interruptStream.count(); 46 | 47 | // Then 48 | assertThat(count).isEqualTo(0); 49 | } 50 | 51 | @Test 52 | public void should_interrupt_a_stream_correctly() { 53 | // Given 54 | Stream strings = Stream.of("one", "two", "three", "", "", "", "", ""); 55 | Predicate interruptor = String::isEmpty; 56 | 57 | // When 58 | Stream interruptStream = StreamsUtils.interrupt(strings, interruptor); 59 | List list = interruptStream.collect(toList()); 60 | 61 | // Then 62 | assertThat(list.size()).isEqualTo(3); 63 | assertThat(list).containsExactly("one", "two", "three"); 64 | } 65 | 66 | @Test 67 | public void should_interrupt_a_sorted_stream_correctly_and_in_a_sorted_stream() { 68 | // Given 69 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("one", "two", "three", "", "", "", "", "")); 70 | Predicate interruptor = String::isEmpty; 71 | 72 | // When 73 | Stream stream = StreamsUtils.interrupt(sortedSet.stream(), interruptor); 74 | 75 | // Then 76 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(Spliterator.SORTED); 77 | } 78 | 79 | @Test 80 | public void should_conform_to_specified_trySplit_behavior() { 81 | // Given 82 | Stream strings = Stream.of("one", "two", "three", "", "", "", "", ""); 83 | Predicate interruptor = String::isEmpty; 84 | 85 | Stream testedStream = StreamsUtils.interrupt(strings, interruptor); 86 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 87 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 88 | 89 | // When 90 | long count = monitoredStream.count(); 91 | 92 | // Then 93 | assertThat(count).isEqualTo(3L); 94 | } 95 | 96 | @Test 97 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 98 | // Given 99 | AtomicBoolean b = new AtomicBoolean(false); 100 | Stream strings = Stream.of("one", "two", "three", "", "", "", "", "").onClose(() -> b.set(true)); 101 | Predicate interruptor = String::isEmpty; 102 | 103 | // When 104 | StreamsUtils.interrupt(strings, interruptor).close(); 105 | 106 | // Then 107 | assertThat(b.get()).isEqualTo(true); 108 | } 109 | 110 | @Test 111 | public void should_correctly_count_the_elements_of_a_sized_stream() { 112 | // Given 113 | Stream strings = Stream.of("one", "two", "three", "", "", "", "", ""); 114 | Predicate interruptor = String::isEmpty; 115 | Stream stream = StreamsUtils.interrupt(strings, interruptor); 116 | 117 | // When 118 | long count = stream.count(); 119 | 120 | // Then 121 | assertThat(count).isEqualTo(3L); 122 | } 123 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/RepeatingSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.function.Function; 26 | import java.util.stream.Collectors; 27 | import java.util.stream.Stream; 28 | import java.util.stream.StreamSupport; 29 | 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 32 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 33 | 34 | /** 35 | * Created by José 36 | */ 37 | public class RepeatingSpliteratorTest { 38 | 39 | @Test 40 | public void should_return_an_empty_stream_when_called_with_an_empty_stream() { 41 | // Given 42 | Stream stream = Stream.empty(); 43 | int repeating = 2; 44 | 45 | // When 46 | Stream repeatingStream = StreamsUtils.repeat(stream, repeating); 47 | 48 | // Then 49 | assertThat(repeatingStream.count()).isEqualTo(0L); 50 | } 51 | 52 | @Test 53 | public void should_return_a_repeating_stream_when_called_on_a_non_empty_stream() { 54 | // Given 55 | Stream stream = Stream.of("a", "b", "c"); 56 | int repeating = 2; 57 | 58 | // When 59 | Stream repeatingStream = StreamsUtils.repeat(stream, repeating); 60 | List result = repeatingStream.collect(Collectors.toList()); 61 | 62 | // Then 63 | assertThat(result).containsExactly("a", "a", "b", "b", "c", "c"); 64 | } 65 | 66 | @Test 67 | public void should_return_a_repeating_stream_when_called_on_a_non_empty_stream_3x() { 68 | // Given 69 | Stream stream = Stream.of("a", "b", "c"); 70 | int repeating = 3; 71 | 72 | // When 73 | Stream repeatingStream = StreamsUtils.repeat(stream, repeating); 74 | List result = repeatingStream.collect(Collectors.toList()); 75 | 76 | // Then 77 | assertThat(result).containsExactly("a", "a", "a", "b", "b", "b", "c", "c", "c"); 78 | } 79 | 80 | @Test 81 | public void should_repeat_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 82 | // Given 83 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("a", "b", "c")); 84 | int repeating = 2; 85 | 86 | // When 87 | Stream stream = StreamsUtils.repeat(sortedSet.stream(), repeating); 88 | 89 | // Then 90 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 91 | } 92 | 93 | @Test 94 | public void should_conform_to_specified_trySplit_behavior() { 95 | // Given 96 | Stream strings = Stream.of("one", "two", "three"); 97 | Stream repeatingStream = StreamsUtils.repeat(strings, 2); 98 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(repeatingStream.spliterator()); 99 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 100 | 101 | // When 102 | long count = monitoredStream.count(); 103 | 104 | // Then 105 | assertThat(count).isEqualTo(6L); 106 | } 107 | 108 | @Test 109 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 110 | // Given 111 | AtomicBoolean b = new AtomicBoolean(false); 112 | Stream strings = Stream.of("one", "two", "three").onClose(() -> b.set(true)); 113 | 114 | // When 115 | StreamsUtils.repeat(strings, 2).close(); 116 | 117 | // Then 118 | assertThat(b.get()).isEqualTo(true); 119 | } 120 | 121 | @Test 122 | public void should_correctly_count_the_elements_of_a_sized_stream() { 123 | // Given 124 | Stream strings = Stream.of("a", "b", "c"); 125 | int repeating = 2; 126 | Stream stream = StreamsUtils.repeat(strings, repeating); 127 | 128 | // When 129 | long count = stream.count(); 130 | 131 | // Then 132 | assertThat(count).isEqualTo(6L); 133 | } 134 | 135 | @Test 136 | public void should_not_build_a_repeating_stream_on_a_non_sized_stream() { 137 | // Given 138 | Stream strings = Stream.iterate("+", s -> s); 139 | 140 | // Then 141 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.repeat(strings, 3)); 142 | } 143 | 144 | @Test 145 | public void should_not_build_a_repeating_spliterator_on_a_null_spliterator() { 146 | // Then 147 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.repeat(null, 3)); 148 | } 149 | 150 | @Test 151 | public void should_not_build_a_repeating_spliterator_with_a_repeating_factor_of_1() { 152 | // Given 153 | Stream stream = Stream.of("a1", "a2"); 154 | 155 | // Then 156 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.repeat(stream, 1)); 157 | 158 | } 159 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/RollingSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.function.Function; 26 | import java.util.stream.Collectors; 27 | import java.util.stream.Stream; 28 | import java.util.stream.StreamSupport; 29 | 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 32 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 33 | 34 | /** 35 | * Created by José 36 | */ 37 | public class RollingSpliteratorTest { 38 | 39 | @Test 40 | public void should_roll_an_empty_stream_into_a_stream_of_an_empty_stream() { 41 | // Given 42 | // a trick to create an empty ORDERED stream 43 | Stream strings = Stream.of("one").filter(s -> s.isEmpty()); 44 | int groupingFactor = 2; 45 | 46 | // When 47 | Stream> stream = StreamsUtils.roll(strings, groupingFactor); 48 | long numberOfRolledStreams = stream.count(); 49 | 50 | // Then 51 | assertThat(numberOfRolledStreams).isEqualTo(1); 52 | } 53 | 54 | @Test 55 | public void should_roll_a_non_empty_stream_with_correct_substreams_content() { 56 | // Given 57 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 58 | int groupingFactor = 3; 59 | 60 | // When 61 | Stream> stream = StreamsUtils.roll(strings, groupingFactor); 62 | List> collect = stream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList()); 63 | 64 | // When 65 | assertThat(collect.size()).isEqualTo(5); 66 | assertThat(collect.get(0)).containsExactly("1", "2", "3"); 67 | assertThat(collect.get(1)).containsExactly("2", "3", "4"); 68 | assertThat(collect.get(2)).containsExactly("3", "4", "5"); 69 | assertThat(collect.get(3)).containsExactly("4", "5", "6"); 70 | assertThat(collect.get(4)).containsExactly("5", "6", "7"); 71 | } 72 | 73 | @Test 74 | public void should_be_able_to_roll_a_sorted_stream_in_an_non_sorted_rolled_stream() { 75 | // Given 76 | SortedMap sortedMap = new TreeMap<>(); 77 | sortedMap.put(1L, "ONE"); 78 | sortedMap.put(2L, "TWO"); 79 | sortedMap.put(3L, "THREE"); 80 | 81 | // When 82 | Stream>> stream = StreamsUtils.roll(sortedMap.entrySet().stream(), 2); 83 | 84 | // Then 85 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 86 | } 87 | 88 | @Test 89 | public void should_conform_to_specified_trySplit_behavior() { 90 | // Given 91 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 92 | int groupingFactor = 2; 93 | 94 | Stream> testedStream = StreamsUtils.roll(strings, groupingFactor); 95 | TryAdvanceCheckingSpliterator> spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 96 | Stream monitoredStream = StreamSupport.stream(spliterator, false).flatMap(Function.identity()); 97 | 98 | // When 99 | long count = monitoredStream.count(); 100 | 101 | // Then 102 | assertThat(count).isEqualTo(12L); 103 | } 104 | 105 | @Test 106 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 107 | // Given 108 | AtomicBoolean b = new AtomicBoolean(false); 109 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7").onClose(() -> b.set(true)); 110 | int groupingFactor = 2; 111 | 112 | // When 113 | StreamsUtils.roll(strings, groupingFactor).close(); 114 | 115 | // Then 116 | assertThat(b.get()).isEqualTo(true); 117 | } 118 | 119 | @Test 120 | public void should_correctly_count_the_elements_of_a_sized_stream() { 121 | // Given 122 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 123 | int groupingFactor = 3; 124 | Stream> stream = StreamsUtils.roll(strings, groupingFactor); 125 | 126 | // When 127 | long count = stream.count(); 128 | 129 | // Then 130 | assertThat(count).isEqualTo(5L); 131 | } 132 | 133 | @Test 134 | public void should_not_build_a_rolling_spliterator_on_a_null_spliterator() { 135 | // Then 136 | assertThatNullPointerException().isThrownBy(() -> RollingSpliterator.of(null, 3)); 137 | } 138 | 139 | @Test 140 | public void should_not_build_a_rolling_spliterator_with_a_grouping_factor_of_1() { 141 | // Given 142 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 143 | int groupingFactor = 1; 144 | 145 | // Then 146 | assertThatIllegalArgumentException().isThrownBy(() -> RollingSpliterator.of(strings.spliterator(), groupingFactor)); 147 | } 148 | 149 | @Test 150 | public void should_not_build_a_rolling_spliterator_on_a_non_ordered_stream() { 151 | // Given 152 | Stream stringsA = Set.of("one", "two").stream(); 153 | 154 | // Then 155 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.roll(stringsA, 2)); 156 | } 157 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/ShiftingWindowAveragingDoubleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.stream.DoubleStream; 26 | import java.util.stream.Stream; 27 | import java.util.stream.StreamSupport; 28 | 29 | import static java.util.stream.Collectors.toList; 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 32 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 33 | 34 | /** 35 | * Created by José 36 | */ 37 | public class ShiftingWindowAveragingDoubleTest { 38 | 39 | @Test 40 | public void should_average_an_empty_stream_into_a_stream_of_an_empty_stream() { 41 | // Given 42 | // a trick to create an empty ORDERED stream 43 | Stream longs = Stream.of(1d, 2d, 3d).filter(d -> d == 0); 44 | int groupingFactor = 3; 45 | 46 | // When 47 | DoubleStream stream = StreamsUtils.shiftingWindowAveragingDouble(longs, groupingFactor, Double::valueOf); 48 | long numberOfRolledStreams = stream.count(); 49 | 50 | // Then 51 | assertThat(numberOfRolledStreams).isEqualTo(1); 52 | } 53 | 54 | @Test 55 | public void should_average_a_non_empty_stream_with_correct_substreams_content() { 56 | // Given 57 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 58 | int groupingFactor = 2; 59 | 60 | // When 61 | DoubleStream averagedStream = StreamsUtils.shiftingWindowAveragingDouble(strings, groupingFactor, Double::parseDouble); 62 | List result = averagedStream.boxed().collect(toList()); 63 | 64 | // When 65 | assertThat(result.size()).isEqualTo(6); 66 | assertThat(result.get(0)).isEqualTo(3); 67 | assertThat(result.get(1)).isEqualTo(3); 68 | assertThat(result.get(2)).isEqualTo(3); 69 | assertThat(result.get(3)).isEqualTo(3); 70 | assertThat(result.get(4)).isEqualTo(3); 71 | assertThat(result.get(5)).isEqualTo(3); 72 | } 73 | 74 | @Test 75 | public void should_process_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 76 | // Given 77 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("2", "4", "2", "4", "2", "4", "2")); 78 | int groupingFactor = 2; 79 | 80 | // When 81 | DoubleStream stream = StreamsUtils.shiftingWindowAveragingDouble(sortedSet.stream(), groupingFactor, Double::parseDouble); 82 | 83 | // Then 84 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 85 | } 86 | 87 | @Test 88 | public void should_conform_to_specified_trySplit_behavior() { 89 | // Given 90 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 91 | int groupingFactor = 3; 92 | 93 | DoubleStream testedStream = StreamsUtils.shiftingWindowAveragingDouble(strings, groupingFactor, Double::parseDouble); 94 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 95 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 96 | 97 | // When 98 | long count = monitoredStream.count(); 99 | 100 | // Then 101 | assertThat(count).isEqualTo(5L); 102 | } 103 | 104 | @Test 105 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 106 | // Given 107 | AtomicBoolean b = new AtomicBoolean(false); 108 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2").onClose(() -> b.set(true)); 109 | int groupingFactor = 3; 110 | 111 | // When 112 | StreamsUtils.shiftingWindowAveragingDouble(strings, groupingFactor, Double::parseDouble).close(); 113 | 114 | // Then 115 | assertThat(b.get()).isEqualTo(true); 116 | } 117 | 118 | @Test 119 | public void should_correctly_count_the_elements_of_a_sized_stream() { 120 | // Given 121 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 122 | int groupingFactor = 3; 123 | DoubleStream stream = StreamsUtils.shiftingWindowAveragingDouble(strings, groupingFactor, Double::parseDouble); 124 | 125 | // When 126 | long count = stream.count(); 127 | 128 | // Then 129 | assertThat(count).isEqualTo(5L); 130 | } 131 | 132 | @Test 133 | public void should_not_build_a_shifting_stream_on_a_non_ordered_stream() { 134 | // Given 135 | Stream strings = Set.of("1", "2", "3", "4", "5", "6", "7").stream(); 136 | 137 | // Then 138 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.shiftingWindowAveragingDouble(strings, 3, Double::parseDouble)); 139 | } 140 | 141 | @Test 142 | public void should_not_build_a_shifting_stream_on_a_null_stream() { 143 | // Then 144 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.shiftingWindowAveragingDouble(null, 3, Double::parseDouble)); 145 | } 146 | 147 | @Test 148 | public void should_not_build_a_shifting_stream_with_a_grouping_factor_of_1() { 149 | // Given 150 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 151 | int groupingFactor = 1; 152 | 153 | // Then 154 | assertThatIllegalArgumentException() 155 | .isThrownBy(() -> StreamsUtils.shiftingWindowAveragingDouble(strings, groupingFactor, Double::parseDouble)); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/ShiftingWindowAveragingIntTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.stream.DoubleStream; 26 | import java.util.stream.Stream; 27 | import java.util.stream.StreamSupport; 28 | 29 | import static java.util.stream.Collectors.toList; 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 32 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 33 | 34 | /** 35 | * Created by José 36 | */ 37 | public class ShiftingWindowAveragingIntTest { 38 | 39 | @Test 40 | public void should_average_an_empty_stream_into_a_stream_of_an_empty_stream() { 41 | // Given 42 | // a trick to create an empty ORDERED stream 43 | Stream ints = Stream.of(1, 2, 3).filter(i -> i == 0); 44 | int groupingFactor = 3; 45 | 46 | // When 47 | DoubleStream stream = StreamsUtils.shiftingWindowAveragingInt(ints, groupingFactor, Integer::valueOf); 48 | long numberOfRolledStreams = stream.count(); 49 | 50 | // Then 51 | assertThat(numberOfRolledStreams).isEqualTo(1); 52 | } 53 | 54 | @Test 55 | public void should_average_a_non_empty_stream_with_correct_substreams_content() { 56 | // Given 57 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 58 | int groupingFactor = 2; 59 | 60 | // When 61 | DoubleStream averagedStream = StreamsUtils.shiftingWindowAveragingInt(strings, groupingFactor, Integer::parseInt); 62 | List result = averagedStream.boxed().collect(toList()); 63 | 64 | // When 65 | assertThat(result.size()).isEqualTo(6); 66 | assertThat(result.get(0)).isEqualTo(3); 67 | assertThat(result.get(1)).isEqualTo(3); 68 | assertThat(result.get(2)).isEqualTo(3); 69 | assertThat(result.get(3)).isEqualTo(3); 70 | assertThat(result.get(4)).isEqualTo(3); 71 | assertThat(result.get(5)).isEqualTo(3); 72 | } 73 | 74 | @Test 75 | public void should_process_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 76 | // Given 77 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("2", "4", "2", "4", "2", "4", "2")); 78 | int groupingFactor = 2; 79 | 80 | // When 81 | DoubleStream stream = StreamsUtils.shiftingWindowAveragingInt(sortedSet.stream(), groupingFactor, Integer::parseInt); 82 | 83 | // Then 84 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 85 | } 86 | 87 | @Test 88 | public void should_conform_to_specified_trySplit_behavior() { 89 | // Given 90 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 91 | int groupingFactor = 3; 92 | 93 | DoubleStream testedStream = StreamsUtils.shiftingWindowAveragingInt(strings, groupingFactor, Integer::parseInt); 94 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 95 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 96 | 97 | // When 98 | long count = monitoredStream.count(); 99 | 100 | // Then 101 | assertThat(count).isEqualTo(5L); 102 | } 103 | 104 | @Test 105 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 106 | // Given 107 | AtomicBoolean b = new AtomicBoolean(false); 108 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2").onClose(() -> b.set(true)); 109 | int groupingFactor = 3; 110 | 111 | // When 112 | StreamsUtils.shiftingWindowAveragingInt(strings, groupingFactor, Integer::parseInt).close(); 113 | 114 | // Then 115 | assertThat(b.get()).isEqualTo(true); 116 | } 117 | 118 | @Test 119 | public void should_correctly_count_the_elements_of_a_sized_stream() { 120 | // Given 121 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 122 | int groupingFactor = 3; 123 | DoubleStream stream = StreamsUtils.shiftingWindowAveragingInt(strings, groupingFactor, Integer::parseInt); 124 | 125 | // When 126 | long count = stream.count(); 127 | 128 | // Then 129 | assertThat(count).isEqualTo(5L); 130 | } 131 | 132 | @Test 133 | public void should_not_build_a_shifting_stream_on_a_non_ordered_stream() { 134 | // Given 135 | Stream strings = Set.of("1", "2", "3", "4", "5", "6", "7").stream(); 136 | 137 | // Then 138 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.shiftingWindowAveragingInt(strings, 3, Integer::parseInt)); 139 | } 140 | 141 | @Test 142 | public void should_not_build_a_shifting_stream_on_a_null_stream() { 143 | // Then 144 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.shiftingWindowAveragingInt(null, 3, Integer::parseInt)); 145 | } 146 | 147 | @Test 148 | public void should_not_build_a_shifting_stream_with_a_grouping_factor_of_1() { 149 | // Given 150 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 151 | int groupingFactor = 1; 152 | 153 | // Then 154 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.shiftingWindowAveragingInt(strings, groupingFactor, Integer::parseInt)); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/ShiftingWindowAveragingLongTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.stream.DoubleStream; 26 | import java.util.stream.Stream; 27 | import java.util.stream.StreamSupport; 28 | 29 | import static java.util.stream.Collectors.toList; 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 32 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 33 | 34 | /** 35 | * Created by José 36 | */ 37 | public class ShiftingWindowAveragingLongTest { 38 | 39 | @Test 40 | public void should_average_an_empty_stream_into_a_stream_of_an_empty_stream() { 41 | // Given 42 | // a trick to create an empty ORDERED stream 43 | Stream longs = Stream.of(1L, 2L, 3L).filter(l -> l == 0); 44 | int groupingFactor = 3; 45 | 46 | // When 47 | DoubleStream stream = StreamsUtils.shiftingWindowAveragingLong(longs, groupingFactor, Long::valueOf); 48 | long numberOfRolledStreams = stream.count(); 49 | 50 | // Then 51 | assertThat(numberOfRolledStreams).isEqualTo(1); 52 | } 53 | 54 | @Test 55 | public void should_average_a_non_empty_stream_with_correct_substreams_content() { 56 | // Given 57 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 58 | int groupingFactor = 2; 59 | 60 | // When 61 | DoubleStream averagedStream = StreamsUtils.shiftingWindowAveragingLong(strings, groupingFactor, Long::parseLong); 62 | List result = averagedStream.boxed().collect(toList()); 63 | 64 | // When 65 | assertThat(result.size()).isEqualTo(6); 66 | assertThat(result.get(0)).isEqualTo(3); 67 | assertThat(result.get(1)).isEqualTo(3); 68 | assertThat(result.get(2)).isEqualTo(3); 69 | assertThat(result.get(3)).isEqualTo(3); 70 | assertThat(result.get(4)).isEqualTo(3); 71 | assertThat(result.get(5)).isEqualTo(3); 72 | } 73 | 74 | @Test 75 | public void should_process_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 76 | // Given 77 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("2", "4", "2", "4", "2", "4", "2")); 78 | int groupingFactor = 2; 79 | 80 | // When 81 | DoubleStream stream = StreamsUtils.shiftingWindowAveragingLong(sortedSet.stream(), groupingFactor, Long::parseLong); 82 | 83 | // Then 84 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 85 | } 86 | 87 | @Test 88 | public void should_conform_to_specified_trySplit_behavior() { 89 | // Given 90 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 91 | int groupingFactor = 3; 92 | 93 | DoubleStream testedStream = StreamsUtils.shiftingWindowAveragingLong(strings, groupingFactor, Long::parseLong); 94 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 95 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 96 | 97 | // When 98 | long count = monitoredStream.count(); 99 | 100 | // Then 101 | assertThat(count).isEqualTo(5L); 102 | } 103 | 104 | @Test 105 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 106 | // Given 107 | AtomicBoolean b = new AtomicBoolean(false); 108 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2").onClose(() -> b.set(true)); 109 | int groupingFactor = 3; 110 | 111 | // When 112 | StreamsUtils.shiftingWindowAveragingLong(strings, groupingFactor, Long::parseLong).close(); 113 | 114 | // Then 115 | assertThat(b.get()).isEqualTo(true); 116 | } 117 | 118 | @Test 119 | public void should_correctly_count_the_elements_of_a_sized_stream() { 120 | // Given 121 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 122 | int groupingFactor = 3; 123 | DoubleStream stream = StreamsUtils.shiftingWindowAveragingLong(strings, groupingFactor, Long::parseLong); 124 | 125 | // When 126 | long count = stream.count(); 127 | 128 | // Then 129 | assertThat(count).isEqualTo(5L); 130 | } 131 | 132 | @Test 133 | public void should_not_build_a_shifting_stream_on_a_non_ordered_stream() { 134 | // Given 135 | Stream strings = Set.of("1", "2", "3", "4", "5", "6", "7").stream(); 136 | 137 | // Then 138 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.shiftingWindowAveragingLong(strings, 3, Long::parseLong)); 139 | } 140 | 141 | @Test 142 | public void should_not_build_a_shifting_stream_on_a_null_stream() { 143 | // Then 144 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.shiftingWindowAveragingLong(null, 3, Long::parseLong)); 145 | } 146 | 147 | @Test 148 | public void should_not_build_a_shifting_stream_with_a_grouping_factor_of_1() { 149 | // Given 150 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 151 | int groupingFactor = 1; 152 | 153 | // Then 154 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.shiftingWindowAveragingLong(strings, groupingFactor, Long::parseLong)); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/ShiftingWindowCollectTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.stream.Stream; 26 | import java.util.stream.StreamSupport; 27 | 28 | import static java.util.stream.Collectors.joining; 29 | import static java.util.stream.Collectors.toList; 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 32 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 33 | 34 | /** 35 | * Created by José 36 | */ 37 | public class ShiftingWindowCollectTest { 38 | 39 | @Test 40 | public void should_collect_an_empty_stream_into_a_stream_of__an_empty_stream() { 41 | // Given 42 | // a trick to create an empty ORDERED stream 43 | Stream strings = Stream.of("one").filter(s -> s.isEmpty()); 44 | int groupingFactor = 3; 45 | 46 | // When 47 | Stream stream = StreamsUtils.shiftingWindowCollect(strings, groupingFactor, joining()); 48 | long numberOfRolledStreams = stream.count(); 49 | 50 | // Then 51 | assertThat(numberOfRolledStreams).isEqualTo(1); 52 | } 53 | 54 | @Test 55 | public void should_collect_a_non_empty_stream_with_correct_substreams_content() { 56 | // Given 57 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 58 | int groupingFactor = 3; 59 | 60 | // When 61 | Stream collectedStream = StreamsUtils.shiftingWindowCollect(strings, groupingFactor, joining()); 62 | List result = collectedStream.collect(toList()); 63 | 64 | // When 65 | assertThat(result.size()).isEqualTo(5); 66 | assertThat(result.get(0)).isEqualTo("123"); 67 | assertThat(result.get(1)).isEqualTo("234"); 68 | assertThat(result.get(2)).isEqualTo("345"); 69 | assertThat(result.get(3)).isEqualTo("456"); 70 | assertThat(result.get(4)).isEqualTo("567"); 71 | } 72 | 73 | @Test 74 | public void should_process_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 75 | // Given 76 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("2", "4", "2", "4", "2", "4", "2")); 77 | int groupingFactor = 2; 78 | 79 | // When 80 | Stream stream = StreamsUtils.shiftingWindowCollect(sortedSet.stream(), groupingFactor, joining()); 81 | 82 | // Then 83 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 84 | } 85 | 86 | @Test 87 | public void should_conform_to_specified_trySplit_behavior() { 88 | // Given 89 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 90 | int groupingFactor = 3; 91 | 92 | Stream testedStream = StreamsUtils.shiftingWindowCollect(strings, groupingFactor, joining()); 93 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 94 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 95 | 96 | // When 97 | long count = monitoredStream.count(); 98 | 99 | // Then 100 | assertThat(count).isEqualTo(5L); 101 | } 102 | 103 | @Test 104 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 105 | // Given 106 | AtomicBoolean b = new AtomicBoolean(false); 107 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2").onClose(() -> b.set(true)); 108 | int groupingFactor = 3; 109 | 110 | // When 111 | StreamsUtils.shiftingWindowCollect(strings, groupingFactor, joining()).close(); 112 | 113 | // Then 114 | assertThat(b.get()).isEqualTo(true); 115 | } 116 | 117 | @Test 118 | public void should_correctly_count_the_elements_of_a_sized_stream() { 119 | // Given 120 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 121 | int groupingFactor = 3; 122 | Stream stream = StreamsUtils.shiftingWindowCollect(strings, groupingFactor, joining()); 123 | 124 | // When 125 | long count = stream.count(); 126 | 127 | // Then 128 | assertThat(count).isEqualTo(5L); 129 | } 130 | 131 | @Test 132 | public void should_not_build_a_rolling_spliterator_on_a_null_spliterator() { 133 | // Then 134 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.shiftingWindowCollect(null, 3, joining())); 135 | } 136 | 137 | @Test 138 | public void should_not_build_a_rolling_spliterator_with_a_grouping_factor_of_1() { 139 | // Given 140 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 141 | int groupingFactor = 1; 142 | 143 | // Then 144 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.shiftingWindowCollect(strings, groupingFactor, joining())); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/ShiftingWindowSummarizingDoubleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.stream.Stream; 26 | import java.util.stream.StreamSupport; 27 | 28 | import static java.util.stream.Collectors.toList; 29 | import static org.assertj.core.api.Assertions.assertThat; 30 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 31 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 32 | 33 | /** 34 | * Created by José 35 | */ 36 | public class ShiftingWindowSummarizingDoubleTest { 37 | 38 | @Test 39 | public void should_summarize_an_empty_stream_into_a_stream_of_an_empty_stream() { 40 | // Given 41 | // a trick to create an empty ORDERED stream 42 | Stream doubles = Stream.of(1d, 2d, 3d).filter(d -> d == 0); 43 | int groupingFactor = 3; 44 | 45 | // When 46 | Stream stream = StreamsUtils.shiftingWindowSummarizingDouble(doubles, groupingFactor, Double::valueOf); 47 | long numberOfRolledStreams = stream.count(); 48 | 49 | // Then 50 | assertThat(numberOfRolledStreams).isEqualTo(1); 51 | } 52 | 53 | @Test 54 | public void should_summarize_a_non_empty_stream_with_correct_substreams_content() { 55 | // Given 56 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 57 | int groupingFactor = 2; 58 | DoubleSummaryStatistics stats = new DoubleSummaryStatistics(); 59 | stats.accept(2d); 60 | stats.accept(4d); 61 | 62 | // When 63 | Stream summarizedStream = StreamsUtils.shiftingWindowSummarizingDouble(strings, groupingFactor, Double::parseDouble); 64 | List result = summarizedStream.collect(toList()); 65 | 66 | // When 67 | assertThat(result.size()).isEqualTo(6); 68 | assertThat(result.get(0).toString()).isEqualTo(stats.toString()); 69 | assertThat(result.get(1).toString()).isEqualTo(stats.toString()); 70 | assertThat(result.get(2).toString()).isEqualTo(stats.toString()); 71 | assertThat(result.get(3).toString()).isEqualTo(stats.toString()); 72 | assertThat(result.get(4).toString()).isEqualTo(stats.toString()); 73 | assertThat(result.get(5).toString()).isEqualTo(stats.toString()); 74 | } 75 | 76 | @Test 77 | public void should_process_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 78 | // Given 79 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("2", "4", "2", "4", "2", "4", "2")); 80 | int groupingFactor = 2; 81 | 82 | // When 83 | Stream stream = StreamsUtils.shiftingWindowSummarizingDouble(sortedSet.stream(), groupingFactor, Double::parseDouble); 84 | 85 | // Then 86 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 87 | } 88 | 89 | @Test 90 | public void should_conform_to_specified_trySplit_behavior() { 91 | // Given 92 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 93 | int groupingFactor = 3; 94 | 95 | Stream testedStream = StreamsUtils.shiftingWindowSummarizingDouble(strings, groupingFactor, Double::parseDouble); 96 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 97 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 98 | 99 | // When 100 | long count = monitoredStream.count(); 101 | 102 | // Then 103 | assertThat(count).isEqualTo(5L); 104 | } 105 | 106 | @Test 107 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 108 | // Given 109 | AtomicBoolean b = new AtomicBoolean(false); 110 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2").onClose(() -> b.set(true)); 111 | int groupingFactor = 3; 112 | 113 | // When 114 | StreamsUtils.shiftingWindowSummarizingDouble(strings, groupingFactor, Double::parseDouble).close(); 115 | 116 | // Then 117 | assertThat(b.get()).isEqualTo(true); 118 | } 119 | 120 | @Test 121 | public void should_correctly_count_the_elements_of_a_sized_stream() { 122 | // Given 123 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 124 | int groupingFactor = 3; 125 | Stream stream = StreamsUtils.shiftingWindowSummarizingDouble(strings, groupingFactor, Double::parseDouble); 126 | 127 | // When 128 | long count = stream.count(); 129 | 130 | // Then 131 | assertThat(count).isEqualTo(5L); 132 | } 133 | 134 | @Test 135 | public void should_not_build_a_shifting_stream_on_a_null_stream() { 136 | // Then 137 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.shiftingWindowSummarizingDouble(null, 3, Double::parseDouble)); 138 | } 139 | 140 | @Test 141 | public void should_not_build_a_shifting_stream_with_a_grouping_factor_of_1() { 142 | // Given 143 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 144 | int groupingFactor = 1; 145 | 146 | // Then 147 | assertThatIllegalArgumentException() 148 | .isThrownBy(() -> StreamsUtils.shiftingWindowSummarizingDouble(strings, groupingFactor, Double::parseDouble)); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/ShiftingWindowSummarizingIntTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.stream.Stream; 26 | import java.util.stream.StreamSupport; 27 | 28 | import static java.util.stream.Collectors.toList; 29 | import static org.assertj.core.api.Assertions.assertThat; 30 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 31 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 32 | 33 | /** 34 | * Created by José 35 | */ 36 | public class ShiftingWindowSummarizingIntTest { 37 | 38 | @Test 39 | public void should_summarize_an_empty_stream_into_a_stream_of_an_empty_stream() { 40 | // Given 41 | // a trick to create an empty ORDERED stream 42 | Stream ints = Stream.of(1, 2, 3).filter(i -> i == 0); 43 | int groupingFactor = 3; 44 | 45 | // When 46 | Stream stream = StreamsUtils.shiftingWindowSummarizingInt(ints, groupingFactor, Integer::valueOf); 47 | long numberOfRolledStreams = stream.count(); 48 | 49 | // Then 50 | assertThat(numberOfRolledStreams).isEqualTo(1); 51 | } 52 | 53 | @Test 54 | public void should_summarize_a_non_empty_stream_with_correct_substreams_content() { 55 | // Given 56 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 57 | int groupingFactor = 2; 58 | IntSummaryStatistics stats = new IntSummaryStatistics(); 59 | stats.accept(2); 60 | stats.accept(4); 61 | 62 | // When 63 | Stream summarizedStream = StreamsUtils.shiftingWindowSummarizingInt(strings, groupingFactor, Integer::parseInt); 64 | List result = summarizedStream.collect(toList()); 65 | 66 | // When 67 | assertThat(result.size()).isEqualTo(6); 68 | assertThat(result.get(0).toString()).isEqualTo(stats.toString()); 69 | assertThat(result.get(1).toString()).isEqualTo(stats.toString()); 70 | assertThat(result.get(2).toString()).isEqualTo(stats.toString()); 71 | assertThat(result.get(3).toString()).isEqualTo(stats.toString()); 72 | assertThat(result.get(4).toString()).isEqualTo(stats.toString()); 73 | assertThat(result.get(5).toString()).isEqualTo(stats.toString()); 74 | } 75 | 76 | @Test 77 | public void should_process_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 78 | // Given 79 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("2", "4", "2", "4", "2", "4", "2")); 80 | int groupingFactor = 2; 81 | 82 | // When 83 | Stream stream = StreamsUtils.shiftingWindowSummarizingInt(sortedSet.stream(), groupingFactor, Integer::parseInt); 84 | 85 | // Then 86 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 87 | } 88 | 89 | @Test 90 | public void should_conform_to_specified_trySplit_behavior() { 91 | // Given 92 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 93 | int groupingFactor = 3; 94 | 95 | Stream testedStream = StreamsUtils.shiftingWindowSummarizingInt(strings, groupingFactor, Integer::parseInt); 96 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 97 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 98 | 99 | // When 100 | long count = monitoredStream.count(); 101 | 102 | // Then 103 | assertThat(count).isEqualTo(5L); 104 | } 105 | 106 | @Test 107 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 108 | // Given 109 | AtomicBoolean b = new AtomicBoolean(false); 110 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2").onClose(() -> b.set(true)); 111 | int groupingFactor = 3; 112 | 113 | // When 114 | StreamsUtils.shiftingWindowSummarizingInt(strings, groupingFactor, Integer::parseInt).close(); 115 | 116 | // Then 117 | assertThat(b.get()).isEqualTo(true); 118 | } 119 | 120 | @Test 121 | public void should_correctly_count_the_elements_of_a_sized_stream() { 122 | // Given 123 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 124 | int groupingFactor = 3; 125 | Stream stream = StreamsUtils.shiftingWindowSummarizingInt(strings, groupingFactor, Integer::parseInt); 126 | 127 | // When 128 | long count = stream.count(); 129 | 130 | // Then 131 | assertThat(count).isEqualTo(5L); 132 | } 133 | 134 | @Test 135 | public void should_not_build_a_shifting_stream_on_a_null_stream() { 136 | // Then 137 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.shiftingWindowSummarizingInt(null, 3, Integer::parseInt)); 138 | } 139 | 140 | @Test 141 | public void should_not_build_a_shifting_stream_with_a_grouping_factor_of_1() { 142 | // Given 143 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 144 | int groupingFactor = 1; 145 | 146 | // Then 147 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.shiftingWindowSummarizingInt(strings, groupingFactor, Integer::parseInt)); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/ShiftingWindowSummarizingLongTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.stream.Stream; 26 | import java.util.stream.StreamSupport; 27 | 28 | import static java.util.stream.Collectors.toList; 29 | import static org.assertj.core.api.Assertions.assertThat; 30 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 31 | import static org.assertj.core.api.Assertions.assertThatNullPointerException; 32 | 33 | /** 34 | * Created by José 35 | */ 36 | public class ShiftingWindowSummarizingLongTest { 37 | 38 | @Test 39 | public void should_summarize_an_empty_stream_into_a_stream_of_an_empty_stream() { 40 | // Given 41 | // a trick to create an empty ORDERED stream 42 | Stream longs = Stream.of(1L, 2L, 3L).filter(l -> l == 0); 43 | int groupingFactor = 3; 44 | 45 | // When 46 | Stream stream = StreamsUtils.shiftingWindowSummarizingLong(longs, groupingFactor, Long::valueOf); 47 | long numberOfRolledStreams = stream.count(); 48 | 49 | // Then 50 | assertThat(numberOfRolledStreams).isEqualTo(1); 51 | } 52 | 53 | @Test 54 | public void should_summarize_a_non_empty_stream_with_correct_substreams_content() { 55 | // Given 56 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 57 | int groupingFactor = 2; 58 | LongSummaryStatistics stats = new LongSummaryStatistics(); 59 | stats.accept(2L); 60 | stats.accept(4L); 61 | 62 | // When 63 | Stream summarizedStream = StreamsUtils.shiftingWindowSummarizingLong(strings, groupingFactor, Long::parseLong); 64 | List result = summarizedStream.collect(toList()); 65 | 66 | // When 67 | assertThat(result.size()).isEqualTo(6); 68 | assertThat(result.get(0).toString()).isEqualTo(stats.toString()); 69 | assertThat(result.get(1).toString()).isEqualTo(stats.toString()); 70 | assertThat(result.get(2).toString()).isEqualTo(stats.toString()); 71 | assertThat(result.get(3).toString()).isEqualTo(stats.toString()); 72 | assertThat(result.get(4).toString()).isEqualTo(stats.toString()); 73 | assertThat(result.get(5).toString()).isEqualTo(stats.toString()); 74 | } 75 | 76 | @Test 77 | public void should_process_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 78 | // Given 79 | SortedSet sortedSet = new TreeSet<>(Arrays.asList("2", "4", "2", "4", "2", "4", "2")); 80 | int groupingFactor = 2; 81 | 82 | // When 83 | Stream stream = StreamsUtils.shiftingWindowSummarizingLong(sortedSet.stream(), groupingFactor, Long::parseLong); 84 | 85 | // Then 86 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 87 | } 88 | 89 | @Test 90 | public void should_conform_to_specified_trySplit_behavior() { 91 | // Given 92 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2"); 93 | int groupingFactor = 3; 94 | 95 | Stream testedStream = StreamsUtils.shiftingWindowSummarizingLong(strings, groupingFactor, Long::parseLong); 96 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 97 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 98 | 99 | // When 100 | long count = monitoredStream.count(); 101 | 102 | // Then 103 | assertThat(count).isEqualTo(5L); 104 | } 105 | 106 | @Test 107 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 108 | // Given 109 | AtomicBoolean b = new AtomicBoolean(false); 110 | Stream strings = Stream.of("2", "4", "2", "4", "2", "4", "2").onClose(() -> b.set(true)); 111 | int groupingFactor = 3; 112 | 113 | // When 114 | StreamsUtils.shiftingWindowSummarizingLong(strings, groupingFactor, Long::parseLong).close(); 115 | 116 | // Then 117 | assertThat(b.get()).isEqualTo(true); 118 | } 119 | 120 | @Test 121 | public void should_correctly_count_the_elements_of_a_sized_stream() { 122 | // Given 123 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 124 | int groupingFactor = 3; 125 | Stream stream = StreamsUtils.shiftingWindowSummarizingLong(strings, groupingFactor, Long::parseLong); 126 | 127 | // When 128 | long count = stream.count(); 129 | 130 | // Then 131 | assertThat(count).isEqualTo(5L); 132 | } 133 | 134 | @Test 135 | public void should_not_build_a_shifting_stream_on_a_null_stream() { 136 | // Then 137 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.shiftingWindowSummarizingLong(null, 3, Long::parseLong)); 138 | } 139 | 140 | @Test 141 | public void should_not_build_a_shifting_stream_with_a_grouping_factor_of_1() { 142 | // Given 143 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 144 | int groupingFactor = 1; 145 | 146 | // Then 147 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.shiftingWindowSummarizingLong(strings, groupingFactor, Long::parseLong)); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/ValidatingSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.function.Function; 26 | import java.util.function.Predicate; 27 | import java.util.function.UnaryOperator; 28 | import java.util.stream.Stream; 29 | import java.util.stream.StreamSupport; 30 | 31 | import static java.util.stream.Collectors.toList; 32 | import static org.assertj.core.api.Assertions.assertThat; 33 | 34 | /** 35 | * Created by José 36 | */ 37 | public class ValidatingSpliteratorTest { 38 | 39 | @Test 40 | public void should_validate_empty_streams_into_an_empty_stream() { 41 | // Given 42 | Stream strings = Stream.empty(); 43 | Predicate validator = String::isEmpty; 44 | 45 | // When 46 | Stream validateStream = 47 | StreamsUtils.validate(strings, validator, Function.identity(), Function.identity()); 48 | long count = validateStream.count(); 49 | 50 | // Then 51 | assertThat(count).isEqualTo(0); 52 | } 53 | 54 | @Test 55 | public void should_validated_a_stream_correctly_with_one_transformation_for_invalid_elements() { 56 | // Given 57 | Stream strings = Stream.of("one", null, "two", null, "three"); 58 | Predicate validator = Objects::nonNull; 59 | UnaryOperator transformIfNotValid = s -> ""; 60 | 61 | // When 62 | Stream validateStream = 63 | StreamsUtils.validate(strings, validator, transformIfNotValid); 64 | List list = validateStream.collect(toList()); 65 | 66 | // Then 67 | assertThat(list.size()).isEqualTo(5); 68 | assertThat(list).containsExactly("one", "", "two", "", "three"); 69 | } 70 | 71 | @Test 72 | public void should_validated_a_stream_correctly_with_two_transformations_for_valid_and_invalid_elements() { 73 | // Given 74 | Stream strings = Stream.of("one", "two", "three"); 75 | Predicate validator = s -> s.length() == 3; 76 | Function transformIfValid = String::toUpperCase; 77 | Function transformIfNotValid = s -> "-"; 78 | 79 | // When 80 | Stream validateStream = 81 | StreamsUtils.validate(strings, validator, transformIfValid, transformIfNotValid); 82 | List list = validateStream.collect(toList()); 83 | 84 | // Then 85 | assertThat(list.size()).isEqualTo(3); 86 | assertThat(list).containsExactly("ONE", "TWO", "-"); 87 | } 88 | 89 | @Test 90 | public void should_validate_a_sorted_stream_correctly_and_in_a_sorted_stream() { 91 | // Given 92 | Stream sortedStream = new TreeSet<>(Arrays.asList("a", "b", "c")).stream(); 93 | Predicate validator = s -> s.length() == 3; 94 | Function transformIfValid = String::toUpperCase; 95 | Function transformIfNotValid = s -> "-"; 96 | 97 | // When 98 | Stream stream = 99 | StreamsUtils.validate(sortedStream, validator, transformIfValid, transformIfNotValid); 100 | 101 | // Then 102 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 103 | } 104 | 105 | @Test 106 | public void should_conform_to_specified_trySplit_behavior() { 107 | // Given 108 | Stream strings = Stream.of("one", "two", "three"); 109 | Predicate validator = s -> s.length() == 3; 110 | Function transformIfValid = String::toUpperCase; 111 | Function transformIfNotValid = s -> "-"; 112 | 113 | Stream testedStream = 114 | StreamsUtils.validate(strings, validator, transformIfValid, transformIfNotValid); 115 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(testedStream.spliterator()); 116 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 117 | 118 | // When 119 | long count = monitoredStream.count(); 120 | 121 | // Then 122 | assertThat(count).isEqualTo(3L); 123 | } 124 | 125 | @Test 126 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 127 | // Given 128 | AtomicBoolean b = new AtomicBoolean(false); 129 | Stream strings = Stream.of("one", "two", "three").onClose(() -> b.set(true)); 130 | Predicate validator = s -> s.length() == 3; 131 | Function transformIfValid = String::toUpperCase; 132 | Function transformIfNotValid = s -> "-"; 133 | 134 | // When 135 | StreamsUtils.validate(strings, validator, transformIfValid, transformIfNotValid).close(); 136 | 137 | // Then 138 | assertThat(b.get()).isEqualTo(true); 139 | } 140 | 141 | @Test 142 | public void should_correctly_count_the_elements_of_a_sized_stream() { 143 | // Given 144 | Stream strings = Stream.of("one", "two", "three"); 145 | Predicate validator = s -> s.length() == 3; 146 | Function transformIfValid = String::toUpperCase; 147 | Function transformIfNotValid = s -> "-"; 148 | Stream stream = 149 | StreamsUtils.validate(strings, validator, transformIfValid, transformIfNotValid); 150 | 151 | // When 152 | long count = stream.count(); 153 | 154 | // Then 155 | assertThat(count).isEqualTo(3L); 156 | } 157 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/WeavingSpliteratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators; 18 | 19 | import org.paumard.spliterators.util.TryAdvanceCheckingSpliterator; 20 | import org.paumard.streams.StreamsUtils; 21 | import org.testng.annotations.Test; 22 | 23 | import java.util.*; 24 | import java.util.concurrent.atomic.AtomicInteger; 25 | import java.util.stream.Collectors; 26 | import java.util.stream.Stream; 27 | import java.util.stream.StreamSupport; 28 | 29 | import static org.assertj.core.api.Assertions.*; 30 | 31 | /** 32 | * Created by José 33 | */ 34 | public class WeavingSpliteratorTest { 35 | 36 | @Test 37 | public void should_weave_empty_streams_into_a_stream_of_an_empty_stream() { 38 | // Given 39 | // a trick to create an empty ORDERED stream 40 | Stream strings1 = Stream.of("one").filter(s -> s.isEmpty()); 41 | Stream strings2 = Stream.of("one").filter(s -> s.isEmpty()); 42 | 43 | // When 44 | Stream weavingStream = StreamsUtils.weave(strings1, strings2); 45 | 46 | // Then 47 | assertThat(weavingStream.count()).isEqualTo(0); 48 | } 49 | 50 | @Test 51 | public void should_weave_a_non_empty_stream_with_correct_substreams_content() { 52 | // Given 53 | Stream strings1 = Stream.of("1", "2", "3", "4"); 54 | Stream strings2 = Stream.of("11", "12", "13", "14"); 55 | 56 | // When 57 | Stream weavingStream = StreamsUtils.weave(strings1, strings2); 58 | List collect = weavingStream.collect(Collectors.toList()); 59 | 60 | // When 61 | assertThat(collect.size()).isEqualTo(8); 62 | assertThat(collect).containsExactly("1", "11", "2", "12", "3", "13", "4", "14"); 63 | } 64 | 65 | @Test 66 | public void should_weave_a_non_empty_stream_with_correct_substreams_content_of_different_sizes() { 67 | // Given 68 | Stream strings1 = Stream.of("1", "2", "3", "4"); 69 | Stream strings2 = Stream.of("11", "12", "13", "14", "15"); 70 | 71 | // When 72 | Stream weavingStream = StreamsUtils.weave(strings1, strings2); 73 | List collect = weavingStream.collect(Collectors.toList()); 74 | 75 | // When 76 | assertThat(collect.size()).isEqualTo(8); 77 | assertThat(collect).containsExactly("1", "11", "2", "12", "3", "13", "4", "14"); 78 | } 79 | 80 | @Test 81 | public void should_weave_a_sorted_stream_correctly_and_in_an_unsorted_stream() { 82 | // Given 83 | Stream sortedStream1 = new TreeSet<>(Arrays.asList("1", "2", "3", "4")).stream(); 84 | Stream sortedStream2 = new TreeSet<>(Arrays.asList("11", "12", "13", "14", "15")).stream(); 85 | 86 | // When 87 | Stream stream = StreamsUtils.weave(sortedStream1, sortedStream2); 88 | 89 | // Then 90 | assertThat(stream.spliterator().characteristics() & Spliterator.SORTED).isEqualTo(0); 91 | } 92 | 93 | @Test 94 | public void should_not_build_a_weaving_spliterator_on_null() { 95 | // Then 96 | assertThatNullPointerException().isThrownBy(() -> StreamsUtils.weave(null)); 97 | } 98 | 99 | @Test 100 | public void should_not_build_a_weaving_spliterator_on_less_than_two_spliterators() { 101 | // Given 102 | Stream strings = Stream.of("1", "2", "3", "4", "5", "6", "7"); 103 | 104 | // Then 105 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.weave(strings)); 106 | } 107 | 108 | @Test 109 | public void should_conform_to_specified_trySplit_behavior() { 110 | // Given 111 | Stream strings1 = Stream.of("one", "two", "three"); 112 | Stream strings2 = Stream.of("one", "two", "three"); 113 | Stream weavingStream = StreamsUtils.weave(strings1, strings2); 114 | TryAdvanceCheckingSpliterator spliterator = new TryAdvanceCheckingSpliterator<>(weavingStream.spliterator()); 115 | Stream monitoredStream = StreamSupport.stream(spliterator, false); 116 | 117 | // When 118 | long count = monitoredStream.count(); 119 | 120 | // Then 121 | assertThat(count).isEqualTo(6L); 122 | } 123 | 124 | @Test 125 | public void should_correctly_call_the_onClose_callbacks_of_the_underlying_streams() { 126 | // Given 127 | AtomicInteger i = new AtomicInteger(0); 128 | Stream strings1 = Stream.of("one", "two", "three").onClose(i::incrementAndGet); 129 | Stream strings2 = Stream.of("one", "two", "three").onClose(i::incrementAndGet); 130 | 131 | // When 132 | StreamsUtils.weave(strings1, strings2).close(); 133 | 134 | // Then 135 | assertThat(i.get()).isEqualTo(2); 136 | } 137 | 138 | @Test 139 | public void should_correctly_count_the_elements_of_a_sized_stream_with_same_length() { 140 | // Given 141 | Stream strings1 = Stream.of("one", "two", "three"); 142 | Stream strings2 = Stream.of("one", "two", "three"); 143 | Stream stream = StreamsUtils.weave(strings1, strings2); 144 | 145 | // When 146 | long count = stream.count(); 147 | 148 | // Then 149 | assertThat(count).isEqualTo(6L); 150 | } 151 | 152 | @Test 153 | public void should_correctly_count_the_elements_of_a_sized_stream_with_different_length() { 154 | // Given 155 | Stream strings1 = Stream.of("one", "two", "three"); 156 | Stream strings2 = Stream.of("one", "two", "three", "four", "five"); 157 | Stream stream = StreamsUtils.weave(strings1, strings2); 158 | 159 | // When 160 | long count = stream.count(); 161 | 162 | // Then 163 | assertThat(count).isEqualTo(6L); 164 | } 165 | 166 | @Test 167 | public void should_not_weave_a_non_ordered_stream() { 168 | // Given 169 | Stream strings1 = Set.of("one", "two", "three").stream(); 170 | Stream strings2 = List.of("one", "two", "three").stream(); 171 | 172 | // Then 173 | assertThatIllegalArgumentException().isThrownBy(() -> StreamsUtils.weave(strings1, strings2)); 174 | } 175 | } -------------------------------------------------------------------------------- /src/test/java/org/paumard/spliterators/util/TryAdvanceCheckingSpliterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 José Paumard 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.paumard.spliterators.util; 18 | 19 | import java.util.Comparator; 20 | import java.util.Spliterator; 21 | import java.util.concurrent.atomic.AtomicBoolean; 22 | import java.util.function.Consumer; 23 | 24 | public class TryAdvanceCheckingSpliterator implements Spliterator { 25 | 26 | private Spliterator spliterator; 27 | 28 | public TryAdvanceCheckingSpliterator(Spliterator spliterator) { 29 | this.spliterator = spliterator; 30 | } 31 | 32 | @Override 33 | public boolean tryAdvance(Consumer action) { 34 | AtomicBoolean hasBeenCalled = new AtomicBoolean(false); 35 | 36 | Consumer consumer = t -> { 37 | if (hasBeenCalled.getAndSet(true)) { 38 | throw new IllegalStateException("Double call on the passed consumer"); 39 | } else { 40 | action.accept(t); 41 | } 42 | }; 43 | 44 | 45 | boolean hasMore = this.spliterator.tryAdvance(consumer); 46 | if (!hasMore && hasBeenCalled.get()) { 47 | throw new IllegalStateException("The passed consumer has been called and the returned value is false"); 48 | } 49 | if (hasMore && !hasBeenCalled.get()) { 50 | throw new IllegalStateException("The passed consumer has not been called and the returned value is true"); 51 | } 52 | return hasMore; 53 | } 54 | 55 | @Override 56 | public Spliterator trySplit() { 57 | return null; 58 | } 59 | 60 | @Override 61 | public long estimateSize() { 62 | return this.spliterator.estimateSize(); 63 | } 64 | 65 | @Override 66 | public int characteristics() { 67 | return this.spliterator.characteristics(); 68 | } 69 | 70 | @Override 71 | public Comparator getComparator() { 72 | return this.spliterator.getComparator(); 73 | } 74 | } --------------------------------------------------------------------------------