1/*
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.openjdk.testlib.java.util.stream;
24
25import java.util.Arrays;
26import java.util.Collection;
27import java.util.Iterator;
28import java.util.PrimitiveIterator;
29import java.util.Spliterator;
30import java.util.Spliterators;
31import java.util.function.DoubleConsumer;
32import java.util.function.Function;
33import java.util.function.IntConsumer;
34import java.util.function.LongConsumer;
35import java.util.function.Supplier;
36import java.util.function.ToIntFunction;
37import java.util.stream.*;
38
39/** Describes a test data set for use in stream tests */
40public interface TestData<T, S extends BaseStream<T, S>>
41        extends Iterable<T> {
42
43    default int size() {
44        throw new UnsupportedOperationException();
45    }
46
47    @Override
48    default Iterator<T> iterator() {
49        return Spliterators.iterator(spliterator());
50    }
51
52    Spliterator<T> spliterator();
53
54    default boolean isOrdered() {
55        return spliterator().hasCharacteristics(Spliterator.ORDERED);
56    }
57
58    StreamShape getShape();
59
60    default <A extends Collection<? super T>> A into(A target) {
61        spliterator().forEachRemaining(target::add);
62        return target;
63    }
64
65    S stream();
66
67    S parallelStream();
68
69    public interface OfRef<T> extends TestData<T, Stream<T>> { }
70
71    public interface OfInt extends TestData<Integer, IntStream> { }
72
73    public interface OfLong extends TestData<Long, LongStream> { }
74
75    public interface OfDouble extends TestData<Double, DoubleStream> { }
76
77    // @@@ Temporary garbage class to avoid triggering bugs with lambdas in static methods in interfaces
78    public static class Factory {
79        public static <T> OfRef<T> ofArray(String name, T[] array) {
80            return new AbstractTestData.RefTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
81                                                      Arrays::spliterator, a -> a.length);
82        }
83
84        public static <T> OfRef<T> ofCollection(String name, Collection<T> collection) {
85            return new AbstractTestData.RefTestData<>(name, collection, Collection::stream, Collection::parallelStream,
86                                                      Collection::spliterator, Collection::size);
87        }
88
89        public static <T> OfRef<T> ofSpinedBuffer(String name, SpinedBuffer<T> buffer) {
90            return new AbstractTestData.RefTestData<>(name, buffer,
91                                                      b -> StreamSupport.stream(b.spliterator(), false),
92                                                      b -> StreamSupport.stream(b.spliterator(), true),
93                                                      SpinedBuffer::spliterator,
94                                                      b -> (int) b.count());
95        }
96
97        public static <T> OfRef<T> ofSupplier(String name, Supplier<Stream<T>> supplier) {
98            return new AbstractTestData.RefTestData<>(name, supplier,
99                                                      Supplier::get,
100                                                      s -> s.get().parallel(),
101                                                      s -> s.get().spliterator(),
102                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
103        }
104
105        public static <T> OfRef<T> ofRefNode(String name, Node<T> node) {
106            return new AbstractTestData.RefTestData<>(name, node,
107                                                      n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED, false),
108                                                      n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED, true),
109                                                      Node::spliterator,
110                                                      n -> (int) n.count());
111        }
112
113        // int factories
114        public static <T> OfInt ofArray(String name, int[] array) {
115            return new AbstractTestData.IntTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
116                                                      Arrays::spliterator, a -> a.length);
117        }
118
119        public static OfInt ofSpinedBuffer(String name, SpinedBuffer.OfInt buffer) {
120            return new AbstractTestData.IntTestData<>(name, buffer,
121                                                      b -> StreamSupport.intStream(b.spliterator(), false),
122                                                      b -> StreamSupport.intStream(b.spliterator(), true),
123                                                      SpinedBuffer.OfInt::spliterator,
124                                                      b -> (int) b.count());
125        }
126
127        public static OfInt ofIntSupplier(String name, Supplier<IntStream> supplier) {
128            return new AbstractTestData.IntTestData<>(name, supplier,
129                                                      Supplier::get,
130                                                      s -> s.get().parallel(),
131                                                      s -> s.get().spliterator(),
132                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
133        }
134
135        public static OfInt ofNode(String name, Node.OfInt node) {
136            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
137            return new AbstractTestData.IntTestData<>(name, node,
138                                                      n -> StreamSupport.intStream(n::spliterator, characteristics, false),
139                                                      n -> StreamSupport.intStream(n::spliterator, characteristics, true),
140                                                      Node.OfInt::spliterator,
141                                                      n -> (int) n.count());
142        }
143
144        // long factories
145        public static <T> OfLong ofArray(String name, long[] array) {
146            return new AbstractTestData.LongTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
147                                                       Arrays::spliterator, a -> a.length);
148        }
149
150        public static OfLong ofSpinedBuffer(String name, SpinedBuffer.OfLong buffer) {
151            return new AbstractTestData.LongTestData<>(name, buffer,
152                                                      b -> StreamSupport.longStream(b.spliterator(), false),
153                                                      b -> StreamSupport.longStream(b.spliterator(), true),
154                                                      SpinedBuffer.OfLong::spliterator,
155                                                      b -> (int) b.count());
156        }
157
158        public static OfLong ofLongSupplier(String name, Supplier<LongStream> supplier) {
159            return new AbstractTestData.LongTestData<>(name, supplier,
160                                                      Supplier::get,
161                                                      s -> s.get().parallel(),
162                                                      s -> s.get().spliterator(),
163                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
164        }
165
166        public static OfLong ofNode(String name, Node.OfLong node) {
167            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
168            return new AbstractTestData.LongTestData<>(name, node,
169                                                      n -> StreamSupport.longStream(n::spliterator, characteristics, false),
170                                                      n -> StreamSupport.longStream(n::spliterator, characteristics, true),
171                                                      Node.OfLong::spliterator,
172                                                      n -> (int) n.count());
173        }
174
175        // double factories
176        public static <T> OfDouble ofArray(String name, double[] array) {
177            return new AbstractTestData.DoubleTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
178                                                         Arrays::spliterator, a -> a.length);
179        }
180
181        public static OfDouble ofSpinedBuffer(String name, SpinedBuffer.OfDouble buffer) {
182            return new AbstractTestData.DoubleTestData<>(name, buffer,
183                                                         b -> StreamSupport.doubleStream(b.spliterator(), false),
184                                                         b -> StreamSupport.doubleStream(b.spliterator(), true),
185                                                         SpinedBuffer.OfDouble::spliterator,
186                                                         b -> (int) b.count());
187        }
188
189        public static OfDouble ofDoubleSupplier(String name, Supplier<DoubleStream> supplier) {
190            return new AbstractTestData.DoubleTestData<>(name, supplier,
191                                                         Supplier::get,
192                                                         s -> s.get().parallel(),
193                                                         s -> s.get().spliterator(),
194                                                         s -> (int) s.get().spliterator().getExactSizeIfKnown());
195        }
196
197        public static OfDouble ofNode(String name, Node.OfDouble node) {
198            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
199            return new AbstractTestData.DoubleTestData<>(name, node,
200                                                         n -> StreamSupport.doubleStream(n::spliterator, characteristics, false),
201                                                         n -> StreamSupport.doubleStream(n::spliterator, characteristics, true),
202                                                         Node.OfDouble::spliterator,
203                                                         n -> (int) n.count());
204        }
205    }
206
207
208    abstract class AbstractTestData<T, S extends BaseStream<T, S>,
209            T_STATE,
210                                    T_SPLITR extends Spliterator<T>>
211            implements TestData<T, S> {
212        private final String name;
213        private final StreamShape shape;
214        protected final T_STATE state;
215        private final ToIntFunction<T_STATE> sizeFn;
216        private final Function<T_STATE, S> streamFn;
217        private final Function<T_STATE, S> parStreamFn;
218        private final Function<T_STATE, T_SPLITR> splitrFn;
219
220        AbstractTestData(String name,
221                         StreamShape shape,
222                         T_STATE state,
223                         Function<T_STATE, S> streamFn,
224                         Function<T_STATE, S> parStreamFn,
225                         Function<T_STATE, T_SPLITR> splitrFn,
226                         ToIntFunction<T_STATE> sizeFn) {
227            this.name = name;
228            this.shape = shape;
229            this.state = state;
230            this.streamFn = streamFn;
231            this.parStreamFn = parStreamFn;
232            this.splitrFn = splitrFn;
233            this.sizeFn = sizeFn;
234        }
235
236        @Override
237        public StreamShape getShape() {
238            return shape;
239        }
240
241        @Override
242        public String toString() {
243            return getClass().getSimpleName() + "[" + name + "]";
244        }
245
246        @Override
247        public int size() {
248            return sizeFn.applyAsInt(state);
249        }
250
251        @Override
252        public T_SPLITR spliterator() {
253            return splitrFn.apply(state);
254        }
255
256        @Override
257        public S stream() {
258            return streamFn.apply(state);
259        }
260
261        @Override
262        public S parallelStream() {
263            return parStreamFn.apply(state);
264        }
265
266        public static class RefTestData<T, I>
267                extends AbstractTestData<T, Stream<T>, I, Spliterator<T>>
268                implements TestData.OfRef<T> {
269
270            protected RefTestData(String name,
271                                  I state,
272                                  Function<I, Stream<T>> streamFn,
273                                  Function<I, Stream<T>> parStreamFn,
274                                  Function<I, Spliterator<T>> splitrFn,
275                                  ToIntFunction<I> sizeFn) {
276                super(name, StreamShape.REFERENCE, state, streamFn, parStreamFn, splitrFn, sizeFn);
277            }
278
279        }
280
281        static class IntTestData<I>
282                extends AbstractTestData<Integer, IntStream, I, Spliterator.OfInt>
283                implements TestData.OfInt {
284
285            protected IntTestData(String name,
286                                  I state,
287                                  Function<I, IntStream> streamFn,
288                                  Function<I, IntStream> parStreamFn,
289                                  Function<I, Spliterator.OfInt> splitrFn,
290                                  ToIntFunction<I> sizeFn) {
291                super(name, StreamShape.INT_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
292            }
293
294            @Override
295            public PrimitiveIterator.OfInt iterator() {
296                return Spliterators.iterator(spliterator());
297            }
298
299            @Override
300            public <A extends Collection<? super Integer>> A into(A target) {
301                spliterator().forEachRemaining((IntConsumer) target::add);
302                return target;
303            }
304        }
305
306        static class LongTestData<I>
307                extends AbstractTestData<Long, LongStream, I, Spliterator.OfLong>
308                implements TestData.OfLong {
309
310            protected LongTestData(String name,
311                                   I state,
312                                   Function<I, LongStream> streamFn,
313                                   Function<I, LongStream> parStreamFn,
314                                   Function<I, Spliterator.OfLong> splitrFn,
315                                   ToIntFunction<I> sizeFn) {
316                super(name, StreamShape.LONG_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
317            }
318
319            @Override
320            public PrimitiveIterator.OfLong iterator() {
321                return Spliterators.iterator(spliterator());
322            }
323
324            @Override
325            public <A extends Collection<? super Long>> A into(A target) {
326                spliterator().forEachRemaining((LongConsumer) target::add);
327                return target;
328            }
329        }
330
331        static class DoubleTestData<I>
332                extends AbstractTestData<Double, DoubleStream, I, Spliterator.OfDouble>
333                implements OfDouble {
334
335            protected DoubleTestData(String name,
336                                     I state,
337                                     Function<I, DoubleStream> streamFn,
338                                     Function<I, DoubleStream> parStreamFn,
339                                     Function<I, Spliterator.OfDouble> splitrFn,
340                                     ToIntFunction<I> sizeFn) {
341                super(name, StreamShape.DOUBLE_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
342            }
343
344            @Override
345            public PrimitiveIterator.OfDouble iterator() {
346                return Spliterators.iterator(spliterator());
347            }
348
349            @Override
350            public <A extends Collection<? super Double>> A into(A target) {
351                spliterator().forEachRemaining((DoubleConsumer) target::add);
352                return target;
353            }
354        }
355    }
356}
357