What is a Generator?

Generator<T>

T

random()

#include <cstdlib> struct RootRandomGen { long int operator () () const { return random(); } };

RootRandomGen

RAND_MAX

template <class T, class GenFunc> class Gen { GenFunc genfunc; public: explicit Gen(GenFunc func) : genfunc(std::move(func)) { } T generate() { return genfunc(); } };

template <class GenFunc> auto make_gen_from(GenFunc&& func) { return Gen<decltype(func()), GenFunc>(std::forward<GenFunc>(func)); }

make_gen_from

Gen<T>

decltype(func())

Gen<T>

make_gen<T>

template <class T> auto make_gen(); template <> auto make_gen<long int>() { return make_gen_from(RootRandomGen()); //return make_gen_from([]() { return random(); }); }

RootRandomGen

void init_random() { time_t t; time(&t); srandom(t); } int main(void) { init_random(); auto gen = make_gen<long int>(); std::cout << gen.generate(); // expect a random value. }

Gen<T>

The Generator<T> Functor

Gen<T>

template <class Gen, class Func> auto map (Gen gt, Func func) { return make_gen_from([gt, func]() { return func(gt.generate()); }); }

int main(void) { init_random(); auto gen = make_gen<long int>(); auto boolgen = map(gen, [](long int i) { return bool(i % 2); }); std::cout << std::boolalpha << boolgen.generate(); // expect a random boolean. }

Gen<T>

gt.generate()

Gen<T>::generate()

template <class Gen, class Func> auto map (Gen&& gt, Func&& func) { return make_gen_from([gt=std::forward<Gen>(gt), func=std::forward<Func>(func)]() mutable { return func(gt.generate()); }); }

Gen<T>

template <class T, class GenFunc> class Gen { GenFunc genfunc; public: explicit Gen(GenFunc func) : genfunc(std::move(func)) { } T generate() { return genfunc(); } template <class Func> auto map (Func&& func) { return make_gen_from([gt=*this, func=std::forward<Func>(func)]() mutable { return func(gt.generate()); }); } };

template <> auto make_gen<int>() { return make_gen<long int>().map([](long int i) { return static_cast<int>(i); }); }

template <class Integer> auto make_range_gen(Integer lo, Integer hi) { return make_gen<long int>().map( [lo, hi](long int x) { return static_cast<Integer>(lo + x % (hi - lo)); }); }

auto uppercase_gen = make_range_gen('A', 'Z'+1); std::cout << uppercase_gen.generate(); // expect a random uppercase character.

Combinators

Gen<T>

zip2

template <class T, class GenFunc> class Gen { // .... template <class UGen, class Zipper2> auto zip2(UGen&& ugen, Zipper2&& func) { return this->map( [ugen=std::forward<UGen>(ugen), func=std::forward<Zipper2>(func)](auto&& t) mutable { return func(std::forward<decltype(t)>(t), ugen.generate()); }); } }; auto uppergen = make_range_gen<char>('A', 'Z'+1); auto lowergen = make_range_gen<char>('a', 'z'+1); auto pairgen = uppergen.zip2(lowergen, [](char up, char low) { return std::make_pair(up, low); });

&std::make_pair<char, char>

template <> auto make_gen<std::string>() { auto char_gen = make_range_gen(32, 127); // printable characters. auto length_gen = make_range_gen(1, 256); return make_gen<bool>().zip2( length_gen, [char_gen](bool empty, int length) mutable { std::string str; if(!empty) { str.reserve(length); for(int i = 0; i < length; ++i) str.push_back(char_gen.generate()); } return str; }); }

single

oneOf

template <class T> auto make_single_gen(T&& t) { return make_gen_from([t=std::forward<T>(t)]() { return t; }); } template <class T> auto make_oneof_gen(std::initializer_list<T> list) { return make_range_gen(0ul, list.size()).map([list](int idx) { return *(list.begin()+idx); }); }

Stateful Generators

fibonacciGen

auto fiboGen() { int a = 0; int b = 1; return make_gen_from([a, b]() mutable { int c = a; a = b; b = c+b; return c; }); }

The Cost of Functional Design

extern "C" bool random_bool1() { return (random()-random()) > 0; } extern "C" bool random_bool2() { auto boolgen = make_gen<long int>() .zip2(make_gen<long int>(), [](long int i, long int j) { return (i-j) > 0; }); return boolgen.generate(); }

Generator size

random_bool2