libzed 1.9.9
A general-purpose library for quick and simple data manipulation.
 
Loading...
Searching...
No Matches
generator.hpp
1#pragma once
2
3#include "array.hpp"
4#include <functional>
5#include <map>
6
7namespace z {
8namespace core {
9
18template <typename T>
19struct yield {
21 bool done;
22
25};
26
28template <typename T, typename S>
30 std::function<const yield<T>(S &)> lambda;
31 S state;
32 yield<T> current_yield;
33
34public:
41 explicit generatorIter(std::function<const yield<T>(S &)> lambda, const S &state, bool dummy = false) : lambda(lambda), state(state), current_yield({false, {}}) {
42 if (!dummy) {
43 ++(*this); // Load the first value
44 }
45 }
46
51 const T &operator*() const {
52 return current_yield.value;
53 }
54
60 current_yield = lambda(state);
61 return *this;
62 }
63
68 bool operator!=(const generatorIter &other) const {
69 (void)other;
70 return !current_yield.done;
71 }
72};
73
84template <typename T, typename S>
85class generator : public iterable<generatorIter<T, S>> {
86 S state;
87 std::function<const yield<T>(S &)> lambda;
88
89 struct countedState {
90 long count;
91 S state;
92 };
93
94public:
100 generator(const S &initial, std::function<const yield<T>(S &)> lambda) : state(initial), lambda(lambda) {}
101
107 return generatorIter<T, S>(lambda, state);
108 }
109
115 return generatorIter<T, S>(lambda, state, true);
116 }
117
125 inline yield<T> next() {
126 return lambda(state);
127 }
128
134 inline long count() {
135 return this
136 ->map<long>([](const T &state) {
137 (void)state;
138 return 1;
139 })
140 .reduce(0, std::plus<long>());
141 }
142
150 for (auto i : *this) {
151 result.push(i);
152 }
153 return result;
154 }
155
161 long consume() {
162 long count = 0;
163 for (auto _ : *this) {
164 count++;
165 }
166 return count;
167 }
168
180
181 for (int i = 0; i < count; i++) {
182 auto item = next();
183 if (item.done) {
184 break;
185 }
186 result.push(item.value);
187 }
188
189 return result;
190 }
191
202 template <typename U>
203 generator<U, S> map(std::function<U(const T &)> mapLambda) {
204 auto lambda = this->lambda;
205
206 return generator<U, S>(state, [lambda, mapLambda](S &state) {
207 auto item = lambda(state);
208 if (item.done) {
209 return yield<U>{true};
210 } else {
211 return yield<U>{false, mapLambda(item.value)};
212 }
213 });
214 }
215
226 generator filter(std::function<T(const T &)> filterLambda) {
227 auto lambda = this->lambda;
228
229 return generator(state, [lambda, filterLambda](S &state) {
230 auto val = lambda(state);
231 while (!val.done) {
232 if (filterLambda(val.value)) {
233 return val;
234 }
235 val = lambda(state);
236 }
237
238 return val;
239 });
240 }
241
255 T reduce(const T &defaultValue, std::function<T(const T &, const T &)> reduceLambda) {
256 auto result = lambda(state);
257
258 if (result.done) {
259 return defaultValue;
260 }
261
262 auto value = result.value;
263
264 while (true) {
265 result = lambda(state);
266 if (result.done) {
267 break;
268 }
269 value = reduceLambda(value, result.value);
270 }
271
272 return value;
273 }
274
286 generator &forEach(std::function<void(const T &)> newLambda) {
287 auto lambda = this->lambda;
288 this->lambda = [lambda, newLambda](S &state) {
289 auto item = lambda(state);
290 if (!item.done) {
291 newLambda(item.value);
292 }
293 return item;
294 };
295
296 return *this;
297 }
298
310 auto lambda = this->lambda;
311
312 return generator<T, countedState>({count, state}, [lambda](countedState &state) {
313 for (long i = 0; i < state.count; i++) {
314 auto item = lambda(state.state);
315 if (item.done) {
316 return item;
317 }
318 }
319 state.count = 0;
320
321 return lambda(state.state);
322 });
323 }
324
332 auto lambda = this->lambda;
333
334 return generator<T, countedState>({count, state}, [lambda](countedState &state) {
335 if (state.count <= 0) {
336 return yield<T>{true};
337 }
338
339 auto item = lambda(state.state);
340 if (item.done) {
341 return item;
342 }
343
344 state.count--;
345
346 return item;
347 });
348 }
349
359 template <typename U, typename S2>
361 typedef std::pair<T, U> pair_type;
362
364 auto item1 = next();
365 if (item1.done) {
366 return yield<pair_type>{true};
367 }
368
369 auto item2 = otherGen.next();
370 if (item2.done) {
371 return yield<pair_type>{true};
372 }
373
374 return yield<pair_type>{false, {item1.value, item2.value}};
375 });
376 }
377
386 generator<std::pair<long, T>, std::pair<long, generator<T, S>>> enumerate() {
387 return generator<std::pair<long, T>, std::pair<long, generator<T, S>>>({0, *this}, [](std::pair<long, generator<T, S>> &state) {
388 auto item = state.second.next();
389 if (item.done) {
390 return yield<std::pair<long, T>>{true};
391 }
392 return yield<std::pair<long, T>>{false, {state.first++, item.value}};
393 });
394 }
395
414 return generator<T, std::pair<generator, yield<T>>>({other, other.next()}, [this](std::pair<generator, yield<T>> &state) {
415 while (true) {
416 auto item1 = next();
417 if (item1.done) {
418 return yield<T>{true};
419 }
420
421 if (state.second.done) {
422 return yield<T>{false, item1.value}; // Yield the item from this generator, as the other generator is done
423 }
424
425 if (item1.value != state.second.value) {
426 return yield<T>{false, item1.value}; // Yield the item from this generator, as it is different
427 }
428
429 // Move to the next item in the other generator
430 state.second = state.first.next();
431 }
432 });
433 }
434
446 return generator<array<T>, generator>(*this, [chunkSize](generator &state) {
448 for (long i = 0; i < chunkSize; i++) {
449 auto item = state.next();
450 if (item.done) {
451 if (chunk.length() == 0) {
452 return yield<array<T>>{true}; // No more items, end the generator
453 }
454 break; // The chunk has data, yield it
455 }
456 chunk.push(item.value);
457 }
458 return yield<array<T>>{false, chunk}; // Return the current chunk
459 });
460 }
461};
462
468template <typename T>
469using deref_type = std::remove_const_t<std::remove_reference_t<decltype(*std::declval<decltype(std::declval<T>().begin())>())>>;
470
476template <typename T>
477using iter_type = std::remove_const_t<decltype(std::declval<T>().begin())>;
478
485template <typename T>
487 return generator<deref_type<T>, iter_type<T>>(list.begin(), [&list](iter_type<T> &iter) {
488 if (iter != list.end()) {
489 auto ret = yield<deref_type<T>>{false, *iter};
490 ++iter; // Move to the next item
491 return ret;
492 }
493
494 return yield<deref_type<T>>{true};
495 });
496}
497
504template <typename T>
505generator<deref_type<T>, std::pair<T, iter_type<T>>> generatorFrom(const T &&list) {
506 return generator<deref_type<T>, std::pair<T, iter_type<T>>>({list, list.begin()}, [](std::pair<T, iter_type<T>> &state) {
507 if (state.second != state.first.end()) {
508 auto ret = yield<deref_type<T>>{false, *state.second};
509 ++state.second; // Move to the next item
510 return ret;
511 }
512
513 return yield<deref_type<T>>{true};
514 });
515}
516
523template <typename T>
524generator<T, std::pair<array<T>, long>> generatorFrom(std::initializer_list<T> list) {
525 return generator<T, std::pair<array<T>, long>>({list, 0}, [&list](std::pair<array<T>, long> &state) {
526 if (state.second < state.first.length()) {
527 return yield<T>{false, state.first[state.second++]};
528 }
529
530 return yield<T>{true};
531 });
532}
533
541template <typename K, typename V>
542generator<std::pair<K, V>, typename std::map<K, V>::const_iterator> generatorFrom(const std::map<K, V> &map) {
543 return generator<std::pair<K, V>, typename std::map<K, V>::const_iterator>(map.begin(), [&map](auto &iter) {
544 if (iter != map.end()) {
545 auto ret = yield<std::pair<K, V>>{false, *iter};
546 ++iter; // Move to the next item
547 return ret;
548 }
549
550 return yield<std::pair<K, V>>{true};
551 });
552}
553
561template <typename K, typename V>
562generator<std::pair<K, V>, std::pair<typename std::map<K, V>::const_iterator, std::map<K, V>>> generatorFrom(std::map<K, V> &&map) {
563 return generator<std::pair<K, V>, std::pair<typename std::map<K, V>::const_iterator, std::map<K, V>>>({map.begin(), map}, [](auto &state) {
564 if (state.first != state.second.end()) {
565 auto ret = yield<std::pair<K, V>>{false, *state.first};
566 ++state.first; // Move to the next item
567 return ret;
568 }
569
570 return yield<std::pair<K, V>>{true};
571 });
572}
573
574} // namespace core
575} // namespace z
A wrapper for std::vector.
Definition array.hpp:72
void increase(int newSize) noexcept
Increase the space allocated for this array.
Definition array.hpp:189
int push(const T &object) noexcept
Add an object to the array.
Definition array.hpp:239
int length() const noexcept override
Get the length of the array.
Definition array.hpp:1011
T * begin() const noexcept override
Get pointer to the beginning of the array.
Definition array.hpp:613
T * end() const noexcept override
Get pointer to the end of the array.
Definition array.hpp:625
array< U > map(std::function< U(const T &)> lambda) const
Applies a transformation function to each element of the array and returns a new array with the resul...
Definition array.hpp:1206
Custom iterator for generators to allow for range-based for loops.
Definition generator.hpp:29
bool operator!=(const generatorIter &other) const
Check if the generator can get more data.
Definition generator.hpp:68
generatorIter & operator++()
Generate the next value.
Definition generator.hpp:59
const T & operator*() const
Get the current value from the generator.
Definition generator.hpp:51
generatorIter(std::function< const yield< T >(S &)> lambda, const S &state, bool dummy=false)
Constructor.
Definition generator.hpp:41
An arbitrary generator for producing sequential results on-the-fly.
Definition generator.hpp:85
generator< std::pair< T, U >, generator< U, S2 > > zip(generator< U, S2 > &other)
Zip this generator with another generator.
Definition generator.hpp:360
generator< std::pair< long, T >, std::pair< long, generator< T, S > > > enumerate()
Enumerate the items in this generator.
Definition generator.hpp:386
array< T > collect()
Concatenate all generator elements into an array.
Definition generator.hpp:148
generator< T, countedState > limit(long count)
Limits the number of items that the generator will yield.
Definition generator.hpp:331
generator & forEach(std::function< void(const T &)> newLambda)
Binds a function to run each time an item comes out of the generator.
Definition generator.hpp:286
generator filter(std::function< T(const T &)> filterLambda)
Filters the generatred items based on a predicate and returns a new generator that yields only the it...
Definition generator.hpp:226
long count()
Get the total count of items that will be generated.
Definition generator.hpp:134
T reduce(const T &defaultValue, std::function< T(const T &, const T &)> reduceLambda)
Reduces the generator to a single value by applying a binary operation cumulatively to all yielded va...
Definition generator.hpp:255
long consume()
Consume and discard all items from the generator.
Definition generator.hpp:161
generator< T, countedState > skip(long count)
Skips a certain number of items from the generator.
Definition generator.hpp:309
generator< U, S > map(std::function< U(const T &)> mapLambda)
Applies a transformation function to each item that comes out of the generator.
Definition generator.hpp:203
generatorIter< T, S > end() const noexcept override
End iterator (end of the range)
Definition generator.hpp:114
yield< T > next()
Get the next item from the generator.
Definition generator.hpp:125
generator< array< T >, generator > chunk(long chunkSize)
Get chunks of items from the generator.
Definition generator.hpp:445
generatorIter< T, S > begin() const noexcept override
Begin iterator (start of the range)
Definition generator.hpp:106
array< T > take(int count)
Take a certain number of items from the generator.
Definition generator.hpp:177
generator< T, std::pair< generator, yield< T > > > diff(generator &other)
List the items in this generator which differ from another generator.
Definition generator.hpp:413
generator(const S &initial, std::function< const yield< T >(S &)> lambda)
Constructor with an initial state.
Definition generator.hpp:100
A base interface for all objects that can be iterated over.
Definition iterable.hpp:10
generator< deref_type< T >, iter_type< T > > generatorFrom(const T &list)
Create a generator from an arbitrary iterable.
Definition generator.hpp:486
std::remove_const_t< decltype(std::declval< T >().begin())> iter_type
The type of the iterator for an iterable. This is used to determine the type of iterator that the gen...
Definition generator.hpp:477
std::remove_const_t< std::remove_reference_t< decltype(*std::declval< decltype(std::declval< T >().begin())>())> > deref_type
The type of the dereferenced value from an iterable. This is used to determine the type of value that...
Definition generator.hpp:469
The return value for generator functions.
Definition generator.hpp:19
T value
The next value that the generator will return.
Definition generator.hpp:24
bool done
Whether the generator has run out of values to return.
Definition generator.hpp:21