{"id":28034868,"url":"https://github.com/operationdarkside/ct_string","last_synced_at":"2025-05-11T12:00:10.253Z","repository":{"id":291779566,"uuid":"978749865","full_name":"OperationDarkside/ct_string","owner":"OperationDarkside","description":"Compile-time string class module for C++","archived":false,"fork":false,"pushed_at":"2025-05-06T13:06:30.000Z","size":18,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-11T12:00:03.263Z","etag":null,"topics":["compile-time","constexpr","constexpr-all-the-things","cpp","cpp-modules","string"],"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/OperationDarkside.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}},"created_at":"2025-05-06T13:03:24.000Z","updated_at":"2025-05-06T13:08:53.000Z","dependencies_parsed_at":"2025-05-06T14:29:54.725Z","dependency_job_id":"b9c3c89a-f2d3-4e3f-883d-5f342e389d6f","html_url":"https://github.com/OperationDarkside/ct_string","commit_stats":null,"previous_names":["operationdarkside/ct_string"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OperationDarkside%2Fct_string","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OperationDarkside%2Fct_string/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OperationDarkside%2Fct_string/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OperationDarkside%2Fct_string/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OperationDarkside","download_url":"https://codeload.github.com/OperationDarkside/ct_string/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253561121,"owners_count":21927767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["compile-time","constexpr","constexpr-all-the-things","cpp","cpp-modules","string"],"created_at":"2025-05-11T12:00:09.656Z","updated_at":"2025-05-11T12:00:10.231Z","avatar_url":"https://github.com/OperationDarkside.png","language":"C++","readme":"# ct_string: A C++20 Compile-Time String Library\n\n`ct_string` is a lightweight, header-only (via C++20 module interface) library that provides a `constexpr`-friendly string type. It's designed to allow for string manipulations, particularly concatenation, at compile time, addressing limitations of `std::string_view` (which cannot own concatenated data) and `std::string` (which typically involves heap allocations unsuitable for `constexpr` contexts before C++20/23's fuller support).\n\nThis library is ideal for scenarios like constructing file paths, generating lookup keys, or any situation where string content can be determined entirely at compile time.\n\n## Features\n\n*   **Compile-Time Operations:** Construct, concatenate, and compare strings entirely at compile time.\n*   **Deduction Guides:** Easy construction from string literals (e.g., `ct_string s = \"Hello\";`).\n*   **Seamless Conversions:**\n    *   Implicit `constexpr` conversion to `std::string_view`.\n    *   Implicit `constexpr` conversion to `const char*`.\n    *   Implicit (runtime) conversion to `std::string`.\n*   **Standard-like API:** Provides `size()`, `empty()`, `c_str()`, `operator[]`, iterators.\n*   **Comparison Operators:** Full set of `constexpr` comparison operators (`==`, `!=`, C++20 `operator\u003c=\u003e`).\n*   **C++20 Module:** Packaged as a C++20 module (`ct_string.ixx`) for cleaner integration.\n*   **No Heap Allocations:** All string data is stored within the `ct_string` object itself (on the stack or in static storage).\n\n## Requirements\n\n*   A C++20 compliant compiler that supports C++20 modules. Tested/Known to work with:\n    *   MSVC (Visual Studio 2022 v17.13.19+ recommended)\n    *   (TODO) Clang (15+ with appropriate flags, support is rapidly improving)\n    *   (TODO) GCC (12+ with appropriate flags, support is rapidly improving)\n*   CMake (version 3.25+ recommended for smoother module support, 3.28+ is even better).\n\n## Installation / Integration\n\nSince `ct_string` is provided as a single C++20 module interface file (`ct_string.ixx`), integration is straightforward.\n\n### Using CMake\n\n1.  Copy `ct_string.ixx` into your project (e.g., in a `modules/` or `include/` directory).\n2.  Add the module to your CMake target:\n\n    ```cmake\n    # In your CMakeLists.txt\n\n    # If ct_string.ixx is providing an interface for other libraries/executables\n    add_library(my_awesome_lib ...) # Or add_executable(my_app ...)\n\n    # Create a FILE_SET for your module interface units\n    # Adjust the path to where you placed ct_string.ixx\n    target_sources(my_awesome_lib PRIVATE\n        FILE_SET CXX_MODULES FILES\n            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/ct_string.ixx\n        # Add other .ixx files here if you have more\n    )\n\n    # If you have an executable that directly uses ct_string:\n    # add_executable(my_app main.cpp)\n    # target_sources(my_app PRIVATE\n    #     FILE_SET CXX_MODULES FILES\n    #         ${CMAKE_CURRENT_SOURCE_DIR}/path/to/ct_string.ixx\n    # )\n    #\n    # If my_app links against my_awesome_lib which exports ct_string,\n    # then my_app might not need to list ct_string.ixx directly in its\n    # sources if the dependency is handled correctly.\n    #\n    # For CMake 3.28+ consumers of a library exporting a module:\n    # target_sources(my_consumer_app PRIVATE\n    #    FILE_SET CXX_MODULE_IMPORTS FILES\n    #        ${CMAKE_CURRENT_SOURCE_DIR}/path/to/ct_string.ixx\n    # )\n    # The exact CMake incantation can vary based on project structure and\n    # whether ct_string is part of a compiled library or used directly.\n    ```\n\n3.  Ensure your compiler flags are set for C++20 and module support. CMake often handles this based on `CMAKE_CXX_STANDARD`. For MSVC, `/std:c++20` (or `/std:c++latest`) and `/experimental:module` (if needed, though often implied by `.ixx` files) are key.\n\n### Manual Integration (Simpler Projects)\n\nFor very simple projects or those not using CMake, you can:\n1.  Copy `ct_string.ixx` into your project.\n2.  Ensure your compiler is invoked with C++20 and module support enabled, and that it knows how to find and compile `ct_string.ixx` before compiling files that import it. The exact commands depend on your compiler.\n\n## Usage\n\n```cpp\n// main.cpp\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n#include \u003cstring_view\u003e\n\nimport ct_string; // Import the module\n\n// For compile-time assertions in examples (like Catch2's STATIC_REQUIRE)\n#define STATIC_ASSERT_MSG(cond, msg) static_assert(cond, msg)\n\nvoid print_std_string(const std::string\u0026 s) {\n    std::cout \u003c\u003c \"std::string: \" \u003c\u003c s \u003c\u003c std::endl;\n}\n\nvoid print_string_view(std::string_view sv) {\n    std::cout \u003c\u003c \"string_view: \" \u003c\u003c sv \u003c\u003c std::endl;\n}\n\nint main() {\n    // Construction\n    constexpr ct_string hello = \"Hello\"; // Deduction guide\n    constexpr ct_string world_suffix = \" World!\";\n    constexpr ct_string empty_str;\n\n    STATIC_ASSERT_MSG(hello.size() == 5, \"Size check\");\n    STATIC_ASSERT_MSG(empty_str.empty(), \"Empty check\");\n\n    // Concatenation\n    constexpr auto greeting = hello + world_suffix;\n    STATIC_ASSERT_MSG(greeting.size() == 12, \"Concatenation size\");\n    STATIC_ASSERT_MSG(std::string_view(greeting) == \"Hello World!\", \"Concatenation content\");\n\n    // Using in a constexpr context\n    constexpr ct_string base_path = \"/usr/local\";\n    constexpr ct_string app_folder = \"/my_app\";\n    constexpr ct_string config_file = \"/config.json\";\n    constexpr auto full_config_path = base_path + app_folder + config_file;\n\n    std::cout \u003c\u003c \"Config path: \" \u003c\u003c full_config_path \u003c\u003c std::endl; // Implicit conversion to const char*\n\n    if constexpr (full_config_path == \"/usr/local/my_app/config.json\") {\n        std::cout \u003c\u003c \"Compile-time path verification successful!\" \u003c\u003c std::endl;\n    }\n\n    // Conversions\n    const char* cstr_from_ct = greeting; // Implicit to const char*\n    std::cout \u003c\u003c \"C-string: \" \u003c\u003c cstr_from_ct \u003c\u003c std::endl;\n\n    std::string std_str_from_ct = greeting; // Implicit to std::string (runtime)\n    std::cout \u003c\u003c \"std::string: \" \u003c\u003c std_str_from_ct \u003c\u003c std::endl;\n\n    // Passing to functions\n    print_string_view(full_config_path);\n    print_std_string(full_config_path);\n\n    // Comparisons\n    constexpr ct_string s1 = \"test\";\n    constexpr ct_string s2 = \"test\";\n    constexpr ct_string s3 = \"Test\";\n\n    STATIC_ASSERT_MSG(s1 == s2, \"Equality check\");\n    STATIC_ASSERT_MSG(s1 != s3, \"Inequality check\");\n    // 'Test' (s3) is lexicographically less than 'test' (s1)\n    STATIC_ASSERT_MSG(s3 \u003c s1, \"Less than check: 'Test' \u003c 'test'\");\n    // 'test' (s1) is lexicographically greater than 'Test' (s3)\n    STATIC_ASSERT_MSG(s1 \u003e s3, \"Greater than check: 'test' \u003e 'Test'\");\n\n    return 0;\n}\n```\n\n## API Overview\n\n*   `ct_string\u003cstd::size_t N = 0\u003e`: The main class template. `N` is the number of characters excluding the null terminator.\n    *   `constexpr ct_string()`: Default constructor (empty string).\n    *   `constexpr ct_string(const char (\u0026str)[N + 1])`: Constructor from C-style string literal.\n    *   `constexpr std::size_t size() const`: Returns the number of characters.\n    *   `constexpr bool empty() const`: Checks if the string is empty.\n    *   `constexpr const char* c_str() const`: Returns a null-terminated C-style string.\n    *   `constexpr operator std::string_view() const`: Converts to `std::string_view`.\n    *   `operator std::string() const`: Converts to `std::string`.\n    *   `constexpr operator const char*() const`: Converts to `const char*`.\n    *   `constexpr const char\u0026 operator[](std::size_t index) const`: Accesses character at index.\n    *   `constexpr const char* begin() const`, `constexpr const char* end() const`: Iterators.\n*   `template\u003cstd::size_t N_with_null\u003e ct_string(const char (\u0026str)[N_with_null]) -\u003e ct_string\u003cN_with_null - 1\u003e;`: Deduction guide.\n*   `operator+`: Concatenates two `ct_string` objects.\n*   `operator==`, `operator!=`, `operator\u003c=\u003e`: Comparison operators for `ct_string` with `ct_string`, `std::string_view`, and `const char*`.\n\n## Building and Running Tests\n\nThe repository includes tests written using [Catch2](https://github.com/catchorg/Catch2). To build and run them:\n1.  Ensure you have CMake and a C++20 compiler installed.\n2.  Clone the repository: `git clone https://github.com/OperationDarkside/ct_string.git`\n3.  Configure and build:\n    ```bash\n    cd ct_string\n    cmake -B build -S .\n    cmake --build build\n    ```\n4.  Run tests:\n    ```bash\n    cd build\n    ctest # Or run the test executable directly, e.g., ./run_tests\n    ```\n    (The test executable name might vary based on your `CMakeLists.txt`).\n\n## Motivation\n\nI needed/wanted a compile-time string type in my game engine that could be used in `constexpr` contexts and could be concatenated with other `constexpr` strings. I also wanted to avoid heap allocations and the overhead of `std::string`. My example use case was to combine file paths in a `constexpr` context. While `std::string_view` is excellent for non-owning string views, it lacks the ability to own data resulting from operations like concatenation. `std::string` can do this but often involves heap allocations, making it less suitable for extensive `constexpr` usage, especially in older C++ standards or when strict compile-time guarantees are needed. `ct_string` fills this gap by providing a string type that stores its data directly and performs all its core operations at compile time.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues or pull requests. If submitting a PR, please ensure existing tests pass and add new tests for your changes.\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE).\n\n## DISCLAIMER\n\nThis project was mostly generated using the LLM Gemini 2.5 Pro Preview 03-25 in Google AI Studio. The code was then reviewed and modified by a human to ensure correctness and readability. This README was also mostly generated using the same LLM. The code is provided as-is, and the author is not responsible for any issues or bugs that may arise.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foperationdarkside%2Fct_string","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foperationdarkside%2Fct_string","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foperationdarkside%2Fct_string/lists"}