├── .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 super Map.Entry> 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 super E> 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 super Map.Entry> 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 super Stream> 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 super E> 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 super E> 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 super E> comparator) {
54 | this.spliterator = spliterator;
55 | this.comparator = comparator;
56 | }
57 |
58 | @Override
59 | public boolean tryAdvance(Consumer super E> 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 super E> 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 super E> 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 super E> 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 super E> comparator) {
58 | this.spliterator = spliterator;
59 | this.numberOfMaxes = numberOfMaxes;
60 | this.comparator = comparator;
61 | }
62 |
63 | @Override
64 | public boolean tryAdvance(Consumer super E> 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 super E> 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 super T> comparator;
108 |
109 | @SuppressWarnings("unchecked")
110 | public InsertionTab(int maxN, Comparator super T> 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 super E> 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 super E> 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 super E> comparator) {
58 | this.spliterator = spliterator;
59 | this.numberOfMaxes = numberOfMaxes;
60 | this.comparator = comparator;
61 | }
62 |
63 | @Override
64 | public boolean tryAdvance(Consumer super E> 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 super E> 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 super T> comparator;
109 |
110 | @SuppressWarnings("unchecked")
111 | public InsertionTab(int maxN, Comparator super T> 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 super E> gate;
36 | private boolean gateIsOpenned = false;
37 |
38 | public static GatingSpliterator of(Spliterator spliterator, Predicate super E> gate) {
39 | Objects.requireNonNull(spliterator);
40 | Objects.requireNonNull(gate);
41 |
42 | return new GatingSpliterator<>(spliterator, gate);
43 | }
44 |
45 | private GatingSpliterator(Spliterator spliterator, Predicate super E> gate) {
46 | this.spliterator = spliterator;
47 | this.gate = gate;
48 | }
49 |
50 | @Override
51 | public boolean tryAdvance(Consumer super E> 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 super E> 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 super E> open;
36 | private final Predicate super E> 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 super E> open, boolean openingElementIncluded,
48 | Predicate super E> 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 super E> open, boolean openingElementIncluded,
63 | Predicate super E> 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 super Stream> 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 super E> 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 super E> 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 super E> splitter, boolean included) {
61 | this.spliterator = spliterator;
62 | this.splitter = splitter;
63 | this.included = included;
64 | }
65 |
66 | @Override
67 | public boolean tryAdvance(Consumer super Stream> 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 super Stream> 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 super E> interruptor;
36 | private boolean hasBeenInterrupted = false;
37 |
38 | public static InterruptingSpliterator of(Spliterator spliterator, Predicate super E> interruptor) {
39 | Objects.requireNonNull(spliterator);
40 | Objects.requireNonNull(interruptor);
41 |
42 | return new InterruptingSpliterator(spliterator, interruptor);
43 | }
44 |
45 | private InterruptingSpliterator(Spliterator spliterator, Predicate super E> interruptor) {
46 | this.spliterator = spliterator;
47 | this.interruptor = interruptor;
48 | }
49 |
50 | @Override
51 | public boolean tryAdvance(Consumer super E> 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 super E> 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 super E> 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 super DoubleStream> 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 super IntStream> 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 super LongStream> 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 super Stream> 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 super Stream> 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 super E, ? extends R> transformIfValid, transformIfNotValid;
36 | private final Predicate super E> validator;
37 |
38 | public static class Builder {
39 |
40 | private Spliterator spliterator;
41 | private Function super E, ? extends R> transformIfValid, transformIfNotValid;
42 | private Predicate super E> 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 super E> validator) {
53 | this.validator = Objects.requireNonNull(validator);
54 | return this;
55 | }
56 |
57 | public Builder withValidFunction(Function super E, ? extends R> validFunction) {
58 | this.transformIfValid = Objects.requireNonNull(validFunction);
59 | return this;
60 | }
61 |
62 | public Builder withNotValidFunction(Function super E, ? extends R> 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 super E> validator,
74 | Function super E, ? extends R> transformIfValid, Function super E, ? extends R> 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 super R> 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 super E> 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 super E1, ? super E2, ? extends R> zipper;
35 |
36 | public static class Builder {
37 |
38 | private Spliterator spliterator1;
39 | private Spliterator spliterator2;
40 | private BiFunction super E1, ? super E2, ? extends R> 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 super E1, ? super E2, ? extends R> 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 super E1, ? super E2, ? extends R> 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 super R> 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