├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── source ├── Reducers.h ├── Stream.h ├── StreamAlgebra.h ├── StreamConversions.h ├── StreamError.h ├── StreamForward.h ├── StreamGenerators.h ├── StreamOperations.h ├── StreamOperators.h ├── StreamTerminators.h ├── Utility.h ├── UtilityImpl.h ├── providers │ ├── AdjacentDifference.h │ ├── AdjacentDistinct.h │ ├── Concatenate.h │ ├── CycledContainer.h │ ├── Difference.h │ ├── Distinct.h │ ├── DropWhile.h │ ├── DynamicGroup.h │ ├── DynamicOverlap.h │ ├── Empty.h │ ├── Filter.h │ ├── FlatMap.h │ ├── Generate.h │ ├── Group.h │ ├── Intersection.h │ ├── Iterate.h │ ├── Iterator.h │ ├── Map.h │ ├── Merge.h │ ├── Overlap.h │ ├── PartialSum.h │ ├── Peek.h │ ├── Providers.h │ ├── Recurrence.h │ ├── Repeat.h │ ├── SetOperation.h │ ├── Singleton.h │ ├── Slice.h │ ├── Sort.h │ ├── Stateful.h │ ├── StreamProvider.h │ ├── StreamProviderIterator.h │ ├── SymmetricDifference.h │ ├── TakeWhile.h │ ├── Union.h │ └── Zip.h └── reducers │ ├── Histogram.h │ ├── Reducer.h │ └── SummaryStats.h └── test ├── AccessTest.cpp ├── AdjacentDifferenceTest.cpp ├── AdjacentDistinctTest.cpp ├── AlgebraTest.cpp ├── CMakeLists.txt ├── ConcatTest.cpp ├── ConversionTest.cpp ├── CounterTest.cpp ├── CycleTest.cpp ├── EmptyTest.cpp ├── FilterTest.cpp ├── FlatMapTest.cpp ├── ForEachTest.cpp ├── FromTest.cpp ├── GroupTest.cpp ├── MapTest.cpp ├── NumericReductionTest.cpp ├── OverlapTest.cpp ├── PartialSumTest.cpp ├── PeekTest.cpp ├── QuantifierTest.cpp ├── RangeTest.cpp ├── RecurrenceTest.cpp ├── ReduceTest.cpp ├── RepeatTest.cpp ├── SampleTest.cpp ├── SaveTest.cpp ├── SetOperationsTest.cpp ├── SingletonTest.cpp ├── SliceTest.cpp ├── StatefulTest.cpp ├── WhileTest.cpp └── ZipTest.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.o 3 | build/ 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.7) 2 | 3 | project(Streams CXX) 4 | 5 | # TODO: Make the following more granular once there's wider compiler support for 6 | # c++14. Note that the absence of "-g" is intentional as the current version of 7 | # clang (3.4) does not support emitting debug info for auto member functions. 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++1y -stdlib=libc++ -Wno-unused-function -pipe") 9 | set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-inline") 10 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native -DNDEBUG") 11 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -march=native -DNDEBUG") 12 | 13 | add_custom_target(linecount 14 | COMMAND wc -l source/*.h source/*/*.h | sort 15 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) 16 | 17 | enable_testing() 18 | 19 | include_directories(source) 20 | add_subdirectory(test) 21 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 by Jonah Scheinerman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++ Streams 2 | 3 | Streams is a C++ library that provides lazy evaluation and functional-style transformations on the data, to ease the use of C++ standard library containers and algorithms. Streams support many common functional operations such as map, filter, and reduce, as well as various other useful operations such as various set operations (union, intersection, difference), partial sum, and adjacent difference, as well as many others. 4 | 5 | To use, simply `#include "Stream.h"`, and compile using a C++14 compatible compiler. All streams classes/functions can be found in the `stream` namespace. 6 | 7 | Links: 8 | 9 | * [Documentation](http://jscheiny.github.io/Streams) 10 | * [Github](http://github.com/jscheiny/Streams) 11 | * [Contact](http://scheinerman.net/jonah) 12 | 13 | C++ Streams are distributed under the MIT open source license. 14 | Copyright (c) 2014 by Jonah Scheinerman 15 | 16 | ## Examples 17 | 18 | ### Coin flip experiment: 19 | 20 | ```cpp 21 | using namespace stream; 22 | using namespace stream::op; 23 | 24 | int number_heads(int flips) { 25 | return MakeStream::coin_flips() 26 | | limit(flips) 27 | | filter() 28 | | count(); 29 | }; 30 | 31 | void experiment(int trials, int flips) { 32 | auto stats = MakeStream::generate(std::bind(number_heads, flips)) 33 | | limit(trials) 34 | | reducers::SummaryStats().reducer(); 35 | std::cout << stats << std::endl; 36 | } 37 | 38 | // Example output for experiment(1000, 1000): 39 | // N=1000, u=499.812, s=252.763, min=452, max=549 40 | ``` 41 | 42 | ### Investigating the Collatz conjecture: 43 | 44 | ```cpp 45 | #include "Stream.h" 46 | #include 47 | 48 | using namespace stream; 49 | using namespace stream::op; 50 | 51 | int collatz_next(int value) { 52 | if(value % 2 == 0) 53 | return value / 2; 54 | return 3 * value + 1; 55 | } 56 | 57 | int collatz_sequence_length(int start) { 58 | return MakeStream::iterate(start, collatz_next) 59 | | take_while([](int x) { return x != 1; }) 60 | | count(); 61 | } 62 | 63 | void print_collatz(int start) { 64 | MakeStream::iterate(start, collatz_next) 65 | | take_while([](int x) { return x != 1; }) 66 | | print_to(std::cout, " -> "); 67 | std::cout << "1" << std::endl; 68 | } 69 | 70 | int main(int argc, char const *argv[]) { 71 | print_collatz(24); 72 | } 73 | 74 | // print_collatz(10): 75 | // 24 -> 12 -> 6 -> 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1 76 | ``` 77 | 78 | ### Vector operations: 79 | 80 | ```cpp 81 | std::vector x = /* ... */; 82 | std::vector y = /* ... */; 83 | 84 | auto to_stream = [](std::vector& vec) { 85 | return MakeStream::from(vec); 86 | }; 87 | 88 | std::vector sum_vec = to_stream(x) + to_stream(y); 89 | std::vector diff_vec = to_stream(x) - to_stream(y); 90 | double dot_product = (to_stream(x) * to_stream(y)) | sum(); 91 | std::vector scaling = to_stream(x) * 10; 92 | std::vector translating = to_stream(x) + 3.7; 93 | ``` 94 | 95 | ### Set operations: 96 | 97 | ```cpp 98 | std::set x = /* ... */; 99 | set::set y = /* ... */; 100 | 101 | auto to_stream = [](std::set& vec) { 102 | return MakeStream::from(vec); 103 | }; 104 | 105 | std::set set_union = to_stream(x) | union_with(to_stream(y)); 106 | // Better than: 107 | // std::set result; 108 | // std::set_union(x.begin(), x.end(), y.begin(), y.end(), 109 | // inserter(result, result.end())); 110 | std::set set_intersect = to_stream(x) 111 | | intersection_with(to_stream(y)); 112 | std::set set_diff = to_stream(x) 113 | | difference_with(to_stream(y)); 114 | std::set set_sym_diff = to_stream(x) 115 | | symmetric_difference_with(to_stream(y)); 116 | ``` 117 | 118 | ### Adding unique ids: 119 | 120 | ```cpp 121 | std::vector objects = /* ... */; 122 | 123 | std::vector objects_with_ids = MakeStream::from(objects) 124 | | zip_with(MakeStream::counter(1), [](T&& object, int id) { 125 | object.set_id(id); 126 | return object; 127 | }); 128 | ``` 129 | 130 | ### Printing containers: 131 | 132 | ```cpp 133 | (MakeStream::from(container) | print_to(std::cout)) << std::endl; 134 | ``` 135 | 136 | ### Operator composition: 137 | 138 | ```cpp 139 | auto square = map_([](auto&& x) { return x * x; }); 140 | (MakeStream::range(1, 6) | square | print_to(std::cout)) << std::endl; // 1 4 9 16 25 141 | 142 | auto square_and_sum = square | sum(); 143 | int result = MakeStream::range(1, 4) | square_and_sum; // 14 144 | 145 | auto every_nth = [](int n) { 146 | return zip_with(MakeStream::counter(0)) 147 | | filter([=](const auto& tup) { return std::get<1>(tup) % n == 0; }) 148 | | map_([](auto&& tup) { return std::get<0>(tup); }); 149 | }; 150 | 151 | MakeStream::from({1, 3, 8, 4, 7}) | every_nth(2) | print_to(std::cout); // 1 8 7 152 | ``` 153 | -------------------------------------------------------------------------------- /source/Reducers.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_REDUCERS_H 2 | #define SCHEINERMAN_STREAM_REDUCERS_H 3 | 4 | #include "reducers/SummaryStats.h" 5 | #include "reducers/Histogram.h" 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /source/Stream.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_STREAM_H 2 | #define SCHEINERMAN_STREAM_STREAM_H 3 | 4 | #include "StreamForward.h" 5 | #include "StreamError.h" 6 | #include "providers/Providers.h" 7 | #include "Utility.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace stream { 22 | 23 | struct MakeStream { 24 | template 25 | static Stream> empty(); 26 | 27 | template 28 | static Stream> repeat(T&& value); 29 | 30 | template 31 | static Stream> repeat(T&& value, size_t times); 32 | 33 | template 34 | static Stream> cycle(Iterator begin, Iterator end); 35 | 36 | template 37 | static Stream> cycle(Iterator begin, Iterator end, 38 | size_t times); 39 | 40 | template 41 | static Stream> cycle(const Container& cont); 42 | 43 | template 44 | static Stream> cycle(const Container& cont, 45 | size_t times); 46 | 47 | template 48 | static Stream cycle(std::initializer_list init); 49 | 50 | template 51 | static Stream cycle(std::initializer_list init, size_t times); 52 | 53 | template 54 | static Stream> cycle_move(Container&& cont); 55 | 56 | template 57 | static Stream> cycle_move(Container&& cont, 58 | size_t times); 59 | 60 | template 61 | static Stream> generate(Generator&& generator); 62 | 63 | template 64 | static Stream> iterate(T&& initial, Function&& function); 65 | 66 | template 67 | static Stream>> recurrence(Function&& function, Args&&... initial); 68 | 69 | template 70 | static Stream> counter(T&& start); 71 | 72 | template 73 | static Stream> counter(T&& start, U&& increment); 74 | 75 | template 76 | static Stream> counter(T&& start, const U& increment); 77 | 78 | template 79 | static Stream> range(T&& lower, T&& upper); 80 | 81 | template 82 | static Stream> range(T&& lower, T&& upper, U&& increment); 83 | 84 | template 85 | static Stream> range(T&& lower, T&& upper, const U& increment); 86 | 87 | template 88 | static Stream> closed_range(T&& lower, T&& upper); 89 | 90 | template 91 | static Stream> closed_range(T&& lower, T&& upper, U&& increment); 92 | 93 | template 94 | static Stream> closed_range(T&& lower, T&& upper, const U& increment); 95 | 96 | template class Distribution, 97 | typename Engine=std::default_random_engine, 98 | typename Seed, 99 | typename ... GenArgs> 100 | static Stream randoms_seeded(Seed&& seed, GenArgs&&... args); 101 | 102 | template class Distribution, 103 | typename Engine=std::default_random_engine, 104 | typename ... GenArgs> 105 | static Stream randoms(GenArgs&&... args); 106 | 107 | template 108 | static Stream uniform_random_ints(T lower, T upper); 109 | 110 | template 111 | static Stream uniform_random_ints(T lower, T upper, Seed&& seed); 112 | 113 | template 114 | static Stream uniform_random_reals(T lower=0.0, T upper=1.0); 115 | 116 | template 117 | static Stream uniform_random_reals(T lower, T upper, Seed&& seed); 118 | 119 | template 120 | static Stream normal_randoms(T mean=0.0, T stddev=1.0); 121 | 122 | template 123 | static Stream normal_randoms(T mean, T stddev, Seed&& seed); 124 | 125 | template 126 | static Stream coin_flips(); 127 | 128 | template 129 | static Stream coin_flips(Seed&& seed); 130 | 131 | template 132 | static Stream> singleton(T&& value); 133 | 134 | template 135 | static Stream> from(Iterator begin, Iterator end); 136 | 137 | template 138 | static Stream> from(const Container& cont); 139 | 140 | template 141 | static Stream from(T* array, std::size_t length); 142 | 143 | template 144 | static Stream from(std::initializer_list init); 145 | 146 | template 147 | static Stream> from_move(Container&& cont); 148 | 149 | private: 150 | static auto default_seed() { 151 | return std::chrono::high_resolution_clock::now().time_since_epoch().count(); 152 | } 153 | 154 | }; 155 | 156 | template class Operator; 157 | template class Terminator; 158 | 159 | template 160 | class Stream { 161 | 162 | public: 163 | using element_type = T; 164 | using iterator = typename provider::StreamProvider::Iterator; 165 | 166 | iterator begin() { 167 | return source_->begin(); 168 | } 169 | 170 | iterator end() { 171 | return source_->end(); 172 | } 173 | 174 | Stream() 175 | : source_(make_stream_provider()) {} 176 | 177 | Stream(Stream&& other) = default; 178 | Stream& operator= (Stream&& other) = default; 179 | 180 | Stream(const Stream& other) = delete; 181 | Stream& operator= (const Stream& other) = default; 182 | 183 | Stream(StreamProviderPtr source) 184 | : source_(std::move(source)) {} 185 | 186 | template 187 | Stream(Iterator begin, Iterator end) 188 | : source_(make_stream_provider( 189 | begin, end)) {} 190 | 191 | template 192 | Stream(const Container& container) 193 | : Stream(container.begin(), container.end()) {} 194 | 195 | Stream(std::initializer_list init) 196 | : Stream(std::deque(init.begin(), init.end())) {} 197 | 198 | template 199 | auto operator| (Operator&& op) -> 200 | decltype(op.apply_to(std::move(*this))) { 201 | return op.apply_to(std::move(*this)); 202 | } 203 | 204 | template 205 | auto operator| (Operator& op) -> 206 | decltype(op.apply_to(std::move(*this))) { 207 | return op.apply_to(std::move(*this)); 208 | } 209 | 210 | template 211 | auto operator| (Terminator&& term) -> 212 | decltype(term.apply_to(std::move(*this))) { 213 | return term.apply_to(std::move(*this)); 214 | } 215 | 216 | template 217 | auto operator| (Terminator& term) -> 218 | decltype(term.apply_to(std::move(*this))) { 219 | return term.apply_to(std::move(*this)); 220 | } 221 | 222 | template operator std::vector(); 223 | template operator std::list(); 224 | template operator std::deque(); 225 | template operator std::set(); 226 | template operator std::multiset(); 227 | template operator std::unordered_set(); 228 | template operator std::unordered_multiset(); 229 | 230 | StreamProviderPtr& getSource() { 231 | return source_; 232 | } 233 | 234 | void close() { 235 | source_.reset(); 236 | } 237 | 238 | bool occupied() const { 239 | return bool(source_); 240 | } 241 | 242 | void swap(Stream& other) { 243 | source_.swap(other.sorce_); 244 | } 245 | 246 | std::string pipeline() { 247 | std::stringstream ss; 248 | provider::PrintInfo info = source_->print(ss, 1); 249 | ss << "Stream pipeline with " 250 | << info.stages << " stage" << (info.stages == 1 ? "" : "s") << " and " 251 | << info.sources << " source" << (info.sources == 1 ? "" : "s") << "."; 252 | return ss.str(); 253 | } 254 | 255 | template friend class Operator; 256 | template friend class Terminator; 257 | 258 | private: 259 | StreamProviderPtr source_; 260 | 261 | void check_vacant(const std::string& method) { 262 | if(!occupied()) { 263 | throw VacantStreamException(method); 264 | } 265 | } 266 | 267 | }; 268 | 269 | } /* namespace stream */ 270 | 271 | #include "StreamOperations.h" 272 | #include "StreamOperators.h" 273 | #include "StreamTerminators.h" 274 | #include "StreamGenerators.h" 275 | #include "StreamAlgebra.h" 276 | #include "StreamConversions.h" 277 | 278 | #endif 279 | -------------------------------------------------------------------------------- /source/StreamAlgebra.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_STREAM_ALGEBRA_H 2 | #define SCHEINERMAN_STREAM_STREAM_ALGEBRA_H 3 | 4 | #include "Utility.h" 5 | 6 | #define STREAM_OP_STREAM(Op, Function) \ 7 | template \ 8 | stream::Stream> \ 9 | operator Op (stream::Stream&& left, stream::Stream&& right) { \ 10 | return left | stream::op::zip_with(std::forward>(right), \ 11 | Function{}); \ 12 | } 13 | 14 | #define STREAM_OP_VALUE(Op) \ 15 | template \ 16 | auto operator Op (stream::Stream&& left, const T& right) \ 17 | -> stream::Stream() Op right)> { \ 18 | return left | stream::op::map_([right] (S&&value) { \ 19 | return value Op right; \ 20 | }); \ 21 | } 22 | 23 | #define VALUE_OP_STREAM(Op) \ 24 | template \ 25 | auto operator Op (const T& left, stream::Stream&& right) \ 26 | -> stream::Stream())> { \ 27 | return right | stream::op::map_([left] (S&& value) { \ 28 | return left Op value; \ 29 | }); \ 30 | } 31 | 32 | #define BINARY_OPERATOR(Op, Function) \ 33 | STREAM_OP_STREAM(Op, Function) \ 34 | STREAM_OP_VALUE(Op) \ 35 | VALUE_OP_STREAM(Op) \ 36 | 37 | #define UNARY_OPERATOR(Op) \ 38 | template \ 39 | stream::Stream())> operator Op (stream::Stream&& stream) { \ 40 | return stream | stream::op::map_([](T&& x) { return Op x; }); \ 41 | } 42 | 43 | 44 | struct ShiftLeft { 45 | template 46 | constexpr auto operator()(L&& left, R&& right) const 47 | -> decltype(std::forward(left) << std::forward(right)) { 48 | return std::forward(left) << std::forward(right); 49 | } 50 | }; 51 | 52 | struct ShiftRight { 53 | template 54 | constexpr auto operator()(L&& left, R&& right) const 55 | -> decltype(std::forward(left) >> std::forward(right)) { 56 | return std::forward(left) >> std::forward(right); 57 | } 58 | }; 59 | 60 | 61 | UNARY_OPERATOR(-); 62 | UNARY_OPERATOR(+); 63 | UNARY_OPERATOR(!); 64 | UNARY_OPERATOR(~); 65 | UNARY_OPERATOR(*); 66 | 67 | BINARY_OPERATOR(+, std::plus); 68 | BINARY_OPERATOR(-, std::minus); 69 | BINARY_OPERATOR(*, std::multiplies); 70 | BINARY_OPERATOR(/, std::divides); 71 | BINARY_OPERATOR(%, std::modulus); 72 | 73 | BINARY_OPERATOR(==, std::equal_to); 74 | BINARY_OPERATOR(!=, std::not_equal_to); 75 | BINARY_OPERATOR(<, std::less); 76 | BINARY_OPERATOR(>, std::greater); 77 | BINARY_OPERATOR(<=, std::less_equal); 78 | BINARY_OPERATOR(>=, std::greater_equal); 79 | 80 | BINARY_OPERATOR(&&, std::logical_and); 81 | BINARY_OPERATOR(||, std::logical_or); 82 | 83 | BINARY_OPERATOR(&, std::bit_and); 84 | BINARY_OPERATOR(|, std::bit_or); 85 | BINARY_OPERATOR(^, std::bit_xor); 86 | BINARY_OPERATOR(<<, ShiftLeft); 87 | BINARY_OPERATOR(>>, ShiftRight); 88 | 89 | #undef STREAM_OP_STREAM 90 | #undef STREAM_OP_VALUE 91 | #undef VALUE_OP_STREAM 92 | #undef BINARY_OPERATOR 93 | #undef UNARY_OPERATOR 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /source/StreamConversions.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_STREAM_CONVERSIONS_H 2 | #define SCHEINERMAN_STREAM_STREAM_CONVERSIONS_H 3 | 4 | namespace stream { 5 | 6 | namespace op { 7 | 8 | namespace detail { 9 | 10 | template class ListContainer> 11 | class ListContainerTerminatorMaker { 12 | 13 | public: 14 | ListContainerTerminatorMaker(const std::string& name) : name_(name) {} 15 | 16 | auto operator() () const { 17 | return make_terminator(name_, [](auto&& stream) { 18 | using T = StreamType; 19 | ListContainer> result; 20 | stream | copy_to(std::back_inserter(result)); 21 | return result; 22 | }); 23 | } 24 | 25 | template> 26 | auto operator() (const Allocator& allocator) const { 27 | return make_terminator(name_, [allocator](auto&& stream) { 28 | using T = StreamType; 29 | ListContainer result(allocator); 30 | stream | copy_to(std::back_inserter(result)); 31 | return result; 32 | }); 33 | } 34 | 35 | private: 36 | std::string name_; 37 | }; 38 | 39 | template class OrderedContainer> 40 | class OrderedContainerTerminatorMaker { 41 | 42 | public: 43 | OrderedContainerTerminatorMaker(const std::string& name) : name_(name) {} 44 | 45 | template 46 | auto operator() (const Compare& compare, 47 | const Allocator& allocator) const { 48 | return make_terminator(name_, [compare, allocator](auto&& stream) { 49 | using T = StreamType; 50 | OrderedContainer result(compare, allocator); 51 | stream | copy_to(std::inserter(result, result.end())); 52 | return result; 53 | }); 54 | } 55 | 56 | template> 57 | auto operator() (const Compare& compare = Compare()) const { 58 | return make_terminator(name_, [compare](auto&& stream) { 59 | using T = StreamType; 60 | OrderedContainer> result(compare); 61 | stream | copy_to(std::inserter(result, result.end())); 62 | return result; 63 | }); 64 | } 65 | 66 | private: 67 | std::string name_; 68 | }; 69 | 70 | struct PolymorphicHash { 71 | template 72 | decltype(auto) operator() (const T& value) { 73 | return std::hash{}(value); 74 | } 75 | }; 76 | 77 | template class UnorderedContainer> 78 | class UnorderedContainerTerminatorMaker { 79 | 80 | public: 81 | UnorderedContainerTerminatorMaker(const std::string& name) : name_(name) {} 82 | 83 | template 84 | auto operator() (const Hash& hash, 85 | const Predicate& predicate, 86 | const Allocator& allocator) const { 87 | return make_terminator(name_, [hash, predicate, allocator](auto&& stream) { 88 | using T = StreamType; 89 | UnorderedContainer result(0, hash, predicate, allocator); 90 | stream | copy_to(std::inserter(result, result.end())); 91 | return result; 92 | }); 93 | } 94 | 95 | template> 97 | auto operator() (const Hash& hash = Hash(), 98 | const Predicate& predicate = Predicate()) const { 99 | return make_terminator(name_, [hash, predicate](auto&& stream) { 100 | using T = StreamType; 101 | UnorderedContainer> result(0, hash, predicate); 102 | stream | copy_to(std::inserter(result, result.end())); 103 | return result; 104 | }); 105 | } 106 | 107 | private: 108 | std::string name_; 109 | }; 110 | 111 | } /* namespace detail */ 112 | 113 | static const detail::ListContainerTerminatorMaker to_vector{"stream::op::to_vector"}; 114 | static const detail::ListContainerTerminatorMaker to_list{"stream::op::to_list"}; 115 | static const detail::ListContainerTerminatorMaker to_deque{"stream::op::to_deque"}; 116 | static const detail::OrderedContainerTerminatorMaker to_set{"stream::op::to_set"}; 117 | static const detail::OrderedContainerTerminatorMaker to_multiset{"stream::op::to_multiset"}; 118 | static const detail::UnorderedContainerTerminatorMaker to_unordered_set{"stream::op::to_unordered_set"}; 119 | static const detail::UnorderedContainerTerminatorMaker to_unordered_multiset{"stream::op::to_unordered_multiset"}; 120 | 121 | } /* namespace op */ 122 | 123 | template 124 | template 125 | Stream::operator std::vector() { 126 | return (*this) | op::to_vector(Allocator()); 127 | } 128 | 129 | template 130 | template 131 | Stream::operator std::list() { 132 | return (*this) | op::to_list(Allocator()); 133 | } 134 | 135 | template 136 | template 137 | Stream::operator std::deque() { 138 | return (*this) | op::to_deque(Allocator()); 139 | } 140 | 141 | template 142 | template 143 | Stream::operator std::set() { 144 | return (*this) | op::to_set(Compare(), Allocator()); 145 | } 146 | 147 | template 148 | template 149 | Stream::operator std::multiset() { 150 | return (*this) | op::to_multiset(Compare(), Allocator()); 151 | } 152 | 153 | template 154 | template 155 | Stream::operator std::unordered_set() { 156 | return (*this) | op::to_unordered_set(Hash(), Predicate(), Allocator()); 157 | } 158 | 159 | template 160 | template 161 | Stream::operator std::unordered_multiset() { 162 | return (*this) | op::to_unordered_multiset(Hash(), Predicate(), Allocator()); 163 | } 164 | 165 | } /* namespace stream */ 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /source/StreamError.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_STREAM_ERROR_H 2 | #define SCHEINERMAN_STREAM_STREAM_ERROR_H 3 | 4 | #include 5 | #include 6 | 7 | namespace stream { 8 | 9 | class StreamException { 10 | 11 | public: 12 | explicit StreamException(const std::string& msg) : message(msg) {} 13 | explicit StreamException(const char* msg) : message(msg) {} 14 | 15 | std::string what() const { return message; } 16 | 17 | private: 18 | std::string message; 19 | 20 | }; 21 | 22 | class EmptyStreamException : public StreamException { 23 | 24 | public: 25 | explicit EmptyStreamException(const std::string& term) 26 | : StreamException(build_message(term)) {} 27 | 28 | private: 29 | static std::string build_message(const std::string& term) { 30 | std::stringstream message; 31 | message << "No terminal result for operation " << term; 32 | return message.str(); 33 | } 34 | }; 35 | 36 | class VacantStreamException : public StreamException { 37 | 38 | public: 39 | explicit VacantStreamException(const std::string& opname) 40 | : StreamException(build_message(opname)) {} 41 | 42 | private: 43 | static std::string build_message(const std::string& opname) { 44 | std::stringstream message; 45 | message << "Cannot perform operation " << opname << " on a vacant stream."; 46 | return message.str(); 47 | } 48 | }; 49 | 50 | class ConsumedIteratorException : public StreamException { 51 | 52 | public: 53 | explicit ConsumedIteratorException(const std::string& op) 54 | : StreamException(build_message(op)) {} 55 | 56 | private: 57 | static std::string build_message(const std::string& op) { 58 | std::stringstream message; 59 | message << "Cannot perform " << op << " on consumed stream iterator."; 60 | return message.str(); 61 | } 62 | }; 63 | 64 | class StopStream : public StreamException { 65 | 66 | public: 67 | StopStream() : StreamException("[End of stream]") {} 68 | 69 | }; 70 | 71 | } /* namespace stream */ 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /source/StreamForward.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_STREAM_FORWARD_H 2 | #define SCHEINERMAN_STREAM_STREAM_FORWARD_H 3 | 4 | #include 5 | 6 | namespace stream { 7 | 8 | template class Stream; 9 | 10 | namespace detail { 11 | 12 | template struct StreamIdentifier { using type = void; }; 13 | template struct StreamIdentifier> { using type = T; }; 14 | 15 | } /* namespace detail */ 16 | 17 | template using StreamType = 18 | typename detail::StreamIdentifier>::type; 19 | 20 | } /* namespace stream */ 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /source/StreamGenerators.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_STREAM_GENERATORS_H 2 | #define SCHEINERMAN_STREAM_STREAM_GENERATORS_H 3 | 4 | namespace stream { 5 | 6 | namespace detail { 7 | 8 | template class Distribution, typename Engine, typename T> 9 | struct RandomGenerator; 10 | 11 | } /* namespace detail */ 12 | 13 | template 14 | Stream> MakeStream::empty() { 15 | return {}; 16 | } 17 | 18 | template 19 | Stream> MakeStream::repeat(T&& value) { 20 | using R = RemoveRef; 21 | return make_stream_provider 22 | (std::forward(value)); 23 | } 24 | 25 | template 26 | Stream> MakeStream::repeat(T&& value, size_t times) { 27 | return MakeStream::repeat(value) | op::limit(times); 28 | } 29 | 30 | template 31 | Stream> MakeStream::cycle(Iterator begin, Iterator end) { 32 | using T = IteratorType; 33 | return MakeStream::repeat(make_pair(begin, end)) 34 | | op::flat_map(splat([](Iterator b, Iterator e) { 35 | return MakeStream::from(b, e); 36 | })); 37 | } 38 | 39 | template 40 | Stream> MakeStream::cycle(Iterator begin, Iterator end, 41 | size_t times) { 42 | using T = IteratorType; 43 | return MakeStream::repeat(make_pair(begin, end), times) 44 | | op::flat_map(splat([](Iterator b, Iterator e) { 45 | return MakeStream::from(b, e); 46 | })); 47 | } 48 | 49 | template 50 | Stream> MakeStream::cycle(const Container& cont, 51 | size_t times) { 52 | return MakeStream::cycle(std::begin(cont), std::end(cont), times); 53 | } 54 | 55 | template 56 | Stream> MakeStream::cycle(const Container& cont) { 57 | return MakeStream::cycle(std::begin(cont), std::end(cont)); 58 | } 59 | 60 | template 61 | Stream MakeStream::cycle(std::initializer_list init) { 62 | using Container = std::deque; 63 | return make_stream_provider 64 | (Container(init), 0); 65 | } 66 | 67 | template 68 | Stream MakeStream::cycle(std::initializer_list init, size_t times) { 69 | using Container = std::deque; 70 | return make_stream_provider 71 | (Container(init), times); 72 | } 73 | 74 | template 75 | Stream> MakeStream::cycle_move(Container&& cont) { 76 | return MakeStream::generate( 77 | [container = std::move(cont)] () { 78 | return container; 79 | }) 80 | | op::flat_map([](const Container& cont) { 81 | return MakeStream::from(cont); 82 | }); 83 | } 84 | 85 | template 86 | Stream> MakeStream::cycle_move(Container&& cont, 87 | size_t times) { 88 | using T = ContainerType; 89 | if(times == 0) 90 | return MakeStream::empty(); 91 | return MakeStream::generate( 92 | [container = std::move(cont)] () { 93 | return container; 94 | }) 95 | | op::limit(times) 96 | | op::flat_map([](const Container& cont) { 97 | return MakeStream::from(cont); 98 | }); 99 | } 100 | 101 | template 102 | Stream> MakeStream::generate(Generator&& generator) { 103 | using T = std::result_of_t; 104 | return make_stream_provider 105 | (std::forward(generator)); 106 | } 107 | 108 | template 109 | Stream> MakeStream::iterate(T&& initial, Function&& function) { 110 | return recurrence(std::forward(function), std::forward(initial)); 111 | } 112 | 113 | template 114 | Stream>> MakeStream::recurrence(Function&& function, Args&&... initial) { 115 | constexpr size_t Order = sizeof...(Args); 116 | using R = RemoveRef>; 117 | return StreamProviderPtr( 118 | new provider::Recurrence( 119 | {{std::forward(initial)...}}, std::forward(function))); 120 | } 121 | 122 | template 123 | Stream> MakeStream::counter(T&& start) { 124 | using R = RemoveRef; 125 | return MakeStream::iterate(std::forward(start), [](R value) { 126 | return ++value; 127 | }); 128 | } 129 | 130 | template 131 | Stream> MakeStream::counter(T&& start, U&& increment) { 132 | using R = RemoveRef; 133 | return MakeStream::iterate(std::forward(start), 134 | [inc = std::forward(increment)](const R& value) { 135 | return value + inc; 136 | }); 137 | } 138 | 139 | template 140 | Stream> MakeStream::counter(T&& start, const U& increment) { 141 | using R = RemoveRef; 142 | return MakeStream::iterate(std::forward(start), 143 | [&inc = increment](const R& value) { 144 | return value + inc; 145 | }); 146 | } 147 | 148 | template 149 | Stream> MakeStream::range(T&& lower, T&& upper) { 150 | using R = RemoveRef; 151 | return MakeStream::counter(lower) 152 | | op::take_while([upper = std::forward(upper)](const R& value) { 153 | return value != upper; 154 | }); 155 | } 156 | 157 | template 158 | Stream> MakeStream::range(T&& lower, T&& upper, U&& increment) { 159 | using R = RemoveRef; 160 | return MakeStream::counter(lower, std::forward(increment)) 161 | | op::take_while([upper = std::forward(upper)](const R& value) { 162 | return value < upper; 163 | }); 164 | } 165 | 166 | template 167 | Stream> MakeStream::range(T&& lower, T&& upper, const U& increment) { 168 | using R = RemoveRef; 169 | return MakeStream::counter(lower, increment) 170 | | op::take_while([upper = std::forward(upper)](const R& value) { 171 | return value < upper; 172 | }); 173 | } 174 | 175 | template 176 | Stream> MakeStream::closed_range(T&& lower, T&& upper) { 177 | using R = RemoveRef; 178 | return MakeStream::counter(lower) 179 | | op::take_while([upper = std::forward(upper)](R& value) { 180 | return value <= upper; 181 | }); 182 | } 183 | 184 | template 185 | Stream> MakeStream::closed_range(T&& lower, T&& upper, U&& increment) { 186 | using R = RemoveRef; 187 | return MakeStream::counter(lower, std::forward(increment)) 188 | | op::take_while([upper = std::forward(upper)](R& value) { 189 | return value <= upper; 190 | }); 191 | } 192 | 193 | template 194 | Stream> MakeStream::closed_range(T&& lower, T&& upper, const U& increment) { 195 | using R = RemoveRef; 196 | return MakeStream::counter(lower, increment) 197 | | op::take_while([upper = std::forward(upper)](R& value) { 198 | return value <= upper; 199 | }); 200 | } 201 | 202 | template class Distribution, 204 | typename Engine, 205 | typename Seed, 206 | typename... GenArgs> 207 | Stream MakeStream::randoms_seeded(Seed&& seed, GenArgs&&... args) { 208 | return generate(detail::RandomGenerator 209 | (seed, std::forward(args)...)); 210 | } 211 | 212 | template class Distribution, 214 | typename Engine, 215 | typename... GenArgs> 216 | Stream MakeStream::randoms(GenArgs&&... args) { 217 | return randoms_seeded 218 | (default_seed(), std::forward(args)...); 219 | } 220 | 221 | template 222 | Stream MakeStream::uniform_random_ints(T lower, T upper) { 223 | return uniform_random_ints(lower, upper, default_seed()); 224 | } 225 | 226 | template 227 | Stream MakeStream::uniform_random_ints(T lower, T upper, Seed&& seed) { 228 | return randoms_seeded 229 | (std::forward(seed), lower, upper); 230 | } 231 | 232 | template 233 | Stream MakeStream::uniform_random_reals(T lower, T upper) { 234 | return uniform_random_reals(lower, upper, default_seed()); 235 | } 236 | 237 | template 238 | Stream MakeStream::uniform_random_reals(T lower, T upper, Seed&& seed) { 239 | return randoms_seeded 240 | (std::forward(seed), lower, upper); 241 | } 242 | 243 | template 244 | Stream MakeStream::normal_randoms(T mean, T stddev) { 245 | return normal_randoms(mean, stddev, default_seed()); 246 | } 247 | 248 | template 249 | Stream MakeStream::normal_randoms(T mean, T stddev, Seed&& seed) { 250 | return randoms_seeded 251 | (std::forward(seed), mean, stddev); 252 | } 253 | 254 | template 255 | Stream MakeStream::coin_flips() { 256 | return uniform_random_ints(0, 1); 257 | } 258 | 259 | template 260 | Stream MakeStream::coin_flips(Seed&& seed) { 261 | return uniform_random_ints(0, 1, std::forward(seed)); 262 | } 263 | 264 | template 265 | Stream> MakeStream::singleton(T&& value) { 266 | using R = RemoveRef; 267 | return make_stream_provider 268 | (std::forward(value)); 269 | } 270 | 271 | template 272 | Stream> MakeStream::from(Iterator begin, Iterator end) { 273 | return {begin, end}; 274 | } 275 | 276 | template 277 | Stream MakeStream::from(T* array, std::size_t length) { 278 | return Stream(array, array + length); 279 | } 280 | 281 | template 282 | Stream> MakeStream::from(const Container& cont) { 283 | return {std::begin(cont), std::end(cont)}; 284 | } 285 | 286 | template 287 | Stream> MakeStream::from_move(Container&& cont) { 288 | using T = ContainerType; 289 | return MakeStream::cycle_move(std::forward(cont), 1); 290 | } 291 | 292 | template 293 | Stream MakeStream::from(std::initializer_list init) { 294 | using Container = std::deque; 295 | return make_stream_provider 296 | (Container(init), 1); 297 | } 298 | 299 | namespace detail { 300 | 301 | template class Distribution, typename Engine, typename T> 302 | struct RandomGenerator { 303 | template 304 | RandomGenerator(Seed seed, GenArgs&&... args) 305 | : generator_{static_cast(seed)}, 306 | distro_{std::forward(args)...} {} 307 | 308 | T operator() () { 309 | return distro_(generator_); 310 | } 311 | 312 | private: 313 | Engine generator_; 314 | Distribution distro_; 315 | 316 | }; 317 | 318 | } /* namespace detail */ 319 | 320 | } /* namespace stream */ 321 | 322 | #endif 323 | -------------------------------------------------------------------------------- /source/StreamOperations.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_STREAM_OPERATIONS_H 2 | #define SCHEINERMAN_STREAM_STREAM_OPERATIONS_H 3 | 4 | namespace stream { 5 | 6 | template 7 | class Compose { 8 | public: 9 | Compose(F&& f, G&& g) : f_(std::forward(f)), g_(std::forward(g)) {} 10 | 11 | template 12 | std::result_of_t&&)>)> operator() (Stream&& stream) { 13 | return f_(g_(std::forward>(stream))); 14 | } 15 | 16 | private: 17 | F f_; 18 | G g_; 19 | }; 20 | 21 | template 22 | class Operator { 23 | public: 24 | Operator(const std::string& name, F&& op) : name_(name), operator_(std::forward(op)) {} 25 | Operator(F&& op) : operator_(std::forward(op)) {} 26 | 27 | template 28 | std::result_of_t&&)> apply_to(Stream&& stream) { 29 | if(!name_.empty()) { 30 | stream.check_vacant(name_); 31 | } 32 | return operator_(std::forward>(stream)); 33 | } 34 | 35 | template 36 | Operator> operator| (Operator&& right) { 37 | return {{std::move(right.operator_), std::move(operator_)}}; 38 | } 39 | 40 | template 41 | Terminator> operator| (Terminator&& right) { 42 | return {{std::move(right.terminator_), std::move(operator_)}}; 43 | } 44 | 45 | Operator rename(const std::string& name) && { 46 | name_ = name; 47 | return std::move(*this); 48 | } 49 | 50 | template friend class Operator; 51 | private: 52 | std::string name_; 53 | F operator_; 54 | }; 55 | 56 | 57 | template 58 | class Terminator { 59 | public: 60 | Terminator(const std::string& name, F&& term) : name_(name), terminator_(term) {} 61 | Terminator(F&& term) : terminator_(term) {} 62 | 63 | template 64 | auto apply_to(Stream&& stream) -> std::result_of_t&&)> { 65 | if(!name_.empty()) { 66 | stream.check_vacant(name_); 67 | } 68 | try { 69 | return terminator_(std::forward>(stream)); 70 | } catch(EmptyStreamException& e) { 71 | if(!name_.empty()) { 72 | throw EmptyStreamException(name_); 73 | } else { 74 | throw; 75 | } 76 | } 77 | stream.close(); 78 | } 79 | 80 | Terminator rename(const std::string& name) && { 81 | name_ = name; 82 | return std::move(*this); 83 | } 84 | 85 | template 86 | Terminator> then(G&& function) { 87 | return {Compose(std::forward(function), std::move(terminator_))}; 88 | } 89 | 90 | template friend class Operator; 91 | private: 92 | std::string name_; 93 | F terminator_; 94 | }; 95 | 96 | template 97 | Operator make_operator(const std::string& name, Function&& function) { 98 | return Operator(name, std::forward(function)); 99 | } 100 | 101 | template 102 | Terminator make_terminator(const std::string& name, Function&& function) { 103 | return Terminator(name, std::forward(function)); 104 | } 105 | 106 | } /* namespace stream */ 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /source/StreamOperators.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_STREAM_OPERATORS_H 2 | #define SCHEINERMAN_STREAM_STREAM_OPERATORS_H 3 | 4 | #include 5 | 6 | namespace stream { 7 | namespace op { 8 | 9 | #define CLASS_SPECIALIZATIONS(operation) \ 10 | template auto operation (R (C::*member)()) \ 11 | { return operation (std::mem_fn(member)); } \ 12 | template auto operation (R (C::*member)() const) \ 13 | { return operation (std::mem_fn(member)); } 14 | 15 | template 16 | inline auto filter(Predicate&& predicate) { 17 | return make_operator("stream::op::filter", [=](auto&& stream) mutable { 18 | using T = StreamType; 19 | return Stream(std::move( 20 | make_stream_provider( 21 | std::move(stream.getSource()), std::forward(predicate)))); 22 | }); 23 | } 24 | 25 | inline auto filter() { 26 | return filter([](bool b){ return b; }); 27 | } 28 | 29 | CLASS_SPECIALIZATIONS(filter); 30 | 31 | template 32 | inline auto take_while(Predicate&& predicate) { 33 | return make_operator("stream::op::take_while", [=](auto&& stream) mutable { 34 | using T = StreamType; 35 | return Stream(std::move( 36 | make_stream_provider 37 | (std::move(stream.getSource()), std::forward(predicate)))); 38 | }); 39 | } 40 | 41 | inline auto take_while() { 42 | return take_while([](bool b){ return b; }); 43 | } 44 | 45 | CLASS_SPECIALIZATIONS(take_while); 46 | 47 | template 48 | inline auto drop_while(Predicate&& predicate) { 49 | return make_operator("stream::op::drop_while", [=](auto&& stream) mutable { 50 | using T = StreamType; 51 | return Stream(std::move( 52 | make_stream_provider( 53 | std::move(stream.getSource()), std::forward(predicate)))); 54 | }); 55 | } 56 | 57 | inline auto drop_while() { 58 | return drop_while([](bool b){ return b; }); 59 | } 60 | 61 | CLASS_SPECIALIZATIONS(drop_while); 62 | 63 | inline auto slice(std::size_t start, std::size_t end, std::size_t increment = 1) { 64 | return make_operator("stream::op::slice", [=](auto&& stream) { 65 | using T = StreamType; 66 | return Stream(std::move( 67 | make_stream_provider( 68 | std::move(stream.getSource()), start, end, increment, false))); 69 | }); 70 | } 71 | 72 | inline auto slice_to_end(std::size_t start, std::size_t increment) { 73 | return make_operator("stream::op::slice", [=](auto&& stream) { 74 | using T = StreamType; 75 | return Stream(std::move( 76 | make_stream_provider( 77 | std::move(stream.getSource()), start, 0, increment, true))); 78 | }); 79 | } 80 | 81 | inline auto limit(std::size_t length) { 82 | return slice(0, length).rename("stream::op::limit"); 83 | } 84 | 85 | inline auto skip(std::size_t amount) { 86 | return slice_to_end(amount, 1).rename("stream::op::skip"); 87 | } 88 | 89 | template 90 | inline auto map_(Function&& function) { 91 | return make_operator("stream::op::map_", [=](auto&& stream) mutable { 92 | using T = StreamType; 93 | using Result = std::result_of_t; 94 | static_assert(!std::is_void::value, 95 | "Return type of the mapping function cannot be void."); 96 | 97 | return Stream(std::move( 98 | make_stream_provider( 99 | std::move(stream.getSource()), std::forward(function)))); 100 | }); 101 | } 102 | 103 | CLASS_SPECIALIZATIONS(map_); 104 | 105 | template 106 | inline auto peek(Action&& action) { 107 | return make_operator("stream::op::peek", [=](auto&& stream) mutable { 108 | using T = StreamType; 109 | return Stream(std::move( 110 | make_stream_provider( 111 | std::move(stream.getSource()), std::forward(action)))); 112 | }); 113 | } 114 | 115 | CLASS_SPECIALIZATIONS(peek); 116 | 117 | template 118 | inline auto flat_map(Transform&& transform) { 119 | return make_operator("stream::op::flat_map", [=](auto&& stream) mutable { 120 | using T = StreamType; 121 | using Result = std::result_of_t; 122 | using S = StreamType; 123 | static_assert(!std::is_void::value, 124 | "Flat map must be passed a function which returns a stream."); 125 | 126 | return Stream(std::move( 127 | make_stream_provider( 128 | std::move(stream.getSource()), std::forward(transform)))); 129 | }); 130 | } 131 | 132 | CLASS_SPECIALIZATIONS(flat_map); 133 | 134 | template> 135 | inline auto adjacent_distinct(Equal&& equal = Equal()) { 136 | return make_operator("stream::op::adjacent_distinct", [=](auto&& stream) mutable { 137 | using T = StreamType; 138 | return Stream(std::move( 139 | make_stream_provider( 140 | std::move(stream.getSource()), std::forward(equal)))); 141 | }); 142 | } 143 | 144 | template> 145 | inline auto adjacent_difference(Subtractor&& subtract = Subtractor()) { 146 | return make_operator("stream::op::adjacent_difference", [=](auto&& stream) mutable { 147 | using T = StreamType; 148 | using Result = std::result_of_t; 149 | return Stream(std::move(StreamProviderPtr( 150 | new provider::AdjacentDifference( 151 | std::move(stream.getSource()), std::forward(subtract))))); 152 | }); 153 | } 154 | 155 | template> 156 | inline auto partial_sum(Adder&& add = Adder()) { 157 | return make_operator("stream::op::partial_sum", [=](auto&& stream) mutable { 158 | using T = StreamType; 159 | return Stream(std::move( 160 | make_stream_provider( 161 | std::move(stream.getSource()), std::forward(add)))); 162 | }); 163 | } 164 | 165 | template 166 | inline auto concat(Stream&& tail) { 167 | return make_operator("stream::op::concat", [tail = std::move(tail)] (auto&& head) mutable { 168 | if(!tail.occupied()) 169 | throw VacantStreamException("stream::op::concat"); 170 | using T = StreamType; 171 | static_assert(std::is_same::value, 172 | "Cannot concatenate streams with different types."); 173 | 174 | auto concat_ptr = dynamic_cast*>(head.getSource().get()); 175 | if(concat_ptr) { 176 | concat_ptr->concat(std::move(tail.getSource())); 177 | return std::move(head); 178 | } 179 | return Stream(std::move( 180 | make_stream_provider( 181 | std::move(head.getSource()), std::move(tail.getSource())))); 182 | }); 183 | } 184 | 185 | template 186 | inline auto concat(Iterator begin, Iterator end) { 187 | return make_operator("stream::op::concat", [=](auto&& stream) { 188 | using I = IteratorType; 189 | using T = StreamType; 190 | static_assert(std::is_same::value, 191 | "Cannot concatenate streams with different types."); 192 | 193 | return stream | op::concat(Stream(begin, end)); 194 | }); 195 | } 196 | 197 | template 198 | inline auto group() { 199 | return make_operator("stream::op::group", [=](auto&& stream) { 200 | using T = StreamType; 201 | using G = provider::detail::GroupResult; 202 | return Stream(std::move(StreamProviderPtr( 203 | new provider::Group(std::move(stream.getSource()))))); 204 | }); 205 | } 206 | 207 | inline auto pairwise() { 208 | return group<2>().rename("stream::op::pairwise"); 209 | } 210 | 211 | inline auto group(size_t N) { 212 | return make_operator("stream::op::group", [=](auto&& stream) { 213 | using T = StreamType; 214 | using G = std::vector; 215 | return Stream(std::move(StreamProviderPtr( 216 | new provider::DynamicGroup(std::move(stream.getSource()), N)))); 217 | }); 218 | } 219 | 220 | template 221 | inline auto overlap() { 222 | return make_operator("stream::op::overlap", [=](auto&& stream) { 223 | using T = StreamType; 224 | using O = NTuple; 225 | return Stream(std::move(StreamProviderPtr( 226 | new provider::Overlap(std::move(stream.getSource()))))); 227 | }); 228 | } 229 | 230 | inline auto overlap(size_t N) { 231 | return make_operator("stream::op::overlap", [=](auto&& stream) { 232 | using T = StreamType; 233 | using O = std::deque; 234 | return Stream(std::move(StreamProviderPtr( 235 | new provider::DynamicOverlap(std::move(stream.getSource()), N)))); 236 | }); 237 | } 238 | 239 | template 240 | inline auto zip_with(Stream&& right, Function&& zipper = Function()) { 241 | return make_operator("stream::op::zip_with", [right = std::move(right), zipper] 242 | (auto&& left) mutable { 243 | if(!right.occupied()) 244 | throw VacantStreamException("stream::op::zip_with"); 245 | 246 | using L = StreamType; 247 | using Result = std::result_of_t; 248 | static_assert(!std::is_void::value, 249 | "Return type of the zipping function cannot be void."); 250 | 251 | return Stream(std::move(StreamProviderPtr( 252 | new provider::Zip( 253 | std::move(left.getSource()), std::move(right.getSource()), 254 | std::forward(zipper))))); 255 | }); 256 | } 257 | 258 | namespace detail { 259 | 260 | template class Provider, typename T, typename Less> 261 | inline auto make_set_operator(const std::string& name, Stream&& right, Less&& less) { 262 | return make_operator(name, [name, right = std::move(right), less] (auto&& left) mutable { 263 | if(!right.occupied()) 264 | throw VacantStreamException(name); 265 | using S = StreamType; 266 | static_assert(std::is_same::value, 267 | "Cannot compute combination of streams of different types."); 268 | 269 | return Stream(std::move( 270 | make_stream_provider( 271 | std::move(left.getSource()), std::move(right.getSource()), 272 | std::forward(less)))); 273 | }); 274 | } 275 | 276 | } /* namespace detail */ 277 | 278 | template> 279 | inline auto merge_with(Stream&& right, Less&& less = Less()) { 280 | return detail::make_set_operator( 281 | "stream::op::merge_with", std::move(right), std::forward(less)); 282 | } 283 | 284 | template> 285 | inline auto union_with(Stream&& right, Less&& less = Less()) { 286 | return detail::make_set_operator( 287 | "stream::op::union_with", std::move(right), std::forward(less)); 288 | } 289 | 290 | template> 291 | inline auto intersect_with(Stream&& right, Less&& less = Less()) { 292 | return detail::make_set_operator( 293 | "stream::op::intersect_with", std::move(right), std::forward(less)); 294 | } 295 | 296 | template> 297 | inline auto difference_with(Stream&& right, Less&& less = Less()) { 298 | return detail::make_set_operator( 299 | "stream::op::difference_with", std::move(right), std::forward(less)); 300 | } 301 | 302 | template> 303 | inline auto symmetric_difference_with(Stream&& right, Less&& less = Less()) { 304 | return detail::make_set_operator( 305 | "stream::op::symmetric_difference_with", std::move(right), std::forward(less)); 306 | } 307 | 308 | inline auto state_point() { 309 | return make_operator("stream::op::state_point", [=](auto&& stream) { 310 | using T = StreamType; 311 | return Stream(std::move(make_stream_provider( 312 | std::move(stream.getSource())))); 313 | }); 314 | } 315 | 316 | template> 317 | inline auto sort(Less&& less = Less()) { 318 | return make_operator("stream::op::sort", [=](auto&& stream) mutable { 319 | using T = StreamType; 320 | return Stream(std::move( 321 | make_stream_provider( 322 | std::move(stream.getSource()), std::forward(less)))); 323 | }); 324 | } 325 | 326 | template> 327 | inline auto distinct(Less&& less = Less()) { 328 | return make_operator("stream::op::distinct", [=](auto&& stream) mutable { 329 | using T = StreamType; 330 | return Stream(std::move( 331 | make_stream_provider( 332 | std::move(stream.getSource()), std::forward(less)))); 333 | }); 334 | } 335 | 336 | #undef CLASS_SPECIALIZATIONS 337 | 338 | } /* namespace op */ 339 | } /* namespace stream */ 340 | 341 | #endif 342 | -------------------------------------------------------------------------------- /source/StreamTerminators.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_STREAM_TERMINATORS_H 2 | #define SCHEINERMAN_STREAM_STREAM_TERMINATORS_H 3 | 4 | namespace stream { 5 | namespace op { 6 | 7 | #define CLASS_SPECIALIZATIONS(operation) \ 8 | template auto operation (R (C::*member)()) \ 9 | { return operation (std::mem_fn(member)); } \ 10 | template auto operation (R (C::*member)() const) \ 11 | { return operation (std::mem_fn(member)); } 12 | 13 | template 14 | inline auto for_each(Function&& function) { 15 | return make_terminator("stream::op::for_each", [=](auto&& stream) mutable { 16 | auto& source = stream.getSource(); 17 | while(source->advance()) { 18 | function(std::move(*source->get())); 19 | } 20 | return function; 21 | }); 22 | } 23 | 24 | CLASS_SPECIALIZATIONS(for_each); 25 | 26 | inline auto count() { 27 | return make_terminator("stream::op::count", [=](auto&& stream) { 28 | auto& source = stream.getSource(); 29 | size_t count = 0; 30 | while(source->advance()) { 31 | std::move(*source->get()); 32 | count++; 33 | } 34 | return count; 35 | }); 36 | } 37 | 38 | template 39 | inline auto identity_reduce(const U& identity, Accumulator&& accumulator) { 40 | return make_terminator("stream::op::identity_reduce", [=](auto&& stream) mutable { 41 | auto& source = stream.getSource(); 42 | U result = identity; 43 | while(source->advance()) { 44 | result = accumulator(std::move(result), std::move(*source->get())); 45 | } 46 | return result; 47 | }); 48 | } 49 | 50 | template 51 | inline auto reduce(Accumulator&& accumulator) { 52 | return make_terminator("stream::op::reduce", [=](auto&& stream) mutable { 53 | auto& source = stream.getSource(); 54 | if(source->advance()) { 55 | auto reduction = identity_reduce(std::move(*source->get()), 56 | std::forward(accumulator)); 57 | return stream | reduction; 58 | } else { 59 | throw EmptyStreamException("stream::op::reduce"); 60 | } 61 | }); 62 | } 63 | 64 | template 65 | inline auto reduce(IdentityFn&& identityFn, Accumulator&& accumulator) { 66 | return make_terminator("stream::op::reduce", [=](auto&& stream) mutable { 67 | auto& source = stream.getSource(); 68 | if(source->advance()) { 69 | auto reduction = identity_reduce(identityFn(std::move(*source->get())), 70 | std::forward(accumulator)); 71 | return stream | reduction; 72 | } else { 73 | throw EmptyStreamException("stream::op::reduce"); 74 | } 75 | }); 76 | } 77 | 78 | inline auto first() { 79 | return make_terminator("stream::op::first", [=](auto&& stream) { 80 | auto& source = stream.getSource(); 81 | if(source->advance()) { 82 | return std::move(*source->get()); 83 | } else { 84 | throw EmptyStreamException("stream::op::first"); 85 | } 86 | }); 87 | } 88 | 89 | inline auto last() { 90 | return reduce([](auto&& first, auto&& second) { return second; }) 91 | .rename("stream::op::last"); 92 | } 93 | 94 | inline auto nth(size_t index) { 95 | return (skip(index) | first()).rename("stream::op::nth"); 96 | } 97 | 98 | inline auto sum() { 99 | return reduce(std::plus()) 100 | .rename("stream::op::sum"); 101 | } 102 | 103 | template 104 | inline auto sum(const T& identity) { 105 | return identity_reduce(identity, std::plus()) 106 | .rename("stream::op::sum"); 107 | } 108 | 109 | inline auto product() { 110 | return reduce(std::multiplies()) 111 | .rename("stream::op::product"); 112 | } 113 | 114 | template 115 | inline auto product(const T& identity) { 116 | return identity_reduce(identity, std::multiplies()) 117 | .rename("stream::op::product"); 118 | } 119 | 120 | template> 121 | inline auto max(Less&& less = Less()) { 122 | return reduce([=](const auto& a, const auto& b) { 123 | return less(a, b) ? b : a; 124 | }).rename("stream::op::max"); 125 | } 126 | 127 | template> 128 | inline auto max_by(Function&& function, Less&& less = Less()) { 129 | /* Pair is (max, max_elem) */ 130 | auto to_pair = [function](auto&& x) { return std::make_pair(function(x), x); }; 131 | auto next = [function, less](auto&& accumulated, auto&& value) { 132 | auto fvalue = function(std::move(value)); 133 | if(less(accumulated.first, fvalue)) { 134 | return std::make_pair(std::move(fvalue), std::move(value)); 135 | } 136 | return accumulated; 137 | }; 138 | 139 | return reduce(to_pair, next) 140 | .then([](auto&& accumulated) { return accumulated.second; }) 141 | .rename("stream::op::max_by"); 142 | } 143 | 144 | template> 145 | inline auto min(Less&& less = Less()) { 146 | return reduce([=](const auto& a, const auto& b) { 147 | return less(a, b) ? a : b; 148 | }).rename("stream::op::min"); 149 | } 150 | 151 | template> 152 | inline auto min_by(Function&& function, Less&& less = Less()) { 153 | /* Pair is (min, min_elem) */ 154 | auto to_pair = [function](auto&& x) { return std::make_pair(function(x), x); }; 155 | auto next = [function, less](auto&& accumulated, auto&& value) { 156 | auto fvalue = function(std::move(value)); 157 | if(less(fvalue, accumulated.first)) { 158 | return std::make_pair(std::move(fvalue), std::move(value)); 159 | } 160 | return accumulated; 161 | }; 162 | 163 | return reduce(to_pair, next) 164 | .then([](auto&& accumulated) { return accumulated.second; }) 165 | .rename("stream::op::min_by"); 166 | } 167 | 168 | template> 169 | inline auto minmax(Less&& less = Less()) { 170 | auto to_pair = [](auto&& x) { return std::make_pair(x, x); }; 171 | auto next_minmax = [less](auto&& accumulated, auto&& value) { 172 | using T = std::remove_reference_t; 173 | if(less(value, accumulated.first)) { 174 | return std::pair(std::move(value), std::move(accumulated.second)); 175 | } 176 | if(less(accumulated.second, value)) { 177 | return std::pair(std::move(accumulated.first), std::move(value)); 178 | } 179 | return accumulated; 180 | }; 181 | 182 | return reduce(to_pair, next_minmax).rename("stream::op::minmax"); 183 | } 184 | 185 | template> 186 | inline auto minmax_by(Function&& function, Less&& less = Less()) { 187 | /* Pair is ((min, min_elem), (max, max_elem)) */ 188 | auto to_pair = [function](auto&& x) { 189 | auto fx = function(x); 190 | return std::make_pair(std::make_pair(fx, x), std::make_pair(fx, x)); 191 | }; 192 | auto next = [function, less](auto&& accumulated, auto&& value) { 193 | auto fvalue = function(std::move(value)); 194 | auto min = accumulated.first; 195 | if(less(fvalue, min.first)) { 196 | min = std::make_pair(std::move(fvalue), std::move(value)); 197 | } 198 | auto max = accumulated.second; 199 | if(less(max.first, fvalue)) { 200 | max = std::make_pair(std::move(fvalue), std::move(value)); 201 | } 202 | return std::make_pair(min, max); 203 | }; 204 | 205 | return reduce(to_pair, next) 206 | .then([](auto&& accumulated) { return std::make_pair(accumulated.first.second, accumulated.second.second); }) 207 | .rename("stream::op::minmax_by"); 208 | } 209 | 210 | template 211 | inline auto any(Predicate&& predicate) { 212 | return make_terminator("stream::op::any", [=](auto&& stream) mutable { 213 | auto& source = stream.getSource(); 214 | while(source->advance()) { 215 | if(predicate(*source->get())) { 216 | return true; 217 | } 218 | } 219 | return false; 220 | }); 221 | } 222 | 223 | inline auto any() { 224 | return any([](bool b){ return b; }); 225 | } 226 | 227 | CLASS_SPECIALIZATIONS(any); 228 | 229 | template 230 | inline auto all(Predicate&& predicate) { 231 | return make_terminator("stream::op::all", [=](auto&& stream) mutable { 232 | auto& source = stream.getSource(); 233 | while(source->advance()) { 234 | if(!predicate(*source->get())) { 235 | return false; 236 | } 237 | } 238 | return true; 239 | }); 240 | } 241 | 242 | inline auto all() { 243 | return all([](bool b){ return b; }); 244 | } 245 | 246 | CLASS_SPECIALIZATIONS(all); 247 | 248 | template 249 | inline auto none(Predicate&& predicate) { 250 | return any(std::forward(predicate)) 251 | .then([](bool x) { return !x; }) 252 | .rename("stream::op::none"); 253 | } 254 | 255 | inline auto none() { 256 | return none([](bool b){ return b; }); 257 | } 258 | 259 | CLASS_SPECIALIZATIONS(none); 260 | 261 | template 262 | inline auto not_all(Predicate&& predicate) { 263 | return all(std::forward(predicate)) 264 | .then([](bool x) { return !x; }) 265 | .rename("stream::op::not_all"); 266 | } 267 | 268 | inline auto not_all() { 269 | return not_all([](bool b){ return b; }); 270 | } 271 | 272 | CLASS_SPECIALIZATIONS(not_all); 273 | 274 | template 275 | inline auto copy_to(OutputIterator out) { 276 | return make_terminator("stream::op::copy_to", [=](auto&& stream) mutable { 277 | using T = StreamType; 278 | auto& source = stream.getSource(); 279 | while(source->advance()) { 280 | *out = *source->get(); 281 | ++out; 282 | } 283 | return out; 284 | }); 285 | } 286 | 287 | template 288 | inline auto move_to(OutputIterator out) { 289 | return make_terminator("stream::op::move_to", [=](auto&& stream) mutable { 290 | using T = StreamType; 291 | auto& source = stream.getSource(); 292 | while(source->advance()) { 293 | *out = std::move(*source->get()); 294 | ++out; 295 | } 296 | return out; 297 | }); 298 | } 299 | 300 | inline auto print_to(std::ostream& os, const char* delimiter = " ") { 301 | return make_terminator("stream::op::print_to", [&os, delimiter](auto&& stream) -> std::ostream& { 302 | using T = StreamType; 303 | stream | copy_to(std::ostream_iterator(os, delimiter)); 304 | return os; 305 | }); 306 | } 307 | 308 | inline auto random_sample(size_t size) { 309 | return make_terminator("stream::op::random_sample", [=](auto&& stream) { 310 | using T = StreamType; 311 | auto& source = stream.getSource(); 312 | 313 | std::vector results; 314 | for(int i = 0; i < size; i++) { 315 | if(source->advance()) { 316 | results.push_back(std::move(*source->get())); 317 | } else { 318 | return results; 319 | } 320 | } 321 | 322 | auto seed = std::chrono::system_clock::now().time_since_epoch().count(); 323 | std::default_random_engine generator(seed); 324 | auto random_index = [&generator](int upper) { 325 | return std::uniform_int_distribution(0, upper - 1)(generator); 326 | }; 327 | 328 | size_t seen = size; 329 | while(source->advance()) { 330 | seen++; 331 | int index = random_index(seen); 332 | if(index < size) { 333 | results[index] = std::move(*source->get()); 334 | } else { 335 | source->get(); 336 | } 337 | } 338 | 339 | return results; 340 | }); 341 | } 342 | 343 | inline auto random_element() { 344 | return random_sample(1) 345 | .then([](auto&& vec) { 346 | if(vec.empty()) { 347 | throw EmptyStreamException("stream::op::random_element"); 348 | } 349 | return vec[0]; 350 | }) 351 | .rename("stream::op::element"); 352 | } 353 | 354 | #undef CLASS_SPECIALIZATIONS 355 | 356 | } /* namespace op */ 357 | } /* namespace stream */ 358 | 359 | 360 | #endif 361 | -------------------------------------------------------------------------------- /source/Utility.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_UTILITY_H 2 | #define SCHEINERMAN_STREAM_UTILITY_H 3 | 4 | #include "StreamForward.h" 5 | #include "UtilityImpl.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace stream { 12 | 13 | template 14 | struct InvertedPredicate { 15 | InvertedPredicate(Function&& fn) : function(fn) {} 16 | 17 | template 18 | bool operator() (Args&&... args) { 19 | return !function(std::forward(args)...); 20 | } 21 | 22 | Function function; 23 | }; 24 | 25 | template 26 | struct HeadImpl { 27 | using type = Head; 28 | }; 29 | 30 | template 31 | using Head = typename HeadImpl::type; 32 | 33 | template 34 | using make_1based_sequence = typename detail::SeqTail>::type; 35 | 36 | template 37 | InvertedPredicate not_(Function&& fn) { 38 | return {std::forward(fn)}; 39 | } 40 | 41 | template 42 | using NTuple = typename detail::NTupleImpl::Type; 43 | 44 | template 45 | using RemoveRef = std::remove_const_t>; 46 | 47 | template 48 | using IteratorType = typename std::iterator_traits::value_type; 49 | 50 | template 51 | using ContainerType = IteratorType 52 | ()))>; 53 | 54 | template 55 | class ComparePtrWrapper { 56 | public: 57 | ComparePtrWrapper(Compare&& comparator) : comparator_(comparator) {} 58 | 59 | bool operator() (const std::shared_ptr& left, 60 | const std::shared_ptr& right) { 61 | return comparator_(*left, *right); 62 | } 63 | 64 | private: 65 | Compare comparator_; 66 | }; 67 | 68 | template 69 | class ComparePtrWrapper { 70 | public: 71 | ComparePtrWrapper(Compare&& comparator) : comparator_(comparator) {} 72 | 73 | bool operator() (const std::shared_ptr& left, 74 | const std::shared_ptr& right) { 75 | return comparator_(*right, *left); 76 | } 77 | 78 | private: 79 | Compare comparator_; 80 | }; 81 | 82 | template 83 | std::ostream& operator<< (std::ostream& os, const std::tuple& tuple) { 84 | 85 | PrintTuple<0, std::tuple_size>::value - 1, Args...> 86 | ::print(os, tuple); 87 | return os; 88 | 89 | } 90 | 91 | template 92 | inline auto apply_tuple(Function&& function, const std::tuple& tuple) 93 | -> decltype(function(std::declval()...)); 94 | 95 | template 96 | inline auto apply_tuple(Function&& function, const std::pair& pair) 97 | -> decltype(function(pair.first, pair.second)); 98 | 99 | template 100 | SplattedFunction splat(Function&& function) { 101 | return SplattedFunction(std::forward(function)); 102 | } 103 | 104 | template 105 | SplattableTuple operator+(const std::tuple& tup) { 106 | return SplattableTuple(tup); 107 | } 108 | 109 | template 110 | SplattableFunction splattable(Function&& function) { 111 | return SplattableFunction(std::forward(function)); 112 | } 113 | 114 | } /* namespace stream */ 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /source/UtilityImpl.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_UTILITY_IMPL_H 2 | #define SCHEINERMAN_STREAM_UTILITY_IMPL_H 3 | 4 | #include 5 | #include 6 | 7 | namespace stream { 8 | 9 | namespace detail { 10 | 11 | template 12 | struct SeqTail {}; 13 | 14 | template 15 | struct SeqTail> { 16 | using type = std::integer_sequence; 17 | }; 18 | 19 | } /* namespace detail */ 20 | 21 | // ===================== N-Tuple ==================== 22 | 23 | namespace detail { 24 | 25 | template 26 | struct Append { 27 | }; 28 | 29 | template class Base, typename... Args, typename Head> 30 | struct Append> { 31 | using Type = Base; 32 | }; 33 | 34 | template 35 | struct NTupleImpl { 36 | using SubType = typename NTupleImpl::Type; 37 | using Type = typename Append::Type; 38 | }; 39 | 40 | template 41 | struct NTupleImpl { 42 | using Type = std::tuple; 43 | }; 44 | 45 | } /* namespace detail*/ 46 | 47 | // ================= Tuple Printing ================= 48 | 49 | template 50 | struct PrintTuple { 51 | static void print(std::ostream& os, const std::tuple& tuple) { 52 | os << std::get(tuple) << ", "; 53 | PrintTuple::print(os, tuple); 54 | } 55 | }; 56 | 57 | template 58 | struct PrintTuple<0, last, Args...> { 59 | static void print(std::ostream& os, const std::tuple& tuple) { 60 | os << "(" << std::get<0>(tuple) << ", "; 61 | PrintTuple<1, last, Args...>::print(os, tuple); 62 | } 63 | }; 64 | 65 | template 66 | struct PrintTuple { 67 | static void print(std::ostream& os, const std::tuple& tuple) { 68 | os << std::get(tuple) << ")"; 69 | } 70 | }; 71 | 72 | // ================= Tuple Splatting ================= 73 | 74 | template 75 | struct TupleWrapper { 76 | using Type = std::tuple; 77 | enum { Length = sizeof...(Types) }; 78 | }; 79 | 80 | template 82 | struct SplatTuple { 83 | static_assert(index >= 0, 84 | "Splat tuple index cannot be less than 0."); 85 | static_assert(index < Tuple::Length, 86 | "Splat tuple index can not be greater than the tuple elements."); 87 | 88 | using TupleType = typename Tuple::Type; 89 | 90 | static Return splat(Function&& function, const TupleType& tuple, 91 | Args&&... args) { 92 | return SplatTuple(tuple))> 94 | ::splat(std::forward(function), tuple, 95 | std::forward(args)..., std::get(tuple)); 96 | } 97 | }; 98 | 99 | template 101 | struct SplatTuple { 102 | using TupleType = typename Tuple::Type; 103 | 104 | static Return splat(Function&& function, const TupleType& tuple) { 105 | return SplatTuple(tuple))> 107 | ::splat(std::forward(function), tuple, std::get<0>(tuple)); 108 | } 109 | }; 110 | 111 | template 113 | struct SplatTuple { 114 | using TupleType = typename Tuple::Type; 115 | 116 | static Return splat(Function&& function, const TupleType& tuple, 117 | Args&&... args) { 118 | return function(std::forward(args)...); 119 | } 120 | }; 121 | 122 | template 123 | inline auto apply_tuple(Function&& function, const std::tuple& tuple) 124 | -> decltype(function(std::declval()...)) { 125 | 126 | using Return = decltype(function(std::declval()...)); 127 | return SplatTuple> 129 | ::splat(std::forward(function), tuple); 130 | 131 | } 132 | 133 | template 134 | inline auto apply_tuple(Function&& function, const std::pair& pair) { 135 | return function(pair.first, pair.second); 136 | } 137 | 138 | template 139 | struct SplattedFunction { 140 | 141 | public: 142 | SplattedFunction(Function&& function) : function_(function) {} 143 | 144 | template 145 | auto operator() (const std::tuple& tuple) 146 | -> decltype(std::declval()(std::declval()...)) { 147 | 148 | return apply_tuple(function_, tuple); 149 | } 150 | 151 | template 152 | auto operator() (const std::pair& pair) 153 | -> decltype(std::declval()(pair.first, pair.second)) { 154 | 155 | return apply_tuple(function_, pair); 156 | } 157 | 158 | private: 159 | Function function_; 160 | 161 | }; 162 | 163 | // More generic splatting 164 | 165 | template 166 | struct SplattableTuple { 167 | SplattableTuple(const std::tuple& value_) : value(value_) {} 168 | 169 | const std::tuple& value; 170 | }; 171 | 172 | template 173 | struct ArgsToTuple { 174 | static auto tuplize(First&& first_arg, Args&&... args) { 175 | return std::tuple_cat(std::make_tuple(std::forward(first_arg)), 176 | ArgsToTuple 177 | ::tuplize(std::forward(args)...)); 178 | } 179 | }; 180 | 181 | template 182 | struct ArgsToTuple { 183 | static auto tuplize(Last&& last_arg) { 184 | return std::make_tuple(std::forward(last_arg)); 185 | } 186 | }; 187 | 188 | template 189 | struct ArgsToTuple, Args...> { 190 | using InTuple = SplattableTuple; 191 | static auto tuplize(InTuple&& first, Args&&... args) { 192 | return std::tuple_cat(first.value, 193 | ArgsToTuple 194 | ::tuplize(std::forward(args)...)); 195 | } 196 | }; 197 | 198 | template 199 | struct ArgsToTuple> { 200 | static std::tuple tuplize(SplattableTuple&& first) { 201 | return first.value; 202 | } 203 | }; 204 | 205 | template 206 | inline auto args2tuple(Args&&... args) { 207 | return ArgsToTuple<0, sizeof...(Args)-1, Args...> 208 | ::tuplize(std::forward(args)...); 209 | } 210 | 211 | template 212 | struct SplattableFunction { 213 | 214 | public: 215 | SplattableFunction(Function&& function) : function_(function) {} 216 | 217 | template 218 | auto operator() (Args&&... args) { 219 | return apply_tuple(function_, 220 | ArgsToTuple<0, sizeof...(Args)-1, Args...> 221 | ::tuplize(std::forward(args)...)); 222 | } 223 | 224 | private: 225 | Function function_; 226 | 227 | }; 228 | 229 | } /* namespace stream */ 230 | 231 | #endif 232 | -------------------------------------------------------------------------------- /source/providers/AdjacentDifference.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_ADJACENT_DIFFERENCE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_ADJACENT_DIFFERENCE_H 3 | 4 | #include "StreamProvider.h" 5 | #include "../Utility.h" 6 | 7 | #include 8 | 9 | namespace stream { 10 | namespace provider { 11 | 12 | template 13 | class AdjacentDifference : public StreamProvider> { 14 | 15 | public: 16 | using DiffType = std::result_of_t; 17 | 18 | AdjacentDifference(StreamProviderPtr source, Subtractor&& subtract) 19 | : source_(std::move(source)), subtract_(subtract) {} 20 | 21 | std::shared_ptr get() override { 22 | return result_; 23 | } 24 | 25 | bool advance_impl() override { 26 | if(first_advance_) { 27 | first_advance_ = false; 28 | if(source_->advance()) { 29 | first_ = source_->get(); 30 | } else { 31 | return false; 32 | } 33 | if(source_->advance()) { 34 | second_ = source_->get(); 35 | } else { 36 | first_.reset(); 37 | return false; 38 | } 39 | result_ = std::make_shared(subtract_(*second_, *first_)); 40 | return true; 41 | } 42 | 43 | first_ = std::move(second_); 44 | if(source_->advance()) { 45 | second_ = source_->get(); 46 | result_ = std::make_shared(subtract_(*second_, *first_)); 47 | return true; 48 | } 49 | first_.reset(); 50 | result_.reset(); 51 | return false; 52 | } 53 | 54 | PrintInfo print(std::ostream& os, int indent) const override { 55 | this->print_indent(os, indent); 56 | os << "AdjacentDifference:\n"; 57 | return source_->print(os, indent + 1).addStage(); 58 | } 59 | 60 | private: 61 | StreamProviderPtr source_; 62 | Subtractor subtract_; 63 | std::shared_ptr first_; 64 | std::shared_ptr second_; 65 | std::shared_ptr result_; 66 | bool first_advance_ = true; 67 | }; 68 | 69 | } /* namespace provider */ 70 | } /* namespace stream */ 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /source/providers/AdjacentDistinct.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_ADJACENT_DISTINCT_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_ADJACENT_DISTINCT_H 3 | 4 | #include "StreamProvider.h" 5 | #include "../Utility.h" 6 | 7 | namespace stream { 8 | namespace provider { 9 | 10 | template 11 | class AdjacentDistinct : public StreamProvider { 12 | 13 | public: 14 | AdjacentDistinct(StreamProviderPtr source, Equal&& equal) 15 | : source_(std::move(source)), equal_(std::forward(equal_)) {} 16 | 17 | std::shared_ptr get() override { 18 | return current_; 19 | } 20 | 21 | bool advance_impl() override { 22 | if(first_) { 23 | first_ = false; 24 | if(source_->advance()) { 25 | current_ = source_->get(); 26 | return true; 27 | } 28 | return false; 29 | } 30 | 31 | while(source_->advance()) { 32 | auto next = source_->get(); 33 | if(!equal_(*current_, *next)) { 34 | current_ = next; 35 | return true; 36 | } 37 | } 38 | 39 | current_.reset(); 40 | return false; 41 | } 42 | 43 | PrintInfo print(std::ostream& os, int indent) const override { 44 | this->print_indent(os, indent); 45 | os << "AdjacentDistinct:\n"; 46 | return source_->print(os, indent + 1).addStage(); 47 | } 48 | 49 | private: 50 | StreamProviderPtr source_; 51 | Equal equal_; 52 | std::shared_ptr current_; 53 | bool first_ = true; 54 | }; 55 | 56 | } /* namespace provider */ 57 | } /* namespace stream */ 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /source/providers/Concatenate.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_CONCATENATE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_CONCATENATE_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include 7 | 8 | namespace stream { 9 | namespace provider { 10 | 11 | template 12 | class Concatenate : public StreamProvider { 13 | 14 | public: 15 | template 16 | Concatenate(Iterator begin, Iterator end) : sources_(begin, end) {} 17 | 18 | Concatenate(StreamProviderPtr first, StreamProviderPtr second) { 19 | sources_.push_back(std::move(first)); 20 | sources_.push_back(std::move(second)); 21 | } 22 | 23 | std::shared_ptr get() override { 24 | return current_; 25 | } 26 | 27 | bool advance_impl() override { 28 | while(!sources_.empty()) { 29 | auto& provider = sources_.front(); 30 | if(provider->advance()) { 31 | current_ = provider->get(); 32 | return true; 33 | } 34 | sources_.pop_front(); 35 | } 36 | current_.reset(); 37 | return false; 38 | } 39 | 40 | void concat(StreamProviderPtr&& source) { 41 | sources_.push_back(std::move(source)); 42 | } 43 | 44 | PrintInfo print(std::ostream& os, int indent) const override { 45 | this->print_indent(os, indent); 46 | os << "Concatenation[" << sources_.size() << "]:\n"; 47 | PrintInfo result{0, 1}; 48 | for(auto& source : sources_) { 49 | result = result + source->print(os, indent + 1); 50 | } 51 | return result; 52 | } 53 | 54 | private: 55 | std::list> sources_; 56 | std::shared_ptr current_; 57 | 58 | }; 59 | 60 | } /* namespace provider */ 61 | } /* namespace stream */ 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /source/providers/CycledContainer.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_CYCLED_CONTAINER_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_CYCLED_CONTAINER_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class CycledContainer : public StreamProvider { 11 | 12 | public: 13 | CycledContainer(Container&& container, size_t times) 14 | : container_{container}, 15 | current_{std::begin(container_)}, 16 | end_{std::end(container_)}, 17 | times_{times} {} 18 | 19 | std::shared_ptr get() override { 20 | return std::make_shared(std::move(*current_)); 21 | } 22 | 23 | bool advance_impl() override { 24 | if(first_) { 25 | first_ = false; 26 | return current_ != end_; 27 | } 28 | ++current_; 29 | if(current_ == end_) { 30 | iteration_++; 31 | if(iteration_ > times_ && times_ != 0) 32 | return false; 33 | current_ = std::begin(container_); 34 | } 35 | return true; 36 | } 37 | 38 | PrintInfo print(std::ostream& os, int indent) const override { 39 | this->print_indent(os, indent); 40 | os << "[cycled container stream]\n"; 41 | return PrintInfo::Source(); 42 | } 43 | 44 | private: 45 | using Iterator = decltype(std::begin(std::declval())); 46 | 47 | bool first_ = true; 48 | Container container_; 49 | Iterator current_; 50 | Iterator end_; 51 | size_t times_; 52 | size_t iteration_ = 1; 53 | }; 54 | 55 | } /* namespace provider */ 56 | } /* namespace stream */ 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /source/providers/Difference.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_DIFFERENCE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_DIFFERENCE_H 3 | 4 | #include "SetOperation.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class Difference : public SetOperation { 11 | 12 | using Parent = SetOperation; 13 | using UpdateState = typename Parent::UpdateState; 14 | using ToAdvance = typename Parent::ToAdvance; 15 | 16 | public: 17 | Difference(StreamProviderPtr&& source1, 18 | StreamProviderPtr&& source2, 19 | Compare&& comparator) 20 | : Parent(std::forward>(source1), 21 | std::forward>(source2), 22 | std::forward(comparator)) {} 23 | 24 | protected: 25 | void on_first_source_advance() override { 26 | source1_advanced_ = true; 27 | } 28 | 29 | void before_update() override { 30 | source1_advanced_ = false; 31 | } 32 | 33 | UpdateState if_neither_depleted() override { 34 | if(this->current1_smaller()) { 35 | this->set_advance(ToAdvance::First); 36 | this->set_result(this->get_current1()); 37 | if(source1_advanced_) 38 | return UpdateState::UpdateFinished; 39 | } else if(this->current2_smaller()) { 40 | this->set_advance(ToAdvance::Second); 41 | } else { 42 | this->set_advance(ToAdvance::Both); 43 | } 44 | return UpdateState::NotFinished; 45 | } 46 | 47 | UpdateState if_first_depleted() override { 48 | return UpdateState::StreamFinished; 49 | } 50 | 51 | std::string get_operation_name() const override { 52 | return "Difference"; 53 | } 54 | 55 | private: 56 | bool source1_advanced_; 57 | 58 | }; 59 | 60 | } /* namespace provider */ 61 | } /* namespace stream */ 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /source/providers/Distinct.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_DISTINCT_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_DISTINCT_H 3 | 4 | #include "StreamProvider.h" 5 | #include "../Utility.h" 6 | 7 | #include 8 | 9 | namespace stream { 10 | namespace provider { 11 | 12 | template 13 | class Distinct : public StreamProvider { 14 | 15 | public: 16 | Distinct(StreamProviderPtr source, RawCompare&& comparator) 17 | : source_(std::move(source)), sorted_(PointerCompare(std::forward(comparator))) {} 18 | 19 | std::shared_ptr get() override { 20 | return current_; 21 | } 22 | 23 | bool advance_impl() override { 24 | if(first_) { 25 | while(source_->advance()) { 26 | sorted_.insert(source_->get()); 27 | } 28 | first_ = false; 29 | } 30 | if(sorted_.empty()) { 31 | current_.reset(); 32 | return false; 33 | } 34 | auto itr = sorted_.begin(); 35 | current_ = *itr; 36 | sorted_.erase(itr); 37 | return true; 38 | } 39 | 40 | PrintInfo print(std::ostream& os, int indent) const override { 41 | this->print_indent(os, indent); 42 | os << "Distinct:\n"; 43 | return source_->print(os, indent + 1).addStage(); 44 | } 45 | 46 | private: 47 | using PointerCompare = ComparePtrWrapper; 48 | using PointerQueue = std::set, PointerCompare>; 49 | 50 | StreamProviderPtr source_; 51 | PointerQueue sorted_; 52 | std::shared_ptr current_; 53 | bool first_ = true; 54 | }; 55 | 56 | } /* namespace provider */ 57 | } /* namespace stream */ 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /source/providers/DropWhile.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_DROP_WHILE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_DROP_WHILE_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class DropWhile : public StreamProvider { 11 | 12 | public: 13 | DropWhile(StreamProviderPtr source, Predicate&& predicate) 14 | : source_(std::move(source)), predicate_(predicate) {} 15 | 16 | std::shared_ptr get() override { 17 | return current_; 18 | } 19 | 20 | bool advance_impl() override { 21 | if(!dropped_) { 22 | dropped_ = true; 23 | while(source_->advance()) { 24 | current_ = source_->get(); 25 | if(!predicate_(*current_)) { 26 | return true; 27 | } 28 | } 29 | current_.reset(); 30 | return false; 31 | } 32 | if(source_->advance()) { 33 | current_ = source_->get(); 34 | return true; 35 | } 36 | current_.reset(); 37 | return false; 38 | } 39 | 40 | PrintInfo print(std::ostream& os, int indent) const override { 41 | this->print_indent(os, indent); 42 | os << "DropWhile:\n"; 43 | return source_->print(os, indent + 1).addStage(); 44 | } 45 | 46 | private: 47 | StreamProviderPtr source_; 48 | Predicate predicate_; 49 | std::shared_ptr current_; 50 | bool dropped_ = false; 51 | }; 52 | 53 | } /* namespace provider */ 54 | } /* namespace stream */ 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /source/providers/DynamicGroup.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_DYNAMIC_GROUP_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_DYNAMIC_GROUP_H 3 | 4 | #include "StreamProvider.h" 5 | #include "../Utility.h" 6 | 7 | #include 8 | 9 | namespace stream { 10 | namespace provider { 11 | 12 | template 13 | class DynamicGroup : public StreamProvider> { 14 | 15 | public: 16 | DynamicGroup(StreamProviderPtr source, size_t N) : source_(std::move(source)), N_(N) {} 17 | 18 | std::shared_ptr> get() override { 19 | return current_; 20 | } 21 | 22 | bool advance_impl() override { 23 | current_ = std::make_shared>(); 24 | current_->reserve(N_); 25 | for(int i = 0; i < N_; i++) { 26 | if(source_->advance()) { 27 | current_->emplace_back(std::move(*source_->get())); 28 | } else { 29 | current_.reset(); 30 | return false; 31 | } 32 | } 33 | return true; 34 | } 35 | 36 | PrintInfo print(std::ostream& os, int indent) const override { 37 | this->print_indent(os, indent); 38 | os << "Grouped[" << N_ << "]:\n"; 39 | return source_->print(os, indent + 1).addStage(); 40 | } 41 | 42 | private: 43 | StreamProviderPtr source_; 44 | std::shared_ptr> current_; 45 | const size_t N_; 46 | 47 | }; 48 | 49 | } /* namespace provider */ 50 | } /* namespace stream */ 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /source/providers/DynamicOverlap.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_DYNAMIC_OVERLAP_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_DYNAMIC_OVERLAP_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include 7 | 8 | namespace stream { 9 | namespace provider { 10 | 11 | template 12 | class DynamicOverlap : public StreamProvider> { 13 | 14 | private: 15 | using Result = std::deque; 16 | 17 | public: 18 | DynamicOverlap(StreamProviderPtr source, size_t N) : source_(std::move(source)), N_(N) {} 19 | 20 | std::shared_ptr get() override { 21 | return current_; 22 | } 23 | 24 | bool advance_impl() override { 25 | if(first_) { 26 | first_ = false; 27 | current_ = std::make_shared(); 28 | for(size_t i = 0; i < N_; i++) { 29 | if(source_->advance()) { 30 | current_->emplace_back(std::move(*source_->get())); 31 | } else { 32 | current_.reset(); 33 | return false; 34 | } 35 | } 36 | return true; 37 | } 38 | 39 | if(source_->advance()) { 40 | current_ = std::make_shared(*current_); 41 | current_->pop_front(); 42 | current_->emplace_back(std::move(*source_->get())); 43 | return true; 44 | } 45 | current_.reset(); 46 | return false; 47 | } 48 | 49 | PrintInfo print(std::ostream& os, int indent) const override { 50 | this->print_indent(os, indent); 51 | os << "Overlapped[" << N_ << "]:\n"; 52 | return source_->print(os, indent + 1).addStage(); 53 | } 54 | 55 | private: 56 | bool first_ = true; 57 | StreamProviderPtr source_; 58 | std::shared_ptr current_; 59 | const size_t N_; 60 | 61 | }; 62 | 63 | } /* namespace provider */ 64 | } /* namespace stream */ 65 | 66 | #endif 67 | 68 | -------------------------------------------------------------------------------- /source/providers/Empty.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_EMPTY_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_EMPTY_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class Empty : public StreamProvider { 11 | 12 | public: 13 | std::shared_ptr get() override { 14 | return nullptr; 15 | } 16 | 17 | bool advance_impl() override { 18 | return false; 19 | } 20 | 21 | PrintInfo print(std::ostream& os, int indent) const override { 22 | this->print_indent(os, indent); 23 | os << "[empty stream]\n"; 24 | return PrintInfo::Source(); 25 | } 26 | 27 | }; 28 | 29 | } /* namespace provider */ 30 | } /* namespace stream */ 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /source/providers/Filter.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_FILTER_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_FILTER_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class Filter : public StreamProvider { 11 | 12 | public: 13 | Filter(StreamProviderPtr source, Predicate&& predicate) 14 | : source_(std::move(source)), predicate_(predicate) {} 15 | 16 | std::shared_ptr get() override { 17 | return current_; 18 | } 19 | 20 | bool advance_impl() override { 21 | while(source_->advance()) { 22 | current_ = source_->get(); 23 | if(predicate_(*current_)) { 24 | return true; 25 | } 26 | } 27 | current_.reset(); 28 | return false; 29 | } 30 | 31 | PrintInfo print(std::ostream& os, int indent) const override { 32 | this->print_indent(os, indent); 33 | os << "Filter:\n"; 34 | return source_->print(os, indent + 1).addStage(); 35 | } 36 | 37 | private: 38 | StreamProviderPtr source_; 39 | Predicate predicate_; 40 | std::shared_ptr current_; 41 | }; 42 | 43 | } /* namespace provider */ 44 | } /* namespace stream */ 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /source/providers/FlatMap.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_FLAT_MAP_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_FLAT_MAP_H 3 | 4 | #include "StreamProvider.h" 5 | #include "../Stream.h" 6 | #include "../Utility.h" 7 | 8 | namespace stream { 9 | namespace provider { 10 | 11 | template 12 | class FlatMap : public StreamProvider { 13 | 14 | public: 15 | FlatMap(StreamProviderPtr source, Transform&& transform) 16 | : source_(std::move(source)), transform_(transform) {} 17 | 18 | std::shared_ptr get() override { 19 | return current_; 20 | } 21 | 22 | bool advance_impl() override { 23 | if(!first_ && current_stream_.getSource()->advance()) { 24 | current_ = current_stream_.getSource()->get(); 25 | return true; 26 | } 27 | 28 | if(first_) 29 | first_ = false; 30 | 31 | while(source_->advance()) { 32 | current_stream_ = std::move(transform_(std::move(*source_->get()))); 33 | if(current_stream_.getSource()->advance()) { 34 | current_ = current_stream_.getSource()->get(); 35 | return true; 36 | } 37 | } 38 | 39 | current_.reset(); 40 | return false; 41 | } 42 | 43 | PrintInfo print(std::ostream& os, int indent) const override { 44 | this->print_indent(os, indent); 45 | os << "FlatMap:\n"; 46 | return source_->print(os, indent + 1).addStage(); 47 | } 48 | 49 | private: 50 | StreamProviderPtr source_; 51 | Transform transform_; 52 | stream::Stream current_stream_; 53 | std::shared_ptr current_; 54 | bool first_ = true; 55 | 56 | }; 57 | 58 | } /* namespace provider */ 59 | } /* namespace stream */ 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /source/providers/Generate.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_GENERATE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_GENERATE_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include "../Utility.h" 7 | 8 | namespace stream { 9 | namespace provider { 10 | 11 | template 12 | class Generate : public StreamProvider { 13 | 14 | public: 15 | Generate(Generator&& generator) 16 | : generator_(generator) {} 17 | 18 | std::shared_ptr get() override { 19 | return current_; 20 | } 21 | 22 | bool advance_impl() override { 23 | current_ = std::make_shared(generator_()); 24 | return true; 25 | } 26 | 27 | PrintInfo print(std::ostream& os, int indent) const override { 28 | this->print_indent(os, indent); 29 | os << "[generated stream]\n"; 30 | return PrintInfo::Source(); 31 | } 32 | 33 | private: 34 | Generator generator_; 35 | std::shared_ptr current_; 36 | 37 | }; 38 | 39 | } /* namespace provider */ 40 | } /* namespace stream */ 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /source/providers/Group.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_GROUP_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_GROUP_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include "../Utility.h" 7 | 8 | namespace stream { 9 | namespace provider { 10 | 11 | namespace detail { 12 | 13 | struct IncompleteGroupError {}; 14 | 15 | template 16 | std::shared_ptr next(StreamProviderPtr& source) { 17 | if(source->advance()) { 18 | return source->get(); 19 | } 20 | throw IncompleteGroupError(); 21 | } 22 | 23 | template 24 | struct Grouper { 25 | using Type = NTuple; 26 | 27 | static Type group(StreamProviderPtr& source) { 28 | auto sub = Grouper::group(source); 29 | auto curr = next(source); 30 | return std::tuple_cat(sub, std::make_tuple(std::move(*curr))); 31 | } 32 | }; 33 | 34 | template 35 | struct Grouper { 36 | using Type = NTuple; 37 | 38 | static Type group(StreamProviderPtr& source) { 39 | auto first = next(source); 40 | auto second = next(source); 41 | auto third = next(source); 42 | return std::make_tuple(std::move(*first), 43 | std::move(*second), 44 | std::move(*third)); 45 | } 46 | }; 47 | 48 | template 49 | struct Grouper { 50 | using Type = std::pair; 51 | 52 | static Type group(StreamProviderPtr& source) { 53 | auto first = next(source); 54 | auto second = next(source); 55 | return std::make_pair(std::move(*first), 56 | std::move(*second)); 57 | } 58 | }; 59 | 60 | template 61 | using GroupResult = typename detail::Grouper::Type; 62 | 63 | } /* namespace detail */ 64 | 65 | template 66 | class Group : public StreamProvider> { 67 | static_assert(N >= 2, "Cannot group stream into chunks of less than size 2."); 68 | 69 | public: 70 | using GroupType = detail::GroupResult; 71 | 72 | Group(StreamProviderPtr source) : source_(std::move(source)) {} 73 | 74 | std::shared_ptr get() override { 75 | return current_; 76 | } 77 | 78 | bool advance_impl() override { 79 | try { 80 | auto group = detail::Grouper::group(source_); 81 | current_ = std::make_shared(std::move(group)); 82 | return true; 83 | } catch(detail::IncompleteGroupError& err) { 84 | return false; 85 | } 86 | } 87 | 88 | PrintInfo print(std::ostream& os, int indent) const override { 89 | this->print_indent(os, indent); 90 | os << "Grouped[" << N << "]:\n"; 91 | return source_->print(os, indent + 1).addStage(); 92 | } 93 | 94 | private: 95 | StreamProviderPtr source_; 96 | std::shared_ptr current_; 97 | 98 | }; 99 | 100 | } /* namespace provider */ 101 | } /* namespace stream */ 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /source/providers/Intersection.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_INTERSECTION_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_INTERSECTION_H 3 | 4 | #include "StreamProvider.h" 5 | #include "../Utility.h" 6 | 7 | namespace stream { 8 | namespace provider { 9 | 10 | template 11 | class Intersection : public SetOperation { 12 | 13 | using Parent = SetOperation; 14 | using UpdateState = typename Parent::UpdateState; 15 | using ToAdvance = typename Parent::ToAdvance; 16 | 17 | public: 18 | Intersection(StreamProviderPtr source1, 19 | StreamProviderPtr source2, 20 | Compare&& comparator) 21 | : Parent(std::forward>(source1), 22 | std::forward>(source2), 23 | std::forward(comparator)) {} 24 | 25 | protected: 26 | UpdateState if_neither_depleted() override { 27 | if(this->current1_smaller()) { 28 | this->set_advance(ToAdvance::First); 29 | } else if(this->current2_smaller()) { 30 | this->set_advance(ToAdvance::Second); 31 | } else { 32 | this->set_advance(ToAdvance::Both); 33 | this->set_result(this->get_current1()); 34 | return UpdateState::UpdateFinished; 35 | } 36 | return UpdateState::NotFinished; 37 | } 38 | 39 | virtual UpdateState if_first_depleted() { 40 | return UpdateState::StreamFinished; 41 | } 42 | 43 | virtual UpdateState if_second_depleted() { 44 | return UpdateState::StreamFinished; 45 | } 46 | 47 | std::string get_operation_name() const override { 48 | return "Intersection"; 49 | } 50 | 51 | }; 52 | 53 | } /* namespace provider */ 54 | } /* namespace stream */ 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /source/providers/Iterate.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_ITERATE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_ITERATE_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include "../Utility.h" 7 | 8 | #include 9 | #include 10 | 11 | namespace stream { 12 | namespace provider { 13 | 14 | template 15 | class Iterate : public StreamProvider { 16 | 17 | public: 18 | Iterate(T initial, Function&& function) 19 | : function_(function), current_(std::make_shared(initial)) {} 20 | 21 | std::shared_ptr get() override { 22 | return current_; 23 | } 24 | 25 | bool advance_impl() override { 26 | if(first_) { 27 | first_ = false; 28 | return true; 29 | } 30 | current_ = std::make_shared(function_(*current_)); 31 | return true; 32 | } 33 | 34 | PrintInfo print(std::ostream& os, int indent) const override { 35 | this->print_indent(os, indent); 36 | os << "[iterated stream]\n"; 37 | return PrintInfo::Source(); 38 | } 39 | 40 | private: 41 | bool first_ = true; 42 | Function function_; 43 | std::shared_ptr current_; 44 | }; 45 | 46 | } /* namespace provider */ 47 | } /* namespace stream */ 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /source/providers/Iterator.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_ITERATOR_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_ITERATOR_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include "../Utility.h" 7 | 8 | namespace stream { 9 | namespace provider { 10 | 11 | template 12 | class Iterator : public StreamProvider { 13 | 14 | public: 15 | Iterator(Itr begin, Itr end) 16 | : current_(begin), end_(end) {} 17 | 18 | std::shared_ptr get() override { 19 | return std::make_shared(std::move(*current_)); 20 | } 21 | 22 | bool advance_impl() override { 23 | if(first_) { 24 | first_ = false; 25 | return current_ != end_; 26 | } 27 | ++current_; 28 | return current_ != end_; 29 | } 30 | 31 | PrintInfo print(std::ostream& os, int indent) const override { 32 | this->print_indent(os, indent); 33 | os << "[iterator stream]\n"; 34 | return PrintInfo::Source(); 35 | } 36 | 37 | private: 38 | bool first_ = true; 39 | Itr current_; 40 | Itr end_; 41 | 42 | }; 43 | 44 | } /* namespace provider */ 45 | } /* namespace stream */ 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /source/providers/Map.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_MAP_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_MAP_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include "../Utility.h" 7 | 8 | namespace stream { 9 | namespace provider { 10 | 11 | template 12 | class Map : public StreamProvider { 13 | 14 | public: 15 | Map(StreamProviderPtr source, Transform&& transform) 16 | : source_(std::move(source)), transform_(transform) {} 17 | 18 | std::shared_ptr get() override { 19 | return current_; 20 | } 21 | 22 | bool advance_impl() override { 23 | if(source_->advance()) { 24 | current_ = std::make_shared(transform_(std::move(*source_->get()))); 25 | return true; 26 | } 27 | current_.reset(); 28 | return false; 29 | } 30 | 31 | PrintInfo print(std::ostream& os, int indent) const override { 32 | this->print_indent(os, indent); 33 | os << "Map:\n"; 34 | return source_->print(os, indent + 1).addStage(); 35 | } 36 | 37 | private: 38 | StreamProviderPtr source_; 39 | Transform transform_; 40 | std::shared_ptr current_; 41 | 42 | }; 43 | 44 | } /* namespace provider */ 45 | } /* namespace stream */ 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /source/providers/Merge.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_MERGE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_MERGE_H 3 | 4 | #include "StreamProvider.h" 5 | #include "../Utility.h" 6 | 7 | #include "SetOperation.h" 8 | 9 | namespace stream { 10 | namespace provider { 11 | 12 | template 13 | class Merge : public SetOperation { 14 | 15 | using Parent = SetOperation; 16 | using UpdateState = typename Parent::UpdateState; 17 | using ToAdvance = typename Parent::ToAdvance; 18 | 19 | public: 20 | Merge(StreamProviderPtr&& source1, 21 | StreamProviderPtr&& source2, 22 | Compare&& comparator) 23 | : Parent(std::forward>(source1), 24 | std::forward>(source2), 25 | std::forward(comparator)) {} 26 | 27 | protected: 28 | // duplicates 29 | UpdateState if_neither_depleted() override { 30 | if(this->current1_smaller()) { 31 | this->set_advance(ToAdvance::First); 32 | this->set_result(this->get_current1()); 33 | } else { 34 | this->set_advance(ToAdvance::Second); 35 | this->set_result(this->get_current2()); 36 | } 37 | return UpdateState::UpdateFinished; 38 | } 39 | 40 | std::string get_operation_name() const override { 41 | return "Merge"; 42 | } 43 | 44 | }; 45 | 46 | } /* namespace provider */ 47 | } /* namespace stream */ 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /source/providers/Overlap.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_OVERLAP_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_OVERLAP_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | NTuple rotate_impl(std::tuple&& tuple, T&& last, std::index_sequence) { 11 | return {std::forward(std::get(tuple))..., std::forward(last)}; 12 | } 13 | 14 | template, size_t N = sizeof...(Args)> 15 | NTuple rotate(std::tuple&& tuple, T&& last) { 16 | return rotate_impl(std::forward>(tuple), 17 | std::forward(last), 18 | make_1based_sequence()); 19 | } 20 | 21 | template 22 | class Overlap : public StreamProvider> { 23 | 24 | private: 25 | using Tuple = NTuple; 26 | 27 | public: 28 | Overlap(StreamProviderPtr source) : source_(std::move(source)) {} 29 | 30 | std::shared_ptr get() override { 31 | return current_; 32 | } 33 | 34 | bool advance_impl() override { 35 | if(first_) { 36 | first_ = false; 37 | try { 38 | current_ = std::make_shared(detail::Grouper::group(source_)); 39 | return true; 40 | } catch(detail::IncompleteGroupError& e) { 41 | return false; 42 | } 43 | } 44 | 45 | if(source_->advance()) { 46 | current_ = std::make_shared( 47 | rotate(std::move(*current_), std::move(*source_->get()))); 48 | return true; 49 | } 50 | current_.reset(); 51 | return false; 52 | } 53 | 54 | PrintInfo print(std::ostream& os, int indent) const override { 55 | this->print_indent(os, indent); 56 | os << "Overlapped[" << N << "]:\n"; 57 | return source_->print(os, indent + 1).addStage(); 58 | } 59 | 60 | private: 61 | bool first_ = true; 62 | StreamProviderPtr source_; 63 | std::shared_ptr current_; 64 | 65 | }; 66 | 67 | } /* namespace provider */ 68 | } /* namespace stream */ 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /source/providers/PartialSum.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_PARTIAL_SUM_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_PARTIAL_SUM_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class PartialSum : public StreamProvider { 11 | 12 | public: 13 | PartialSum(StreamProviderPtr source, Adder&& add) 14 | : source_(std::move(source)), add_(add) {} 15 | 16 | std::shared_ptr get() override { 17 | return current_; 18 | } 19 | 20 | bool advance_impl() override { 21 | if(first_) { 22 | first_ = false; 23 | if(source_->advance()) { 24 | current_ = source_->get(); 25 | return true; 26 | } 27 | return false; 28 | } 29 | 30 | if(source_->advance()) { 31 | current_ = std::make_shared(add_( 32 | std::move(*current_), 33 | std::move(*source_->get()))); 34 | return true; 35 | } 36 | current_.reset(); 37 | return false; 38 | } 39 | 40 | PrintInfo print(std::ostream& os, int indent) const override { 41 | this->print_indent(os, indent); 42 | os << "PartialSum:\n"; 43 | return source_->print(os, indent + 1).addStage(); 44 | } 45 | 46 | private: 47 | StreamProviderPtr source_; 48 | Adder add_; 49 | std::shared_ptr current_; 50 | bool first_ = true; 51 | }; 52 | 53 | } /* namespace provider */ 54 | } /* namespace stream */ 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /source/providers/Peek.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_PEEK_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_PEEK_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class Peek : public StreamProvider { 11 | 12 | public: 13 | Peek(StreamProviderPtr source, Action&& action) 14 | : source_(std::move(source)), action_(action) {} 15 | 16 | std::shared_ptr get() override { 17 | return current_; 18 | } 19 | 20 | bool advance_impl() override { 21 | if(source_->advance()) { 22 | current_ = source_->get(); 23 | action_(*current_); 24 | return true; 25 | } 26 | current_.reset(); 27 | return false; 28 | } 29 | 30 | PrintInfo print(std::ostream& os, int indent) const override { 31 | this->print_indent(os, indent); 32 | os << "Peek:\n"; 33 | return source_->print(os, indent + 1).addStage(); 34 | } 35 | 36 | private: 37 | StreamProviderPtr source_; 38 | Action action_; 39 | std::shared_ptr current_; 40 | 41 | }; 42 | 43 | } /* namespace provider */ 44 | } /* namespace stream */ 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /source/providers/Providers.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include "AdjacentDifference.h" 7 | #include "AdjacentDistinct.h" 8 | #include "Concatenate.h" 9 | #include "CycledContainer.h" 10 | #include "Difference.h" 11 | #include "Distinct.h" 12 | #include "DropWhile.h" 13 | #include "DynamicGroup.h" 14 | #include "DynamicOverlap.h" 15 | #include "Empty.h" 16 | #include "Filter.h" 17 | #include "FlatMap.h" 18 | #include "Generate.h" 19 | #include "Group.h" 20 | #include "Intersection.h" 21 | #include "Iterate.h" 22 | #include "Iterator.h" 23 | #include "Map.h" 24 | #include "Merge.h" 25 | #include "PartialSum.h" 26 | #include "Overlap.h" 27 | #include "Peek.h" 28 | #include "Recurrence.h" 29 | #include "Repeat.h" 30 | #include "Singleton.h" 31 | #include "Slice.h" 32 | #include "Sort.h" 33 | #include "Stateful.h" 34 | #include "SymmetricDifference.h" 35 | #include "TakeWhile.h" 36 | #include "Union.h" 37 | #include "Zip.h" 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /source/providers/Recurrence.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_RECURRENCE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_RECURRENCE_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include 7 | 8 | namespace stream { 9 | namespace provider { 10 | 11 | namespace detail { 12 | 13 | template 14 | inline auto apply_impl(Function&& function, Array& args, std::index_sequence) { 15 | return function(std::get(args)...); 16 | } 17 | 18 | template 19 | inline auto apply(Function&& function, std::array& args) { 20 | return apply_impl(std::forward(function), args, 21 | std::make_index_sequence()); 22 | } 23 | 24 | template 25 | std::array rotate_impl(std::array&& array, const T& last, std::index_sequence) { 26 | return {{std::forward(std::get(array))..., last}}; 27 | } 28 | 29 | template 30 | std::array rotate(std::array&& array, const T& last) { 31 | return rotate_impl(std::forward>(array), last, 32 | make_1based_sequence()); 33 | } 34 | 35 | } /* namespace detail */ 36 | 37 | template 38 | class Recurrence : public StreamProvider { 39 | public: 40 | Recurrence(std::array&& arguments, Function&& function) 41 | : arguments_(arguments), function_(function) {} 42 | 43 | std::shared_ptr get() override { 44 | return std::make_shared(next_); 45 | } 46 | 47 | bool advance_impl() override { 48 | if(index_ < Order) { 49 | next_ = arguments_[index_++]; 50 | return true; 51 | } 52 | next_ = detail::apply(function_, arguments_); 53 | arguments_ = detail::rotate(std::move(arguments_), next_); 54 | return true; 55 | } 56 | 57 | PrintInfo print(std::ostream& os, int indent) const override { 58 | this->print_indent(os, indent); 59 | os << "[recurrence stream]\n"; 60 | return PrintInfo::Source(); 61 | } 62 | 63 | private: 64 | size_t index_ = 0; 65 | std::array arguments_; 66 | Function function_; 67 | T next_; 68 | }; 69 | 70 | }; /* namespace provider */ 71 | }; /* namespace stream */ 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /source/providers/Repeat.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_REPEAT_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_REPEAT_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include "../Utility.h" 7 | 8 | namespace stream { 9 | namespace provider { 10 | 11 | template 12 | class Repeat : public StreamProvider { 13 | 14 | public: 15 | Repeat(const T& value) : value_(std::make_shared(value)) {} 16 | 17 | Repeat(T&& value) : value_(std::make_shared(value)) {} 18 | 19 | std::shared_ptr get() override { 20 | return value_; 21 | } 22 | 23 | bool advance_impl() override { 24 | return true; 25 | } 26 | 27 | PrintInfo print(std::ostream& os, int indent) const override { 28 | this->print_indent(os, indent); 29 | os << "[repeated value stream]\n"; 30 | return PrintInfo::Source(); 31 | } 32 | 33 | private: 34 | std::shared_ptr value_; 35 | 36 | }; 37 | 38 | } /* namespace provider */ 39 | } /* namespace stream */ 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /source/providers/SetOperation.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_SET_OPERATION_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_SET_OPERATION_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class SetOperation : public StreamProvider { 11 | 12 | public: 13 | SetOperation(StreamProviderPtr source1, 14 | StreamProviderPtr source2, 15 | Compare&& comparator) 16 | : comparator_(comparator), 17 | source1_(std::move(source1)), 18 | source2_(std::move(source2)) {} 19 | 20 | std::shared_ptr get() override { 21 | return result_; 22 | } 23 | 24 | bool advance_impl() override { 25 | if(depletion_ == DepleteState::Both) { 26 | return false; 27 | } 28 | 29 | return perform_update(); 30 | } 31 | 32 | PrintInfo print(std::ostream& os, int indent) const override { 33 | this->print_indent(os, indent); 34 | os << get_operation_name() << ":\n"; 35 | return source1_->print(os, indent + 1) + 36 | source2_->print(os, indent + 1); 37 | } 38 | 39 | protected: 40 | enum class ToAdvance { 41 | First, 42 | Second, 43 | Both 44 | }; 45 | 46 | enum class DepleteState { 47 | Neither, 48 | First, 49 | Second, 50 | Both 51 | }; 52 | 53 | enum class UpdateState { 54 | NotFinished, 55 | UpdateFinished, 56 | StreamFinished 57 | }; 58 | 59 | std::shared_ptr get_current1() { 60 | return current1_; 61 | } 62 | 63 | std::shared_ptr get_current2() { 64 | return current2_; 65 | } 66 | 67 | void set_result(std::shared_ptr result) { 68 | result_ = result; 69 | } 70 | 71 | void set_advance(ToAdvance advance) { 72 | advance_ = advance; 73 | } 74 | 75 | void set_deplete(DepleteState depletion) { 76 | depletion_ = depletion; 77 | } 78 | 79 | bool current1_smaller() { 80 | return comparator_(*current1_, *current2_); 81 | } 82 | 83 | bool current2_smaller() { 84 | return comparator_(*current2_, *current1_); 85 | } 86 | 87 | virtual void on_first_source_advance() {} 88 | virtual void on_second_source_advance() {} 89 | 90 | virtual void before_update() {} 91 | 92 | virtual UpdateState if_neither_depleted() = 0; 93 | 94 | virtual UpdateState if_first_depleted() { 95 | set_result(current2_); 96 | return UpdateState::UpdateFinished; 97 | } 98 | 99 | virtual UpdateState if_second_depleted() { 100 | set_result(current1_); 101 | return UpdateState::UpdateFinished; 102 | } 103 | 104 | virtual UpdateState if_both_depleted() { 105 | return UpdateState::StreamFinished; 106 | } 107 | 108 | virtual std::string get_operation_name() const = 0; 109 | 110 | private: 111 | ToAdvance advance_ = ToAdvance::Both; 112 | DepleteState depletion_ = DepleteState::Neither; 113 | 114 | Compare comparator_; 115 | StreamProviderPtr source1_; 116 | StreamProviderPtr source2_; 117 | std::shared_ptr current1_; 118 | std::shared_ptr current2_; 119 | std::shared_ptr result_; 120 | bool allow_duplicates_; 121 | 122 | void advance_stream(StreamProviderPtr& source, 123 | std::shared_ptr& current, 124 | DepleteState deplete_state, 125 | ToAdvance advance_result) { 126 | if(source->advance()) { 127 | current = source->get(); 128 | } else { 129 | current.reset(); 130 | if(depletion_ == DepleteState::Neither) { 131 | depletion_ = deplete_state; 132 | advance_ = advance_result; 133 | } else { 134 | depletion_ = DepleteState::Both; 135 | } 136 | } 137 | } 138 | 139 | void advance_first() { 140 | advance_stream(source1_, current1_, DepleteState::First, 141 | ToAdvance::Second); 142 | on_first_source_advance(); 143 | } 144 | 145 | void advance_second() { 146 | advance_stream(source2_, current2_, DepleteState::Second, 147 | ToAdvance::First); 148 | on_second_source_advance(); 149 | } 150 | 151 | void perform_advance() { 152 | switch(advance_) { 153 | case ToAdvance::First: 154 | advance_first(); 155 | break; 156 | case ToAdvance::Second: 157 | advance_second(); 158 | break; 159 | case ToAdvance::Both: 160 | advance_first(); 161 | advance_second(); 162 | break; 163 | } 164 | } 165 | 166 | bool perform_update() { 167 | before_update(); 168 | while(true) { 169 | perform_advance(); 170 | UpdateState state; 171 | if(depletion_ == DepleteState::Neither) { 172 | state = if_neither_depleted(); 173 | } else if(depletion_ == DepleteState::First) { 174 | state = if_first_depleted(); 175 | } else if(depletion_ == DepleteState::Second) { 176 | state = if_second_depleted(); 177 | } else { // depletion_ == DepleteState::Both 178 | state = if_both_depleted(); 179 | } 180 | 181 | if(state == UpdateState::UpdateFinished) { 182 | return true; 183 | } else if(state == UpdateState::StreamFinished) { 184 | return false; 185 | } else if(state == UpdateState::NotFinished) { 186 | continue; 187 | } 188 | } 189 | } 190 | 191 | }; 192 | 193 | } /* namespace provider */ 194 | } /* namespace stream */ 195 | 196 | #endif 197 | -------------------------------------------------------------------------------- /source/providers/Singleton.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_SINGLETON_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_SINGLETON_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include "../Utility.h" 7 | 8 | #include 9 | #include 10 | 11 | namespace stream { 12 | namespace provider { 13 | 14 | template 15 | class Singleton : public StreamProvider { 16 | 17 | public: 18 | Singleton(const T& value) : value_(std::make_shared(value)) {} 19 | 20 | Singleton(T&& value) : value_(std::make_shared(value)) {} 21 | 22 | std::shared_ptr get() override { 23 | return value_; 24 | } 25 | 26 | bool advance_impl() override { 27 | if(first_) { 28 | first_ = false; 29 | return true; 30 | } 31 | value_.reset(); 32 | return false; 33 | } 34 | 35 | PrintInfo print(std::ostream& os, int indent) const override { 36 | this->print_indent(os, indent); 37 | os << "[singleton stream]\n"; 38 | return PrintInfo::Source(); 39 | } 40 | 41 | private: 42 | bool first_ = true; 43 | std::shared_ptr value_; 44 | }; 45 | 46 | } /* namespace provider */ 47 | } /* namespace stream */ 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /source/providers/Slice.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_SLICE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_SLICE_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class Slice : public StreamProvider { 11 | 12 | public: 13 | Slice(StreamProviderPtr source, size_t start, size_t end, size_t increment, bool no_end_) 14 | : source_(std::move(source)), 15 | start_(start), 16 | end_(end), 17 | increment_(increment), 18 | no_end_(no_end_) {} 19 | 20 | std::shared_ptr get() override { 21 | return current_; 22 | } 23 | 24 | bool advance_impl() override { 25 | if(index_ < start_) { 26 | for(; index_ <= start_; index_++) { 27 | if(source_->advance()) { 28 | current_ = source_->get(); 29 | } else { 30 | current_.reset(); 31 | return false; 32 | } 33 | } 34 | return true; 35 | } 36 | 37 | if(no_end_ || index_ + increment_ <= end_) { 38 | for(size_t k = 0; k < increment_; k++) { 39 | index_++; 40 | if(source_->advance()) { 41 | current_ = source_->get(); 42 | } else { 43 | current_.reset(); 44 | return false; 45 | } 46 | } 47 | return true; 48 | } 49 | 50 | current_.reset(); 51 | return false; 52 | } 53 | 54 | PrintInfo print(std::ostream& os, int indent) const override { 55 | this->print_indent(os, indent); 56 | os << "Slice[" << start_ << ", " 57 | << (no_end_ ? -1 : static_cast(end_)) << ", " 58 | << increment_ << "]:\n"; 59 | return source_->print(os, indent + 1).addStage(); 60 | } 61 | 62 | private: 63 | bool first_ = true; 64 | StreamProviderPtr source_; 65 | std::shared_ptr current_; 66 | size_t index_ = 0; 67 | size_t start_; 68 | size_t end_; 69 | size_t increment_; 70 | bool no_end_; 71 | 72 | 73 | }; 74 | 75 | } /* namespace provider */ 76 | } /* namespace stream */ 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /source/providers/Sort.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_SORT_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_SORT_H 3 | 4 | #include "StreamProvider.h" 5 | #include "../Utility.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace stream { 11 | namespace provider { 12 | 13 | template 14 | class Sort : public StreamProvider { 15 | 16 | public: 17 | Sort(StreamProviderPtr source, RawCompare&& comparator) 18 | : source_(std::move(source)), sorted_(PointerCompare(std::forward(comparator))) {} 19 | 20 | std::shared_ptr get() override { 21 | return current_; 22 | } 23 | 24 | bool advance_impl() override { 25 | if(first_) { 26 | while(source_->advance()) { 27 | sorted_.push(source_->get()); 28 | } 29 | first_ = false; 30 | } 31 | if(sorted_.empty()) { 32 | current_.reset(); 33 | return false; 34 | } 35 | current_ = sorted_.top(); 36 | sorted_.pop(); 37 | return true; 38 | } 39 | 40 | PrintInfo print(std::ostream& os, int indent) const override { 41 | this->print_indent(os, indent); 42 | os << "Sort:\n"; 43 | return source_->print(os, indent + 1).addStage(); 44 | } 45 | 46 | private: 47 | using PointerCompare = ComparePtrWrapper; 48 | using PointerQueue = std::priority_queue, 49 | std::vector>, 50 | PointerCompare>; 51 | 52 | StreamProviderPtr source_; 53 | PointerQueue sorted_; 54 | std::shared_ptr current_; 55 | bool first_ = true; 56 | }; 57 | 58 | } /* namespace provider */ 59 | } /* namespace stream */ 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /source/providers/Stateful.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_STATEFUL_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_STATEFUL_H 3 | 4 | #include "StreamProvider.h" 5 | #include "../Utility.h" 6 | 7 | #include 8 | 9 | namespace stream { 10 | namespace provider { 11 | 12 | template 13 | class Stateful : public StreamProvider { 14 | 15 | public: 16 | Stateful(StreamProviderPtr source) 17 | : source_(std::move(source)) {} 18 | 19 | std::shared_ptr get() override { 20 | return *current_; 21 | } 22 | 23 | bool advance_impl() override { 24 | if(first_) { 25 | first_ = false; 26 | while(source_->advance()) { 27 | state_.push_back(source_->get()); 28 | } 29 | current_ = state_.begin(); 30 | return current_ != state_.end(); 31 | } 32 | ++current_; 33 | return current_ != state_.end(); 34 | } 35 | 36 | PrintInfo print(std::ostream& os, int indent) const override { 37 | this->print_indent(os, indent); 38 | os << "StatePoint:\n"; 39 | return source_->print(os, indent + 1).addStage(); 40 | } 41 | 42 | private: 43 | using List = std::list>; 44 | using Iterator = typename List::iterator; 45 | 46 | bool first_ = true; 47 | StreamProviderPtr source_; 48 | List state_; 49 | Iterator current_; 50 | Iterator end_; 51 | 52 | }; 53 | 54 | } /* namespace provider */ 55 | } /* namespace stream */ 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /source/providers/StreamProvider.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDER_H 2 | #define SCHEINERMAN_STREAM_PROVIDER_H 3 | 4 | #include "../StreamError.h" 5 | 6 | #include 7 | 8 | namespace stream { 9 | namespace provider { 10 | 11 | struct PrintInfo { 12 | PrintInfo(int sources_, int stages_) 13 | : sources(sources_), stages(stages_) {} 14 | 15 | static PrintInfo Source() { 16 | return {1, 0}; 17 | } 18 | 19 | PrintInfo operator+ (const PrintInfo& info) { 20 | return {sources + info.sources, stages + info.stages}; 21 | } 22 | 23 | PrintInfo addStage(int stages = 1) { 24 | return {sources, this->stages + stages}; 25 | } 26 | 27 | int sources; 28 | int stages; 29 | }; 30 | 31 | template 32 | struct StreamProvider { 33 | 34 | public: 35 | struct Iterator; 36 | 37 | virtual std::shared_ptr get() = 0; 38 | 39 | bool advance() { 40 | try { 41 | return advance_impl(); 42 | } catch(stream::StopStream& stop) { 43 | return false; 44 | } catch(...) { 45 | throw; 46 | } 47 | } 48 | 49 | Iterator begin(); 50 | Iterator end(); 51 | 52 | virtual PrintInfo print(std::ostream& os, int indent) const = 0; 53 | 54 | protected: 55 | virtual bool advance_impl() = 0; 56 | 57 | protected: 58 | static void print_indent(std::ostream& os, int indent) { 59 | for(int i = 0; i < indent - 1; i++) { 60 | os << " "; 61 | } 62 | if(indent != 0) { 63 | os << "> "; 64 | } 65 | } 66 | }; 67 | 68 | } /* namespace provider */ 69 | } /* namespace stream */ 70 | 71 | #include "StreamProviderIterator.h" 72 | 73 | template 74 | typename stream::provider::StreamProvider::Iterator 75 | stream::provider::StreamProvider::begin() { 76 | return Iterator::begin(this); 77 | } 78 | 79 | template 80 | typename stream::provider::StreamProvider::Iterator 81 | stream::provider::StreamProvider::end() { 82 | return Iterator::end(this); 83 | } 84 | 85 | namespace stream { 86 | 87 | template 88 | using StreamProviderPtr = std::unique_ptr>; 89 | 90 | template class Provider, 91 | typename T, 92 | typename... TemplateArgs, 93 | typename... ConstructorArgs> 94 | StreamProviderPtr make_stream_provider(ConstructorArgs&&... args) { 95 | return StreamProviderPtr( 96 | new Provider( 97 | std::forward(args)...)); 98 | } 99 | 100 | } /* namespace stream */ 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /source/providers/StreamProviderIterator.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_STREAM_PROVIDER_ITERATOR_H 2 | #define SCHEINERMAN_STREAM_STREAM_PROVIDER_ITERATOR_H 3 | 4 | namespace stream { 5 | namespace provider { 6 | 7 | template 8 | struct StreamProvider::Iterator { 9 | 10 | public: 11 | T& operator* (); 12 | Iterator& operator++ (); 13 | Iterator operator++ (int); 14 | bool operator== (Iterator& other); 15 | bool operator!= (Iterator& other); 16 | 17 | friend struct StreamProvider; 18 | 19 | private: 20 | enum class State { 21 | Initial, 22 | Consumed, 23 | Iterating, 24 | End 25 | }; 26 | 27 | static Iterator begin(StreamProvider* source); 28 | static Iterator iterating(StreamProvider* source, std::shared_ptr value); 29 | static Iterator end(StreamProvider* source); 30 | 31 | Iterator(StreamProvider* source, State state, std::shared_ptr value); 32 | 33 | void update_initial(); 34 | void check_consumed(const std::string& op) const; 35 | 36 | StreamProvider* source_; 37 | State state_; 38 | std::shared_ptr current_; 39 | 40 | }; 41 | 42 | template 43 | typename StreamProvider::Iterator 44 | StreamProvider::Iterator::begin(StreamProvider* source) { 45 | return Iterator(source, State::Initial, nullptr); 46 | } 47 | 48 | template 49 | typename StreamProvider::Iterator 50 | StreamProvider::Iterator::iterating(StreamProvider* source, 51 | std::shared_ptr value) { 52 | return Iterator(source, State::Iterating, value); 53 | } 54 | 55 | template 56 | typename StreamProvider::Iterator 57 | StreamProvider::Iterator::end(StreamProvider* source) { 58 | return Iterator(source, State::End, nullptr); 59 | } 60 | 61 | template 62 | StreamProvider::Iterator::Iterator(StreamProvider* source, State state, 63 | std::shared_ptr value) 64 | : source_(source), state_(state), current_(value) {} 65 | 66 | template 67 | T& StreamProvider::Iterator::operator* () { 68 | update_initial(); 69 | return *current_; 70 | } 71 | 72 | template 73 | typename StreamProvider::Iterator& 74 | StreamProvider::Iterator::operator++() { 75 | update_initial(); 76 | check_consumed("prefix increment"); 77 | if(source_->advance()) { 78 | current_ = source_->get(); 79 | } else { 80 | state_ = State::End; 81 | current_.reset(); 82 | } 83 | return *this; 84 | } 85 | 86 | template 87 | typename StreamProvider::Iterator 88 | StreamProvider::Iterator::operator++(int) { 89 | update_initial(); 90 | check_consumed("postfix increment"); 91 | Iterator result(nullptr, State::Consumed, current_); 92 | if(source_->advance()) { 93 | current_ = source_->get(); 94 | } else { 95 | state_ = State::End; 96 | current_.reset(); 97 | } 98 | return result; 99 | } 100 | 101 | template 102 | bool StreamProvider::Iterator::operator== (Iterator& other) { 103 | update_initial(); 104 | check_consumed("equality check"); 105 | other.update_initial(); 106 | other.check_consumed(); 107 | if(state_ == State::End) { 108 | return other.state_ == State::End; 109 | } 110 | if(other.state_ == State::End) { 111 | return false; 112 | } 113 | return source_ == other.source_ && current_ == other.current_; 114 | } 115 | 116 | template 117 | bool StreamProvider::Iterator::operator!= (Iterator& other) { 118 | update_initial(); 119 | check_consumed("inequality check"); 120 | other.update_initial(); 121 | other.check_consumed("inequality check"); 122 | if(state_ == State::End) { 123 | return other.state_ != State::End; 124 | } 125 | if(other.state_ == State::End) { 126 | return true; 127 | } 128 | return source_ != other.source_ || current_ != other.current_; 129 | } 130 | 131 | template 132 | void StreamProvider::Iterator::update_initial() { 133 | if(state_ == State::Initial) { 134 | if(source_->advance()) { 135 | current_ = source_->get(); 136 | state_ = State::Iterating; 137 | } else { 138 | current_.reset(); 139 | state_ = State::End; 140 | } 141 | } 142 | } 143 | 144 | template 145 | void StreamProvider::Iterator::check_consumed(const std::string& op) const { 146 | if(state_ == State::Consumed) { 147 | throw stream::ConsumedIteratorException(op); 148 | } 149 | } 150 | 151 | } /* namespace provider */ 152 | } /* namespace stream */ 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /source/providers/SymmetricDifference.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_SYMMETRIC_DIFFERENCE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_SYMMETRIC_DIFFERENCE_H 3 | 4 | #include "SetOperation.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class SymmetricDifference : public SetOperation { 11 | 12 | using Parent = SetOperation; 13 | using UpdateState = typename Parent::UpdateState; 14 | using ToAdvance = typename Parent::ToAdvance; 15 | 16 | public: 17 | SymmetricDifference(StreamProviderPtr&& source1, 18 | StreamProviderPtr&& source2, 19 | Compare&& comparator) 20 | : Parent(std::forward>(source1), 21 | std::forward>(source2), 22 | std::forward(comparator)) {} 23 | 24 | protected: 25 | UpdateState if_neither_depleted() override { 26 | if(this->current1_smaller()) { 27 | this->set_advance(ToAdvance::First); 28 | this->set_result(this->get_current1()); 29 | return UpdateState::UpdateFinished; 30 | } else if(this->current2_smaller()) { 31 | this->set_advance(ToAdvance::Second); 32 | this->set_result(this->get_current2()); 33 | return UpdateState::UpdateFinished; 34 | } else { 35 | this->set_advance(ToAdvance::Both); 36 | return UpdateState::NotFinished; 37 | } 38 | } 39 | 40 | std::string get_operation_name() const override { 41 | return "SymmetricDifference"; 42 | } 43 | }; 44 | 45 | } /* namespace provider */ 46 | } /* namespace stream */ 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /source/providers/TakeWhile.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_TAKE_WHILE_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_TAKE_WHILE_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | namespace stream { 7 | namespace provider { 8 | 9 | template 10 | class TakeWhile : public StreamProvider { 11 | 12 | public: 13 | TakeWhile(StreamProviderPtr source, Predicate&& predicate) 14 | : source_(std::move(source)), predicate_(predicate) {} 15 | 16 | std::shared_ptr get() override { 17 | return current_; 18 | } 19 | 20 | bool advance_impl() override { 21 | if(source_->advance()) { 22 | current_ = source_->get(); 23 | if(!predicate_(*current_)) { 24 | current_.reset(); 25 | return false; 26 | } 27 | return true; 28 | } 29 | current_.reset(); 30 | return false; 31 | } 32 | 33 | PrintInfo print(std::ostream& os, int indent) const override { 34 | this->print_indent(os, indent); 35 | os << "TakeWhile:\n"; 36 | return source_->print(os, indent + 1).addStage(); 37 | } 38 | 39 | private: 40 | StreamProviderPtr source_; 41 | Predicate predicate_; 42 | std::shared_ptr current_; 43 | }; 44 | 45 | } /* namespace provider */ 46 | } /* namespace stream */ 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /source/providers/Union.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_UNION_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_UNION_H 3 | 4 | #include "StreamProvider.h" 5 | #include "../Utility.h" 6 | 7 | #include "SetOperation.h" 8 | 9 | namespace stream { 10 | namespace provider { 11 | 12 | template 13 | class Union : public SetOperation { 14 | 15 | using Parent = SetOperation; 16 | using UpdateState = typename Parent::UpdateState; 17 | using ToAdvance = typename Parent::ToAdvance; 18 | 19 | public: 20 | Union(StreamProviderPtr&& source1, 21 | StreamProviderPtr&& source2, 22 | Compare&& comparator) 23 | : Parent(std::forward>(source1), 24 | std::forward>(source2), 25 | std::forward(comparator)) {} 26 | 27 | protected: 28 | UpdateState if_neither_depleted() override { 29 | if(this->current1_smaller()) { 30 | this->set_advance(ToAdvance::First); 31 | this->set_result(this->get_current1()); 32 | } else if(this->current2_smaller()) { 33 | this->set_advance(ToAdvance::Second); 34 | this->set_result(this->get_current2()); 35 | } else { 36 | this->set_advance(ToAdvance::Both); 37 | this->set_result(this->get_current1()); 38 | } 39 | return UpdateState::UpdateFinished; 40 | } 41 | 42 | std::string get_operation_name() const override { 43 | return "Union"; 44 | } 45 | }; 46 | 47 | } /* namespace provider */ 48 | } /* namespace stream */ 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /source/providers/Zip.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_PROVIDERS_ZIP_H 2 | #define SCHEINERMAN_STREAM_PROVIDERS_ZIP_H 3 | 4 | #include "StreamProvider.h" 5 | 6 | #include 7 | #include 8 | 9 | namespace stream { 10 | namespace provider { 11 | 12 | namespace detail { 13 | 14 | template 15 | struct ZipperImpl { 16 | using Type = std::tuple; 17 | 18 | static Type zip(L&& a, R&& b) { 19 | return std::make_tuple(std::move(a), std::move(b)); 20 | } 21 | }; 22 | 23 | template 24 | struct ZipperImpl> { 25 | using Type = std::tuple; 26 | 27 | static Type zip(L&& a, std::tuple&& b) { 28 | return std::tuple_cat(std::make_tuple(std::move(a)), std::move(b)); 29 | } 30 | }; 31 | 32 | 33 | template 34 | struct ZipperImpl, R> { 35 | using Type = std::tuple; 36 | 37 | static Type zip(std::tuple&& a, R&& b) { 38 | return std::tuple_cat(std::move(a), std::make_tuple(std::move(b))); 39 | } 40 | }; 41 | 42 | template 43 | struct ZipperImpl, std::tuple> { 44 | using Type = std::tuple; 45 | 46 | static Type zip(std::tuple&& a, std::tuple&& b) { 47 | return std::tuple_cat(std::move(a), std::move(b)); 48 | } 49 | }; 50 | 51 | struct Zipper { 52 | template 53 | auto operator() (L&& left, R&& right) { 54 | using Left = typename std::decay::type; 55 | using Right = typename std::decay::type; 56 | return detail::ZipperImpl::zip(std::forward(left), 57 | std::forward(right)); 58 | } 59 | }; 60 | 61 | } /* namespace detail */ 62 | 63 | template 64 | class Zip : public StreamProvider> { 65 | 66 | public: 67 | using ValueType = std::result_of_t; 68 | 69 | Zip(StreamProviderPtr left_source, 70 | StreamProviderPtr right_source, 71 | Function&& zipper) 72 | : left_source_(std::move(left_source)), 73 | right_source_(std::move(right_source)), 74 | zipper_(zipper) {} 75 | 76 | std::shared_ptr get() override { 77 | return current_; 78 | } 79 | 80 | bool advance_impl() override { 81 | if(left_source_->advance() && right_source_->advance()) { 82 | current_ = std::make_shared( 83 | zipper_(std::move(*left_source_->get()), 84 | std::move(*right_source_->get()))); 85 | return true; 86 | } 87 | current_.reset(); 88 | return false; 89 | } 90 | 91 | PrintInfo print(std::ostream& os, int indent) const override { 92 | this->print_indent(os, indent); 93 | os << "Zip:\n"; 94 | return left_source_->print(os, indent + 1) 95 | + right_source_->print(os, indent + 1); 96 | } 97 | 98 | private: 99 | StreamProviderPtr left_source_; 100 | StreamProviderPtr right_source_; 101 | std::shared_ptr current_; 102 | Function zipper_; 103 | }; 104 | 105 | } /* namespace provider */ 106 | } /* namespace stream */ 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /source/reducers/Histogram.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_REDUCER_HISTOGRAM_H 2 | #define SCHEINERMAN_STREAM_REDUCER_HISTOGRAM_H 3 | 4 | #include "Reducer.h" 5 | 6 | #include 7 | 8 | namespace reducers { 9 | 10 | template> 11 | class Histogram : public Reducer> { 12 | 13 | public: 14 | using Map = std::map; 15 | 16 | Histogram(Less&& less = Less()) : less_(less) {} 17 | 18 | Map initial(In&& in) const override { 19 | Map histogram(less_); 20 | histogram[in]++; 21 | return histogram; 22 | } 23 | 24 | Map accumulate(Map&& result, In&& value) const override { 25 | result[value]++; 26 | return result; 27 | } 28 | 29 | private: 30 | Less less_; 31 | 32 | }; 33 | 34 | } 35 | 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /source/reducers/Reducer.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_REDUCER_H 2 | #define SCHEINERMAN_STREAM_REDUCER_H 3 | 4 | #include "../Stream.h" 5 | 6 | #include 7 | 8 | template 9 | struct Reducer { 10 | virtual Out initial(In&& in) const = 0; 11 | virtual Out accumulate(Out&& out, In&& in) const = 0; 12 | auto reducer() const { 13 | using namespace std::placeholders; 14 | return stream::op::reduce( 15 | std::bind(&Reducer::initial, this, _1), 16 | std::bind(&Reducer::accumulate, this, _1, _2) 17 | ); 18 | } 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /source/reducers/SummaryStats.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEINERMAN_STREAM_REDUCER_SUMMARY_STATS_H 2 | #define SCHEINERMAN_STREAM_REDUCER_SUMMARY_STATS_H 3 | 4 | #include "Reducer.h" 5 | 6 | namespace reducers { 7 | 8 | template class SummaryStats; 9 | 10 | template 11 | class Stats { 12 | 13 | public: 14 | Stats(const Stats&) = default; 15 | Stats(Stats&&) = default; 16 | Stats& operator= (const Stats&) = default; 17 | Stats& operator= (Stats&&) = default; 18 | 19 | size_t number() const { return number_; } 20 | Out mean() const { return mean_; } 21 | Out stddev() const { 22 | return (number_ > 1) ? variance_ / (number_ - 1) : 0; 23 | } 24 | In min() const { return min_; } 25 | In max() const { return max_; } 26 | 27 | friend class SummaryStats; 28 | 29 | private: 30 | Stats(In value) 31 | : number_(1), mean_(value), variance_(0), min_(value), max_(value) {} 32 | 33 | Stats accept(In&& value) { 34 | number_++; 35 | double prev_mean = mean_; 36 | mean_ += (value - mean_) / number_; 37 | variance_ += (value - prev_mean) * (value - mean_); 38 | if(value < min_) 39 | min_ = value; 40 | if(value > max_) 41 | max_ = value; 42 | return *this; 43 | } 44 | 45 | size_t number_; 46 | Out mean_; 47 | Out variance_; 48 | Out stddev_; 49 | In max_; 50 | In min_; 51 | }; 52 | 53 | template 54 | std::ostream& operator<< (std::ostream& os, const Stats& stats) { 55 | return os << "N=" << stats.number() 56 | << ", u=" << stats.mean() 57 | << ", s=" << stats.stddev() 58 | << ", min=" << stats.min() 59 | << ", max=" << stats.max(); 60 | } 61 | 62 | template 63 | class SummaryStats : public Reducer> { 64 | 65 | public: 66 | using Out = Stats; 67 | 68 | Out initial(In&& in) const override { 69 | return Out(std::forward(in)); 70 | } 71 | 72 | Out accumulate(Out&& out, In&& in) const override { 73 | return out.accept(std::forward(in)); 74 | } 75 | }; 76 | 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /test/AccessTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | #define EXCEPTION_TEST(Operation, Exception) \ 10 | [](){ \ 11 | bool thrown = false; \ 12 | try { Operation; } catch(Exception& e) { thrown = true; } \ 13 | return thrown; \ 14 | }() 15 | 16 | #define EXPECT_EXCEPTION(Operation, Exception) \ 17 | EXPECT_THAT(EXCEPTION_TEST(Operation, Exception), Eq(true)); 18 | 19 | TEST(FirstTest, Default) { 20 | EXPECT_THAT(MakeStream::counter(0) | first(), Eq(0)); 21 | } 22 | 23 | TEST(FirstTest, EmptyStream) { 24 | EXPECT_EXCEPTION(MakeStream::empty() | first(), EmptyStreamException); 25 | } 26 | 27 | TEST(LastTest, Default) { 28 | EXPECT_THAT(MakeStream::range(0, 10) | last(), Eq(9)); 29 | } 30 | 31 | TEST(LastTest, EmptyStream) { 32 | EXPECT_EXCEPTION(MakeStream::empty() | last(), EmptyStreamException); 33 | } 34 | 35 | TEST(NthTest, Default) { 36 | EXPECT_THAT(MakeStream::counter(0) | nth(5), Eq(5)); 37 | } 38 | 39 | TEST(NthTest, EmptyStream) { 40 | EXPECT_EXCEPTION(MakeStream::range(0, 3) | nth(5), EmptyStreamException); 41 | EXPECT_EXCEPTION(MakeStream::empty() | nth(5), EmptyStreamException); 42 | } 43 | -------------------------------------------------------------------------------- /test/AdjacentDifferenceTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(AdjacentDifferenceTest, Default) { 10 | EXPECT_THAT(MakeStream::range(0, 10, 2) 11 | | adjacent_difference() 12 | | to_vector(), 13 | ElementsAre(2, 2, 2, 2)); 14 | } 15 | 16 | TEST(AdjacentDifferenceTest, WithSubtraction) { 17 | EXPECT_THAT(MakeStream::from({1, 3, -2, 5, 7}) 18 | | adjacent_difference(std::plus()) 19 | | to_vector(), 20 | ElementsAre(4, 1, 3, 12)); 21 | } 22 | -------------------------------------------------------------------------------- /test/AdjacentDistinctTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(AdjacentDistinctTest, Default) { 10 | EXPECT_THAT(MakeStream::from({1, 1, 1, 2, 2, 2, 1, 1, 1, 3}) 11 | | adjacent_distinct() 12 | | to_vector(), 13 | ElementsAre(1, 2, 1, 3)); 14 | } 15 | 16 | TEST(AdjacentDistinctTest, WithEquals) { 17 | EXPECT_THAT(MakeStream::from({1, 2, 5, 10, 0, 8, 12, -1, 3, 5}) 18 | | adjacent_distinct([](int x, int y) { return x < y; }) 19 | | to_vector(), 20 | ElementsAre(1, 0, -1)); 21 | } 22 | -------------------------------------------------------------------------------- /test/AlgebraTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | // Arithmetic operators 10 | 11 | TEST(AlgebraTest, Negate) { 12 | EXPECT_THAT(-MakeStream::from({1, 2, 3}) | to_vector(), 13 | ElementsAre(-1, -2, -3)); 14 | } 15 | 16 | TEST(AlgebraTest, Addition) { 17 | EXPECT_THAT((MakeStream::from({1, 2, 3}) + MakeStream::from({-1, 0, 5})) | to_vector(), 18 | ElementsAre(0, 2, 8)); 19 | EXPECT_THAT((MakeStream::from({1, 2, 3}) + 5) | to_vector(), 20 | ElementsAre(6, 7, 8)); 21 | EXPECT_THAT((5 + MakeStream::from({1, 2, 3})) | to_vector(), 22 | ElementsAre(6, 7, 8)); 23 | } 24 | 25 | TEST(AlgebraTest, Subtraction) { 26 | EXPECT_THAT((MakeStream::from({1, 2, 3}) - MakeStream::from({-1, 0, 5})) | to_vector(), 27 | ElementsAre(2, 2, -2)); 28 | EXPECT_THAT((MakeStream::from({1, 2, 3}) - 5) | to_vector(), 29 | ElementsAre(-4, -3, -2)); 30 | EXPECT_THAT((5 - MakeStream::from({1, 2, 3})) | to_vector(), 31 | ElementsAre(4, 3, 2)); 32 | } 33 | 34 | TEST(AlgebraTest, Multiplication) { 35 | EXPECT_THAT((MakeStream::from({1, 2, 3}) * MakeStream::from({-1, 0, 5})) | to_vector(), 36 | ElementsAre(-1, 0, 15)); 37 | EXPECT_THAT((MakeStream::from({1, 2, 3}) * 5) | to_vector(), 38 | ElementsAre(5, 10, 15)); 39 | EXPECT_THAT((5 * MakeStream::from({1, 2, 3})) | to_vector(), 40 | ElementsAre(5, 10, 15)); 41 | } 42 | 43 | TEST(AlgebraTest, Division) { 44 | EXPECT_THAT((MakeStream::from({5, 10, 15}) / MakeStream::from({5, 1, 3})) | to_vector(), 45 | ElementsAre(1, 10, 5)); 46 | EXPECT_THAT((MakeStream::from({5, 10, 15}) / 5.0) | to_vector(), 47 | ElementsAre(1, 2, 3)); 48 | EXPECT_THAT((1.0 / MakeStream::from({1, 2, 4})) | to_vector(), 49 | ElementsAre(1, .5, .25)); 50 | } 51 | 52 | TEST(AlgebraTest, Modulus) { 53 | EXPECT_THAT((MakeStream::from({12, 13, 14}) % MakeStream::from({6, 5, 4})) | to_vector(), 54 | ElementsAre(0, 3, 2)); 55 | EXPECT_THAT((MakeStream::from({5, 6, 7}) % 5) | to_vector(), 56 | ElementsAre(0, 1, 2)); 57 | EXPECT_THAT((5 % MakeStream::from({3, 4, 5})) | to_vector(), 58 | ElementsAre(2, 1, 0)); 59 | } 60 | 61 | // Comparison Operators 62 | 63 | TEST(AlgebraTest, Equality) { 64 | EXPECT_THAT((MakeStream::from({5, 6}) == MakeStream::from({5, 4})) | to_vector(), 65 | ElementsAre(true, false)); 66 | EXPECT_THAT((MakeStream::from({0, 3, 0}) == 3) | to_vector(), 67 | ElementsAre(false, true, false)); 68 | EXPECT_THAT((3 == MakeStream::from({0, 3, 0})) | to_vector(), 69 | ElementsAre(false, true, false)); 70 | } 71 | 72 | TEST(AlgebraTest, Inequality) { 73 | EXPECT_THAT((MakeStream::from({5, 6}) != MakeStream::from({5, 4})) | to_vector(), 74 | ElementsAre(false, true)); 75 | EXPECT_THAT((MakeStream::from({0, 3, 0}) != 3) | to_vector(), 76 | ElementsAre(true, false, true)); 77 | EXPECT_THAT((3 != MakeStream::from({0, 3, 0})) | to_vector(), 78 | ElementsAre(true, false, true)); 79 | } 80 | 81 | TEST(AlgebraTest, LessThan) { 82 | EXPECT_THAT((MakeStream::from({4, 5, 6}) < MakeStream::from({6, 5, 4})) | to_vector(), 83 | ElementsAre(true, false, false)); 84 | EXPECT_THAT((MakeStream::from({0, 1, 2}) < 1) | to_vector(), 85 | ElementsAre(true, false, false)); 86 | EXPECT_THAT((1 < MakeStream::from({0, 1, 2})) | to_vector(), 87 | ElementsAre(false, false, true)); 88 | } 89 | 90 | TEST(AlgebraTest, LessThanOrEqual) { 91 | EXPECT_THAT((MakeStream::from({4, 5, 6}) <= MakeStream::from({6, 5, 4})) | to_vector(), 92 | ElementsAre(true, true, false)); 93 | EXPECT_THAT((MakeStream::from({0, 1, 2}) <= 1) | to_vector(), 94 | ElementsAre(true, true, false)); 95 | EXPECT_THAT((1 <= MakeStream::from({0, 1, 2})) | to_vector(), 96 | ElementsAre(false, true, true)); 97 | } 98 | 99 | TEST(AlgebraTest, GreaterThan) { 100 | EXPECT_THAT((MakeStream::from({4, 5, 6}) > MakeStream::from({6, 5, 4})) | to_vector(), 101 | ElementsAre(false, false, true)); 102 | EXPECT_THAT((MakeStream::from({0, 1, 2}) > 1) | to_vector(), 103 | ElementsAre(false, false, true)); 104 | EXPECT_THAT((1 > MakeStream::from({0, 1, 2})) | to_vector(), 105 | ElementsAre(true, false, false)); 106 | } 107 | 108 | TEST(AlgebraTest, GreaterThanOrEqual) { 109 | EXPECT_THAT((MakeStream::from({4, 5, 6}) >= MakeStream::from({6, 5, 4})) | to_vector(), 110 | ElementsAre(false, true, true)); 111 | EXPECT_THAT((MakeStream::from({0, 1, 2}) >= 1) | to_vector(), 112 | ElementsAre(false, true, true)); 113 | EXPECT_THAT((1 >= MakeStream::from({0, 1, 2})) | to_vector(), 114 | ElementsAre(true, true, false)); 115 | } 116 | 117 | // Logical operators 118 | 119 | 120 | TEST(AlgebraTest, LogicalNot) { 121 | EXPECT_THAT(!MakeStream::from({true, false}) | to_vector(), 122 | ElementsAre(false, true)); 123 | } 124 | 125 | TEST(AlgebraTest, LogicalAnd) { 126 | EXPECT_THAT((MakeStream::from({true, true, false, false}) && MakeStream::from({true, false, true, false})) | to_vector(), 127 | ElementsAre(true, false, false, false)); 128 | EXPECT_THAT((MakeStream::from({true, false}) && true) | to_vector(), 129 | ElementsAre(true, false)); 130 | EXPECT_THAT((false && MakeStream::from({true, false})) | to_vector(), 131 | ElementsAre(false, false)); 132 | } 133 | 134 | TEST(AlgebraTest, LogicalOr) { 135 | EXPECT_THAT((MakeStream::from({true, true, false, false}) || MakeStream::from({true, false, true, false})) | to_vector(), 136 | ElementsAre(true, true, true, false)); 137 | EXPECT_THAT((MakeStream::from({true, false}) || true) | to_vector(), 138 | ElementsAre(true, true)); 139 | EXPECT_THAT((false || MakeStream::from({true, false})) | to_vector(), 140 | ElementsAre(true, false)); 141 | } 142 | 143 | // Bitwise operators 144 | 145 | TEST(AlgebraTest, BitwiseNot) { 146 | EXPECT_THAT(~MakeStream::from({0, 1, 2, 3}) | to_vector(), 147 | ElementsAre(~0, ~1, ~2, ~3)); 148 | } 149 | 150 | TEST(AlgebraTest, BitwiseAnd) { 151 | EXPECT_THAT((MakeStream::from({3, 4}) & MakeStream::from({5, 6})) | to_vector(), 152 | ElementsAre(3 & 5, 4 & 6)); 153 | EXPECT_THAT((MakeStream::from({3, 4, 5}) & 12) | to_vector(), 154 | ElementsAre(3 & 12, 4 & 12, 5 & 12)); 155 | EXPECT_THAT((12 & MakeStream::from({3, 4, 5})) | to_vector(), 156 | ElementsAre(12 & 3, 12 & 4, 12 & 5)); 157 | } 158 | 159 | TEST(AlgebraTest, BitwiseOr) { 160 | EXPECT_THAT((MakeStream::from({3, 4}) | MakeStream::from({5, 6})) | to_vector(), 161 | ElementsAre(3 | 5, 4 | 6)); 162 | EXPECT_THAT((MakeStream::from({3, 4, 5}) | 12) | to_vector(), 163 | ElementsAre(3 | 12, 4 | 12, 5 | 12)); 164 | EXPECT_THAT((12 | MakeStream::from({3, 4, 5})) | to_vector(), 165 | ElementsAre(12 | 3, 12 | 4, 12 | 5)); 166 | } 167 | 168 | TEST(AlgebraTest, BitwiseXor) { 169 | EXPECT_THAT((MakeStream::from({3, 4}) ^ MakeStream::from({5, 6})) | to_vector(), 170 | ElementsAre(3 ^ 5, 4 ^ 6)); 171 | EXPECT_THAT((MakeStream::from({3, 4, 5}) ^ 12) | to_vector(), 172 | ElementsAre(3 ^ 12, 4 ^ 12, 5 ^ 12)); 173 | EXPECT_THAT((12 ^ MakeStream::from({3, 4, 5})) | to_vector(), 174 | ElementsAre(12 ^ 3, 12 ^ 4, 12 ^ 5)); 175 | } 176 | 177 | TEST(AlgebraTest, BitShiftLeft) { 178 | EXPECT_THAT((MakeStream::from({3, 4}) << MakeStream::from({5, 6})) | to_vector(), 179 | ElementsAre(3 << 5, 4 << 6)); 180 | EXPECT_THAT((MakeStream::from({3, 4, 5}) << 12) | to_vector(), 181 | ElementsAre(3 << 12, 4 << 12, 5 << 12)); 182 | EXPECT_THAT((12 << MakeStream::from({3, 4, 5})) | to_vector(), 183 | ElementsAre(12 << 3, 12 << 4, 12 << 5)); 184 | } 185 | 186 | TEST(AlgebraTest, BitShiftRight) { 187 | EXPECT_THAT((MakeStream::from({3, 4}) >> MakeStream::from({5, 6})) | to_vector(), 188 | ElementsAre(3 >> 5, 4 >> 6)); 189 | EXPECT_THAT((MakeStream::from({3, 4, 5}) >> 12) | to_vector(), 190 | ElementsAre(3 >> 12, 4 >> 12, 5 >> 12)); 191 | EXPECT_THAT((12 >> MakeStream::from({3, 4, 5})) | to_vector(), 192 | ElementsAre(12 >> 3, 12 >> 4, 12 >> 5)); 193 | } 194 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(ExternalProject) 2 | 3 | externalproject_add(googlemock 4 | PREFIX "${CMAKE_BINARY_DIR}/gtest-1.7.0" 5 | URL "http://googlemock.googlecode.com/files/gmock-1.7.0.zip" 6 | URL_HASH SHA1=f9d9dd882a25f4069ed9ee48e70aff1b53e3c5a5 7 | INSTALL_COMMAND "") 8 | externalproject_get_property(googlemock source_dir binary_dir) 9 | 10 | include_directories("${source_dir}/include") 11 | include_directories("${source_dir}/gtest/include") 12 | link_directories("${binary_dir}") 13 | 14 | function(add_stream_test test_name) 15 | add_executable(${test_name} "${test_name}.cpp") 16 | add_dependencies(${test_name} googlemock) 17 | target_link_libraries(${test_name} gmock gmock_main) 18 | add_test(${test_name} ${test_name}) 19 | endfunction(add_stream_test) 20 | 21 | # Stream generators 22 | add_stream_test(EmptyTest) 23 | add_stream_test(SingletonTest) 24 | add_stream_test(RepeatTest) 25 | add_stream_test(CycleTest) 26 | add_stream_test(CounterTest) 27 | add_stream_test(RecurrenceTest) 28 | add_stream_test(RangeTest) 29 | add_stream_test(FromTest) 30 | 31 | # Stream operators 32 | add_stream_test(AlgebraTest) 33 | add_stream_test(FilterTest) 34 | add_stream_test(WhileTest) 35 | add_stream_test(SliceTest) 36 | add_stream_test(PeekTest) 37 | add_stream_test(MapTest) 38 | add_stream_test(FlatMapTest) 39 | add_stream_test(AdjacentDistinctTest) 40 | add_stream_test(AdjacentDifferenceTest) 41 | add_stream_test(PartialSumTest) 42 | add_stream_test(ConcatTest) 43 | add_stream_test(GroupTest) 44 | add_stream_test(OverlapTest) 45 | add_stream_test(ZipTest) 46 | add_stream_test(SetOperationsTest) 47 | add_stream_test(StatefulTest) 48 | 49 | # Stream terminators 50 | add_stream_test(AccessTest) 51 | add_stream_test(NumericReductionTest) 52 | add_stream_test(QuantifierTest) 53 | add_stream_test(ConversionTest) 54 | add_stream_test(ReduceTest) 55 | add_stream_test(SaveTest) 56 | add_stream_test(SampleTest) 57 | add_stream_test(ForEachTest) 58 | -------------------------------------------------------------------------------- /test/ConcatTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(ConcatTest, Stream) { 10 | EXPECT_THAT(MakeStream::from({1, 2, 3}) | concat(MakeStream::from({6, 7, 8})) | to_vector(), 11 | ElementsAre(1, 2, 3, 6, 7, 8)); 12 | } 13 | 14 | TEST(ConcatTest, Iterator) { 15 | std::vector v = {6, 7, 8}; 16 | EXPECT_THAT(MakeStream::from({1, 2, 3}) | concat(std::begin(v), std::end(v)) | to_vector(), 17 | ElementsAre(1, 2, 3, 6, 7, 8)); 18 | } 19 | -------------------------------------------------------------------------------- /test/ConversionTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(ConversionTest, ToVectorExplicit) { 10 | EXPECT_THAT(MakeStream::from({1, 3, 5}) | to_vector(), 11 | ElementsAre(1, 3, 5)); 12 | } 13 | 14 | TEST(ConversionTest, ToVectorImplicit) { 15 | std::vector implicit = MakeStream::from({1, 3, 5}); 16 | EXPECT_THAT(implicit, ElementsAre(1, 3, 5)); 17 | } 18 | 19 | TEST(ConversionTest, ToListExplicit) { 20 | EXPECT_THAT(MakeStream::from({1, 3, 5}) | to_list(), 21 | ElementsAre(1, 3, 5)); 22 | } 23 | 24 | TEST(ConversionTest, ToListImplicit) { 25 | std::list implicit = MakeStream::from({1, 3, 5}); 26 | EXPECT_THAT(implicit, ElementsAre(1, 3, 5)); 27 | } 28 | 29 | TEST(ConversionTest, ToDequeExplicit) { 30 | EXPECT_THAT(MakeStream::from({1, 3, 5}) | to_deque(), 31 | ElementsAre(1, 3, 5)); 32 | } 33 | 34 | TEST(ConversionTest, ToDequeImplicit) { 35 | std::deque implicit = MakeStream::from({1, 3, 5}); 36 | EXPECT_THAT(implicit, ElementsAre(1, 3, 5)); 37 | } 38 | 39 | TEST(ConversionTest, ToSetExplicit) { 40 | EXPECT_THAT(MakeStream::from({1, 5, 3, 3, 1}) | to_set(), 41 | ElementsAre(1, 3, 5)); 42 | } 43 | 44 | TEST(ConversionTest, ToSetImplicit) { 45 | std::set implicit = MakeStream::from({1, 5, 3, 3, 1}); 46 | EXPECT_THAT(implicit, ElementsAre(1, 3, 5)); 47 | } 48 | 49 | TEST(ConversionTest, ToMultiSetExplicit) { 50 | EXPECT_THAT(MakeStream::from({1, 5, 3, 3, 1}) | to_multiset(), 51 | ElementsAre(1, 1, 3, 3, 5)); 52 | } 53 | 54 | TEST(ConversionTest, ToMultiSetImplicit) { 55 | std::multiset implicit = MakeStream::from({1, 5, 3, 3, 1}); 56 | EXPECT_THAT(implicit, ElementsAre(1, 1, 3, 3, 5)); 57 | } 58 | 59 | TEST(ConversionTest, ToUnorderedSetExplicit) { 60 | EXPECT_THAT(MakeStream::from({1, 5, 3, 3, 1}) | to_unordered_set(), 61 | UnorderedElementsAre(1, 3, 5)); 62 | } 63 | 64 | TEST(ConversionTest, ToUnorderedSetImplicit) { 65 | std::unordered_set implicit = MakeStream::from({1, 5, 3, 3, 1}); 66 | EXPECT_THAT(implicit, UnorderedElementsAre(1, 3, 5)); 67 | } 68 | 69 | TEST(ConversionTest, ToUnorderedMultiSetExplicit) { 70 | EXPECT_THAT(MakeStream::from({1, 5, 3, 3, 1}) | to_unordered_multiset(), 71 | UnorderedElementsAre(1, 1, 3, 3, 5)); 72 | } 73 | 74 | TEST(ConversionTest, ToUnorderedMultimultisetImplicit) { 75 | std::unordered_multiset implicit = MakeStream::from({1, 5, 3, 3, 1}); 76 | EXPECT_THAT(implicit, UnorderedElementsAre(1, 1, 3, 3, 5)); 77 | } 78 | 79 | -------------------------------------------------------------------------------- /test/CounterTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(CounterTest, Start) { 10 | EXPECT_THAT(MakeStream::counter(-5) | limit(5) | to_vector(), 11 | ElementsAre(-5, -4, -3, -2, -1)); 12 | 13 | EXPECT_THAT(MakeStream::counter(3.0) | limit(5) | to_vector(), 14 | ElementsAre(3.0, 4.0, 5.0, 6.0, 7.0)); 15 | } 16 | 17 | TEST(CounterTest, Increment) { 18 | EXPECT_THAT(MakeStream::counter(0, 5) | limit(5) | to_vector(), 19 | ElementsAre(0, 5, 10, 15, 20)); 20 | 21 | 22 | EXPECT_THAT(MakeStream::counter(3.0, 1.5) | limit(5) | to_vector(), 23 | ElementsAre(3.0, 4.5, 6, 7.5, 9)); 24 | 25 | int increment = 5; 26 | const int& inc_ref = increment; 27 | EXPECT_THAT(MakeStream::counter(0, inc_ref) | limit(5) | to_vector(), 28 | ElementsAre(0, 5, 10, 15, 20)); 29 | } 30 | -------------------------------------------------------------------------------- /test/CycleTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(CycleTest, Iterator) { 10 | std::vector v = {1, 2, 3}; 11 | EXPECT_THAT( 12 | MakeStream::cycle(std::begin(v), std::end(v)) | limit(6) | to_vector(), 13 | ElementsAre(1, 2, 3, 1, 2, 3)); 14 | 15 | std::vector v2 = {1, 2}; 16 | EXPECT_THAT(MakeStream::cycle(std::begin(v2), std::end(v2), 2) | to_vector(), 17 | ElementsAre(1, 2, 1, 2)); 18 | } 19 | 20 | TEST(CycleTest, Container) { 21 | std::vector v = {1, 2, 3, 4}; 22 | EXPECT_THAT(MakeStream::cycle(v) | limit(7) | to_vector(), 23 | ElementsAre(1, 2, 3, 4, 1, 2, 3)); 24 | 25 | std::vector v2 = {1}; 26 | EXPECT_THAT(MakeStream::cycle(v2, 2) | to_vector(), ElementsAre(1, 1)); 27 | } 28 | 29 | TEST(CycleTest, InitializerList) { 30 | EXPECT_THAT(MakeStream::cycle({1, 2, 3}) | limit(5) | to_vector(), 31 | ElementsAre(1, 2, 3, 1, 2)); 32 | 33 | EXPECT_THAT(MakeStream::cycle({1, 2, 3}, 2) | to_vector(), 34 | ElementsAre(1, 2, 3, 1, 2, 3)); 35 | } 36 | 37 | TEST(CycleTest, CycleMove) { 38 | std::vector v = {1, 2, 3, 4}; 39 | EXPECT_THAT(MakeStream::cycle_move(std::move(v)) | limit(5) | to_vector(), 40 | ElementsAre(1, 2, 3, 4, 1)); 41 | 42 | EXPECT_THAT(MakeStream::cycle_move(std::vector{1, 2, 3}, 2) | to_vector(), 43 | ElementsAre(1, 2, 3, 1, 2, 3)); 44 | } 45 | -------------------------------------------------------------------------------- /test/EmptyTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(EmptyTest, MakeStream) { 10 | EXPECT_THAT(MakeStream::empty() | to_vector(), IsEmpty()); 11 | } 12 | 13 | TEST(EmptyTest, Constructor) { 14 | EXPECT_THAT(Stream() | to_vector(), IsEmpty()); 15 | } 16 | -------------------------------------------------------------------------------- /test/FilterTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | bool is_even_fn(int x) { 10 | return x % 2 == 0; 11 | } 12 | 13 | auto is_even_lambda = [](int x) { 14 | return x % 2 == 0; 15 | }; 16 | 17 | struct Number { 18 | Number(int value_) : value(value_) {} 19 | bool is_even() { return value % 2 == 0; } 20 | bool is_even_const() const { return value % 2 == 0; } 21 | 22 | bool operator== (const Number& other) const { 23 | return value == other.value; 24 | } 25 | 26 | int value; 27 | }; 28 | 29 | TEST(FilterTest, Function) { 30 | EXPECT_THAT(MakeStream::range(1, 5) | filter(is_even_fn) | to_vector(), 31 | ElementsAre(2, 4)); 32 | EXPECT_THAT(MakeStream::range(1, 5) | filter(is_even_lambda) | to_vector(), 33 | ElementsAre(2, 4)); 34 | } 35 | 36 | TEST(FilterTest, MemberFunction) { 37 | EXPECT_THAT(MakeStream::from({Number(1), Number(2), Number(3), Number(4)}) 38 | | filter(&Number::is_even_const) 39 | | to_vector(), 40 | ElementsAre(Number(2), Number(4))); 41 | 42 | EXPECT_THAT(MakeStream::from({Number(1), Number(2), Number(3), Number(4)}) 43 | | filter(&Number::is_even) 44 | | to_vector(), 45 | ElementsAre(Number(2), Number(4))); 46 | } 47 | 48 | TEST(FilterTest, BoolConversion) { 49 | Number n{1}; 50 | Number* null = nullptr; 51 | EXPECT_THAT(MakeStream::from({&n, null, &n}) | filter() | to_vector(), 52 | ElementsAre(&n, &n)); 53 | } 54 | -------------------------------------------------------------------------------- /test/FlatMapTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | struct Number { 10 | Number(int v) : value(v) {} 11 | 12 | Stream get_stream() const { return MakeStream::repeat(value, value); } 13 | 14 | int value; 15 | }; 16 | 17 | TEST(FlatMapTest, Function) { 18 | EXPECT_THAT(MakeStream::range(0, 4) 19 | | flat_map([](int x) { return MakeStream::repeat(x, x); }) 20 | | to_vector(), 21 | ElementsAre(1, 2, 2, 3, 3, 3)); 22 | } 23 | 24 | TEST(FlatMapTest, MemberFunction) { 25 | EXPECT_THAT(MakeStream::from({Number(1), Number(3), Number(2)}) 26 | | flat_map(&Number::get_stream) 27 | | to_vector(), 28 | ElementsAre(1, 3, 3, 3, 2, 2)); 29 | } 30 | -------------------------------------------------------------------------------- /test/ForEachTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | #define EXCEPTION_TEST(Operation, Exception) \ 10 | [](){ \ 11 | bool thrown = false; \ 12 | try { Operation; } catch(Exception& e) { thrown = true; } \ 13 | return thrown; \ 14 | }() 15 | 16 | #define EXPECT_EXCEPTION(Operation, Exception) \ 17 | EXPECT_THAT(EXCEPTION_TEST(Operation, Exception), Eq(true)); 18 | 19 | TEST(ForEachTest, Default) { 20 | std::vector result; 21 | MakeStream::range(1, 5) | for_each([&](int x) { result.push_back(x); }); 22 | EXPECT_THAT(result, ElementsAre(1, 2, 3, 4)); 23 | } 24 | 25 | template 26 | struct Accumulator { 27 | void operator() (T&& t) { 28 | result.emplace_back(std::forward(t)); 29 | } 30 | std::vector result; 31 | }; 32 | 33 | TEST(ForEachTest, Result) { 34 | Accumulator accum = MakeStream::range(1, 5) | for_each(Accumulator{}); 35 | EXPECT_THAT(accum.result, ElementsAre(1, 2, 3, 4)); 36 | } 37 | -------------------------------------------------------------------------------- /test/FromTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(FromTest, Iterator) { 10 | std::vector v = {1, 2, 3}; 11 | EXPECT_THAT(MakeStream::from(std::begin(v), std::end(v)) | to_vector(), 12 | ElementsAre(1, 2, 3)); 13 | } 14 | 15 | TEST(FromTest, Container) { 16 | std::vector v = {1, 2, 3}; 17 | EXPECT_THAT(MakeStream::from(v) | to_vector(), 18 | ElementsAre(1, 2, 3)); 19 | } 20 | 21 | TEST(FromTest, Array) { 22 | int array[3] = {1, 2, 3}; 23 | EXPECT_THAT(MakeStream::from(array, 3) | to_vector(), 24 | ElementsAre(1, 2, 3)); 25 | } 26 | 27 | TEST(FromTest, InitializerList) { 28 | EXPECT_THAT(MakeStream::from({1, 2, 3}) | to_vector(), 29 | ElementsAre(1, 2, 3)); 30 | } 31 | 32 | TEST(FromTest, FromMove) { 33 | std::vector v = {1, 2, 3}; 34 | EXPECT_THAT(MakeStream::from_move(std::move(v)) | to_vector(), 35 | ElementsAre(1, 2, 3)); 36 | } 37 | -------------------------------------------------------------------------------- /test/GroupTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(GroupTest, CompilePairs) { 10 | using G = std::pair; 11 | EXPECT_THAT(MakeStream::range(0, 6) | pairwise() | to_vector(), 12 | ElementsAre(G{0, 1}, G{2, 3}, G{4, 5})); 13 | EXPECT_THAT(MakeStream::range(0, 6) | group<2>() | to_vector(), 14 | ElementsAre(G{0, 1}, G{2, 3}, G{4, 5})); 15 | EXPECT_THAT(MakeStream::range(0, 5) | pairwise() | to_vector(), 16 | ElementsAre(G{0, 1}, G{2, 3})); 17 | } 18 | 19 | TEST(GroupTest, CompileTriples) { 20 | using G = std::tuple; 21 | EXPECT_THAT(MakeStream::range(0, 6) | group<3>() | to_vector(), 22 | ElementsAre(G{0, 1, 2}, G{3, 4, 5})); 23 | EXPECT_THAT(MakeStream::range(0, 7) | group<3>() | to_vector(), 24 | ElementsAre(G{0, 1, 2}, G{3, 4, 5})); 25 | EXPECT_THAT(MakeStream::range(0, 8) | group<3>() | to_vector(), 26 | ElementsAre(G{0, 1, 2}, G{3, 4, 5})); 27 | } 28 | 29 | 30 | TEST(GroupTest, CompileFourTuples) { 31 | using G = std::tuple; 32 | EXPECT_THAT(MakeStream::range(0, 8) | group<4>() | to_vector(), 33 | ElementsAre(G{0, 1, 2, 3}, G{4, 5, 6, 7})); 34 | } 35 | 36 | TEST(GroupTest, DynamicTriples) { 37 | using G = std::vector; 38 | EXPECT_THAT(MakeStream::range(0, 6) | group(3) | to_vector(), 39 | ElementsAre(G{0, 1, 2}, G{3, 4, 5})); 40 | EXPECT_THAT(MakeStream::range(0, 7) | group(3) | to_vector(), 41 | ElementsAre(G{0, 1, 2}, G{3, 4, 5})); 42 | EXPECT_THAT(MakeStream::range(0, 8) | group(3) | to_vector(), 43 | ElementsAre(G{0, 1, 2}, G{3, 4, 5})); 44 | } 45 | 46 | 47 | TEST(GroupTest, DynamicFourTuples) { 48 | using G = std::vector; 49 | EXPECT_THAT(MakeStream::range(0, 8) | group(4) | to_vector(), 50 | ElementsAre(G{0, 1, 2, 3}, G{4, 5, 6, 7})); 51 | } 52 | -------------------------------------------------------------------------------- /test/MapTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | int square(int num) { 10 | return num * num; 11 | } 12 | 13 | struct Number { 14 | Number(int v) : value(v) {} 15 | 16 | int get_value_const() const { return value; } 17 | int get_value() { return value; } 18 | 19 | bool operator== (const Number& other) const { 20 | return value == other.value; 21 | } 22 | 23 | int value = 0; 24 | }; 25 | 26 | TEST(MapTest, Function) { 27 | EXPECT_THAT(MakeStream::range(0, 5) | map_(square) | to_vector(), 28 | ElementsAre(0, 1, 4, 9, 16)); 29 | } 30 | 31 | TEST(MapTest, MemberFunction) { 32 | EXPECT_THAT(MakeStream::from({Number(1), Number(2), Number(3)}) 33 | | map_(&Number::get_value) 34 | | to_vector(), 35 | ElementsAre(1, 2, 3)); 36 | 37 | EXPECT_THAT(MakeStream::from({Number(1), Number(2), Number(3)}) 38 | | map_(&Number::get_value_const) 39 | | to_vector(), 40 | ElementsAre(1, 2, 3)); 41 | } 42 | -------------------------------------------------------------------------------- /test/NumericReductionTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | #define EXCEPTION_TEST(Operation, Exception) \ 10 | [](){ \ 11 | bool thrown = false; \ 12 | try { Operation; } catch(Exception& e) { thrown = true; } \ 13 | return thrown; \ 14 | }() 15 | 16 | #define EXPECT_EXCEPTION(Operation, Exception) \ 17 | EXPECT_THAT(EXCEPTION_TEST(Operation, Exception), Eq(true)); 18 | 19 | TEST(CountTest, Default) { 20 | EXPECT_THAT(MakeStream::range(0, 10) | count(), Eq(10)); 21 | EXPECT_THAT(MakeStream::empty() | count(), Eq(0)); 22 | } 23 | 24 | TEST(SumTest, NoIdentity) { 25 | EXPECT_THAT(MakeStream::from({3, 7}) | sum(), Eq(10)); 26 | EXPECT_EXCEPTION(MakeStream::empty() | sum(), EmptyStreamException); 27 | } 28 | 29 | TEST(SumTest, Identity) { 30 | EXPECT_THAT(MakeStream::from({3, 7}) | sum(5), Eq(15)); 31 | EXPECT_THAT(MakeStream::empty() | sum(0), Eq(0)); 32 | } 33 | 34 | TEST(ProductTest, NoIdentity) { 35 | EXPECT_THAT(MakeStream::closed_range(1, 5) | product(), Eq(120)); 36 | EXPECT_EXCEPTION(MakeStream::empty() | product(), EmptyStreamException); 37 | } 38 | 39 | TEST(ProductTest, Identity) { 40 | EXPECT_THAT(MakeStream::from({3, 7}) | product(0), Eq(0)); 41 | EXPECT_THAT(MakeStream::empty() | product(1), Eq(1)); 42 | } 43 | 44 | TEST(StatisticTest, Min) { 45 | EXPECT_THAT(MakeStream::from({3, -2, 8}) | min(), Eq(-2)); 46 | EXPECT_EXCEPTION(MakeStream::empty() | min(), EmptyStreamException); 47 | } 48 | 49 | TEST(StatisticTest, MinBy) { 50 | EXPECT_THAT(MakeStream::from({3, -2, 8}) | min_by([](auto x) { return -x; }), Eq(8)); 51 | EXPECT_EXCEPTION(MakeStream::empty() | min_by([](auto x) { return -x; }), EmptyStreamException); 52 | } 53 | 54 | TEST(StatisticTest, Max) { 55 | EXPECT_THAT(MakeStream::from({3, -2, 8}) | max(), Eq(8)); 56 | EXPECT_EXCEPTION(MakeStream::empty() | max(), EmptyStreamException); 57 | } 58 | 59 | TEST(StatisticTest, MaxBy) { 60 | EXPECT_THAT(MakeStream::from({3, -2, 8}) | max_by([](auto x) { return -x; }), Eq(-2)); 61 | EXPECT_EXCEPTION(MakeStream::empty() | max_by([](auto x) { return -x; }), EmptyStreamException); 62 | } 63 | 64 | TEST(StatisticTest, MinMax) { 65 | EXPECT_THAT(MakeStream::from({3, -2, 8}) | minmax(), Eq(std::make_pair(-2, 8))); 66 | EXPECT_EXCEPTION(MakeStream::empty() | minmax(), EmptyStreamException); 67 | } 68 | 69 | TEST(StatisticTest, MinMaxBy) { 70 | EXPECT_THAT(MakeStream::from({3, -2, 8}) | minmax_by([](auto x) { return -x; }), Eq(std::make_pair(8, -2))); 71 | EXPECT_EXCEPTION(MakeStream::empty() | minmax_by([](auto x) { return -x; }), EmptyStreamException); 72 | } 73 | -------------------------------------------------------------------------------- /test/OverlapTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(OverlapTest, CompileOrder2) { 10 | using T = NTuple; 11 | EXPECT_THAT(MakeStream::range(1, 5) | overlap<2>() | to_vector(), 12 | ElementsAre(T{1,2}, T{2,3}, T{3,4})); 13 | } 14 | 15 | TEST(OverlapTest, CompileOrder3) { 16 | using T = NTuple; 17 | EXPECT_THAT(MakeStream::closed_range(1, 5) | overlap<3>() | to_vector(), 18 | ElementsAre(T{1,2,3}, T{2,3,4}, T{3,4,5})); 19 | } 20 | 21 | TEST(OverlapTest, CompileOrder4) { 22 | using T = NTuple; 23 | EXPECT_THAT(MakeStream::closed_range(1, 6) | overlap<4>() | to_vector(), 24 | ElementsAre(T{1,2,3,4}, T{2,3,4,5}, T{3,4,5,6})); 25 | } 26 | 27 | TEST(OverlapTest, DynamicOrder2) { 28 | using T = std::deque; 29 | EXPECT_THAT(MakeStream::range(1, 5) | overlap(2) | to_vector(), 30 | ElementsAre(T{1,2}, T{2,3}, T{3,4})); 31 | } 32 | 33 | TEST(OverlapTest, DynamicOrder3) { 34 | using T = std::deque; 35 | EXPECT_THAT(MakeStream::closed_range(1, 5) | overlap(3) | to_vector(), 36 | ElementsAre(T{1,2,3}, T{2,3,4}, T{3,4,5})); 37 | } 38 | 39 | TEST(OverlapTest, DynamicOrder4) { 40 | using T = std::deque; 41 | EXPECT_THAT(MakeStream::closed_range(1, 6) | overlap(4) | to_vector(), 42 | ElementsAre(T{1,2,3,4}, T{2,3,4,5}, T{3,4,5,6})); 43 | } 44 | -------------------------------------------------------------------------------- /test/PartialSumTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(AdjacentDifferenceTest, Default) { 10 | EXPECT_THAT(MakeStream::closed_range(1, 6) 11 | | partial_sum() 12 | | to_vector(), 13 | ElementsAre(1, 3, 6, 10, 15, 21)); 14 | } 15 | 16 | TEST(AdjacentDifferenceTest, WithSubtraction) { 17 | EXPECT_THAT(MakeStream::closed_range(1, 6) 18 | | partial_sum(std::multiplies()) 19 | | to_vector(), 20 | ElementsAre(1, 2, 6, 24, 120, 720)); 21 | } 22 | -------------------------------------------------------------------------------- /test/PeekTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | struct Number { 10 | Number(int v) : value(v) {} 11 | 12 | void accumulate_const() const { 13 | elements.push_back(value); 14 | } 15 | 16 | void accumulate() { 17 | elements.push_back(value); 18 | } 19 | 20 | int value = 0; 21 | 22 | static std::vector elements; 23 | static void reset() { 24 | elements.clear(); 25 | } 26 | }; 27 | 28 | std::vector Number::elements = {}; 29 | 30 | TEST(PeekTest, Function) { 31 | std::vector values; 32 | MakeStream::range(0, 3) 33 | | peek([&](int x) { values.push_back(x); }) 34 | | sum(); 35 | EXPECT_THAT(values, ElementsAre(0, 1, 2)); 36 | } 37 | 38 | TEST(PeekTest, MemberFunction) { 39 | Number::reset(); 40 | MakeStream::from({Number(0), Number(1), Number(2)}) 41 | | peek(&Number::accumulate) 42 | | for_each([](Number n) { /* do nothing */ }); 43 | EXPECT_THAT(Number::elements, ElementsAre(0, 1, 2)); 44 | 45 | Number::reset(); 46 | MakeStream::from({Number(0), Number(1), Number(2)}) 47 | | peek(&Number::accumulate_const) 48 | | for_each([](Number n) { /* do nothing */ }); 49 | EXPECT_THAT(Number::elements, ElementsAre(0, 1, 2)); 50 | } 51 | -------------------------------------------------------------------------------- /test/QuantifierTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | bool is_even(int x) { 10 | return x % 2 ==0; 11 | } 12 | 13 | struct Number { 14 | Number(int v) : value(v) {} 15 | 16 | bool is_even() const { return value % 2 == 0; } 17 | 18 | int value; 19 | }; 20 | 21 | // Any 22 | 23 | TEST(AnyTest, Function) { 24 | EXPECT_THAT(MakeStream::from({1, 3, 4}) | any(is_even), Eq(true)); 25 | EXPECT_THAT(MakeStream::from({1, 3, 5}) | any(is_even), Eq(false)); 26 | EXPECT_THAT(MakeStream::empty() | any(is_even), Eq(false)); 27 | } 28 | 29 | TEST(AnyTest, MemberFunction) { 30 | EXPECT_THAT(MakeStream::from({Number(1), Number(2)}) | any(&Number::is_even), Eq(true)); 31 | EXPECT_THAT(MakeStream::from({Number(1), Number(3)}) | any(&Number::is_even), Eq(false)); 32 | } 33 | 34 | TEST(AnyTest, BoolConversion) { 35 | EXPECT_THAT(MakeStream::from({0, 3, 0}) | any(), Eq(true)); 36 | EXPECT_THAT(MakeStream::from({false, false}) | any(), Eq(false)); 37 | } 38 | 39 | // All 40 | 41 | TEST(AllTest, Function) { 42 | EXPECT_THAT(MakeStream::from({0, 2, 4}) | all(is_even), Eq(true)); 43 | EXPECT_THAT(MakeStream::from({2, 3, 4}) | all(is_even), Eq(false)); 44 | EXPECT_THAT(MakeStream::empty() | all(is_even), Eq(true)); 45 | } 46 | 47 | TEST(AllTest, MemberFunction) { 48 | EXPECT_THAT(MakeStream::from({Number(0), Number(2)}) | all(&Number::is_even), Eq(true)); 49 | EXPECT_THAT(MakeStream::from({Number(0), Number(1)}) | all(&Number::is_even), Eq(false)); 50 | } 51 | 52 | TEST(AllTest, BoolConversion) { 53 | EXPECT_THAT(MakeStream::from({3, 3, 3}) | all(), Eq(true)); 54 | EXPECT_THAT(MakeStream::from({false, true}) | all(), Eq(false)); 55 | } 56 | 57 | // None 58 | 59 | TEST(NoneTest, Function) { 60 | EXPECT_THAT(MakeStream::from({1, 3, 5}) | none(is_even), Eq(true)); 61 | EXPECT_THAT(MakeStream::from({2, 3, 5}) | none(is_even), Eq(false)); 62 | EXPECT_THAT(MakeStream::empty() | none(is_even), Eq(true)); 63 | } 64 | 65 | TEST(NoneTest, MemberFunction) { 66 | EXPECT_THAT(MakeStream::from({Number(1), Number(3)}) | none(&Number::is_even), Eq(true)); 67 | EXPECT_THAT(MakeStream::from({Number(0), Number(1)}) | none(&Number::is_even), Eq(false)); 68 | } 69 | 70 | TEST(NoneTest, BoolConversion) { 71 | EXPECT_THAT(MakeStream::from({0, 0, 0}) | none(), Eq(true)); 72 | EXPECT_THAT(MakeStream::from({false, true}) | none(), Eq(false)); 73 | } 74 | 75 | // Not all 76 | 77 | TEST(NotAllTest, Function) { 78 | EXPECT_THAT(MakeStream::from({2, 3, 4}) | not_all(is_even), Eq(true)); 79 | EXPECT_THAT(MakeStream::from({0, 2, 4}) | not_all(is_even), Eq(false)); 80 | EXPECT_THAT(MakeStream::empty() | not_all(is_even), Eq(false)); 81 | } 82 | 83 | TEST(NotAllTest, MemberFunction) { 84 | EXPECT_THAT(MakeStream::from({Number(0), Number(1)}) | not_all(&Number::is_even), Eq(true)); 85 | EXPECT_THAT(MakeStream::from({Number(0), Number(2)}) | not_all(&Number::is_even), Eq(false)); 86 | } 87 | 88 | TEST(NotAllTest, BoolConversion) { 89 | EXPECT_THAT(MakeStream::from({0, 0, 1}) | not_all(), Eq(true)); 90 | EXPECT_THAT(MakeStream::from({true, true}) | not_all(), Eq(false)); 91 | } 92 | -------------------------------------------------------------------------------- /test/RangeTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(RangeTest, Default) { 10 | EXPECT_THAT(MakeStream::range(0, 5) | to_vector(), 11 | ElementsAre(0, 1, 2, 3, 4)); 12 | } 13 | 14 | TEST(RangeTest, Increment) { 15 | EXPECT_THAT(MakeStream::range(0, 6, 3) | to_vector(), 16 | ElementsAre(0, 3)); 17 | 18 | EXPECT_THAT(MakeStream::range(0, 7, 3) | to_vector(), 19 | ElementsAre(0, 3, 6)); 20 | 21 | int increment = 5; 22 | const int& inc_ref = increment; 23 | EXPECT_THAT(MakeStream::range(0, 11, inc_ref) | to_vector(), 24 | ElementsAre(0, 5, 10)); 25 | } 26 | 27 | TEST(ClosedRangeTest, Default) { 28 | EXPECT_THAT(MakeStream::closed_range(0, 5) | to_vector(), 29 | ElementsAre(0, 1, 2, 3, 4, 5)); 30 | } 31 | 32 | TEST(ClosedRangeTest, Increment) { 33 | EXPECT_THAT(MakeStream::closed_range(0, 6, 3) | to_vector(), 34 | ElementsAre(0, 3, 6)); 35 | 36 | EXPECT_THAT(MakeStream::closed_range(0, 7, 3) | to_vector(), 37 | ElementsAre(0, 3, 6)); 38 | 39 | int increment = 5; 40 | const int& inc_ref = increment; 41 | EXPECT_THAT(MakeStream::closed_range(0, 11, inc_ref) | to_vector(), 42 | ElementsAre(0, 5, 10)); 43 | } 44 | -------------------------------------------------------------------------------- /test/RecurrenceTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(RecurrenceTest, Order1) { 10 | auto addone = [](int x) { return x + 1; }; 11 | EXPECT_THAT(MakeStream::recurrence(addone, 1) | limit(5) | to_vector(), 12 | ElementsAre(1, 2, 3, 4, 5)); 13 | 14 | } 15 | 16 | TEST(RecurrenceTest, Iterate) { 17 | auto addone = [](int x) { return x + 1; }; 18 | EXPECT_THAT(MakeStream::iterate(1, addone) | limit(5) | to_vector(), 19 | ElementsAre(1, 2, 3, 4, 5)); 20 | } 21 | 22 | TEST(RecurrenceTest, Order2) { 23 | EXPECT_THAT(MakeStream::recurrence(std::plus{}, 0, 1) | limit(8) | to_vector(), 24 | ElementsAre(0, 1, 1, 2, 3, 5, 8, 13)); 25 | } 26 | 27 | TEST(RecurrenceTest, Order3) { 28 | auto F = [](int a3, int a2, int a1) { 29 | return 2 * a3 + a2 + a1; 30 | }; 31 | EXPECT_THAT(MakeStream::recurrence(F, 1, 2, 3) | limit(8) | to_vector(), 32 | ElementsAre(1, 2, 3, 7, 14, 27, 55, 110)); 33 | } 34 | -------------------------------------------------------------------------------- /test/ReduceTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | using namespace std::string_literals; 9 | 10 | std::string int_concat(std::string&& s, int x) { 11 | std::stringstream ss; 12 | ss << s << x; 13 | return ss.str(); 14 | } 15 | 16 | std::string to_string(int x) { 17 | return int_concat("", x); 18 | } 19 | 20 | #define EXCEPTION_TEST(Operation, Exception) \ 21 | [](){ \ 22 | bool thrown = false; \ 23 | try { Operation; } catch(Exception& e) { thrown = true; } \ 24 | return thrown; \ 25 | }() 26 | 27 | #define EXPECT_EXCEPTION(Operation, Exception) \ 28 | EXPECT_THAT(EXCEPTION_TEST(Operation, Exception), Eq(true)); 29 | 30 | TEST(Reduce, NoIdentity) { 31 | EXPECT_THAT(MakeStream::range(1, 6) | reduce(std::plus{}), Eq(15)); 32 | EXPECT_EXCEPTION(MakeStream::empty() | reduce(std::plus{}), EmptyStreamException); 33 | } 34 | 35 | TEST(Reduce, IdentityFunction) { 36 | EXPECT_THAT(MakeStream::range(1, 6) | reduce(to_string, int_concat), Eq("12345"s)); 37 | EXPECT_EXCEPTION(MakeStream::empty() | reduce(to_string, int_concat), 38 | EmptyStreamException); 39 | } 40 | 41 | TEST(Reduce, SameTypeIdentity) { 42 | EXPECT_THAT(MakeStream::range(1, 6) | identity_reduce(1, std::multiplies{}), 43 | Eq(120)); 44 | EXPECT_THAT(MakeStream::empty() | identity_reduce(1, std::multiplies{}), 45 | Eq(1)); 46 | } 47 | 48 | TEST(Reduce, DiffTypeIdentity) { 49 | EXPECT_THAT(MakeStream::range(1, 6) | identity_reduce(""s, int_concat), 50 | Eq("12345"s)); 51 | EXPECT_THAT(MakeStream::empty() | identity_reduce("BLAH"s, int_concat), 52 | Eq("BLAH"s)); 53 | } 54 | -------------------------------------------------------------------------------- /test/RepeatTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(RepeatTest, Times) { 10 | EXPECT_THAT(MakeStream::repeat(42, 0) | to_vector(), IsEmpty()); 11 | EXPECT_THAT(MakeStream::repeat(42, 2) | to_vector(), ElementsAre(42, 42)); 12 | } 13 | 14 | TEST(RepeatTest, InfiniteTimes) { 15 | EXPECT_THAT(MakeStream::repeat(42) | limit(3) | to_vector(), ElementsAre(42, 42, 42)); 16 | } 17 | -------------------------------------------------------------------------------- /test/SampleTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | MATCHER_P2(IsBetween, a, b, 10 | std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) 11 | { return a <= arg && arg <= b; } 12 | 13 | #define EXCEPTION_TEST(Operation, Exception) \ 14 | [](){ \ 15 | bool thrown = false; \ 16 | try { Operation; } catch(Exception& e) { thrown = true; } \ 17 | return thrown; \ 18 | }() 19 | 20 | #define EXPECT_EXCEPTION(Operation, Exception) \ 21 | EXPECT_THAT(EXCEPTION_TEST(Operation, Exception), Eq(true)); 22 | 23 | TEST(SampleTest, RandomSample) { 24 | EXPECT_THAT(MakeStream::closed_range(1, 5) | random_sample(5), ElementsAre(1, 2, 3, 4, 5)); 25 | EXPECT_THAT(MakeStream::closed_range(1, 2) | random_sample(5), ElementsAre(1, 2)); 26 | EXPECT_THAT(MakeStream::empty() | random_sample(5), IsEmpty()); 27 | EXPECT_THAT(MakeStream::closed_range(1, 100) | random_sample(10), SizeIs(10)); 28 | } 29 | 30 | TEST(SampleTest, RandomElement) { 31 | EXPECT_THAT(MakeStream::singleton(1) | random_element(), Eq(1)); 32 | EXPECT_THAT(MakeStream::closed_range(1, 10) | random_element(), IsBetween(1, 10)); 33 | EXPECT_EXCEPTION(MakeStream::empty() | random_element(), EmptyStreamException); 34 | } 35 | -------------------------------------------------------------------------------- /test/SaveTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(SaveTest, CopyTo) { 10 | std::vector destination; 11 | MakeStream::range(1,6) | copy_to(std::back_inserter(destination)); 12 | EXPECT_THAT(destination, ElementsAre(1, 2, 3, 4, 5)); 13 | } 14 | 15 | TEST(SaveTest, MoveTo) { 16 | std::vector> destination; 17 | MakeStream::range(1, 3) 18 | | map_([](int x) { return std::make_unique(x); }) 19 | | move_to(std::back_inserter(destination)); 20 | EXPECT_THAT(destination, ElementsAre(Pointee(1), Pointee(2))); 21 | } 22 | 23 | TEST(SaveTest, PrintTo) { 24 | std::stringstream result; 25 | (MakeStream::closed_range(1, 3) | print_to(result, "|")) << "END"; 26 | EXPECT_THAT(result.str(), Eq("1|2|3|END")); 27 | } 28 | -------------------------------------------------------------------------------- /test/SetOperationsTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(SetOperationsTest, Merge) { 10 | EXPECT_THAT(MakeStream::from({1, 1, 2, 3, 3, 4}) 11 | | merge_with(MakeStream::from({2, 4, 4, 6})) 12 | | to_vector(), 13 | ElementsAre(1, 1, 2, 2, 3, 3, 4, 4, 4, 6)); 14 | } 15 | 16 | TEST(SetOperationsTest, Union) { 17 | EXPECT_THAT(MakeStream::from({1, 2, 3, 4, 5}) 18 | | union_with(MakeStream::from({2, 3, 4, 6, 7})) 19 | | to_vector(), 20 | ElementsAre(1, 2, 3, 4, 5, 6, 7)); 21 | } 22 | 23 | TEST(SetOperationsTest, Intersect) { 24 | EXPECT_THAT(MakeStream::from({1, 2, 3, 4, 5}) 25 | | intersect_with(MakeStream::from({2, 3, 4, 6, 7})) 26 | | to_vector(), 27 | ElementsAre(2, 3, 4)); 28 | } 29 | 30 | TEST(SetOperationsTest, Difference) { 31 | EXPECT_THAT(MakeStream::from({1, 2, 3, 4, 5}) 32 | | difference_with(MakeStream::from({2, 3, 4, 6, 7})) 33 | | to_vector(), 34 | ElementsAre(1, 5)); 35 | } 36 | 37 | TEST(SetOperationsTest, SymmetricDifference) { 38 | EXPECT_THAT(MakeStream::from({1, 2, 3, 4, 5}) 39 | | symmetric_difference_with(MakeStream::from({2, 3, 4, 6, 7})) 40 | | to_vector(), 41 | ElementsAre(1, 5, 6, 7)); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /test/SingletonTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(SingletonTest, Default) { 10 | EXPECT_THAT(MakeStream::singleton(5) | to_vector(), ElementsAre(5)); 11 | } 12 | -------------------------------------------------------------------------------- /test/SliceTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(SliceTest, Slice) { 10 | EXPECT_THAT(MakeStream::range(0, 10) | slice(0, 5) | to_vector(), 11 | ElementsAre(0, 1, 2, 3, 4)); 12 | EXPECT_THAT(MakeStream::range(0, 10) | slice(2, 8, 2) | to_vector(), 13 | ElementsAre(2, 4, 6)); 14 | EXPECT_THAT(MakeStream::range(0, 10) | slice(1, 8, 2) | to_vector(), 15 | ElementsAre(1, 3, 5, 7)); 16 | } 17 | 18 | TEST(SliceTest, SliceToEnd) { 19 | EXPECT_THAT(MakeStream::range(1, 11) | slice_to_end(5, 2) | to_vector(), 20 | ElementsAre(6, 8, 10)); 21 | EXPECT_THAT(MakeStream::range(0, 5) | slice_to_end(7, 10) | to_vector(), 22 | IsEmpty()); 23 | } 24 | 25 | TEST(SliceTest, Skip) { 26 | EXPECT_THAT(MakeStream::range(1, 8) | skip(3) | to_vector(), 27 | ElementsAre(4, 5, 6, 7)); 28 | EXPECT_THAT(MakeStream::range(1, 5) | skip(10) | to_vector(), 29 | IsEmpty()); 30 | EXPECT_THAT(MakeStream::empty() | skip(5) | to_vector(), 31 | IsEmpty()); 32 | } 33 | 34 | TEST(SliceTest, Limit) { 35 | EXPECT_THAT(MakeStream::counter(0) | limit(5) | to_vector(), 36 | ElementsAre(0, 1, 2, 3, 4)); 37 | EXPECT_THAT(MakeStream::range(0, 3) | limit(5) | to_vector(), 38 | ElementsAre(0, 1, 2)); 39 | EXPECT_THAT(MakeStream::empty() | limit(20) | to_vector(), 40 | IsEmpty()); 41 | } 42 | -------------------------------------------------------------------------------- /test/StatefulTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(StatefulTest, StatePoint) { 10 | std::vector result; 11 | MakeStream::range(0, 5) 12 | | peek([&](int x) { result.push_back(x); }) 13 | | state_point() 14 | | filter() 15 | | sum(); 16 | EXPECT_THAT(result, ElementsAre(0, 1, 2, 3, 4)); 17 | } 18 | 19 | TEST(StatefulTest, Sort) { 20 | EXPECT_THAT(MakeStream::from({1, 0, 3, 5, 8, 7, 9}) | sort() | to_vector(), 21 | ElementsAre(0, 1, 3, 5, 7, 8, 9)); 22 | } 23 | 24 | TEST(StatefulTest, Distinct) { 25 | EXPECT_THAT(MakeStream::from({1, 2, 1, 3, 3, 8, 5, 2, 8}) | distinct() | to_vector(), 26 | ElementsAre(1, 2, 3, 5, 8)); 27 | } 28 | -------------------------------------------------------------------------------- /test/WhileTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | bool less_than_5_fn(int x) { 10 | return x < 5; 11 | } 12 | 13 | auto less_than_5_lambda = [](int x) { 14 | return x < 5; 15 | }; 16 | 17 | struct Number { 18 | Number(int value_) : value(value_) {} 19 | bool less_than_5() { return value < 5; } 20 | bool less_than_5_const() const { return value < 5; } 21 | 22 | bool operator== (const Number& other) const { 23 | return value == other.value; 24 | } 25 | 26 | int value; 27 | }; 28 | 29 | TEST(TakeWhileTest, Function) { 30 | EXPECT_THAT(MakeStream::range(2, 8) | take_while(less_than_5_fn) | to_vector(), 31 | ElementsAre(2, 3, 4)); 32 | EXPECT_THAT(MakeStream::range(2, 8) | take_while(less_than_5_lambda) | to_vector(), 33 | ElementsAre(2, 3, 4)); 34 | } 35 | 36 | TEST(DropWhileTest, Function) { 37 | EXPECT_THAT(MakeStream::range(2, 8) | drop_while(less_than_5_fn) | to_vector(), 38 | ElementsAre(5, 6, 7)); 39 | EXPECT_THAT(MakeStream::range(2, 8) | drop_while(less_than_5_lambda) | to_vector(), 40 | ElementsAre(5, 6, 7)); 41 | } 42 | 43 | TEST(TakeWhileTest, MemberFunction) { 44 | EXPECT_THAT(MakeStream::from({Number(3), Number(4), Number(5), Number(6)}) 45 | | take_while(&Number::less_than_5) 46 | | to_vector(), 47 | ElementsAre(Number(3), Number(4))); 48 | 49 | EXPECT_THAT(MakeStream::from({Number(3), Number(4), Number(5), Number(6)}) 50 | | take_while(&Number::less_than_5_const) 51 | | to_vector(), 52 | ElementsAre(Number(3), Number(4))); 53 | } 54 | 55 | TEST(DropWhileTest, MemberFunction) { 56 | EXPECT_THAT(MakeStream::from({Number(3), Number(4), Number(5), Number(6)}) 57 | | drop_while(&Number::less_than_5) 58 | | to_vector(), 59 | ElementsAre(Number(5), Number(6))); 60 | 61 | EXPECT_THAT(MakeStream::from({Number(3), Number(4), Number(5), Number(6)}) 62 | | drop_while(&Number::less_than_5_const) 63 | | to_vector(), 64 | ElementsAre(Number(5), Number(6))); 65 | } 66 | 67 | TEST(TakeWhileTest, BoolConversion) { 68 | Number n{1}; 69 | Number* null = nullptr; 70 | EXPECT_THAT(MakeStream::from({&n, &n, null, &n}) | take_while() | to_vector(), 71 | ElementsAre(&n, &n)); 72 | } 73 | 74 | TEST(DropWhileTest, BoolConversion) { 75 | Number n{1}; 76 | Number* null = nullptr; 77 | EXPECT_THAT(MakeStream::from({&n, &n, null, &n}) | drop_while() | to_vector(), 78 | ElementsAre(null, &n)); 79 | } 80 | -------------------------------------------------------------------------------- /test/ZipTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace testing; 6 | using namespace stream; 7 | using namespace stream::op; 8 | 9 | TEST(ZipTest, EqualLength) { 10 | using Z = std::tuple; 11 | EXPECT_THAT(MakeStream::range(0, 3) | zip_with(MakeStream::range(3, 6)) | to_vector(), 12 | ElementsAre(Z(0, 3), Z(1, 4), Z(2, 5))); 13 | } 14 | 15 | TEST(ZipTest, UnequalLengths) { 16 | using Z = std::tuple; 17 | EXPECT_THAT(MakeStream::range(0, 5) | zip_with(MakeStream::range(3, 6)) | to_vector(), 18 | ElementsAre(Z(0, 3), Z(1, 4), Z(2, 5))); 19 | EXPECT_THAT(MakeStream::range(0, 3) | zip_with(MakeStream::range(3, 9)) | to_vector(), 20 | ElementsAre(Z(0, 3), Z(1, 4), Z(2, 5))); 21 | } 22 | 23 | TEST(ZipTest, MultiZips) { 24 | using Z3 = std::tuple; 25 | EXPECT_THAT(MakeStream::range(0, 3) 26 | | zip_with(MakeStream::range(3, 6)) 27 | | zip_with(MakeStream::range(6, 9)) 28 | | to_vector(), 29 | ElementsAre(Z3(0, 3, 6), Z3(1, 4, 7), Z3(2, 5, 8))); 30 | 31 | using Z4 = std::tuple; 32 | EXPECT_THAT(MakeStream::range(0, 2) 33 | | zip_with(MakeStream::range(2, 4)) 34 | | zip_with(MakeStream::range(4, 8)) 35 | | zip_with(MakeStream::range(8, 10)) 36 | | to_vector(), 37 | ElementsAre(Z4(0, 2, 4, 8) , Z4(1, 3, 5, 9))); 38 | } 39 | 40 | TEST(ZipTest, CustomZipper) { 41 | EXPECT_THAT(MakeStream::range(0, 5) 42 | | zip_with(MakeStream::repeat(2), std::plus()) 43 | | to_vector(), 44 | ElementsAre(2, 3, 4, 5, 6)); 45 | } 46 | --------------------------------------------------------------------------------