# rrgen: filling STL containers with uniformly distributed random values

> rrgen is a header-only C++ library that populates standard containers with random values drawn from the standard library's distribution engines, so the values follow a uniform integer distribution rather than coming from an ad hoc generator. It supports vector, list, array and stack, and is MIT licensed.

**josh0xA/rrgen** — A Header Only C++ Library for Storing Safe Pseudorandom Values into Modern Containers with Uniform Integer Distributions

- Repository: https://github.com/josh0xA/rrgen
- Stars: 560 · Forks: 103
- Language: C++
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/josh0xa-rrgen

## The problem is the hand rolled generator, not the container

rrgen was developed to combat insecure methods of storing random data into modern C++ containers, for example old and clunky PRNGs, and the solution is to use the STL's distribution engines in order to efficiently and safely store a random number distribution into a given C++ container. That framing is worth unpacking, because it identifies the actual failure mode. The problem is rarely the container, since a vector holds integers perfectly well. The problem is what you put in it, because a hand written generator usually means a modulo of a raw random value, a small state, a predictable sequence and a distribution that is not uniform over the range you asked for. The library takes the distribution out of your hands and out of the generator's, using the standard library engines so the value you request from a given range is actually uniform over that range, and then the container question becomes a separate, easy problem. The library is a single header, include/rrgen.hpp, with the classes and functions accessed by adding it to your project tree, and the primary language of the repository is C++.

## The API is a template on element type, container type and size

The example in the README shows the shape of the API, and it is consistent across all four supported containers. A generator is declared as an rrgen::rrand with three template parameters, the element type, the container type, and a size, and the second kind of generator is named for the container it produces, rrgen::rrand_array and rrgen::rrand_stack. The size is therefore part of the type, which means a generator for ten elements and one for five are different types and cannot be confused at a call site, and it also means the container can be a fixed size std::array rather than a dynamically sized one. The generation call takes a set of parameters, and in the examples the first two booleans are followed by the bounds of the range to draw from, so the values are uniform over the interval you give.

```cpp
#include "../include/rrgen.hpp"
#include <iostream>

int main(void)
{
    // Example usage for rrgen vector
    rrgen::rrand<float, std::vector, 10> rrvec;
    rrvec.gen_rrvector(false, true, 0, 10);
    for (auto &i : rrvec.contents())
    {
        std::cout << i << " ";
    } // ^ the same as rrvec.show_contents()
```

The contents accessor returns the underlying container, and the show_contents call is documented in the example as being the same thing, so the library lets you either pull the data out or print it. For the list the generation call additionally takes a placement argument, the example passing fside for front side insertion, which makes sense for a list where the insertion point changes the ordering of the elements. For the array the bounds are given directly, and for the stack the same uniform range is used with the values drawn from a larger interval in the example.

## A stack is read by popping, which is worth knowing before you use it

The stack example is the one that shows how the library expects a stack to be consumed, and it is the part of the API a user is most likely to trip over. The loop starts from xsize and counts down, and each iteration takes the top element with grab_top, prints it, and then removes it with pop_off.

```cpp
    // Example usage for rrgen stack 
    rrgen::rrand_stack<float, 10> rrstack;
    rrstack.gen_rrstack(false, true, 200, 1000);
    for (auto m = rrstack.xsize(); m > 0; m--)
    {
        std::cout << rrstack.grab_top() << " ";
        rrstack.pop_off();
        if (m == 1) { std::cout << '\n'; }
    } 
```

So the stack case is destructive by construction. There is no peek-then-iterate pattern here, and the values come out in reverse order of insertion, which is what a stack does. If you want to inspect a generated stack without emptying it, the contents accessor is the way, and you would then have to copy the values out before using the stack. The three other containers, vector, list and array, are non-destructive, since their values stay where they were put. The other detail visible in the stack example is the range, 200 to 1000 for a float, which is a wider interval than the integer examples use, and the resulting values are printed with a trailing space because the separator is in the stream call rather than in the data.

## Building it is a clone and a make, and the docs live in the repository

The installation is four steps and there is no package manager entry, no submodule and no dependency to resolve. You clone the repository, change into the rrgen directory, run make, and then add include/rrgen.hpp to your project tree for access to the library classes and functions. The make step matters less than it looks for a header-only library, since there is nothing to link, so what it produces is whatever the build does for examples and tests, and the actual deliverable you copy is the single header. The official documentation is rrgen/docs/index.rst, an reStructuredText file inside the repository rather than a hosted site, and the top level of the tree is small with a LICENSE, the README, a docs directory, an examples directory and the include directory. The example program lives in examples/examples.cc, and the example code in the README is the same usage, which means the README snippet is a genuine artefact of the repository rather than an illustration written for the README.

## The repository name is not what it was, and the release history is empty

There is a line at the end of the example that any adopter should read, that this is a transferred repository, from a completely unrelated project. That is unusual to state in a README, and it changes how the repository should be read. The name, the topic and the history of the tree may all predate the current library, so the earlier state of the project is probably something else entirely, and the commit history is unlikely to tell you why the current design is the way it is. What that means practically is that the documentation in the repository and the upstream project it came from may disagree, and the code is the only reliable source. Alongside that, the recent releases list is empty. The repository has no GitHub releases, the last push was on 2026-04-14, and the repository is not archived, so the code is still being worked on, but there is no tagged version to pin to and no changelog to read. The licence is MIT, with the copyright held by Josh Schiavone.

## Where rrgen is the wrong choice

The first limit is scope, and the README is clear about it. This is about uniform integer distributions in four standard containers, and the supported container list is std::vector, std::list, std::array and std::stack. If you need a normal distribution, a geometric one, a value from a range of a non-integer type beyond the float example, or a container that is not on that list, the library does not offer it. The second is that the design embeds a size in the type, which is a genuine C++ idiom and buys type safety between generators of different lengths, but it also means the size has to be a compile-time constant. A vector whose length is decided at runtime cannot be generated by this library without changing the type, which is a real constraint for code that sizes its buffers dynamically. The third is that the parameter list of the generation calls takes booleans whose meaning is only documented by example, and the example does not label them, so a user has to infer the semantics from the arguments and the ranges, and a wrong guess produces wrong data rather than a compile error. The fourth is the security framing, which needs care. The library uses the standard library's distribution engines, which are built on pseudorandom generators rather than on a cryptographic source, so the values are suitable for simulation, sampling and testing, and unsuitable for anything where predictability is a security problem, such as tokens, session identifiers or keys. The library is best read as a way to stop writing clumsy generators, not as a way to get secure randomness.

## Conclusion

Adopt rrgen if you need reproducible random data in standard containers and want the values to come from the standard library's distribution engines rather than from a hand rolled generator. Skip it if you need a specific distribution, since this one is about uniform integer values, or if you need cryptographic randomness, since a pseudorandom generator is not a random source. Verify first that the include path is added to your project, since the library ships as a single header, and that the container type and the size template parameter are set as you intend, since the size is part of the type.

## FAQ

### What does rrgen do and which containers does it support?

It is a header-only C++ library that uses the STL distribution engines to store a random number distribution into a given container, so that values are drawn uniformly from a range rather than produced by an ad hoc generator. The supported containers are std::vector, std::list, std::array and std::stack, and the library is included by adding include/rrgen.hpp to your project tree.

### How do I install and build rrgen?

Clone the repository with git clone https://github.com/josh0xA/rrgen.git, change into the rrgen directory, run make, and then add include/rrgen.hpp to your project tree. The official documentation is rrgen/docs/index.rst inside the repository, and the sample program is in examples/examples.cc.

### How is a generated stack read back in rrgen?

Destructively, as the example shows. You loop down from xsize, take the top element with grab_top, print it, and remove it with pop_off, so the values come out in reverse order of insertion and the stack ends empty. For the other containers the values are not removed, and contents() returns the container itself.

## Sources

- [Issues](https://github.com/josh0xA/rrgen/issues)
- [josh0xA/rrgen on GitHub](https://github.com/josh0xA/rrgen)
- [License: MIT](https://github.com/josh0xA/rrgen/blob/master/LICENSE)
- [README](https://github.com/josh0xA/rrgen/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/josh0xa-rrgen
