Requires C++23 (e.g.,
-std=c++23for GCC/Clang,/std:c++latestfor MSVC).
API Reference · Usage Guide · Releases
A small framework for generating entities from your own components, with dependencies, validation and replay.
-
Core — Generate entities composed of user-defined components. Each component produces a typed random value accessible via
entity.get<T>(key). Register, remove, and generate with fluent chaining. -
Batch Generation. Generate thousands of entities from one seed, on several threads with the same output for any thread count, optionally unique by a key, and stream them as JSON Lines or CSV (see the usage guide).
-
Generic Components — Ready-made templates for common patterns:
constant_component<T>,choice_component<T>,range_component<T>,callback_component, andweighted_choice_component<T>. All accept an optional custom formatter. -
Request-First API —
entity_requestcarries component selection, group, batch count, entity validation and per-callinputs(a country, a reference date, ...) for each call. Generation methods accept(request)or(request, seed); setup stays on the instance. -
Dependencies & Fields — A component declares
depends_on(): a request pulls in what it needs, orders it, and skips a component whose dependency was skipped.field(key, fn)builds a component in one expression, with a label, formatter, JSON mapper, validator and condition. -
Randomness & Replay — Explicit per-call seeds and caller-owned deterministic sequences. Every entity and component stores its seed for full replay via seed signatures;
generate(request, e.seed())reproduces an entity with the same request and setup. -
Identical Everywhere — A seed gives the same entity on every compiler, standard library and CPU (GCC, Clang, MSVC, Emscripten; x86-64 and ARM64), checked by known-answer tests. Each component draws from its own stream, so adding a component does not change the others.
-
Advanced Generation — Batch generation (synchronous and concurrent), named component groups, selective generation by key subset, component weights for probabilistic inclusion, and conditional components for logic-driven inclusion via
should_generate(ctx). -
Validation & Hooks — Per-component
validate()with automatic retries, entity-level validator callbacks, and ageneration_observerinterface with 15 lifecycle hooks. Multiple observers can be attached simultaneously viaadd_observer/remove_observer. -
Extensions —
dasmig::ext::stats_observertracks generation counts, skips, retries, and failures out of the box. -
ECS Integration — Optional adapter headers for EnTT and Flecs. Register key→component mappings, then
spawn()converts generated entities into typed ECS entities. -
Serialization —
entity.to_string(),operator<<,entity.to_map()for structured key–value export, andentity.to_json()with typed values, arrays, objects, nested documents from dotted keys (identity.age), and a replay signature that covers the inputs and the data behind the components. -
Composable & Thread-Safe — Components can wrap name-generator and nickname-generator. Independent
eginstances enable lock-free concurrent generation.
entitygen.hpp is the library released here. Keep core.hpp and the core/ directory (dasmig-core) in the same directory. You need to add
#include <dasmig/entitygen.hpp>
// For convenience.
using eg = dasmig::eg;to the files you want to generate entities and set the necessary switches to enable C++23 (e.g., -std=c++23 for GCC and Clang).
Components draw random numbers from ctx.random() with the dasmig-core functions (dasmig::core::uniform_int, pick, bernoulli, ...), which give the same results on every platform. Version 2 changes every seeded result and the component random API; see Migrating from v1.
Define a component by implementing the component interface:
#include <dasmig/entitygen.hpp>
class character_class : public dasmig::component
{
public:
[[nodiscard]] std::wstring key() const override { return L"class"; }
[[nodiscard]] std::any generate(
const dasmig::generation_context& ctx) const override
{
static const std::vector<std::wstring> classes{
L"Warrior", L"Mage", L"Rogue", L"Healer"};
return dasmig::core::pick(ctx.random(), classes);
}
[[nodiscard]] std::wstring to_string(const std::any& value) const override
{
return default_to_string(value);
}
};
class age : public dasmig::component
{
public:
[[nodiscard]] std::wstring key() const override { return L"age"; }
[[nodiscard]] std::any generate(
const dasmig::generation_context& ctx) const override
{
return dasmig::core::uniform_int(ctx.random(), 18, 65);
}
[[nodiscard]] std::wstring to_string(const std::any& value) const override
{
return default_to_string(value);
}
};Register components and generate entities:
using eg = dasmig::eg;
eg::instance()
.add(std::make_unique<character_class>())
.add(std::make_unique<age>());
// Generate and stream.
std::wcout << eg::instance().generate({}) << std::endl;
// e.g. "class: Mage age: 34"
// Typed access.
auto entity = eg::instance().generate({});
std::wstring cls = entity.get<std::wstring>(L"class");
int char_age = entity.get<int>(L"age");
// Reproducible with a seed.
auto seeded = eg::instance().generate({}, 42);
// Reusable per-call selection.
dasmig::entity_request request{
.component_keys = std::vector<std::wstring>{L"class"}};
auto partial = eg::instance().generate(request, 42);
request.count = 3;
auto batch = eg::instance().generate_batch(request, 42);The positional generation overloads and generator seed / unseed and validator setters have been removed. See Migrating to the request-first API.
For the complete feature guide — component dependencies, custom types, seed signatures, batch generation, groups, weights, validation, event hooks, extensions, and more — see the Usage Guide.
For planned features — Python/Node.js/.NET wrappers and more — see the Roadmap.
# Example
make
# Tests
make test
# Targeted API, replay, selection, and validation tests (after building)
./build/test_runner "[request],[seed],[batch],[group],[validation],[kat]"
# Benchmarks (results in build/bench.tsv)
make bench
# Code coverage
make coverage
# API docs
make docsTested with:
- Clang 18+ (
-std=c++23) - GCC 14+ (
-std=c++23) - MSVC 19.38+ (
/std:c++latest) - Emscripten 3.1.74
| Dependency | Version | Bundled | Purpose |
|---|---|---|---|
| dasmig-core | 1.0 | Yes (core.hpp, core/) |
Platform-independent random engine and distributions, JSON |
| Catch2 | 3.x | Yes (amalgamated) | Unit testing |
| EnTT, Flecs | - | No | Only for the optional adapter headers in dasmig/ext/ |
| Library | Description |
|---|---|
| address-generator | Postal addresses with real streets by place |
| biodata-generator | Procedural human physical characteristics |
| birth-generator | Demographically plausible birthdays |
| city-generator | Weighted city selection by population |
| country-generator | Weighted country selection by population |
| email-generator | Email addresses in each country's style |
| interest-generator | Religion, hobbies and favourite media by country, age and sex |
| name-generator | Culturally appropriate full names |
| nickname-generator | Gamer-style nicknames |
| occupation-generator | Employment status, education and occupation by country, age and sex |
| persona-generator | Complete characters composed from the other generators |
| phone-generator | Phone numbers valid in each country's numbering plan |
| trait-generator | Personality traits with conflicts, synergies and Big Five axes |
This library is released under the MIT License.
MIT License
Copyright (c) 2020-2026 Diego Dasso Migotto
