{"id":50312444,"url":"https://github.com/aurimasniekis/cpp-commons","last_synced_at":"2026-05-28T22:01:35.038Z","repository":{"id":360245862,"uuid":"1249277680","full_name":"aurimasniekis/cpp-commons","owner":"aurimasniekis","description":"Header-only C++23 library of common/shared types for the C++ libraries","archived":false,"fork":false,"pushed_at":"2026-05-25T15:35:09.000Z","size":188,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-25T17:26:00.251Z","etag":null,"topics":["commons","cpp","cpp23"],"latest_commit_sha":null,"homepage":"https://aurimasniekis.github.io/cpp-commons/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aurimasniekis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-25T14:31:31.000Z","updated_at":"2026-05-25T15:35:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/aurimasniekis/cpp-commons","commit_stats":null,"previous_names":["aurimasniekis/cpp-commons"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/aurimasniekis/cpp-commons","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aurimasniekis%2Fcpp-commons","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aurimasniekis%2Fcpp-commons/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aurimasniekis%2Fcpp-commons/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aurimasniekis%2Fcpp-commons/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aurimasniekis","download_url":"https://codeload.github.com/aurimasniekis/cpp-commons/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aurimasniekis%2Fcpp-commons/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33627941,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["commons","cpp","cpp23"],"created_at":"2026-05-28T22:01:34.056Z","updated_at":"2026-05-28T22:01:35.028Z","avatar_url":"https://github.com/aurimasniekis.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Commons\n\n[![CI](https://github.com/aurimasniekis/cpp-commons/actions/workflows/ci.yml/badge.svg)](https://github.com/aurimasniekis/cpp-commons/actions/workflows/ci.yml)\n[![Docs](https://github.com/aurimasniekis/cpp-commons/actions/workflows/docs.yml/badge.svg)](https://aurimasniekis.github.io/cpp-commons/)\n\nA header-only C++23 library of small, shared building-block types — a\ncompile-time fixed-size string, Rust-flavoured fixed-width numeric aliases, an\nRGBA `Color` with full HSL/HSV manipulation and CSS/Material-UI palettes, an\nIconify `Icon` identifier, presentation metadata (`DisplayInfo`), a compile-time\nnamed-`Flag` system, a Spring-style `Prioritized` ordering toolkit,\n`SemVer` / `VersionConstraint` semantic-version types, and an `IOrigin`\nprovenance envelope. Every type carries optional nlohmann/json serialization that\nturns on by itself when the dependency is available. The namespace is `comms`;\nheaders live under `\u003ccommons/...\u003e`.\n\n## Why use this library?\n\n- **Good for** sharing one definition of common vocabulary types across several\n  projects instead of re-implementing them per repository.\n- **Good for** UI-adjacent backend code: colors, icons, and display metadata\n  that need to round-trip to JSON for a frontend.\n- **Light by default.** The core depends only on the C++23 standard library.\n  The JSON hooks stay completely inert unless nlohmann/json is on the include\n  path, so you never pay for an integration you don't use.\n- **Compile-time friendly.** `FixedString`, `Color`, and `Icon` are literal\n  types usable in `constexpr` and `static_assert` contexts and as non-type\n  template parameters.\n- **Not ideal for** large, hot containers: `PrioritizedSet` and `FlagSet` are\n  designed for config-sized collections and use linear-time lookups.\n- **Not ideal for** projects that cannot move to C++23 — the whole library\n  requires it.\n\n## Quick example\n\n```cpp\n#include \u003ccommons/commons.hpp\u003e\n\n#include \u003ciostream\u003e\n\nint main() {\n    namespace c = comms;\n\n    c::FixedString tag{\"order.created\"};   // compile-time string, usable as an NTTP\n    c::u32 count = 42;\n    c::f64 ratio = 1.0 / 3.0;\n\n    std::cout \u003c\u003c tag.view() \u003c\u003c \" x\" \u003c\u003c count \u003c\u003c \" (\" \u003c\u003c ratio \u003c\u003c \")\\n\";\n    std::cout \u003c\u003c \"commons \" \u003c\u003c c::version \u003c\u003c \"\\n\";\n}\n```\n\n`FixedString` is built with class template argument deduction (CTAD) straight\nfrom the literal, so you never spell its size. It is a *structural* type, which\nmeans it can also appear directly in a template argument list, e.g.\n`Event\u003c\"order.created\"\u003e`. The numeric aliases (`u32`, `f64`, …) are lowercase\nnames for the standard fixed-width types. Including `commons/commons.hpp` pulls\nin every core type plus the self-gating JSON hooks; it is always safe to include\neven when nlohmann/json is absent.\n\n## Installation\n\n`commons` is a header-only `INTERFACE` library. There is no compiled artifact to\nlink — you only need the headers on your include path and C++23 enabled.\n\nPackage-manager support (vcpkg, Conan, system packages) is not provided. The\nsupported integration paths are CMake, Meson, and copying the headers.\n\n### CMake — vendored subdirectory\n\nThe most reliable option: drop the repository into your tree (a submodule or\ncopy) and add it.\n\n```cmake\ncmake_minimum_required(VERSION 3.25)\nproject(example LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 23)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\n\nadd_subdirectory(third_party/commons)\n\nadd_executable(example main.cpp)\ntarget_link_libraries(example PRIVATE commons::commons)\n```\n\nLinking `commons::commons` brings the include directory and the `cxx_std_23`\nrequirement along with it.\n\n### CMake — FetchContent\n\n```cmake\ninclude(FetchContent)\n\nFetchContent_Declare(\n    commons\n    URL      https://github.com/aurimasniekis/cpp-commons/archive/refs/tags/v0.1.4.tar.gz\n    URL_HASH SHA256=511268a30e692e82365669738c734d093edc7ca76c898337125f032569c8f907\n    DOWNLOAD_EXTRACT_TIMESTAMP TRUE\n)\n\nFetchContent_MakeAvailable(commons)\n\ntarget_link_libraries(example PRIVATE commons::commons)\n```\n\nBy default no optional dependency is fetched: the JSON hooks auto-detect\nnlohmann/json. To *force* the integration on — which additionally fetches\nnlohmann/json (version 3.12.0 or newer) and hard-defines the gate macro —\nconfigure with `-DCOMMONS_WITH_NLOHMANN_JSON=ON`.\n\n### CMake — installed package\n\nAfter `cmake --install`, the package is consumable via `find_package`:\n\n```cmake\nfind_package(commons 0.1 REQUIRED)\ntarget_link_libraries(my_app PRIVATE commons::commons)\n```\n\nInstall rules are automatically disabled when nlohmann/json was fetched (a\nfetched dependency cannot be re-exported). For a clean install, leave\n`COMMONS_WITH_NLOHMANN_JSON=OFF` (the default) or provide nlohmann/json through a\nsystem package.\n\n### Meson\n\n```meson\ncommons_dep = dependency('commons', version: '\u003e=0.1.0',\n    fallback: ['commons', 'commons_dep'])\n```\n\nMeson options mirror the CMake ones: `-Djson=true|false`, `-Dtests=true|false`,\n`-Dexamples=true|false`. A `pkg-config` file is generated on install.\n\n### Manual / header-only\n\nCopy `include/commons` onto your include path and compile with C++23. The only\ngenerated header is `commons/version.hpp`: CMake and Meson produce it from\n`commons/version.hpp.in` using the project version. For a pure manual copy,\neither configure once with CMake/Meson and copy the generated\n`commons/version.hpp` alongside the rest, or create it by hand from the template\n(replace the four `@PROJECT_VERSION...@` tokens). It is only needed if you\ninclude the umbrella `commons/commons.hpp` or `commons/version.hpp` directly.\n\n## Requirements\n\n- **C++23.** The library uses structural non-type template parameters,\n  `constexpr` `std::string_view`, `std::format`, and concepts. CMake enforces\n  this with `target_compile_features(commons INTERFACE cxx_std_23)`.\n- **Build tooling:** CMake 3.25 or newer, or Meson 1.3.0 or newer. Neither is\n  required if you only copy the headers.\n- **Optional dependency:** [nlohmann/json](https://github.com/nlohmann/json)\n  3.12.0 or newer, which enables `\u003ccommons/json.hpp\u003e`.\n\n## Core concepts\n\n### `comms::FixedString\u003cN\u003e`\n\nA fixed-capacity string whose contents are fixed at compile time. `N` is the\nbuffer size *including* the trailing null terminator, so `size()` returns\n`N - 1`. Because it is a structural type, it can be a non-type template\nparameter.\n\n```cpp\n#include \u003ccommons/fixed_string.hpp\u003e\n\n#include \u003ciostream\u003e\n\ntemplate \u003ccomms::FixedString Name\u003e\nstruct Event {\n    static constexpr std::string_view name = Name.view();\n};\n\nint main() {\n    comms::FixedString id{\"login\"};   // N = 6 (5 chars + null), size() == 5\n    std::cout \u003c\u003c id.view() \u003c\u003c \" / \" \u003c\u003c id.size() \u003c\u003c \"\\n\";\n\n    static_assert(Event\u003c\"login\"\u003e::name == \"login\");\n}\n```\n\nIt converts implicitly to `std::string_view`, and `operator==` compares against\nany `FixedString\u003cM\u003e` (different sizes simply compare unequal).\n\n### `comms::Color`\n\nFour `u8` channels (`r`, `g`, `b`, `a`), with almost the entire API `constexpr`:\npacked-integer conversions, HSL/HSV conversion, channel and alpha tweaks, the\nHSL transforms, WCAG luminance/contrast, palette generation, and parsing. Only\nthe `std::string`-producing methods are non-`constexpr`. The default `Color` is\nopaque black.\n\n```cpp\n#include \u003ccommons/literals.hpp\u003e   // brings in color.hpp and the _color literal\n\n#include \u003ciostream\u003e\n\nint main() {\n    using comms::Color;\n    using namespace comms::literals;\n\n    constexpr Color indigo = \"#6366f1\"_color;   // compile-time hex literal\n    std::cout \u003c\u003c indigo.lighten(0.15).to_hex_string() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c indigo.complement().to_hex_string() \u003c\u003c \"\\n\";\n}\n```\n\n### `comms::Icon`\n\nA value type holding an Iconify `set:name` identifier (e.g. `mdi:abacus`) inline\nin a 64-byte buffer — no heap, trivially copyable, usable in `constexpr`\ncontexts. Construct it from a whole value or from the two parts; both validate.\n\n```cpp\n#include \u003ccommons/literals.hpp\u003e   // brings in icon.hpp and the _icon literal\n\n#include \u003ciostream\u003e\n\nint main() {\n    using namespace comms::literals;\n\n    constexpr comms::Icon cog = comms::Icon::from(\"mdi\", \"cog\");\n    constexpr comms::Icon home = \"mdi:home\"_icon;   // compile-time literal\n    std::cout \u003c\u003c cog.value() \u003c\u003c \" | \" \u003c\u003c cog.set() \u003c\u003c \" | \" \u003c\u003c cog.name() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c home.value() \u003c\u003c \"\\n\";\n}\n```\n\n### `comms::DisplayInfo`\n\nOptional presentation metadata — `name`, `description`, `icon`, `color`, every\nfield an `std::optional`. The intent is *static* data attached to a type once and\nnever mutated. The `icon`/`color` fields reuse `Icon`/`Color`, so they serialize\nto JSON for a frontend out of the box.\n\n### `comms::Flag` family\n\nCompile-time named flags grouped into categories, a runtime `FlagSet` that keeps\ninsertion order, a program-wide `GlobalFlagRegistry`, and mixins for types that\nown a flag set. Flags are *types*, declared (and optionally auto-registered) with\nthe `COMMONS_*_FLAG*` macros.\n\n### `comms::IOrigin`\n\nA polymorphic provenance envelope — *where a definition came from* — for an open\nset of sources. The `kind()` discriminator is a compile-time `FixedString`\ntemplate parameter: derive from `OriginKind\u003c\"yourkind\", YourType\u003e` and you get\n`kind()`, a deep `clone()`, and a `DisplayInfo`-backed `info()` (so every origin\nis also `Displayable`). Built-ins are `CoreOrigin`, `InternalOrigin`,\n`ExternalOrigin` (carrying a `source`), and `UnknownOrigin`; carry one as an\n`OriginPtr` (`std::unique_ptr\u003cIOrigin\u003e`). New kinds self-register into the\n`GlobalOriginRegistry` with `COMMONS_REGISTER_ORIGIN(Type)` — mirroring the flag\nregistry — so a JSON `kind` can be resolved back to the right type.\n\n### `comms::Prioritized`\n\nAttaches integer priorities to orderable things and sorts them deterministically,\nmirroring Spring's `Ordered`: **lower value sorts first** (higher precedence).\n`HIGHEST_PRECEDENCE` is `INT_MIN`, `LOWEST_PRECEDENCE` is `INT_MAX`, and the\nneutral `DEFAULT_PRIORITY` is `0`.\n\n### `comms::SemVer`\n\nA [Semantic Versioning 2.0.0](https://semver.org) value — `major.minor.patch`\nplus optional prerelease and build metadata. `SemVer::parse` is non-throwing\n(returns `std::optional`), accepts an optional `v` prefix, and parses partial\nversions leniently (`\"1\"`, `\"1.2\"`). Ordering implements the full §11 prerelease\nprecedence — a prerelease ranks below its release and numeric identifiers compare\nnumerically, so `1.0.0-alpha.2 \u003c 1.0.0-alpha.10 \u003c 1.0.0-beta \u003c 1.0.0` — while\nbuild metadata is preserved in the text form but ignored by comparison and\nequality. Because it holds `std::string` members it is a runtime type (not\n`constexpr`).\n\n### `comms::VersionConstraint`\n\nAn npm-style semver range that answers `satisfies(SemVer)`: `*`, an exact\nversion, the comparisons `\u003e=`/`\u003e`/`\u003c=`/`\u003c`/`!=`, caret (`^1.2.3` → `\u003e=1.2.3\n\u003c2.0.0`) and tilde (`~1.2.3` → `\u003e=1.2.3 \u003c1.3.0`) ranges, and space-separated\nintersections like `\u003e=1.0.0 \u003c2.0.0` (all must match). Unlike `SemVer::parse`,\n`VersionConstraint::parse` **throws** `std::invalid_argument` on a malformed\nsub-version.\n\n## Common usage patterns\n\n### Working with colors\n\n```cpp\n#include \u003ccommons/commons.hpp\u003e\n\n#include \u003cformat\u003e\n#include \u003ciostream\u003e\n#include \u003coptional\u003e\n\nint main() {\n    using comms::Color;\n\n    // Parsing returns std::optional — always check before dereferencing.\n    if (std::optional\u003cColor\u003e red = Color::parse(\"rgb(255 0 0)\")) {\n        std::cout \u003c\u003c red-\u003eto_hex_string() \u003c\u003c \"\\n\";          // #ff0000\n    }\n\n    // Named colors, hex, and HSL functional notation all parse.\n    std::cout \u003c\u003c Color::parse(\"rebeccapurple\")-\u003eto_hex_string() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c Color::parse(\"hsl(120, 100%, 50%)\")-\u003eto_hex_string() \u003c\u003c \"\\n\";\n\n    // Palettes from the CSS and Material-UI sets.\n    std::cout \u003c\u003c comms::Colors::css::indigo.to_hex_string() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c comms::Colors::mui::red_500.to_hex_string() \u003c\u003c \"\\n\";   // flat alias\n    std::cout \u003c\u003c comms::Colors::mui::red[700].to_hex_string() \u003c\u003c \"\\n\";  // indexed shade\n    std::cout \u003c\u003c comms::Colors::mui::blue.accent(200).to_hex_string() \u003c\u003c \"\\n\";\n\n    // WCAG: choose readable text and report contrast.\n    constexpr Color bg{0x63, 0x66, 0xf1};\n    const Color text = bg.readable_text_color();   // black or white\n    std::cout \u003c\u003c text.to_hex_string() \u003c\u003c \" contrast \"\n              \u003c\u003c bg.contrast_ratio(text) \u003c\u003c \"\\n\";\n\n    // std::format specs: h (lowercase hex, default), H (uppercase), r (CSS rgb).\n    std::cout \u003c\u003c std::format(\"{:H}\", bg) \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c std::format(\"{:r}\", bg.fade(0.5)) \u003c\u003c \"\\n\";\n}\n```\n\nThis covers the main paths: successful parsing (with the mandatory `optional`\ncheck), the palette accessors, the WCAG helpers, and the formatter specs.\n`fade(opacity)` takes a `[0, 1]` opacity and sets the alpha channel. Transforms\nsuch as `lighten`/`darken`/`saturate`/`rotate_hue` clamp their results, so they\nnever produce an out-of-range channel.\n\n\u003e **Pitfall — invalid shades throw.** `mui::red[shade]` accepts only\n\u003e `50, 100, 200, …, 900`, and `accent(shade)` only `100, 200, 400, 700`. Any\n\u003e other value throws `std::out_of_range`. The flat aliases (`red_500`, `red_a200`)\n\u003e cannot be misindexed, so prefer them for fixed shades.\n\n### Building and parsing icons\n\n```cpp\n#include \u003ccommons/icons.hpp\u003e   // opt-in predefined catalogs\n\n#include \u003ciostream\u003e\n\nint main() {\n    // Predefined Material Design Icons (only via \u003ccommons/icons.hpp\u003e).\n    constexpr comms::Icon abacus = comms::Icons::mdi::abacus;\n    std::cout \u003c\u003c abacus.value() \u003c\u003c \"\\n\";\n\n    // Keyword-named icons get a trailing underscore; the value is unchanged.\n    std::cout \u003c\u003c comms::Icons::mdi::delete_.value() \u003c\u003c \"\\n\";   // mdi:delete\n\n    // Non-throwing validation for runtime/untrusted input.\n    if (std::optional\u003ccomms::Icon\u003e icon = comms::Icon::parse(\"mdi:cog\")) {\n        std::cout \u003c\u003c \"valid: \" \u003c\u003c icon-\u003evalue() \u003c\u003c \"\\n\";\n    }\n    if (!comms::Icon::parse(\"not-an-icon\")) {\n        std::cout \u003c\u003c \"rejected (no single ':')\\n\";\n    }\n}\n```\n\nUse `Icon::parse` for runtime input — it returns `std::nullopt` on malformed\nvalues. Use `Icon::from` when you want a hard failure: it throws\n`std::invalid_argument` for a malformed value or `std::length_error` for one that\nexceeds the 64-byte capacity. In a `constexpr` context, either failure becomes a\ncompile error.\n\n\u003e **Pitfall — predefined catalogs are not in the umbrella.** The MDI table has\n\u003e 7,447 entries, so `commons/commons.hpp` does not include it. Add\n\u003e `#include \u003ccommons/icons.hpp\u003e` in the translation units that need\n\u003e `comms::Icons::mdi::...`.\n\n### Attaching display metadata to a type\n\nThere are two ways to attach `DisplayInfo`, and a concept to detect it.\n\n```cpp\n#include \u003ccommons/display_info.hpp\u003e\n\n#include \u003ciostream\u003e\n\n// 1) Intrusive: a static member returning a reference.\nstruct Widget {\n    static const comms::DisplayInfo\u0026 display_info() {\n        static const comms::DisplayInfo info{\n            .name = \"Widget\",\n            .icon = comms::Icon::from(\"mdi:widgets\"),\n            .color = comms::Colors::css::indigo,\n        };\n        return info;\n    }\n};\n\n// A third-party enum we cannot edit.\nenum class Severity { Info, Warning, Error };\n\n// 2) Non-intrusive: specialize the trait (in namespace comms).\ntemplate \u003c\u003e\nstruct comms::HasDisplayInfo\u003cSeverity\u003e {\n    static const DisplayInfo\u0026 display_info() {\n        static const DisplayInfo info{.name = \"Severity\",\n                                      .color = Colors::css::orange};\n        return info;\n    }\n};\n\ntemplate \u003ctypename T\u003e\n    requires comms::Displayable\u003cT\u003e\nvoid show(std::string_view label) {\n    const auto\u0026 d = comms::display_info\u003cT\u003e();\n    std::cout \u003c\u003c label \u003c\u003c \": \" \u003c\u003c d.name.value_or(\"(none)\") \u003c\u003c \"\\n\";\n}\n\nint main() {\n    show\u003cWidget\u003e(\"intrusive\");\n    show\u003cSeverity\u003e(\"trait\");\n\n    static_assert(!comms::Displayable\u003cstruct Plain\u003e);   // no metadata → not Displayable\n}\n```\n\n`comms::display_info\u003cT\u003e()` dispatches to whichever mechanism is present.\n`comms::Displayable\u003cT\u003e` reports whether either exists, so you can constrain\ntemplates on it. Calling `display_info\u003cT\u003e()` on a type that has neither is a\ncompile error, by design.\n\n### Declaring and collecting flags\n\n```cpp\n#include \u003ccommons/flag.hpp\u003e\n\n#include \u003ciostream\u003e\n\nnamespace {\nCOMMONS_FLAG_CATEGORY(Network, \"network\");\nCOMMONS_DEFINE_FLAG_IN(Ipv6, \"ipv6\", Network);        // defined + auto-registered\nCOMMONS_DEFINE_FLAG_IN(KeepAlive, \"keep-alive\", Network);\nCOMMONS_DEFINE_FLAG(Verbose, \"verbose\");              // default \"unset\" category\n\n// A builder that owns a FlagSet limited to Network flags and is readable\n// through the IHasFlags interface.\nclass Config : public comms::FlagBuilderGetters\u003cConfig, Network\u003e {};\n}  // namespace\n\nint main() {\n    comms::FlagSet set;\n    set.insert\u003cVerbose\u003e();\n    set.insert\u003cIpv6\u003e();\n    set.insert\u003cIpv6\u003e();   // duplicate by name — ignored, returns false\n\n    for (const auto\u0026 f : set) {                       // insertion order preserved\n        std::cout \u003c\u003c f.name \u003c\u003c \" [\" \u003c\u003c f.category \u003c\u003c \"]\\n\";\n    }\n\n    Config cfg;\n    cfg.flag\u003cIpv6\u003e().set_flag\u003cKeepAlive\u003e(true);       // fluent, returns Config\u0026\n    // cfg.flag\u003cVerbose\u003e();  // will not compile: Verbose is not in Network\n\n    const comms::IHasFlags\u0026 view = cfg;               // read polymorphically\n    std::cout \u003c\u003c \"has ipv6? \" \u003c\u003c view.has_flag\u003cIpv6\u003e() \u003c\u003c \"\\n\";\n\n    std::cout \u003c\u003c comms::GlobalFlagRegistry::instance().flags().size()\n              \u003c\u003c \" flags registered\\n\";\n}\n```\n\n`FlagSet` deduplicates by flag name and keeps insertion order; `insert` returns\n`false` when the name is already present. `group_by_category()` returns a\n`std::map` from category name to the flags in it. The `COMMONS_DEFINE_FLAG*`\nmacros register each flag into the `GlobalFlagRegistry` automatically; the\nbuilder mixins (`FlagBuilderMixin` for a private set, `FlagBuilderGetters` for an\nobservable one) constrain their typed overloads to the listed categories.\n\n### Ordering things by priority\n\n```cpp\n#include \u003ccommons/prioritized.hpp\u003e\n\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n\n// Carry a mutable priority via the CRTP builder mixin.\nstruct Adapter : comms::PrioritizedBuilder\u003cAdapter\u003e {\n    std::string name;\n    explicit Adapter(std::string n) : name(std::move(n)) {}\n};\n\nint main() {\n    Adapter fast(\"fast\");\n    fast.highest_priority();                 // fluent; sets INT_MIN\n    std::cout \u003c\u003c fast.name \u003c\u003c \" = \" \u003c\u003c fast.priority() \u003c\u003c \"\\n\";\n\n    // Attach a priority to any value. The FIRST argument is always the priority.\n    auto level = comms::with_priority(-5, 42);          // WithPriority\u003cint\u003e\n    std::cout \u003c\u003c *level \u003c\u003c \" @ \" \u003c\u003c level.priority() \u003c\u003c \"\\n\";\n\n    // A set that iterates in (priority asc, insertion-order asc) order.\n    comms::PrioritizedSet\u003cstd::string\u003e pipeline;\n    pipeline.insert(5, \"compress\");\n    pipeline.insert(1, \"auth\");\n    pipeline.insert(5, \"log\");               // ties with \"compress\" → insertion order\n    for (const auto\u0026 stage : pipeline) {\n        std::cout \u003c\u003c \"[\" \u003c\u003c pipeline.priority_of(stage) \u003c\u003c \"] \" \u003c\u003c stage \u003c\u003c \"\\n\";\n    }\n    // Prints auth (1), compress (5), log (5).\n}\n```\n\n`get_priority(x)` is a uniform, null-safe lookup that works on values,\nreferences, raw pointers, and smart pointers, falling back to `DEFAULT_PRIORITY`\nwhen no priority is discoverable. `PrioritizedCompare` and\n`LenientPrioritizedCompare\u003cT\u003e` order `std::shared_ptr`s for use as the comparator\nof a `std::set`.\n\n\u003e **Pitfall — `insert` never updates an existing priority.** Like `std::set`,\n\u003e re-inserting an equal value is a no-op; the originally stored priority stays.\n\u003e Use `set_priority(value, p)` to change it. Also note `PrioritizedSet`'s\n\u003e `insert`/`find`/`erase(value)` are O(n) — it targets config-sized collections,\n\u003e not large data sets.\n\n### Versions and constraints\n\n```cpp\n#include \u003ccommons/semver.hpp\u003e\n#include \u003ccommons/version_constraint.hpp\u003e\n\n#include \u003calgorithm\u003e\n#include \u003ciostream\u003e\n#include \u003cvector\u003e\n\nint main() {\n    // Parsing is non-throwing; a `v` prefix and partial versions are accepted.\n    comms::SemVer v = comms::SemVer::parse(\"v1.4.0-rc.1\").value();\n    std::cout \u003c\u003c v \u003c\u003c \"\\n\";                              // 1.4.0-rc.1\n\n    // Full SemVer ordering: prereleases sort below the release, and numeric\n    // identifiers compare numerically (alpha.2 \u003c alpha.10).\n    std::vector\u003ccomms::SemVer\u003e versions;\n    for (const auto* s : {\"1.0.0\", \"1.0.0-alpha.10\", \"1.0.0-alpha.2\", \"1.0.0-beta\"}) {\n        versions.push_back(comms::SemVer::parse(s).value());\n    }\n    std::ranges::sort(versions);\n    // -\u003e 1.0.0-alpha.2, 1.0.0-alpha.10, 1.0.0-beta, 1.0.0\n\n    // Range constraints answer satisfies(SemVer).\n    auto range = comms::VersionConstraint::parse(\"\u003e=1.2.0 \u003c2.0.0\");\n    std::cout \u003c\u003c std::boolalpha\n              \u003c\u003c range.satisfies(comms::SemVer::parse(\"1.5.0\").value()) \u003c\u003c \"\\n\";  // true\n}\n```\n\n`SemVer` works directly in `std::set`/`std::map`/`std::sort` (via its\n`operator\u003c=\u003e`) and in `std::unordered_*` (via the `std::hash` specialization);\nboth `SemVer` and `VersionConstraint` also support `std::format`, `operator\u003c\u003c`,\nand JSON.\n\n### JSON serialization (optional)\n\nWith nlohmann/json available, every public type gains `to_json`/`from_json`.\n\n```cpp\n// Build with -DCOMMONS_WITH_NLOHMANN_JSON=ON, or simply have nlohmann/json\n// on the include path.\n#include \u003ccommons/commons.hpp\u003e\n#include \u003ccommons/json.hpp\u003e\n\n#include \u003cnlohmann/json.hpp\u003e\n\n#include \u003ciostream\u003e\n\nint main() {\n    using json = nlohmann::json;\n\n    comms::FixedString id{\"order.created\"};\n    json j = id;                                   // -\u003e \"order.created\"\n    auto back = j.get\u003ccomms::FixedString\u003c14\u003e\u003e();   // round-trips\n\n    json color = comms::Colors::css::indigo;       // -\u003e \"#4b0082\" (hex string)\n    json icon  = comms::Icon::from(\"mdi:cog\");     // -\u003e \"mdi:cog\"\n\n    comms::cf64 signal{0.5, -1.25};\n    json sig = signal;                             // -\u003e [0.5, -1.25]\n\n    std::cout \u003c\u003c color.dump() \u003c\u003c \" \" \u003c\u003c icon.dump() \u003c\u003c \" \" \u003c\u003c sig.dump() \u003c\u003c \"\\n\";\n}\n```\n\nThe mappings are: `FixedString` and `Icon` ⇄ strings; `Color` ⇄ a hex string\n(`#RRGGBB`, or `#RRGGBBAA` when not opaque); `Hsl`/`Hsv` ⇄ objects; `DisplayInfo`\n⇄ an object with absent fields omitted; `FlagRef` ⇄ its name and `FlagSet` ⇄ an\narray of names; `SemVer` ⇄ its canonical version string and `VersionConstraint`\n⇄ its raw range string; `IOrigin`/`OriginPtr` ⇄ a `{\"kind\", …fields}` object\n(null `OriginPtr` ⇄ `null`), with the four built-in kinds round-tripping their\nfields and the `kind` resolved back through the `GlobalOriginRegistry` (an\nunknown kind throws; a custom kind brings its own `to_json`/`from_json`);\n`i128`/`u128` ⇄ decimal strings; the complex aliases ⇄\n`[real, imaginary]` arrays; `WithPriority\u003cT\u003e` ⇄ `{\"priority\":N,\"value\":\u003cT\u003e}` and\n`PrioritizedSet\u003cT\u003e` ⇄ a sorted array — both only when `T` is itself\nJSON-serializable.\n\n## Error handling\n\nThe library uses three distinct strategies, by type:\n\n- **`std::optional` for parsing.** `Color::parse`, `Color::parse_hex`, and\n  `Icon::parse` return `std::nullopt` on malformed input. Check before\n  dereferencing.\n- **Exceptions for hard failures.** `Icon::from` throws `std::invalid_argument`\n  (malformed) or `std::length_error` (too long). `Color`'s MUI shade accessors\n  (`operator[]`, `accent`) throw `std::out_of_range`. The `std::format`\n  specializations throw `std::format_error` on a bad spec. The JSON `from_json`\n  hooks throw nlohmann's exception type when a value is invalid (an unparseable\n  color, a string too long for a `FixedString`, an unregistered flag name, …).\n- **Compile-time errors.** The `_color` and `_icon` user-defined literals are\n  `consteval`, so a malformed literal fails to compile. `Icon::from` in a\n  `constexpr` context turns its throws into compile errors. Calling\n  `display_info\u003cT\u003e()` on a non-`Displayable` type is a compile error.\n\n```cpp\n#include \u003ccommons/color.hpp\u003e\n#include \u003ccommons/icon.hpp\u003e\n\n#include \u003ciostream\u003e\n\nint main() {\n    // optional path\n    if (auto c = comms::Color::parse(\"#zzzzzz\"); !c) {\n        std::cout \u003c\u003c \"bad color\\n\";\n    }\n\n    // exception path\n    try {\n        (void)comms::Icon::from(\"missing-colon\");\n    } catch (const std::invalid_argument\u0026 e) {\n        std::cout \u003c\u003c \"rejected: \" \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    }\n}\n```\n\n## Edge cases and pitfalls\n\n- **`FixedString` size counts the null terminator.** `FixedString{\"hi\"}` has\n  `N == 3` and `size() == 2`. When you need to name the type explicitly for JSON,\n  use the size *with* the terminator: a 13-character string round-trips through\n  `FixedString\u003c14\u003e`.\n- **`FixedString` JSON overflow throws.** Deserializing a string longer than the\n  fixed capacity is an error, not a silent truncation.\n- **Unchecked `parse` dereference is undefined behavior.** `Color::parse(...)`\n  and `Icon::parse(...)` return `std::optional`; calling `-\u003e` on a `nullopt`\n  result is UB. Always check.\n- **MUI shade accessors throw on bad shades.** See the color section above —\n  prefer the flat aliases (`red_500`) for compile-time-fixed shades.\n- **128-bit aliases may be absent.** `i128`/`u128` are only defined when the\n  compiler provides 128-bit integers. Guard their use with\n  `#if defined(COMMONS_HAS_INT128)`. They have no default `operator\u003c\u003c`; in JSON\n  they travel as decimal strings to avoid lossy narrowing.\n- **`PrioritizedSet` snapshots priority at insert.** Mutating an element's own\n  priority afterward does not reorder the set; use `set_priority`. `clear()` does\n  not reset the internal insertion-order counter.\n- **`PrioritizedSet` `from_json` needs recoverable priority.** Reading a set back\n  works only when `T` derives from `Prioritized` or is otherwise\n  `Prioritizable`; for a plain `T`, the set is serialize-only.\n- **`WithPriority\u003cT\u003e` flavor depends on `T`.** For a non-final class it inherits\n  `T` (a true *is-a* `T`); for final classes and fundamentals it composes,\n  exposing the value through `value()` / `operator*` / `operator-\u003e`. Either way,\n  the constructor's first argument is the priority.\n- **Flag registration order.** The `GlobalFlagRegistry` is populated at static\n  initialization; do not query it before `main`.\n\nThread safety is not documented. The value types (`FixedString`, `Color`,\n`Icon`, `DisplayInfo`) are plain data and safe to read concurrently when not\nmutated. `FlagSet`, `PrioritizedSet`, and the `GlobalFlagRegistry` are not\nsynchronized; treat concurrent mutation as unsafe.\n\n## API overview\n\n| Header                           | Provides                                                                                                                                                                                    |\n|----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `commons/commons.hpp`            | Umbrella header (all core types + JSON hooks).                                                                                                                                              |\n| `commons/version.hpp`            | Generated from `version.hpp.in` by the build: `COMMONS_VERSION_MAJOR/MINOR/PATCH/STRING` macros and the `comms::version` / `version_major` / `version_minor` / `version_patch` constants.   |\n| `commons/types.hpp`              | `i8`…`u64`, `f32`/`f64`, `usize`/`isize`, complex aliases (`cs8`…`cs64`, `cu8`…`cu64`, `cf32`/`cf64`), and `i128`/`u128` (gated by `COMMONS_HAS_INT128`).                                   |\n| `commons/fixed_string.hpp`       | `comms::FixedString\u003cN\u003e` — structural, NTTP-friendly fixed string.                                                                                                                           |\n| `commons/color.hpp`              | `comms::Color`, `comms::Hsl`/`comms::Hsv`, and `comms::Colors::css` / `comms::Colors::mui` palettes.                                                                                        |\n| `commons/icon.hpp`               | `comms::Icon` — an Iconify `set:name` identifier; `Icon::from` / `Icon::parse`.                                                                                                             |\n| `commons/icons.hpp`              | Opt-in predefined catalogs: `comms::Icons::mdi::...`. Not pulled by the umbrella.                                                                                                           |\n| `commons/literals.hpp`           | The `comms::literals` user-defined literals: `\"#6366f1\"_color` and `\"mdi:home\"_icon` (both `consteval`).                                                                                    |\n| `commons/display_info.hpp`       | `comms::DisplayInfo`, the `comms::HasDisplayInfo\u003cT\u003e` trait, free `comms::display_info\u003cT\u003e()`, and the `comms::Displayable\u003cT\u003e` concept.                                                       |\n| `commons/flag.hpp`               | `comms::Flag`/`FlagCategory`, `FlagRef`, `FlagSet`, `GlobalFlagRegistry`, the `IHasFlags`/`HasFlags`/`FlagBuilderMixin`/`FlagBuilderGetters` mixins, and the `COMMONS_*_FLAG*` macros.      |\n| `commons/origin.hpp`             | `comms::IOrigin`/`OriginPtr`, the `OriginKind\u003cFixedString, Derived\u003e` CRTP base, built-in `Core`/`Internal`/`External`/`Unknown` origins, `GlobalOriginRegistry`, `COMMONS_REGISTER_ORIGIN`. |\n| `commons/prioritized.hpp`        | `comms::Prioritized`, `get_priority`, the comparators, `PrioritizedSet\u003cT\u003e`, `PrioritizedBuilder\u003cDerived\u003e`, and `WithPriority\u003cT\u003e` / `with_priority` / `make_prioritized`.                    |\n| `commons/semver.hpp`             | `comms::SemVer` — a Semantic Versioning 2.0.0 value; non-throwing `SemVer::parse`, full §11 ordering, `std::hash`.                                                                          |\n| `commons/version_constraint.hpp` | `comms::VersionConstraint` — an npm-style semver range answering `satisfies(SemVer)`; `VersionConstraint::parse` throws on a malformed sub-version.                                         |\n| `commons/config.hpp`             | The `COMMONS_WITH_*` feature-gate macros.                                                                                                                                                   |\n| `commons/json.hpp`               | Optional nlohmann/json hooks (inert unless the dependency is present).                                                                                                                      |\n\n## Examples\n\nEach example is a self-contained program under `examples/`.\n\n| Example                             | Demonstrates                                                                                 |\n|-------------------------------------|----------------------------------------------------------------------------------------------|\n| `examples/hello.cpp`                | `FixedString`, the numeric aliases, and `version`.                                           |\n| `examples/color.cpp`                | Parsing, hex/CSS output, HSL transforms, palettes, WCAG, and the formatter specs.            |\n| `examples/icon.cpp`                 | Predefined icons, ad-hoc construction, the `set`/`name` accessors, and text output.          |\n| `examples/display_info.cpp`         | Intrusive and non-intrusive `DisplayInfo` attachment and the `Displayable` concept.          |\n| `examples/flag.cpp`                 | `FlagSet`, the global registry, and a category-constrained builder read through `IHasFlags`. |\n| `examples/origin.cpp`               | `IOrigin` kinds, `clone()`, the `DisplayInfo` description, and registry resolution by kind.  |\n| `examples/prioritized.cpp`          | The builder mixin, both `WithPriority` flavors, `PrioritizedSet`, and the comparators.       |\n| `examples/semver.cpp`               | Parsing, full-precedence sorting, `std::format`, and `VersionConstraint` range checks.       |\n| `examples/json_integration.cpp`     | The optional nlohmann/json round-trips (requires the integration).                           |\n| `examples/consumers/fetch_content/` | A standalone downstream project that pulls `commons` via FetchContent.                       |\n\n## Testing\n\nThe test suite uses GoogleTest. With the bundled `Makefile`:\n\n```bash\nmake test           # base library: configure + build + run ctest\nmake integrations   # same, with nlohmann/json forced on (runs the JSON tests)\nmake examples       # build and run every example\n```\n\nEquivalently, with raw CMake:\n\n```bash\ncmake -S . -B build\ncmake --build build\nctest --test-dir build\n```\n\nThe JSON tests (`tests/test_json.cpp`) are compiled only when the integration is\nenabled. With Meson:\n\n```bash\nmeson setup build-meson -Dtests=true -Dexamples=true\nmeson test -C build-meson\n```\n\nAdd `-Djson=true` to force the JSON integration under Meson.\n\n## FAQ\n\n**Do I need to link a library?** No. `commons` is header-only; linking\n`commons::commons` only adds the include path and the C++23 requirement.\n\n**What happens if I give `Color::parse` or `Icon::parse` bad input?** They return\n`std::nullopt`. The `from` factory on `Icon` throws instead, and the `_color`\nliteral fails to compile.\n\n**Can I use it in multiple threads?** Thread safety is not documented. The plain\nvalue types are safe to read concurrently; the registries and the mutable\ncollections are not synchronized.\n\n**Does `FixedString` own its characters?** Yes — it stores them inline. `view()`\nreturns a `std::string_view` into that storage, so do not let the view outlive\nthe `FixedString`.\n\n**Why won't `comms::Icons::mdi::...` compile?** Add\n`#include \u003ccommons/icons.hpp\u003e`; the predefined catalogs are intentionally left\nout of the umbrella header.\n\n**How do I get the JSON hooks?** Include `\u003ccommons/json.hpp\u003e` (or the umbrella,\nwhich includes it) and make sure `\u003cnlohmann/json.hpp\u003e` is reachable. To force the\ndependency to be fetched and linked, configure with\n`-DCOMMONS_WITH_NLOHMANN_JSON=ON` (CMake) or `-Djson=true` (Meson).\n\n## Contributing\n\nContributions to the library are welcome! If you encounter any issues or have suggestions for\nimprovements,\nplease feel free to submit a pull request or open an issue on the project's repository.\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faurimasniekis%2Fcpp-commons","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faurimasniekis%2Fcpp-commons","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faurimasniekis%2Fcpp-commons/lists"}