{"id":49547299,"url":"https://github.com/pennywise007/ext","last_synced_at":"2026-05-02T20:04:09.245Z","repository":{"id":167012654,"uuid":"436595908","full_name":"Pennywise007/ext","owner":"Pennywise007","description":"C++17 header only extensions library","archived":false,"fork":false,"pushed_at":"2026-04-23T18:49:51.000Z","size":523,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-23T20:25:15.065Z","etag":null,"topics":["dependency-injection","dispatcher","dump","exception","exception-handling","serialization","synchronization","thread","thread-pool","trace","tracer"],"latest_commit_sha":null,"homepage":"","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/Pennywise007.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":"2021-12-09T11:43:57.000Z","updated_at":"2026-04-23T18:49:55.000Z","dependencies_parsed_at":"2024-05-30T01:01:01.113Z","dependency_job_id":null,"html_url":"https://github.com/Pennywise007/ext","commit_stats":{"total_commits":139,"total_committers":4,"mean_commits":34.75,"dds":"0.49640287769784175","last_synced_commit":"68e2e2877cfb6c093cc9066e0006e1f9e0b7217a"},"previous_names":["pennywise007/ext"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Pennywise007/ext","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pennywise007%2Fext","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pennywise007%2Fext/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pennywise007%2Fext/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pennywise007%2Fext/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Pennywise007","download_url":"https://codeload.github.com/Pennywise007/ext/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Pennywise007%2Fext/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32547653,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-02T19:18:06.202Z","status":"ssl_error","status_checked_at":"2026-05-02T19:16:21.335Z","response_time":132,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["dependency-injection","dispatcher","dump","exception","exception-handling","serialization","synchronization","thread","thread-pool","trace","tracer"],"created_at":"2026-05-02T20:04:05.895Z","updated_at":"2026-05-02T20:04:09.230Z","avatar_url":"https://github.com/Pennywise007.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/c27e7ac4-7453-498a-90ea-dfab4a430a43\" alt=\"Ext logo\"\u003e\n\u003c/div\u003e\n\nComprehensive header-only C++ library, EXT designed to enhance productivity and flexibility in C++20 and later standards(most of the features supports C++17 also).\n\n# Build\n\n\u003cdetails\u003e\u003csummary\u003eBazel build and run tests\u003c/summary\u003e\n\n```ps\nbazel build //...\nbazel test //...\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eCMake build and run tests\u003c/summary\u003e\n\n```ps\ncmake -B build -DEXT_BUILD_TESTS=ON\ncmake --build build --parallel\n# On windows\n.\\build\\tests\\Debug\\ext_tests.exe\n# On linux\n./build/tests/ext_tests\n```\n\n\u003c/details\u003e\n\n# Dependency injection\n\nUsage simple with .Net [Microsoft.Extensions.DependencyInjection](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/)\n\n\u003cdetails\u003e\u003csummary\u003eExample\u003c/summary\u003e\n\n```c++\n\n#include \u003cext/core/dependency_injection.h\u003e\n\nstruct SomeInterface\n{\n    virtual ~SomeInterface() = default;\n};\n\nstruct InterfaceImplementation : SomeInterface\n{};\n\nstruct Object\n{\n    explicit Object(std::shared_ptr\u003cSomeInterface\u003e interface)\n        : m_interface(std::move(interface))\n    {}\n\n    std::shared_ptr\u003cSomeInterface\u003e m_interface;\n};\n\next::ServiceCollection\u0026 serviceCollection = ext::get_singleton\u003cext::ServiceCollection\u003e();\nserviceCollection.RegisterScoped\u003cInterfaceImplementationExample, InterfaceExample\u003e();\n// Register other classes\nauto serviceProvider = serviceCollection.BuildServiceProvider();\n\nstd::shared_ptr\u003cObject\u003e object = ext::CreateObject\u003cObject\u003e(serviceProvider);\n```\n\n\u003c/details\u003e\n\n- [Source](https://github.com/Pennywise007/ext/blob/main/include/ext/core/dependency_injection.h)\n- [Tests and examples](https://github.com/Pennywise007/ext/blob/main/tests/core/dependency_injection_test.cpp)\n\n# Reflection\n\nSupport of the compile time reflection in C++, getting object fields, functions\n\n\u003cdetails\u003e\u003csummary\u003eObject\u003c/summary\u003e\n\n```c++\nstruct TestStruct\n{\n    int intField;\n    bool booleanField;\n    std::string_view charArrayField;\n\n    void existingFunction(int) {}\n};\n\n// Checking the brace constructor size(basically the fields count)\next::reflection::brace_constructor_size\u003cTestStruct\u003e == 3;\n\n// Fields iteration\nconstexpr auto kGlobalObj = TestStruct{ 100, true, \"test\"};\nstd::get\u003c0\u003e(ext::reflection::get_object_fields(kGlobalObj)) == 100\nstd::get\u003c1\u003e(ext::reflection::get_object_fields(kGlobalObj)) == true\nstd::get\u003c2\u003e(ext::reflection::get_object_fields(kGlobalObj)) == \"test\"\n\n// Getting field names(C++20 or later)\n#if C++20\next::reflection::get_field_name\u003cdecltype(kGlobalObj), 0\u003e == \"intField\"\next::reflection::get_field_name\u003cTestStruct, 1\u003e == \"booleanField\"\next::reflection::get_field_name\u003cTestStruct, 2\u003e == \"charArrayField\"\n#endif\n\n// Checking if object has some field\nHAS_FIELD(TestStruct, booleanField) = true;\nHAS_FIELD(TestStruct, unknown) = false;\n\n// Checking if object has some function\nHAS_FUNCTION(TestStruct, existingFunction) == true;\n!HAS_FUNCTION(TestStruct, unknownFunction) == false;\n\n// Real usage of the reflection\ntemplate \u003ctypename T\u003e\nvoid serializeObject(T\u0026 object)\n{\n    if constexpr (HAS_FUNCTION(T, onSerializationStart))\n        object.onSerializationStart();\n    // ...\n    if constexpr (HAS_FUNCTION(T, onSerializationEnd))\n        object.onSerializationEnd();\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eEnums\u003c/summary\u003e\n\n```c++\n#include \u003cext/reflection/enum.h\u003e\n\nenum class TestEnum\n{\n    eEnumValue1,\n    eEnumValue2,\n    eEnumValue5 = 5,\n};\n\n// Enum to string\next::reflection::enum_to_string(TestEnum::eEnumValue1) == \"TestEnum::eEnumValue1\"\next::reflection::enum_to_string(TestEnum(5)) == \"TestEnum::eEnumValue5\"\next::reflection::enum_to_string(TestEnum(int)) -\u003e exception in runtime\n// Enum to string in compile time\next::reflection::enum_to_string\u003cTestEnum(0)\u003e() == \"TestEnum::eEnumValue1\";\next::reflection::enum_to_string\u003cTestEnum::eEnumValue5\u003e() == \"TestEnum::eEnumValue5\";\n\n// String to enum\next::reflection::get_enum_value_by_name\u003cTestEnum\u003e(\"TestEnum::eEnumValue1\") == TestEnum::eEnumValue1\next::reflection::get_enum_value_by_name\u003cTestEnum\u003e(\"InvalidEnumValueName\") -\u003e exception\n\n// Enum size\next::reflection::get_enum_size\u003cTestEnum\u003e() == 3;\n\n// Getting enum value by index\next::reflection::get_enum_value\u003cTestEnum, 0\u003e() == TestEnum::eEnumValue1\next::reflection::get_enum_value\u003cTestEnum, 1\u003e() == TestEnum::eEnumValue2\next::reflection::get_enum_value\u003cTestEnum, 2\u003e() == TestEnum::eEnumValue5\n\n// Compilation time checks\nswitch (TestEnum)\n{\ncase TestEnum::eEnumValue1: // ...\ncase TestEnum::eEnumValue2: // ...\ncase TestEnum::eEnumValue5: // ...\ndefault: static_assert(ext::reflection::get_enum_size\u003cTestEnum\u003e() == 3, \"Unhandled enum case state\");\n}\n\n// Enum values iteration\nfor (TestEnum val : ext::reflection::get_enum_values\u003cTestEnum\u003e())\n    // ...\n\nEXPECT_TRUE(ext::reflection::is_enum_value\u003cTestEnum\u003e(0));\nEXPECT_TRUE(ext::reflection::is_enum_value\u003cTestEnum\u003e(TestEnum::eEnumValue2));\nEXPECT_FALSE(ext::reflection::is_enum_value\u003cTestEnum\u003e(-1));\n```\n\n\u003c/details\u003e\n\n# Serialization\n\nSerialization objects to/from json etc.\n\n## Optional Fields\n\nYou can mark fields as optional using `DECLARE_OPTIONAL_SERIALIZABLE_FIELD` or `REGISTER_OPTIONAL_SERIALIZABLE_FIELD`. Optional fields are not required in the JSON during deserialization - if a field is missing, it keeps its default value instead of causing an error.\n\n\u003cdetails\u003e\u003csummary\u003eExample\u003c/summary\u003e\n\n```c++\n#include \u003cext/serialization/iserializable.h\u003e\n\nusing namespace ext::serializable;\nusing namespace ext::serializer;\n\n#if C++20 // we use reflection to get fields info, no macro needed, to use base classes you need to use REGISTER_SERIALIZABLE_OBJECT\nstruct Settings\n{\n    struct User\n    {\n        std::int64_t id;\n        std::string firstName;\n        std::string userName;\n    };\n    \n    std::wstring password;\n    std::list\u003cUser\u003e registeredUsers;\n};\n\n#else // not C++20\n\nstruct InternalStruct\n{\n    REGISTER_SERIALIZABLE_OBJECT();\n    DECLARE_SERIALIZABLE_FIELD(long, value);\n    DECLARE_SERIALIZABLE_FIELD(std::list\u003cint\u003e, valueList);\n};\n\nstruct CustomValue : ISerializableValue {\n// ISerializableValue\n    [[nodiscard]] SerializableValue SerializeValue() const override { return std::to_wstring(val); }\n    void DeserializeValue(const SerializableValue\u0026 value) override { val = std::wtoi(value); }\n    int val = 10;\n};\n\nstruct Setting : InternalStruct\n{\n    REGISTER_SERIALIZABLE_OBJECT(InternalStruct);\n\n    DECLARE_SERIALIZABLE_FIELD(long, valueLong, 2);\n    DECLARE_SERIALIZABLE_FIELD(int, valueInt);\n    DECLARE_SERIALIZABLE_FIELD(std::vector\u003cbool\u003e, boolVector, { true, false });\n\n    DECLARE_SERIALIZABLE_FIELD(CustomValue, value);\n    DECLARE_SERIALIZABLE_FIELD(InternalStruct, internalStruct);\n\n    // Optional field - if missing in JSON, keeps default value (5)\n    DECLARE_OPTIONAL_SERIALIZABLE_FIELD(unsigned, repeatIntervalMinutes, 5);\n\n    // Instead of using macroses - use REGISTER_SERIALIZABLE_FIELD in constructor\n    std::list\u003cint\u003e m_listOfParams;\n\n    MyTestStruct()\n    {\n        REGISTER_SERIALIZABLE_FIELD(m_listOfParams); // or use DECLARE_SERIALIZABLE_FIELD macro\n    }\n};\n\n#endif\n\nSettings settings;\n\nstd::wstring json;\ntry {\n    SerializeToJson(settings, json);\n}\ncatch (...) {\n    ext::ManageException(EXT_TRACE_FUNCTION);\n}\n...\ntry {\n    DeserializeFromJson(settings, json);\n}\ncatch (...) {\n    ext::ManageException(EXT_TRACE_FUNCTION);\n}\n\n```\n\nYou can also declare this functions in your REGISTER_SERIALIZABLE_OBJECT object to get notified when (de)serialization was called:\n\n// Called before object serialization\nvoid OnSerializationStart() {}\n// Called after object serialization\nvoid OnSerializationEnd() {};\n\n// Called before deserializing object, allow to change deserializable tree and avoid unexpected data, allows to add upgraders for outdated settings\n// Also used to allocate collections elements\nvoid OnDeserializationStart(SerializableNode\u0026 serializableTree) {}\n// Called after collection deserialization\nvoid OnDeserializationEnd() {};\n\n\u003c/details\u003e\n\n- [Source](https://github.com/Pennywise007/ext/tree/main/include/ext/serialization)\n\nTests and examples:\n- [C++ 20 tests and examples](https://github.com/Pennywise007/ext/blob/main/tests/serialization/serialization_c++20_test.cpp)\n- [C++ 17 tests and examples](https://github.com/Pennywise007/ext/blob/main/tests/serialization/serialization_test.cpp)\n\n# Event dispatcher\n\nAllow to register events and notify subscribers\n\n\u003cdetails\u003e\u003csummary\u003eExample\u003c/summary\u003e\n\n```c++\n#include \u003cext/core/dispatcher.h\u003e\n\n// Example of event interface\nstruct IEvent : ext::events::IBaseEvent\n{\n\tvirtual void Event(int val) = 0;\n};\n\n// Example of sending an event:\next::send_event(\u0026IEvent::Event, 10);\n\n// Example of recipient:\nstruct Recipient : ext::events::ScopeSubscription\u003cIEvent\u003e\n{\n\tvoid Event(int val) override { std::cout \u003c\u003c \"Event\"; }\n}\n```\n\n\u003c/details\u003e\n\n- [Source](https://github.com/Pennywise007/ext/blob/main/include/ext/core/dispatcher.h)\n\n# Threading\n\n\u003cdetails\u003e\u003csummary\u003eInterruptible thread(boost/thread analog)\u003c/summary\u003e\n\n```c++\n#include \u003cext/thread/thread.h\u003e\n\next::thread myThread(thread_function, []()\n{\n\twhile (!ext::this_thread::interruption_requested())\n\t{\n\t\ttry\n\t\t{\n\t\t\t...\n\t\t}\n\t\tcatch (const ext::thread::thread_interrupted\u0026)\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n});\n\nmyThread.interrupt();\nEXPECT_TRUE(myThread.interrupted());\n```\n\n- [Source](https://github.com/Pennywise007/ext/blob/main/include/ext/thread/thread.h)\n- [Tests](https://github.com/Pennywise007/ext/blob/main/tests/thread/thread_test.cpp)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eThread pool\u003c/summary\u003e\n\n```c++\n#include \u003cext/thread/thread_pool.h\u003e\n\nstd::set\u003cext::task::TaskId, ext::task::TaskIdComparer\u003e taskList;\next::thread_pool threadPool([\u0026taskList, \u0026listMutex](const ext::task::TaskId\u0026 taskId)\n{\n\ttaskList.erase(taskId);\n});\n\nconst auto maxThreads = std::thread::hardware_concurrency();\nfor (auto i = maxThreads; i != 0; --i)\n{\n\ttaskList.emplace(threadPool.add_task([]()\n\t{\n\t\t...\n\t}));\n}\nthreadPool.wait_for_tasks();\n```\n\n- [Source](https://github.com/Pennywise007/ext/blob/main/include/ext/thread/thread_pool.h)\n- [Tests](https://github.com/Pennywise007/ext/blob/main/tests/thread/thread_pool_test.cppp)\n\n\u003c/details\u003e\n\n\n## And others\n\n- [Task scheduler](https://github.com/Pennywise007/ext/blob/main/include/ext/thread/scheduler.h)\n- [Main thread methods invoker(for GUI and other synchronized actions)](https://github.com/Pennywise007/ext/blob/main/include/ext/thread/invoker.h)\n- [Event](https://github.com/Pennywise007/ext/blob/main/include/ext/thread/event.h)\n- [Tick timer, allow to synchronize sth(for example animations)](https://github.com/Pennywise007/ext/blob/main/include/ext/thread/tick.h)\n- [Wait group(GO analog)](https://github.com/Pennywise007/ext/blob/main/include/ext/thread/wait_group.h)\n- [Channel(GO analog)](https://github.com/Pennywise007/ext/blob/main/include/ext/thread/channel.h)\n\n```c++\next::Channel\u003cint\u003e channel;\n\nstd::thread([\u0026]()\n    {\n        for (auto val : channel) {\n            ...\n        }\n    });\nchannel.add(1);\nchannel.add(10);\nchannel.close();\n```\n\n- [C++17 stop token](https://github.com/Pennywise007/ext/blob/main/include/ext/utils/stop_token_details.h)\n\n```c++\next::stop_source source;\next::thread myThread([stop_token = source.get_token()]()\n{\n    while (!stop_token.stop_requested())\n    {\n        ...\n    }\n});\n\nsource.request_stop();\nmyThread.join();\n```\n\n# Tracer\n\n\u003cdetails\u003e\u003csummary\u003eShow traces with defferent levels and time stamps in cout/cerr/output/trace file\u003c/summary\u003e\n\n```c++\n#include \u003cext/core/tracer.h\u003e\next::get_tracer().Enable();\n```\n\nSimple macroses:\n\n- Default information trace `EXT_TRACE() \u003c\u003c \"My trace\";`\n- Debug information only for Debug build `EXT_TRACE_DBG() \u003c\u003c EXT_TRACE_FUNCTION \"called\";`\n- Error trace to cerr, mostly used in EXT_CHECK/EXT_EXPECT `EXT_TRACE_ERR() \u003c\u003c EXT_TRACE_FUNCTION \"called\";`\n- Can be called for scope call function check. Trace start and end scope with the given text `EXT_TRACE_SCOPE() \u003c\u003c EXT_TRACE_FUNCTION \u003c\u003c \"Main function called with \" \u003c\u003c args;`\n\n- [Source](https://github.com/Pennywise007/ext/blob/main/include/ext/core/tracer.h)\n\n\u003c/details\u003e\n\n# Check code execution and handling errors\n\n\u003cdetails\u003e\u003csummary\u003eAllows to add simple checks inside executing code and manage exceptions\u003c/summary\u003e\n\n```c++\n#include \u003cext/core/check.h\u003e\n```\n\n**EXT_CHECK** - throws exception if expression is false\n\n**EXT_CHECK**(bool_expression) \u003c\u003c \"Text\";\n\n```c++\nif (!bool_expression)\n\tthrow ::ext::check::CheckFailedException(std::source_location::current(), #bool_expression \"Text\");\n```\n\n**EXT_EXPECT** - if expression is false:\n\n- Only on first failure: debug break if debugger presents, create dump otherwise\n- throws exception\n\n**EXT_EXPECT**(bool_expression) \u003c\u003c \"Text\";\n\n```c++\nif (!bool_expression)\n{\n\tif (IsDebuggerPresent())                                            \n\t\tDebugBreak();                                                   \n\telse                                                                \n\t\tEXT_DUMP_CREATE();\n\tthrow ::ext::check::CheckFailedException(std::source_location::current(), #bool_expression \"Text\"));\n}\n```\n\n**EXT_ASSERT / EXT_REQUIRE** - if expression is false in debug mode. Only on first failure: debug break if debugger presents, create dump otherwise\n\n**EXT_ASSERT**(bool_expression) \u003c\u003c \"Text\";\n\n```c++\n#ifdef _DEBUG\nif (!bool_expression)\n{\n\tif (IsDebuggerPresent())                                            \n\t\tDebugBreak();                                                   \n\telse                                                                \n\t\tEXT_DUMP_CREATE();\n}\n#endif\n```\n\n- [Source](https://github.com/Pennywise007/ext/blob/main/include/ext/core/check.h)\n\n\u003c/details\u003e\n\n# Managing exceptions\n\n\u003cdetails\u003e\u003csummary\u003eAllow to simplify managing exceptions and output error text\u003c/summary\u003e\n\n```c++\n#include \u003cext/error/exception.h\u003e\n\ntry\n{ \n\tEXT_EXPECT(is_ok()) \u003c\u003c \"Something wrong!\";\n}\ncatch (...)\n{\t\n\ttry\n\t{\n\t\tstd::throw_with_nested(ext::exception(std::source_location::current(), \"Job failed\")); \n\t}\n\tcatch (...)\n\t{\n\t\t::MessageBox(NULL, ext::ManageExceptionText(\"Big bang\"));\n\t}\n}\n```\n\n- [Source](https://github.com/Pennywise007/ext/blob/main/include/ext/error/exception.h)\n\n\u003c/details\u003e\n\n# Dumper and debugging\n\n\u003cdetails\u003e\u003csummary\u003eAllow to catch unhandled exceptions and generate dump file\u003c/summary\u003e\n\nDeclare unhandled exceptions handler(called automatic on calling ext::dump::create_dump())\n\n```c++\n#include \u003cext/error/dump_writer.h\u003e\n\nvoid main()\n{\n\tEXT_DUMP_DECLARE_HANDLER();\n\t...\n}\n```\n\nIf you need to catch error inside you code you add check:\n\n```c++\nEXT_DUMP_IF(is_something_wrong());\n```\n\nIn this case if debugger presents - it will be stopped here, otherwise generate dump file and **continue** execution, @see DEBUG_BREAK_OR_CREATE_DUMP.\nDump generation and debug break in case with EXT_DUMP_IF generates only once to avoid spam.\n\n- [Source](https://github.com/Pennywise007/ext/blob/main/include/ext/error/dump_writer.h)\n\n\u003c/details\u003e\n\n# Compile time classes\n\n\u003cdetails\u003e\u003csummary\u003eConstexpr string\u003c/summary\u003e\n\nAllows to combine and check text in compile time.\n\n```c++\n#include \u003cext/constexpr/string.h\u003e\n\nconstexpr ext::constexpr_string textFirst = \"test\";\nconstexpr ext::constexpr_string textSecond = \"second\";\n\nconstexpr auto TextCombination = textFirst + \"_\" + textSecond;\nstatic_assert(TextCombination == \"test_second\");\n```\n\nIn C++20 can be used to store text as a template argument:\n\n```c++\n    template \u003cext::constexpr_string name__\u003e\n    struct Object {\n        constexpr std::string_view Name() const {\n            return name__.str();\n        }\n        ...\n    };\n\n    Object\u003c\"object_name\"\u003e object;\n    static_assert(object.Name() == std::string_view(\"object_name\"));\n```\n\n[Source](https://github.com/Pennywise007/ext/blob/main/include/ext/constexpr/string.h)\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eConstexpr map\u003c/summary\u003e\n\nCompile time extension for strings, allow to combine and check text in compile time.\n\n```c++\n#include \u003cext/constexpr/map.h\u003e\n\nconstexpr ext::constexpr_map my_map = {std::pair{11, 10}, {std::pair{22, 33}}};\nstatic_assert(my_map.size() == 2);\n\nstatic_assert(10 == my_map.get_value(11));\nstatic_assert(33 == my_map.get_value(22));\n```\n\n[Source](https://github.com/Pennywise007/ext/blob/main/include/ext/constexpr/map.h)\n\u003c/details\u003e\n\n# Std extensions\n\n## Memory\n\n- [lazy_shared_ptr](https://github.com/Pennywise007/ext/blob/main/include/ext/std/memory.h#L56C8-L56C23) - allow to create a shared memory which will be created only on first call\n\n## Strings\n\n- [Trim all](https://github.com/Pennywise007/ext/blob/main/include/ext/std/string.h#L19)\n- [String/wstring converters](https://github.com/Pennywise007/ext/blob/main/include/ext/std/string.h#L36)\n- [String format](https://github.com/Pennywise007/ext/blob/main/include/ext/std/string.h#L116C27-L116C41)\n\n## Filesystem\n\n- [Full exe path](https://github.com/Pennywise007/ext/blob/main/include/ext/std/filesystem.h#L17C44-L17C61)\n\n# Other\n\n- [Call once (GO analog)](https://github.com/Pennywise007/ext/blob/main/include/ext/utils/call_once.h#L23)\n- [Thread safe singleton with lifetime check](https://github.com/Pennywise007/ext/blob/main/include/ext/core/singleton.h)\n- [Extension for tuples/variants and types array](https://github.com/Pennywise007/ext/blob/main/include/ext/core/mpl.h)\n- [Auto setter on scope change](https://github.com/Pennywise007/ext/blob/main/include/ext/scope/auto_setter.h)\n- [Defer (GO analog)](https://github.com/Pennywise007/ext/blob/main/include/ext/scope/defer.h)\n- [Object holder](https://github.com/Pennywise007/ext/blob/main/include/ext/scope/on_exit.h#L70)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpennywise007%2Fext","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpennywise007%2Fext","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpennywise007%2Fext/lists"}