Skip to content

About

A header-only C++23 library for generating entities with extensible, user-defined components.

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Latest commit

 

History

64 Commits

Folders and files

Repository files navigation

Entity Generator for C++

Requires C++23 (e.g., -std=c++23 for GCC/Clang, /std:c++latest for MSVC).

Entity Generator for C++

GitHub license CI GitHub Releases C++23 Header-only Documentation

API Reference · Usage Guide · Releases

A small framework for generating entities from your own components, with dependencies, validation and replay.

Features

  • 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, and weighted_choice_component<T>. All accept an optional custom formatter.

  • Request-First API — entity_request carries component selection, group, batch count, entity validation and per-call inputs (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 a generation_observer interface with 15 lifecycle hooks. Multiple observers can be attached simultaneously via add_observer / remove_observer.

  • Extensions — dasmig::ext::stats_observer tracks 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, and entity.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 eg instances enable lock-free concurrent generation.

Integration

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.

Quick Start

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.

Building

# 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 docs

Compiler Support

Tested with:

  • Clang 18+ (-std=c++23)
  • GCC 14+ (-std=c++23)
  • MSVC 19.38+ (/std:c++latest)
  • Emscripten 3.1.74

Dependencies

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/

Related Libraries

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

License

This library is released under the MIT License.

MIT License

Copyright (c) 2020-2026 Diego Dasso Migotto

About

A header-only C++23 library for generating entities with extensible, user-defined components.

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Contributors

Languages