# gmp **Repository Path**: iggi128/gmp ## Basic Information - **Project Name**: gmp - **Description**: https://github.com/lkimuk/gmp.git - **Primary Language**: C++ - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-07 - **Last Updated**: 2026-09-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

GMP banner

License Language Last commit

Documentation: https://lkimuk.github.io/gmp/

- [Overview](#overview) - [Compiler Support](#compiler-support) - [Install](#install) - [Macro Metaprogramming](#macro-metaprogramming) - [Features](#features) - [Examples](#examples) - [Reflection Metaprogramming](#reflection-metaprogramming) - [Features](#features-1) - [Examples](#examples-1) - [Serialization](#serialization) - [Named Operators](#named-operators) - [Features](#features-2) - [Examples](#examples-2) - [Generic Design Patterns](#generic-design-patterns) - [Features](#features-3) - [Examples](#examples-3) - [Compile-time Tests](#compile-time-tests) - [Acknowledgments](#acknowledgments) ## Overview GMP is a header-only C++ metaprogramming library for compile-time programming and code generation. It provides five complementary layers: - **Macro metaprogramming**: Preprocessor utilities for boolean logic, arithmetic, tuple manipulation, loops, overload selection, and code generation. This layer is available in **C++11**. - **Reflection metaprogramming**: Compile-time utilities for fixed strings, type names, enum reflection, and aggregate member introspection. This layer requires **C++20**. - **Serialization**: Reflection-driven JSON and XML serialization and deserialization with structured errors and explicit customization escape hatches. - **Named operators**: Utilities for turning callables into custom infix operators with value-category-aware operand binding. This layer requires **C++20**. - **Generic design patterns**: Lightweight synchronization, singleton, and object-factory helpers for reusable generic infrastructure. This layer is available in **C++11**, with some conveniences improving under **C++20**. **Key Features** - **Header-only design**: Zero compilation required, just include and use - **Two-tier language support**: - Macro metaprogramming and generic design-pattern utilities require **C++11** - Reflection, serialization, and named-operator utilities require **C++20** - **Cross-platform**: Compatible with GCC, Clang, and MSVC - **Zero dependencies**: Pure standard C++, with no external dependencies - **Compile-time focused**: Designed for compile-time evaluation and code generation - **Broad coverage**: Includes macros, reflection, serialization, named operators, and reusable design-pattern components ## Compiler Support GMP provides feature sets with different compiler requirements: **Macro Metaprogramming and Generic Design Patterns** The macro metaprogramming utilities and the core design-pattern components should work correctly with **C++11** compilers and later. **Reflection Metaprogramming, Serialization, and Named Operators** The reflection, serialization, and named-operator utilities require **C++20** and the following compiler versions or newer: | Compiler | Minimum Version | |----------|-----------------| | MSVC | 19.37+ | | GCC | 11.1+ | | Clang | 18.1.0+ | ## Install **Try online quickly:** Compiler Explorer: [https://godbolt.org/z/W156818n5](https://godbolt.org/z/W156818n5) **Header-only version** Copy the [include](https://github.com/lkimuk/gmp/releases/download/v0.4.0/include.zip) folder to your build tree and include `gmp/gmp.hpp`. **CMake integration** Install system-wide and use CMake's `find_package`: ```bash $ git clone https://github.com/lkimuk/gmp.git $ cd gmp $ cmake -B ./build $ cmake --build ./build $ cmake --install ./build # sudo on Linux/macOS ``` ```cpp find_package(gmp 0.4.0 REQUIRED) target_link_libraries(your_target PRIVATE gmp::gmp) ``` ## Macro Metaprogramming ### Features #### Macro Utilities - **Boolean operations**: `GMP_BOOL`, `GMP_NOT`, `GMP_AND`, `GMP_OR`, `GMP_XOR`, `GMP_IMPLIES` - **Arithmetic macros**: `GMP_INC`, `GMP_DEC`, `GMP_ADD`, `GMP_SUB` - **Comparison macros**: `GMP_EQUAL_INT`, `GMP_GREATER_INT`, `GMP_GREATER_EQUAL_INT`, `GMP_LESS_INT`, `GMP_LESS_EQUAL_INT`, `GMP_EQUAL_INT_INDEPENDENT` - **Conditional macros**: `GMP_IF`, `GMP_IF_THEN_ELSE` - **Stringification**: `GMP_STRINGIFY`, `GMP_CONCAT`, `GMP_CONCATS` - **Variadic handling**: `GMP_SIZE_OF_VAARGS`, `GMP_GET_N`, `GMP_GET_FIRST_N`, `GMP_IS_EMPTY` - **Algorithms**: `GMP_MAX`, `GMP_MIN`, `GMP_MINMAX`, `GMP_MAXMIN`, `GMP_SWAP` - **Remove trailing comma**: `GMP_REMOVE_TRAILING_COMMA` - **Identifiers**: `GMP_IDENTIFIERS` #### Tuple Operations - **Size & Access**: `GMP_TUPLE_SIZE`, `GMP_GET_TUPLE` - **Modification**: `GMP_TUPLE_APPEND`, `GMP_TUPLE_PREPEND`, `GMP_TUPLE_CONCAT` - **Slicing**: `GMP_TUPLE_SKIP`, `GMP_TUPLE_TAKE` - **Detection**: `GMP_IS_TUPLE` #### Advanced Features - **Loop macros**: `GMP_REPEAT`, `GMP_WHILE`, `GMP_FOR_EACH`, `GMP_FOR_EACH_INDEPENDENT` - **Overload dispatch**: `GMP_OVERLOAD_INVOKE` - **Expansion control**: `GMP_EXPAND`, `GMP_EVAL`, `GMP_DEFER` - **Index sequences**: `GMP_MAKE_INDEX_SEQUENCE`, `GMP_RANGE` - **Namespace generation**: `GMP_GENERATE_NAMESPACES_BEGIN`, `GMP_GENERATE_NAMESPACES_END` ### Examples #### Macro Utilities ```cpp #include static_assert(GMP_BOOL(42) == 1, "Non-zero values are true"); static_assert(GMP_NOT(0) == 1, "NOT false is true"); static_assert(GMP_AND(1, 1) == 1, "Logical AND"); static_assert(GMP_OR(0, 1) == 1, "Logical OR"); static_assert(GMP_XOR(1, 0) == 1, "Logical XOR"); static_assert(GMP_INC(5) == 6, "Increment"); static_assert(GMP_DEC(8) == 7, "Decrement"); static_assert(GMP_ADD(2, 3) == 5, "Addition"); static_assert(GMP_SUB(10, 4) == 6, "Subtraction"); static_assert(GMP_EQUAL_INT(5, 5) == 1, "Equality check"); static_assert(GMP_GREATER_INT(7, 3) == 1, "Greater than"); static_assert(GMP_LESS_INT(2, 9) == 1, "Less than"); static_assert(GMP_MAX(3, 7) == 7, "Maximum value"); static_assert(GMP_MIN(10, 2) == 2, "Minimum value"); GMP_IF(1, expr) // expands to: expr GMP_IF_THEN_ELSE(0, expr1, expr2) // expands to: expr2 GMP_SIZE_OF_VAARGS(a, b, c) // expands to: 3 GMP_GET_N(1, a, b, c) // expands to: b GMP_IS_EMPTY() // expands to: 1 GMP_IS_TUPLE((a, b, c)) // expands to: 1 GMP_MINMAX(7, 3) // expands to: (3, 7) GMP_MAXMIN(7, 3) // expands to: (7, 3) GMP_SWAP(x, y) // expands to: y, x ``` #### Tuple Operations ```cpp GMP_TUPLE_SIZE((a, b, c, d, e)) // expands to: 5 GMP_TUPLE_TAKE(2, (a, b, c, d, e)) // expands to: (a, b) GMP_TUPLE_SKIP(2, (a, b, c, d, e)) // expands to: (c, d, e) GMP_TUPLE_APPEND((a, b, c), d) // expands to: (a, b, c, d) GMP_TUPLE_PREPEND((b, c, d), a) // expands to: (a, b, c, d) GMP_TUPLE_CONCAT((a, b), (c, d)) // expands to: (a, b, c, d) GMP_TUPLE_GET(1, (42, "hello", 3.14)) // expands to: "hello" ``` #### Advanced Features ```cpp #define PRINT(x) std::cout << x << " "; GMP_FOR_EACH(PRINT, 1, 2, 3) #define OVERLOAD_FUNCTION_0 "OVERLOAD_FUNCTION_0" #define OVERLOAD_FUNCTION_X_Y "OVERLOAD_FUNCTION_X_Y" GMP_OVERLOAD_INVOKE(OVERLOAD_FUNCTION, 0) // expands to: "OVERLOAD_FUNCTION_0" GMP_OVERLOAD_INVOKE(OVERLOAD_FUNCTION, X, Y) // expands to: "OVERLOAD_FUNCTION_X_Y" GMP_MAKE_INDEX_SEQUENCE(5) // expands to: 0, 1, 2, 3, 4 GMP_RANGE(5, 10) // expands to: 5, 6, 7, 8, 9 #define MYLIB_NAMESPACE_BEGIN GMP_GENERATE_NAMESPACES_BEGIN(mylib, parser) #define MYLIB_NAMESPACE_END GMP_GENERATE_NAMESPACES_END(mylib, parser) MYLIB_NAMESPACE_BEGIN MYLIB_NAMESPACE_END ``` ## Reflection Metaprogramming ### Features #### Compile-time Fixed String and Type Utilities - `fixed_string`: A compile-time string type whose content can be manipulated - `operator+(fixed_string, fixed_string)`: Concatenates two `fixed_string` values - `operator""_fs`: Creates `fixed_string` values from string literals - `to_fixed_string_v`: Converts an integer to `fixed_string` at compile time - `type_name()`: Returns the compiler-extracted name of `T` at compile time - `pretty_type_name()()`: Returns a more readable type name for supported standard types - `remove_all(constant_arg_t)`: Removes all occurrences of `Values...` from a `fixed_string` #### Utilities - `constant_arg_t`: Statically enforces the type of an NTTP compile-time argument - `constant_arg`: Statically enforces that `V` is a compile-time value - `any`: A type implicitly convertible to any type - `as_value()`: Defines a compile-time value of type `T` #### Enum Reflection - `enum_count()`: Returns the number of enumerators in an enumeration type at compile time - `enum_name()`: Returns the name of an enumerator at compile time - `enum_names()`: Returns all enumerator names of an enumeration type at compile time - `enum_values()`: Returns all enumerator values of an enumeration type at compile time - `enum_entries()`: Returns all enumerator `(value, name)` pairs at compile time - `enum_index(value)`: Returns the index of an enumerator within `enum_values()` - `enum_cast(name)`: Converts an enumerator name to `std::optional` - `enum_underlying(value)`: Returns the underlying integer value of an enumerator - `enum_contains(value)`: Tests whether an enumerator is reflected - `GMP_ENUM_RANGE(Enum, Min, Max)`: Customizes the scanned range for enum reflection - `GMP_ENUM_VALUES(Enum, ...)`: Supplies explicit enumerator values for enum reflection #### Aggregate Introspection - `member_count()`: Returns the number of members in an aggregate type at compile time - `member_count_v`: Inline constant containing the number of members - `reflectable`: Basic constraint for reflection candidates; reference helpers require aggregates without base classes or bit-fields - `member_name()`: Returns the name of the `I`-th member of a type at compile time - `member_names()`: Returns the names of all members of a type at compile time - `member_index(name)`: Finds a member index by name - `has_member(name)`: Tests whether a member name exists - `member_type_t`: Returns the type of the `I`-th member of an aggregate type - `member_type_names()`: Returns readable member type names of an aggregate type - `member_ref(obj)`: Returns a reference to the `I`-th member of an aggregate object - `tie_members(obj)`: Returns a tuple of references to all aggregate members - `apply_members(obj, fn)`: Calls a function with all aggregate members - `for_each_member(obj, fn)`: Visits each member of an aggregate object together with its name - `visit_member(obj, name, fn)`: Visits one member selected by name - `type_size()`: Returns the aggregate payload size excluding padding ### Examples #### Reflection Metaprogramming ```cpp #include #include #include #include #include #include struct Person { std::string name; int age; std::array scores; }; enum class Color { Red, Green, Blue }; int main() { constexpr auto type = gmp::type_name>(); constexpr auto pretty = gmp::pretty_type_name>()(); constexpr auto member_names = gmp::member_names(); constexpr auto member_types = gmp::member_type_names(); constexpr auto colors = gmp::enum_entries(); static_assert(gmp::member_count() == 3); static_assert(std::is_same_v, int>); static_assert(gmp::type_size() == sizeof(std::string) + sizeof(int) + sizeof(std::array)); std::cout << "== Type Info ==\n"; std::cout << "raw_type : " << type << "\n"; std::cout << "pretty_type : " << pretty << "\n"; std::cout << "first_member : " << member_names[0] << " -> " << member_types[0] << "\n"; std::cout << "\n== Enum Entries ==\n"; for (const auto& [value, name] : colors) { std::cout << static_cast(value) << " : " << name << "\n"; } Person person{ "Miles", 28, {95, 88, 91} }; std::cout << "\n== Person Members ==\n"; gmp::for_each_member(person, [](auto&& member_name, auto&& member_value) { using member_t = std::remove_cvref_t; if constexpr (std::is_same_v>) { std::cout << member_name << ": ["; for (std::size_t i = 0; i < member_value.size(); ++i) { if (i != 0) { std::cout << ", "; } std::cout << member_value[i]; } std::cout << "]\n"; } else { std::cout << member_name << ": " << member_value << "\n"; } }); gmp::member_ref<1>(person) = 29; auto color = gmp::enum_cast("Green"); std::cout << std::boolalpha; std::cout << "\n== Mutations ==\n"; std::cout << "updated_age : " << person.age << "\n"; std::cout << "enum_cast_success : " << color.has_value() << "\n"; } ``` On MSVC, the output is: ```cpp == Type Info == raw_type : std::vector,std::allocator >,std::allocator,std::allocator > > > pretty_type : std::vector first_member : name -> std::string == Enum Entries == 0 : Red 1 : Green 2 : Blue == Person Members == name: Miles age: 28 scores: [95, 88, 91] == Mutations == updated_age : 29 enum_cast_success : true ``` ## Serialization Reflected aggregates serialize recursively without registration or member tables: ```cpp struct person { std::string name; int age; std::optional nickname; }; person value{"Miles", 28, std::nullopt}; auto json = gmp::to_json(value); auto decoded = gmp::from_json(*json); auto xml = gmp::to_xml(value); auto xml_decoded = gmp::from_xml(*xml); ``` The archive-driven serialization layer also supports enums, strings, standard sequences and sets, arbitrary-key maps, tuples, variants, nested aggregates, structured errors, strict input/output limits, declarative `serialization_schema` field rules, and format-independent `serialization_traits` customization. JSON and XML output stream directly without constructing an intermediate DOM; `serialization_value` remains available as an optional value-tree backend. XML uses a versioned, type-preserving GMP document representation. This avoids guessing scalar types and preserves null values, signed and unsigned integers, empty field names, arbitrary-key maps, and variants. The parser accepts UTF-8 XML declarations and character references, rejects DTDs and external entities, and enforces the same depth, size, schema, and customization policies as JSON. ## Named Operators ### Features - Expressive operator-like DSL syntax: Enables playful and readable forms such as `^_^`, `<_>`, `+_+`, `*_*`, `-_-`, `/_/`, `%_%`, `&_&`, `|_|`, and `^o^` - `make_named_operator(...)`: Creates a token that turns a callable into a named operator - `GMP_GENERATE_NAMED_OPERATOR_PAIRS(...)`: Generates named-operator pairs from explicit operator tuples - `GMP_GENERATE_NAMED_OPERATOR_IDENTICAL_PAIRS(...)`: Generates named-operator pairs that use the same token on both sides - `GMP_DISABLE_DEFAULT_NAMED_OPERATORS`: Disables the default predefined named-operator pairs so custom sets can be supplied - Value-category-aware binding: Preserves lvalue/rvalue semantics for operands during operator composition - Default operator forms: `lhs ^op^ rhs`, `lhs rhs`, `lhs +op+ rhs`, `lhs *op* rhs`, `lhs -op- rhs`, `lhs /op/ rhs`, `lhs %op% rhs`, `lhs &op& rhs`, and `lhs |op| rhs` - Expression-style examples: `a ^_^ b`, `a <_> b`, `a +_+ b`, `a *_* b`, `a -_- b`, `a /_/ b`, `a %_% b`, `a &_& b`, `a |_| b`, `a *_^ b`, and `a ^o^ b` ### Examples #### Named Operators ```cpp #include #include #include int main() { int a = 10; int b = 3; auto _ = gmp::make_named_operator([](int x, int y) { return x + y; }); auto o = gmp::make_named_operator([](int x, int y) { return x * y; }); auto consume = gmp::make_named_operator([](std::unique_ptr p, int n) { return *p + n; }); assert((a ^_^ b) == 13); assert((a <_> b) == 13); assert((a +_+ b) == 13); assert((a *_* b) == 13); assert((a -_- b) == 13); assert((a /_/ b) == 13); assert((a %_% b) == 13); assert((a &_& b) == 13); assert((a |_| b) == 13); assert((a *_^ b) == 13); assert((a ^o^ b) == 30); assert((std::make_unique(40) ^consume^ 2) == 42); } ``` ## Generic Design Patterns ### Features - `singleton`: A CRTP-based singleton utility with optional long-lifetime support - `object_factory`: A singleton-based object factory for runtime registration and creation - `object_factory::contains(key)`: Tests whether a product key is registered - `object_factory::registered_keys()`: Returns registered product keys - `object_factory::try_create_unique(key, args...)`: Creates a product without throwing for an unknown key - `object_factory::try_create_shared(key, args...)`: Shared-pointer counterpart to `try_create_unique` - `GMP_DISABLE_CONSTRUCTION(Class)`: Disables direct construction for `singleton`-derived types - `GMP_FACTORY_REGISTER(...)`: Registers product types with `object_factory` ### Examples #### Generic Design Patterns ```cpp #include #include #include #include struct logger : gmp::singleton { void write(const std::string& message) const { std::cout << message << "\n"; } GMP_DISABLE_CONSTRUCTION(logger) }; struct shape { virtual ~shape() = default; virtual const char* name() const = 0; }; struct circle : shape { const char* name() const override { return "circle"; } }; struct square : shape { const char* name() const override { return "square"; } }; GMP_FACTORY_REGISTER(shape, (), circle, square) int main() { logger::instance().write("hello from singleton"); auto product = gmp::object_factory::instance().create_unique("circle"); std::cout << product->name() << "\n"; } ``` ## Compile-time Tests The library includes compile-time-oriented tests using `static_assert` and build-time validation: ```bash cmake -B ./build -DBUILD_TESTS=ON cmake --build ./build ctest --test-dir ./build --output-on-failure ``` ## Acknowledgments Inspired by Boost.Preprocessor and other metaprogramming libraries. ## License GMP is licensed under the MIT license, see [LICENSE](https://github.com/lkimuk/gmp/blob/main/LICENSE) for more information.