Skip to content

Building Custom Generator from Scratch

GenFunction<T> - Common representation for all generators for type T

All generators, including the default ones, share the same base function type. A generator can be a callable (function, functor, or lambda) with following common signature:

// (Random&) -> Shrinkable<T>

This can be represented as (or coerced to) a standard function type, std::function<Shrinkable<T>(Random&)>. In cppproptest, this function type is aliased as GenFunction<T>. We will use this term GenFunction throughout this page to refer the generator function type.

template <typename T>
using GenFunction = std::function<Shrinkable<T>(Random&);

By the way, you may have noticed a strange template type Shrinkable in this signature. You can refer to Shrinkable for its further detail, but it can be treated as a wrapper for type T for now. So a generator (Generator<T>) basically generates a value of type T from a random number generator of Random type. A generator can be defined as function, functor, or lambda, as following:

// lambda style
auto myIntGen = [](Random& rand) {
    int smallInt = rand.getRandomInt8();
    return make_shrinkable<int>(smallInt);
};

// function style
Shrinkable<int> myIntGen(Random& rand) {
    int smallInt = rand.getRandomInt8();
    return make_shrinkable<int>(smallInt);
}

// functor style
struct MyIntGen {
    Shrinkable<int> operator()(Random& rand) {
        int smallInt = rand.getRandomInt8();
        return make_shrinkable<int>(smallInt);
    }
};

Generator<T> - Decorator class for supercharging a generator

The template class Generator<T> is an abstract functor class that also coerces to GenFunction<T>. A Generator<T> gives access to some useful methods so that you can wrap your callable with this to decorate with those methods. As all accompanied generators and combinators of cppproptest produce decorated Generator<T>s, you can use the utility methods out-of-box.

// decorate a GenFunction with Generator<T>
auto myIntGen = Generator<int>([](Random& rand) {
    int smallInt = rand.getRandomInt8();
    return make_shrinkable<int>(smallInt);
});

// .filter and other utility methods can be used once the generator is decorated with Generator<T>
auto evenGen = myIntGen.filter([](int& value) {
    return value % 2 == 0;
}); // generates even numbers only

Last update: April 1, 2023