libzed 1.9.12
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
30 operator bool() const {
31 return !done;
32 }
33};
34
36template <typename T, typename S>
38 std::function<const yield<T>(S &)> lambda;
39 S state;
40 yield<T> current_yield;
41
42public:
49 explicit generatorIter(std::function<const yield<T>(S &)> lambda, const S &state, bool dummy = false) : lambda(lambda), state(state), current_yield({false, {}}) {
50 if (!dummy) {
51 ++(*this); // Load the first value
52 }
53 }
54
59 const T &operator*() const {
60 return current_yield.value;
61 }
62
68 current_yield = lambda(state);
69 return *this;
70 }
71
76 bool operator!=(const generatorIter &other) const {
77 (void)other;
78 return !current_yield.done;
79 }
80};
81
92template <typename T, typename S>
93class generator : public iterable<generatorIter<T, S>> {
94 S state;
95 std::function<const yield<T>(S &)> lambda;
96
97 struct countedState {
98 long count;
99 S state;
100 };
101
102public:
108 generator(const S &initial, std::function<const yield<T>(S &)> lambda) : state(initial), lambda(lambda) {}
109
115 return generatorIter<T, S>(lambda, state);
116 }
117
123 return generatorIter<T, S>(lambda, state, true);
124 }
125
133 inline yield<T> next() {
134 return lambda(state);
135 }
136
142 inline long count() {
143 return this
144 ->map<long>([](const T &state) {
145 (void)state;
146 return 1;
147 })
148 .reduce(0, std::plus<long>());
149 }
150
158 for (auto i : *this) {
159 result.push(i);
160 }
161 return result;
162 }
163
169 long consume() {
170 long count = 0;
171 for (auto _ : *this) {
172 count++;
173 }
174 return count;
175 }
176
188
189 for (int i = 0; i < count; i++) {
190 auto item = next();
191 if (item.done) {
192 break;
193 }
194 result.push(item.value);
195 }
196
197 return result;
198 }
199
210 template <typename U>
211 generator<U, S> map(std::function<U(const T &)> mapLambda) {
212 auto lambda = this->lambda;
213
214 return generator<U, S>(state, [lambda, mapLambda](S &state) {
215 auto item = lambda(state);
216 if (item.done) {
217 return yield<U>{true};
218 } else {
219 return yield<U>{false, mapLambda(item.value)};
220 }
221 });
222 }
223
234 generator filter(std::function<T(const T &)> filterLambda) {
235 auto lambda = this->lambda;
236
237 return generator(state, [lambda, filterLambda](S &state) {
238 auto val = lambda(state);
239 while (!val.done) {
240 if (filterLambda(val.value)) {
241 return val;
242 }
243 val = lambda(state);
244 }
245
246 return val;
247 });
248 }
249
263 T reduce(const T &defaultValue, std::function<T(const T &, const T &)> reduceLambda) {
264 auto result = lambda(state);
265
266 if (result.done) {
267 return defaultValue;
268 }
269
270 auto value = result.value;
271
272 while (true) {
273 result = lambda(state);
274 if (result.done) {
275 break;
276 }
277 value = reduceLambda(value, result.value);
278 }
279
280 return value;
281 }
282
294 generator &forEach(std::function<void(const T &)> newLambda) {
295 auto lambda = this->lambda;
296 this->lambda = [lambda, newLambda](S &state) {
297 auto item = lambda(state);
298 if (!item.done) {
299 newLambda(item.value);
300 }
301 return item;
302 };
303
304 return *this;
305 }
306
318 auto lambda = this->lambda;
319
320 return generator<T, countedState>({count, state}, [lambda](countedState &state) {
321 for (long i = 0; i < state.count; i++) {
322 auto item = lambda(state.state);
323 if (item.done) {
324 return item;
325 }
326 }
327 state.count = 0;
328
329 return lambda(state.state);
330 });
331 }
332
340 auto lambda = this->lambda;
341
342 return generator<T, countedState>({count, state}, [lambda](countedState &state) {
343 if (state.count <= 0) {
344 return yield<T>{true};
345 }
346
347 auto item = lambda(state.state);
348 if (item.done) {
349 return item;
350 }
351
352 state.count--;
353
354 return item;
355 });
356 }
357
367 template <typename U, typename S2>
369 typedef std::pair<T, U> pair_type;
370
372 auto item1 = next();
373 if (item1.done) {
374 return yield<pair_type>{true};
375 }
376
377 auto item2 = otherGen.next();
378 if (item2.done) {
379 return yield<pair_type>{true};
380 }
381
382 return yield<pair_type>{false, {item1.value, item2.value}};
383 });
384 }
385
394 generator<std::pair<long, T>, std::pair<long, generator<T, S>>> enumerate() {
395 return generator<std::pair<long, T>, std::pair<long, generator<T, S>>>({0, *this}, [](std::pair<long, generator<T, S>> &state) {
396 auto item = state.second.next();
397 if (item.done) {
398 return yield<std::pair<long, T>>{true};
399 }
400 return yield<std::pair<long, T>>{false, {state.first++, item.value}};
401 });
402 }
403
422 return generator<T, std::pair<generator, yield<T>>>({other, other.next()}, [this](std::pair<generator, yield<T>> &state) {
423 while (true) {
424 auto item1 = next();
425 if (item1.done) {
426 return yield<T>{true};
427 }
428
429 if (state.second.done) {
430 return yield<T>{false, item1.value}; // Yield the item from this generator, as the other generator is done
431 }
432
433 if (item1.value != state.second.value) {
434 return yield<T>{false, item1.value}; // Yield the item from this generator, as it is different
435 }
436
437 // Move to the next item in the other generator
438 state.second = state.first.next();
439 }
440 });
441 }
442
454 return generator<array<T>, generator>(*this, [chunkSize](generator &state) {
456 for (long i = 0; i < chunkSize; i++) {
457 auto item = state.next();
458 if (item.done) {
459 if (chunk.length() == 0) {
460 return yield<array<T>>{true}; // No more items, end the generator
461 }
462 break; // The chunk has data, yield it
463 }
464 chunk.push(item.value);
465 }
466 return yield<array<T>>{false, chunk}; // Return the current chunk
467 });
468 }
469
480 return generator<std::pair<T, yield<T>>, std::pair<yield<T>, generator>>({next(), *this}, [](std::pair<yield<T>, generator> &state) {
481 const auto prevValue = state.first;
482 auto &gen = state.second;
483
484 if (prevValue.done) {
485 // No more items, end the generator
486 return yield<std::pair<T, yield<T>>>{true};
487 }
488 auto nextValue = gen.next();
489 state.first = nextValue;
490
491 return yield<std::pair<T, yield<T>>>{false, std::pair<T, yield<T>>(prevValue.value, nextValue)};
492 });
493 }
494};
495
501template <typename T>
502using deref_type = std::remove_const_t<std::remove_reference_t<decltype(*std::declval<decltype(std::declval<T>().begin())>())>>;
503
509template <typename T>
510using iter_type = std::remove_const_t<decltype(std::declval<T>().begin())>;
511
518template <typename T>
520 return generator<deref_type<T>, iter_type<T>>(list.begin(), [&list](iter_type<T> &iter) {
521 if (iter != list.end()) {
522 auto ret = yield<deref_type<T>>{false, *iter};
523 ++iter; // Move to the next item
524 return ret;
525 }
526
527 return yield<deref_type<T>>{true};
528 });
529}
530
537template <typename T>
538generator<deref_type<T>, std::pair<T, iter_type<T>>> generatorFrom(const T &&list) {
539 return generator<deref_type<T>, std::pair<T, iter_type<T>>>({list, list.begin()}, [](std::pair<T, iter_type<T>> &state) {
540 if (state.second != state.first.end()) {
541 auto ret = yield<deref_type<T>>{false, *state.second};
542 ++state.second; // Move to the next item
543 return ret;
544 }
545
546 return yield<deref_type<T>>{true};
547 });
548}
549
556template <typename T>
557generator<T, std::pair<array<T>, long>> generatorFrom(std::initializer_list<T> list) {
558 return generator<T, std::pair<array<T>, long>>({list, 0}, [&list](std::pair<array<T>, long> &state) {
559 if (state.second < state.first.length()) {
560 return yield<T>{false, state.first[state.second++]};
561 }
562
563 return yield<T>{true};
564 });
565}
566
574template <typename K, typename V>
575generator<std::pair<K, V>, typename std::map<K, V>::const_iterator> generatorFrom(const std::map<K, V> &map) {
576 return generator<std::pair<K, V>, typename std::map<K, V>::const_iterator>(map.begin(), [&map](auto &iter) {
577 if (iter != map.end()) {
578 auto ret = yield<std::pair<K, V>>{false, *iter};
579 ++iter; // Move to the next item
580 return ret;
581 }
582
583 return yield<std::pair<K, V>>{true};
584 });
585}
586
594template <typename K, typename V>
595generator<std::pair<K, V>, std::pair<typename std::map<K, V>::const_iterator, std::map<K, V>>> generatorFrom(std::map<K, V> &&map) {
596 return generator<std::pair<K, V>, std::pair<typename std::map<K, V>::const_iterator, std::map<K, V>>>({map.begin(), map}, [](auto &state) {
597 if (state.first != state.second.end()) {
598 auto ret = yield<std::pair<K, V>>{false, *state.first};
599 ++state.first; // Move to the next item
600 return ret;
601 }
602
603 return yield<std::pair<K, V>>{true};
604 });
605}
606
607} // namespace core
608} // namespace z
A wrapper for std::vector.
Definition array.hpp:75
void increase(int newSize) noexcept
Increase the space allocated for this array.
Definition array.hpp:192
int push(const T &object) noexcept
Add an object to the array.
Definition array.hpp:242
int length() const noexcept override
Get the length of the array.
Definition array.hpp:1014
T * begin() const noexcept override
Get pointer to the beginning of the array.
Definition array.hpp:616
T * end() const noexcept override
Get pointer to the end of the array.
Definition array.hpp:628
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:1209
Custom iterator for generators to allow for range-based for loops.
Definition generator.hpp:37
bool operator!=(const generatorIter &other) const
Check if the generator can get more data.
Definition generator.hpp:76
generatorIter & operator++()
Generate the next value.
Definition generator.hpp:67
const T & operator*() const
Get the current value from the generator.
Definition generator.hpp:59
generatorIter(std::function< const yield< T >(S &)> lambda, const S &state, bool dummy=false)
Constructor.
Definition generator.hpp:49
An arbitrary generator for producing sequential results on-the-fly.
Definition generator.hpp:93
generator< std::pair< T, U >, generator< U, S2 > > zip(generator< U, S2 > &other)
Zip this generator with another generator.
Definition generator.hpp:368
generator< std::pair< long, T >, std::pair< long, generator< T, S > > > enumerate()
Enumerate the items in this generator.
Definition generator.hpp:394
array< T > collect()
Concatenate all generator elements into an array.
Definition generator.hpp:156
generator< T, countedState > limit(long count)
Limits the number of items that the generator will yield.
Definition generator.hpp:339
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:294
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:234
long count()
Get the total count of items that will be generated.
Definition generator.hpp:142
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:263
long consume()
Consume and discard all items from the generator.
Definition generator.hpp:169
generator< T, countedState > skip(long count)
Skips a certain number of items from the generator.
Definition generator.hpp:317
generator< std::pair< T, yield< T > >, std::pair< yield< T >, generator > > peek()
Allow peeking at the next item in the generator as items are generated.
Definition generator.hpp:479
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:211
generatorIter< T, S > end() const noexcept override
End iterator (end of the range)
Definition generator.hpp:122
yield< T > next()
Get the next item from the generator.
Definition generator.hpp:133
generator< array< T >, generator > chunk(long chunkSize)
Get chunks of items from the generator.
Definition generator.hpp:453
generatorIter< T, S > begin() const noexcept override
Begin iterator (start of the range)
Definition generator.hpp:114
array< T > take(int count)
Take a certain number of items from the generator.
Definition generator.hpp:185
generator< T, std::pair< generator, yield< T > > > diff(generator &other)
List the items in this generator which differ from another generator.
Definition generator.hpp:421
generator(const S &initial, std::function< const yield< T >(S &)> lambda)
Constructor with an initial state.
Definition generator.hpp:108
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:519
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:510
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:502
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