├── doc ├── .gitignore ├── config.json ├── qbk │ ├── quickref.xml │ ├── index.xml │ └── main.qbk ├── externals.hpp └── Jamfile ├── CHANGELOG.md ├── .gitignore ├── .gitattributes ├── include └── boost │ ├── static_string.hpp │ └── static_string │ └── config.hpp ├── example └── static_cstring │ ├── Jamfile │ ├── README.md │ ├── static_cstring.hpp │ └── static_cstring_test.cpp ├── meta └── libraries.json ├── test ├── cmake_test │ ├── main.cpp │ └── CMakeLists.txt ├── Jamfile ├── compile_fail.hpp ├── CMakeLists.txt └── constexpr_tests.hpp ├── .codecov.yml ├── index.html ├── .drone └── codecov_coveralls.sh ├── LICENSE_1_0.txt ├── .github └── workflows │ ├── ci.yml │ └── example.yml ├── tools └── codecov.sh ├── README.md ├── CMakeLists.txt ├── .appveyor.yml └── .drone.star /doc/.gitignore: -------------------------------------------------------------------------------- 1 | html 2 | temp 3 | out.txt 4 | qbk/reference.qbk 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | bin64/ 3 | build/ 4 | 5 | # Because of CMake and VS2017 6 | Win32/ 7 | x64/ 8 | .vs/ 9 | out/ 10 | 11 | # VS CMake settings 12 | /CMakeSettings.json 13 | # CMake presets 14 | /CMakePresets.json 15 | /CMakeUserPresets.json 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Github 5 | .md text eol=lf 6 | 7 | # Visual Studio 8 | *.sln text eol=crlf 9 | *.vcproj text eol=crlf 10 | *.vcxproj text eol=crlf 11 | *.props text eol=crlf 12 | *.filters text eol=crlf 13 | -------------------------------------------------------------------------------- /doc/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "include_private": false, 3 | "legacy_behavior": false, 4 | "external_marker": "!EXTERNAL!", 5 | "link_prefix": "static_string.ref.", 6 | "default_namespace": "boost::static_strings", 7 | "allowed_prefixes": ["boost::static_strings::", "std::"], 8 | "convenience_header": "boost/static_string.hpp", 9 | "replace_strings": { 10 | "__see_below__": "``['see-below]``" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /include/boost/static_string.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Krystian Stasiowski (sdkrystian at gmail dot com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // Official repository: https://github.com/boostorg/static_string 8 | // 9 | 10 | #ifndef BOOST_STATIC_STRING_HPP 11 | #define BOOST_STATIC_STRING_HPP 12 | #include 13 | #endif -------------------------------------------------------------------------------- /example/static_cstring/Jamfile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2025 Gennaro Prota (gennaro dot prota at gmail dot com) 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | # file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | # Official repository: https://github.com/boostorg/static_string 8 | # 9 | 10 | import testing ; 11 | 12 | project 13 | : requirements 14 | ../../include 15 | extra 16 | 20 17 | ; 18 | 19 | run static_cstring_test.cpp ; 20 | -------------------------------------------------------------------------------- /meta/libraries.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "static_string", 3 | "name": "Static String", 4 | "authors": [ 5 | "Krystian Stasiowski", 6 | "Vinnie Falco" 7 | ], 8 | "description": "A fixed capacity dynamically sized string.", 9 | "category": [ 10 | "Containers", 11 | "String" 12 | ], 13 | "maintainers": [ 14 | "Alan de Freitas ", 15 | "Vinnie Falco ", 16 | "Gennaro Prota " 17 | ], 18 | "cxxstd": "11" 19 | } 20 | -------------------------------------------------------------------------------- /doc/qbk/quickref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/cmake_test/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2025 Alexander Grund 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // Official repository: https://github.com/boostorg/static_string 8 | // 9 | 10 | #include 11 | 12 | int main() 13 | { 14 | // Smoke test only 15 | boost::static_string<1> s_empty; 16 | boost::static_string<4> s_3(3, 'x'); 17 | return (s_empty.empty() && s_3.size() == 3) ? 0 : 1; 18 | } 19 | -------------------------------------------------------------------------------- /doc/qbk/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 |
14 | Index 15 | 16 |
17 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 - 2021 Alexander Grund 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) 4 | # 5 | # Sample codecov configuration file. Edit as required 6 | 7 | codecov: 8 | max_report_age: off 9 | require_ci_to_pass: yes 10 | notify: 11 | # Increase this if you have multiple coverage collection jobs 12 | after_n_builds: 1 13 | wait_for_ci: yes 14 | 15 | # Change how pull request comments look 16 | comment: 17 | layout: "reach,diff,flags,files,footer" 18 | 19 | # Ignore specific files or folders. Glob patterns are supported. 20 | # See https://docs.codecov.com/docs/ignoring-paths 21 | ignore: 22 | - extra/* 23 | - extra/**/* 24 | - test/* 25 | - test/**/* 26 | -------------------------------------------------------------------------------- /test/Jamfile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | # Official repository: https://github.com/boostorg/static_string 8 | # 9 | 10 | import testing ; 11 | import-search /boost/config/checks ; 12 | import config : requires ; 13 | 14 | local defines = 15 | [ requires 16 | cxx11_constexpr 17 | cxx11_decltype 18 | cxx11_hdr_tuple 19 | cxx11_hdr_type_traits 20 | cxx11_template_aliases 21 | cxx11_variadic_templates 22 | ] 23 | ; 24 | 25 | project : requirements $(defines) 26 | /boost/static_string//boost_static_string ; 27 | 28 | run static_string.cpp ; 29 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Boost.StaticString 4 | 5 | 6 | 7 | Automatic redirection failed, please go to 8 | ./doc/html/index.html 9 |
10 | 11 | Boost.StaticString
12 |
13 | Copyright (C) 2019 Vinnie Falco
14 | Copyright (C) 2019-2020 Krystian Stasiowski
15 |
16 | Distributed under the Boost Software License, Version 1.0. 17 | (See accompanying file LICENSE_1_0.txt or copy at 18 | http://www.boost.org/LICENSE_1_0.txt)
19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /test/cmake_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 Alexander Grund 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 4 | 5 | cmake_minimum_required(VERSION 3.8...3.16) 6 | 7 | project(cmake_subdir_test LANGUAGES CXX) 8 | 9 | # Those 2 should work the same 10 | # while using find_package for the installed Boost avoids the need to manually specify dependencies 11 | if(BOOST_CI_INSTALL_TEST) 12 | find_package(boost_static_string REQUIRED) 13 | else() 14 | set(BOOST_INCLUDE_LIBRARIES static_string) 15 | add_subdirectory(../../../.. deps/boost EXCLUDE_FROM_ALL) 16 | endif() 17 | 18 | add_executable(main main.cpp) 19 | target_link_libraries(main Boost::static_string) 20 | 21 | enable_testing() 22 | add_test(NAME main COMMAND main) 23 | 24 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) -------------------------------------------------------------------------------- /example/static_cstring/README.md: -------------------------------------------------------------------------------- 1 | This directory contains an experimental implementation of `basic_static_cstring`, which differs from `basic_static_string` in the following ways: 2 | 3 | | | `basic_static_cstring` | `basic_static_string` | 4 | |---------------------|------------------------|-----------------------| 5 | | Layout | `sizeof == N + 1` | Has size member | 6 | | Embedded NULs | Not supported | Supported | 7 | | Trivially copyable | Yes | No | 8 | 9 | Additionally, when `N <= UCHAR_MAX`, `basic_static_cstring` employs an optimization that avoids calling `std::strlen()` to compute the size. 10 | 11 | This work stems from [boostorg/static_string#23](https://github.com/boostorg/static_string/issues/23). 12 | 13 | If you believe `basic_static_cstring` should become part of the public API, please share your feedback on the Boost mailing list. -------------------------------------------------------------------------------- /.drone/codecov_coveralls.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2020 Rene Rivera, Sam Darwin 4 | # Copyright 2025 Alexander Grund 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt) 7 | 8 | 9 | set -xe 10 | 11 | # Run the regular Boost CI script which does the test & upload to codecov.io 12 | wget https://github.com/boostorg/boost-ci/raw/refs/heads/master/.drone/drone.sh 13 | . drone.sh 14 | 15 | # coveralls 16 | # uses multiple lcov steps from boost-ci codecov.sh script 17 | if [ -n "${COVERALLS_REPO_TOKEN}" ]; then 18 | echo "processing coveralls" 19 | pip3 install --user cpp-coveralls 20 | cd "$BOOST_CI_SRC_FOLDER" 21 | 22 | export PATH=/tmp/lcov/bin:$PATH 23 | command -v lcov 24 | lcov --version 25 | 26 | lcov --remove coverage.info -o coverage_filtered.info '*/test/*' '*/extra/*' 27 | cpp-coveralls --verbose -l coverage_filtered.info 28 | fi 29 | -------------------------------------------------------------------------------- /test/compile_fail.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace boost { 5 | namespace static_strings { 6 | 7 | static_assert(!detail::is_input_iterator::value, "is_input_iterator is incorrect"); 8 | static_assert(!detail::is_input_iterator::value, "is_input_iterator is incorrect"); 9 | static_assert(detail::is_input_iterator::value, "is_input_iterator is incorrect"); 10 | static_assert(detail::is_input_iterator>::value, "is_input_iterator is incorrect"); 11 | 12 | static_assert(!detail::is_forward_iterator::value, "is_forward_iterator is incorrect"); 13 | static_assert(!detail::is_forward_iterator::value, "is_forward_iterator is incorrect"); 14 | static_assert(detail::is_forward_iterator::value, "is_forward_iterator is incorrect"); 15 | static_assert(!detail::is_forward_iterator>::value, "is_forward_iterator is incorrect"); 16 | } // boost 17 | } // static_strings -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | # Official repository: https://github.com/boostorg/static_string 8 | # 9 | 10 | # Custom target used by the boost super-project 11 | if(NOT TARGET tests) 12 | add_custom_target(tests) 13 | set_property(TARGET tests PROPERTY FOLDER _deps) 14 | endif() 15 | 16 | set(BOOST_STATIC_STRING_TESTS_FILES 17 | CMakeLists.txt 18 | Jamfile 19 | constexpr_tests.hpp 20 | compile_fail.hpp 21 | static_string.cpp 22 | ) 23 | 24 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${BOOST_STATIC_STRING_TESTS_FILES}) 25 | add_executable(boost_static_string_tests ${BOOST_STATIC_STRING_TESTS_FILES}) 26 | 27 | # The include dependencies are found in the CMakeLists.txt 28 | # of the root project directory. 29 | # See: BOOST_STATIC_STRING_UNIT_TEST_LIBRARIES 30 | target_link_libraries(boost_static_string_tests PRIVATE Boost::static_string) 31 | add_test(NAME boost_static_string_tests COMMAND boost_static_string_tests) 32 | add_dependencies(tests boost_static_string_tests) 33 | -------------------------------------------------------------------------------- /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020-2021 Peter Dimov 3 | # Copyright 2021 Andrey Semashev 4 | # Copyright 2021-2025 Alexander Grund 5 | # Copyright 2022-2025 James E. King III 6 | # 7 | # Distributed under the Boost Software License, Version 1.0. 8 | # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) 9 | # 10 | # This workflow uses the Boost.CI reusable workflow which builds a variety of 11 | # configurations of your project, runs tests, and generates code coverage reports. 12 | # 13 | # To use it, copy this file into your repository as `.github/workflows/ci.yml` and 14 | # customize it appropriately. 15 | # 16 | --- 17 | name: CI 18 | 19 | on: 20 | pull_request: 21 | push: 22 | branches: 23 | - master 24 | - develop 25 | - bugfix/** 26 | - feature/** 27 | - fix/** 28 | - github/** 29 | - pr/** 30 | paths-ignore: 31 | - LICENSE 32 | - meta/** 33 | - README.md 34 | 35 | jobs: 36 | call-boost-ci: 37 | name: Run Boost.CI 38 | uses: boostorg/boost-ci/.github/workflows/reusable.yml@master 39 | with: 40 | exclude_cxxstd: '98,03,0x' 41 | enable_pr_coverage: false 42 | enable_multiarch: false 43 | # Example of customization: 44 | # with: 45 | # enable_reflection: true 46 | # enable_windows: false 47 | # secrets: 48 | # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 49 | # COVERITY_SCAN_NOTIFICATION_EMAIL: ${{ secrets.COVERITY_SCAN_NOTIFICATION_EMAIL }} 50 | # COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 51 | -------------------------------------------------------------------------------- /doc/externals.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace boost { 4 | 5 | /// !EXTERNAL! 6 | /// 7 | /// @see https://www.boost.org/doc/libs/release/libs/utility/doc/html/utility/utilities/string_view.html 8 | template 9 | struct basic_string_view {}; 10 | 11 | } // namespace boost 12 | 13 | namespace std { 14 | 15 | /// !EXTERNAL! 16 | /// 17 | /// @see https://en.cppreference.com/w/cpp/iterator/reverse_iterator 18 | template 19 | struct reverse_iterator {}; 20 | 21 | /// !EXTERNAL! 22 | /// 23 | /// @see https://en.cppreference.com/w/cpp/types/size_t 24 | struct size_t {}; 25 | 26 | /// !EXTERNAL! 27 | /// 28 | /// @see https://en.cppreference.com/w/cpp/types/integer 29 | struct uint64_t {}; 30 | 31 | /// !EXTERNAL! 32 | /// 33 | /// @see https://en.cppreference.com/w/cpp/types/integer 34 | struct int64_t {}; 35 | 36 | /// !EXTERNAL! 37 | /// 38 | /// @see https://en.cppreference.com/w/cpp/types/nullptr_t 39 | struct nullptr_t {}; 40 | 41 | /// !EXTERNAL! 42 | /// 43 | /// @see https://en.cppreference.com/w/cpp/types/ptrdiff_t 44 | struct ptrdiff_t {}; 45 | 46 | /// !EXTERNAL! 47 | /// 48 | /// @see https://en.cppreference.com/w/cpp/utility/initializer_list 49 | template 50 | struct initializer_list {}; 51 | 52 | /// !EXTERNAL! 53 | /// 54 | /// @see https://en.cppreference.com/w/cpp/io/basic_ostream 55 | template 56 | struct basic_ostream {}; 57 | 58 | /// !EXTERNAL! 59 | /// 60 | /// @see https://en.cppreference.com/w/cpp/types/numeric_limits 61 | template 62 | struct numeric_limits {}; 63 | 64 | } // namespace std 65 | -------------------------------------------------------------------------------- /tools/codecov.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # 3 | # Copyright 2017 - 2019 James E. King III 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE_1_0.txt or copy at 6 | # http://www.boost.org/LICENSE_1_0.txt) 7 | # 8 | # Bash script to run in travis to perform codecov.io integration 9 | # 10 | 11 | # assumes cwd is the top level directory of the boost project 12 | # assumes an environment variable $SELF is the boost project name 13 | 14 | set -ex 15 | 16 | . ci/enforce.sh 17 | 18 | if [ -z "$GCOV" ]; then 19 | if [ "${B2_TOOLSET%%-*}" == "gcc" ]; then 20 | ver="${B2_TOOLSET#*-}" 21 | GCOV=gcov-${ver} 22 | else 23 | GCOV=gcov-7 # default 24 | fi 25 | fi 26 | 27 | # lcov after 1.14 needs this 28 | # sudo apt install --no-install-recommends -y libperlio-gzip-perl libjson-perl 29 | 30 | # install the latest lcov we know works 31 | # some older .travis.yml files install the tip which may be unstable 32 | rm -rf /tmp/lcov 33 | pushd /tmp 34 | git clone -b v1.14 https://github.com/linux-test-project/lcov.git 35 | export PATH=/tmp/lcov/bin:$PATH 36 | which lcov 37 | lcov --version 38 | popd 39 | 40 | B2_VARIANT=variant=debug 41 | ci/travis/build.sh cxxflags=--coverage linkflags=--coverage 42 | #cxxflags=-fprofile-arcs cxxflags=-ftest-coverage linkflags=-fprofile-arcs linkflags=-ftest-coverage 43 | 44 | # switch back to the original source code directory 45 | cd $TRAVIS_BUILD_DIR 46 | 47 | # coverage files are in ../../b2 from this location 48 | lcov --gcov-tool=$GCOV --rc lcov_branch_coverage=0 --base-directory "$BOOST_ROOT/libs/$SELF" --directory "$BOOST_ROOT" --capture --output-file all.info 49 | 50 | # all.info contains all the coverage info for all projects - limit to ours 51 | # first we extract the interesting headers for our project then we use that list to extract the right things 52 | for f in `for f in include/boost/*; do echo $f; done | cut -f2- -d/`; do echo "*/$f*"; done > /tmp/interesting 53 | echo headers that matter: 54 | cat /tmp/interesting 55 | xargs -L 999999 -a /tmp/interesting lcov --gcov-tool=$GCOV --rc lcov_branch_coverage=1 --extract all.info {} "*/libs/$SELF/src/*" --output-file coverage.info 56 | 57 | # dump a summary on the console - helps us identify problems in pathing 58 | lcov --gcov-tool=$GCOV --rc lcov_branch_coverage=1 --list coverage.info 59 | 60 | # 61 | # upload to codecov.io 62 | # 63 | curl -s https://codecov.io/bash > .codecov 64 | chmod +x .codecov 65 | ./.codecov -f coverage.info -X gcov -x "$GCOV" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Boost.StaticString 2 | 3 | Branch | GHA CI | Appveyor | Azure Pipelines | codecov.io | Docs | Matrix | 4 | :-------------: | ------ | -------- | --------------- | ---------- | ---- | ------ | 5 | [`master`](https://github.com/boostorg/static_string/tree/master) | [![Build Status](https://github.com/boostorg/static_string/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/static_string/actions?query=branch:master) | [![Build status](https://ci.appveyor.com/api/projects/status/64es4wg4w7mc5wn2/branch/master?svg=true)](https://ci.appveyor.com/project/sdkrystian/static-string/branch/master) | [![Build Status](https://krystiands.visualstudio.com/static_string/_apis/build/status/Boost.StaticString?branchName=master)](https://krystiands.visualstudio.com/static_string/_build/latest?definitionId=3&branchName=master) | [![codecov](https://codecov.io/gh/boostorg/static_string/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/static_string/branch/master) | [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](http://www.boost.org/doc/libs/release/libs/static_string) | [![Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](https://regression.boost.org/master/developer/static_string.html) 6 | [`develop`](https://github.com/boostorg/static_string/tree/develop) | [![Build Status](https://github.com/boostorg/static_string/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/static_string/actions?query=branch:develop) | [![Build status](https://ci.appveyor.com/api/projects/status/64es4wg4w7mc5wn2/branch/develop?svg=true)](https://ci.appveyor.com/project/sdkrystian/static-string/branch/develop) | [![Build Status](https://krystiands.visualstudio.com/static_string/_apis/build/status/Boost.StaticString?branchName=develop)](https://krystiands.visualstudio.com/static_string/_build/latest?definitionId=3&branchName=develop) | [![codecov](https://codecov.io/gh/boostorg/static_string/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/static_string/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/develop/libs/static_string) | [![Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](https://regression.boost.org/develop/developer/static_string.html) 7 | 8 | ## Introduction 9 | 10 | This library provides a dynamically resizable string of characters with 11 | compile-time fixed capacity and contiguous embedded storage in which the 12 | characters are placed within the string object itself. Its API closely 13 | resembles that of `std::string`. 14 | 15 | **[Documentation](http://www.boost.org/doc/libs/release/libs/static_string)** 16 | 17 | ## License 18 | 19 | Distributed under the Boost Software License, Version 1.0. 20 | (See accompanying file [LICENSE_1_0.txt](LICENSE_1_0.txt) or copy at 21 | https://www.boost.org/LICENSE_1_0.txt) 22 | -------------------------------------------------------------------------------- /doc/Jamfile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) 3 | # Copyright (c) 2020 Krystian Stasiowski (sdkrystian at gmail dot com) 4 | # Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) 5 | # 6 | # Distributed under the Boost Software License, Version 1.0. (See accompanying 7 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 | # 9 | 10 | project static_string/doc ; 11 | 12 | import-search /boost/docca ; 13 | 14 | import docca ; 15 | import path ; 16 | import os ; 17 | 18 | local include-prefix = [ path.root $(__file__:D) [ path.pwd ] ] ; 19 | include-prefix = [ path.native $(include-prefix:D)/include ] ; 20 | 21 | docca.pyreference reference.qbk 22 | : 23 | [ glob-tree-ex ../include/boost/static_string : *.hpp *.ipp : detail impl ] 24 | externals.hpp 25 | : 26 | ALIASES="esafe=\"@par Exception Safety\"" 27 | DISTRIBUTE_GROUP_DOC=YES 28 | MACRO_EXPANSION=YES 29 | EXPAND_ONLY_PREDEF=YES 30 | PREDEFINED="\\ 31 | BOOST_STATIC_STRING_DOCS \\ 32 | \"BOOST_STATIC_STRING_CPP11_CONSTEXPR=constexpr\" \\ 33 | \"BOOST_STATIC_STRING_CPP14_CONSTEXPR=constexpr\" \\ 34 | \"BOOST_STATIC_STRING_CPP17_CONSTEXPR=constexpr\" \\ 35 | \"BOOST_STATIC_STRING_CPP20_CONSTEXPR=constexpr\"" 36 | ABBREVIATE_BRIEF= 37 | INLINE_INHERITED_MEMB=YES 38 | JAVADOC_AUTOBRIEF=YES 39 | AUTOLINK_SUPPORT=NO 40 | EXTRACT_ALL=YES 41 | EXTRACT_PRIVATE=YES 42 | EXTRACT_LOCAL_CLASSES=NO 43 | INLINE_INFO=NO 44 | SORT_MEMBER_DOCS=NO 45 | SORT_MEMBERS_CTORS_1ST=YES 46 | STRIP_FROM_PATH=$(include-prefix) 47 | 48 | # ALLOW_UNICODE_NAMES=NO 49 | # GROUP_NESTED_COMPOUNDS=NO 50 | # HIDE_COMPOUND_REFERENCE=NO 51 | # WARN_AS_ERROR=NO 52 | 53 | config.json 54 | ; 55 | 56 | #------------------------------------------------------------------------------- 57 | # 58 | # Produce the Boost.Book XML from the QuickBook 59 | # 60 | 61 | install images 62 | : 63 | : 64 | html/static_string/images 65 | ; 66 | 67 | explicit images ; 68 | 69 | xml static_string_doc 70 | : 71 | qbk/main.qbk 72 | : 73 | images 74 | reference.qbk 75 | ; 76 | 77 | explicit static_string_doc ; 78 | 79 | #------------------------------------------------------------------------------- 80 | # 81 | # HTML documentation for $(BOOST_ROOT)/doc/html 82 | # 83 | #------------------------------------------------------------------------------- 84 | 85 | boostbook static_string 86 | : 87 | static_string_doc 88 | : 89 | boost.root=../../../.. 90 | chapter.autolabel=0 91 | chunk.section.depth=8 # Depth to which sections should be chunked 92 | chunk.first.sections=1 # Chunk the first top-level section? 93 | generate.toc="chapter toc,title section nop reference nop" 94 | ../../../tools/boostbook/dtd 95 | : 96 | images 97 | ; 98 | 99 | #------------------------------------------------------------------------------- 100 | # 101 | # These are used to inform the build system of the 102 | # means to build the integrated and stand-alone docs. 103 | # 104 | 105 | alias boostdoc ; 106 | explicit boostdoc ; 107 | 108 | alias boostrelease : static_string ; 109 | explicit boostrelease ; 110 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | # Official repository: https://github.com/boostorg/static_string 8 | # 9 | 10 | cmake_minimum_required(VERSION 3.8...3.16) 11 | 12 | project(boost_static_string VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) 13 | 14 | set(BOOST_STATIC_STRING_IS_ROOT OFF) 15 | if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 16 | set(BOOST_STATIC_STRING_IS_ROOT ON) 17 | endif () 18 | 19 | if (BOOST_STATIC_STRING_IS_ROOT) 20 | include(CTest) 21 | endif () 22 | 23 | # Options 24 | if (NOT BOOST_SUPERPROJECT_VERSION) 25 | option(BOOST_STATIC_STRING_INSTALL "Install boost::static_string files" ${BOOST_STATIC_STRING_IS_ROOT}) 26 | option(BOOST_STATIC_STRING_BUILD_TESTS "Build boost::static_string tests" OFF) 27 | else () 28 | set(BOOST_STATIC_STRING_BUILD_TESTS ${BUILD_TESTING}) 29 | endif () 30 | 31 | # Find boost 32 | if (BOOST_SUPERPROJECT_VERSION) 33 | set(BOOST_STATIC_STRING_FIND_PACKAGE_BOOST OFF) 34 | elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../CMakeLists.txt" AND 35 | EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../Jamroot" AND 36 | EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../boost-build.jam" AND 37 | EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../bootstrap.sh" AND 38 | EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../libs") 39 | set(BOOST_STATIC_STRING_FIND_PACKAGE_BOOST OFF) 40 | else () 41 | set(BOOST_STATIC_STRING_FIND_PACKAGE_BOOST ON) 42 | endif () 43 | 44 | if (BOOST_STATIC_STRING_FIND_PACKAGE_BOOST) 45 | find_package(Boost 1.78.0 REQUIRED COMPONENTS container) 46 | elseif (BOOST_STATIC_STRING_IS_ROOT) 47 | set(BOOST_STATIC_STRING_UNIT_TEST_LIBRARIES core) 48 | set(BOOST_INCLUDE_LIBRARIES static_string assert container_hash throw_exception utility ${BOOST_STATIC_STRING_UNIT_TEST_LIBRARIES}) 49 | set(BOOST_EXCLUDE_LIBRARIES static_string) 50 | set(CMAKE_FOLDER Dependencies) 51 | add_subdirectory(../.. Dependencies/boost EXCLUDE_FROM_ALL) 52 | unset(CMAKE_FOLDER) 53 | endif () 54 | 55 | # Sources 56 | include(GNUInstallDirs) 57 | file(GLOB_RECURSE BOOST_STATIC_STRING_HEADERS CONFIGURE_DEPENDS 58 | include/boost/*.hpp 59 | include/boost/*.ipp 60 | include/boost/*.natvis 61 | ) 62 | 63 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 64 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/include/boost PREFIX "" FILES ${BOOST_STATIC_STRING_HEADERS}) 65 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/src PREFIX "" FILES ${BOOST_STATIC_STRING_SOURCES}) 66 | 67 | # Target 68 | add_library(boost_static_string INTERFACE) 69 | add_library(Boost::static_string ALIAS boost_static_string) 70 | 71 | target_compile_features(boost_static_string INTERFACE cxx_constexpr) 72 | if (BOOST_SUPERPROJECT_VERSION) 73 | target_include_directories(boost_static_string INTERFACE "${PROJECT_SOURCE_DIR}/include") 74 | else () 75 | target_include_directories(boost_static_string 76 | INTERFACE 77 | "$" 78 | "$" 79 | ) 80 | endif () 81 | 82 | if (BOOST_STATIC_STRING_FIND_PACKAGE_BOOST) 83 | target_link_libraries(boost_static_string 84 | INTERFACE 85 | Boost::headers 86 | ) 87 | else () 88 | target_link_libraries(boost_static_string 89 | INTERFACE 90 | Boost::assert 91 | Boost::container_hash 92 | Boost::core 93 | Boost::throw_exception 94 | Boost::utility 95 | ) 96 | endif () 97 | 98 | if (BOOST_STATIC_STRING_INSTALL AND NOT BOOST_SUPERPROJECT_VERSION) 99 | install(TARGETS boost_static_string 100 | RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" 101 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" 102 | ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" 103 | ) 104 | 105 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/boost 106 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 107 | FILES_MATCHING 108 | PATTERN "*.hpp" 109 | PATTERN "*.ipp" 110 | ) 111 | endif () 112 | 113 | 114 | if (BUILD_TESTING OR BOOST_STATIC_STRING_BUILD_TESTS) 115 | add_subdirectory(test) 116 | endif () 117 | 118 | -------------------------------------------------------------------------------- /.github/workflows/example.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2025 Gennaro Prota (gennaro dot prota at gmail dot com) 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | # file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | # Official repository: https://github.com/boostorg/static_string 8 | # 9 | 10 | name: Example (basic_static_cstring) 11 | 12 | on: 13 | pull_request: 14 | push: 15 | branches: 16 | - master 17 | - develop 18 | - bugfix/** 19 | - feature/** 20 | - fix/** 21 | - github/** 22 | - pr/** 23 | paths-ignore: 24 | - LICENSE 25 | - meta/** 26 | - README.md 27 | 28 | jobs: 29 | linux: 30 | runs-on: ubuntu-24.04 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | include: 35 | - { toolset: gcc-13, cxxstd: '20,23' } 36 | - { toolset: gcc-14, cxxstd: '20,23,26' } 37 | - { toolset: clang-17, cxxstd: '20,23' } 38 | - { toolset: clang-18, cxxstd: '20,23,26' } 39 | 40 | steps: 41 | - name: Checkout Boost super-project 42 | uses: actions/checkout@v4 43 | with: 44 | repository: boostorg/boost 45 | ref: develop 46 | fetch-depth: 0 47 | 48 | - name: Checkout this library 49 | uses: actions/checkout@v4 50 | with: 51 | path: libs/static_string 52 | fetch-depth: 0 53 | 54 | - name: Initialize Boost submodules 55 | run: | 56 | git submodule update --init tools/boostdep 57 | python tools/boostdep/depinst/depinst.py --git_args '--jobs 4' static_string 58 | 59 | - name: Bootstrap b2 60 | run: ./bootstrap.sh 61 | 62 | - name: Generate Boost headers 63 | run: ./b2 headers 64 | 65 | - name: Build and run example tests 66 | run: | 67 | ./b2 libs/static_string/example/static_cstring \ 68 | toolset=${{ matrix.toolset }} \ 69 | cxxstd=${{ matrix.cxxstd }} \ 70 | variant=debug,release \ 71 | -j$(nproc) 72 | 73 | macos: 74 | runs-on: macos-14 75 | strategy: 76 | fail-fast: false 77 | matrix: 78 | include: 79 | - { toolset: clang, cxxstd: '20,23' } 80 | 81 | steps: 82 | - name: Checkout Boost super-project 83 | uses: actions/checkout@v4 84 | with: 85 | repository: boostorg/boost 86 | ref: develop 87 | fetch-depth: 0 88 | 89 | - name: Checkout this library 90 | uses: actions/checkout@v4 91 | with: 92 | path: libs/static_string 93 | fetch-depth: 0 94 | 95 | - name: Initialize Boost submodules 96 | run: | 97 | git submodule update --init tools/boostdep 98 | python3 tools/boostdep/depinst/depinst.py --git_args '--jobs 4' static_string 99 | 100 | - name: Bootstrap b2 101 | run: ./bootstrap.sh 102 | 103 | - name: Generate Boost headers 104 | run: ./b2 headers 105 | 106 | - name: Build and run example tests 107 | run: | 108 | ./b2 libs/static_string/example/static_cstring \ 109 | toolset=${{ matrix.toolset }} \ 110 | cxxstd=${{ matrix.cxxstd }} \ 111 | variant=debug,release \ 112 | -j$(sysctl -n hw.ncpu) 113 | 114 | windows: 115 | runs-on: windows-2022 116 | strategy: 117 | fail-fast: false 118 | matrix: 119 | include: 120 | - { toolset: msvc-14.3, cxxstd: '20,latest' } 121 | 122 | steps: 123 | - name: Checkout Boost super-project 124 | uses: actions/checkout@v4 125 | with: 126 | repository: boostorg/boost 127 | ref: develop 128 | fetch-depth: 0 129 | 130 | - name: Checkout this library 131 | uses: actions/checkout@v4 132 | with: 133 | path: libs/static_string 134 | fetch-depth: 0 135 | 136 | - name: Initialize Boost submodules 137 | run: | 138 | git submodule update --init tools/boostdep 139 | python tools/boostdep/depinst/depinst.py --git_args '--jobs 4' static_string 140 | 141 | - name: Bootstrap b2 142 | run: .\bootstrap.bat 143 | shell: cmd 144 | 145 | - name: Generate Boost headers 146 | run: .\b2 headers 147 | shell: cmd 148 | 149 | - name: Build and run example tests 150 | run: | 151 | .\b2 libs/static_string/example/static_cstring ^ 152 | toolset=${{ matrix.toolset }} ^ 153 | cxxstd=${{ matrix.cxxstd }} ^ 154 | variant=debug,release ^ 155 | address-model=64 156 | shell: cmd 157 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2016, 2017 Peter Dimov 2 | # Copyright 2017 - 2019 James E. King III 3 | # Copyright 2019 - 2021 Alexander Grund 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) 6 | 7 | # 8 | # Generic Appveyor build script for boostorg repositories 9 | # See: https://github.com/boostorg/boost-ci/ 10 | # 11 | # Instructions for customizing this script for your library: 12 | # 13 | # 1. Customize the compilers and language levels you want. 14 | # 2. If you have more than include/, src/, test/, example/, examples/, 15 | # benchmark/ or tools/ directories, set the environment variable DEPINST. 16 | # For example if your build uses code in "bench/" and "fog/" directories: 17 | # - DEPINST: --include bench --include fog 18 | # 3. Enable pull request builds in your boostorg/ account. 19 | # 20 | # That's it - the script will do everything else for you. 21 | # 22 | 23 | version: 1.0.{build}-{branch} 24 | 25 | shallow_clone: false 26 | 27 | branches: 28 | only: 29 | - master 30 | - develop 31 | - /bugfix\/.*/ 32 | - /feature\/.*/ 33 | - /fix\/.*/ 34 | - /pr\/.*/ 35 | 36 | matrix: 37 | fast_finish: false 38 | # Adding MAYFAIL to any matrix job allows it to fail but the build stays green: 39 | allow_failures: 40 | - MAYFAIL: true 41 | 42 | environment: 43 | global: 44 | B2_CI_VERSION: 1 45 | GIT_FETCH_JOBS: 4 46 | # see: http://www.boost.org/build/doc/html/bbv2/overview/invocation.html#bbv2.overview.invocation.properties 47 | # to use the default for a given environment, comment it out; recommend you build debug and release however: 48 | # on Windows it is important to exercise all the possibilities, especially shared vs static, however most 49 | # libraries that care about this exercise it in their Jamfiles... 50 | B2_ADDRESS_MODEL: 32,64 51 | B2_LINK: shared,static 52 | # B2_THREADING: threading=multi,single 53 | B2_VARIANT: release 54 | 55 | matrix: 56 | - FLAVOR: Visual Studio 2022 57 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 58 | B2_CXXFLAGS: -permissive- 59 | B2_CXXSTD: 14,17,20 60 | B2_TOOLSET: msvc-14.3 61 | 62 | - FLAVOR: Visual Studio 2019 63 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 64 | B2_CXXFLAGS: -permissive- 65 | B2_CXXSTD: 14,17,2a 66 | B2_TOOLSET: msvc-14.2 67 | 68 | - FLAVOR: Visual Studio 2017 C++2a Strict 69 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 70 | B2_CXXFLAGS: -permissive- 71 | B2_CXXSTD: 2a 72 | B2_TOOLSET: msvc-14.1 73 | 74 | - FLAVOR: Visual Studio 2017 C++14/17 75 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 76 | B2_CXXSTD: 14,17 77 | B2_TOOLSET: msvc-14.1 78 | 79 | - FLAVOR: clang-cl 80 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 81 | ADDCOMMANDS: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"' 82 | B2_ADDRESS_MODEL: 64 83 | B2_CXXSTD: 11,14,17 84 | B2_TOOLSET: clang-win 85 | 86 | # not supported 87 | # - FLAVOR: Visual Studio 2015, 2013 88 | # APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 89 | # B2_TOOLSET: msvc-12.0,msvc-14.0 90 | 91 | # - FLAVOR: Visual Studio 2008, 2010, 2012 92 | # APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 93 | # B2_TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0 94 | # B2_ADDRESS_MODEL: 32 # No 64bit support 95 | 96 | - FLAVOR: cygwin (32-bit) 97 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 98 | ADDPATH: C:\cygwin\bin; 99 | B2_ADDRESS_MODEL: 32 100 | B2_CXXSTD: 11,14,1z 101 | B2_TOOLSET: gcc 102 | 103 | - FLAVOR: cygwin (64-bit) 104 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 105 | ADDPATH: C:\cygwin64\bin; 106 | B2_ADDRESS_MODEL: 64 107 | B2_CXXSTD: 11,14,1z 108 | B2_TOOLSET: gcc 109 | 110 | - FLAVOR: mingw64 (32-bit) 111 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 112 | ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin; 113 | B2_ADDRESS_MODEL: 32 114 | B2_CXXSTD: 11,14,17,2a 115 | B2_TOOLSET: gcc 116 | 117 | - FLAVOR: mingw64 118 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 119 | ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin; 120 | B2_ADDRESS_MODEL: 64 121 | B2_CXXSTD: 11,14,17,2a 122 | B2_TOOLSET: gcc 123 | 124 | install: 125 | - '%ADDCOMMANDS%' 126 | - git clone --depth 1 https://github.com/boostorg/boost-ci.git C:\boost-ci-cloned 127 | # Copy ci folder if not testing Boost.CI 128 | - if NOT "%APPVEYOR_PROJECT_NAME%" == "boost-ci" xcopy /s /e /q /i /y C:\boost-ci-cloned\ci .\ci 129 | - rmdir /s /q C:\boost-ci-cloned 130 | - ci\appveyor\install.bat 131 | 132 | build: off 133 | 134 | test_script: ci\build.bat 135 | -------------------------------------------------------------------------------- /doc/qbk/main.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 3 | Copyright (c) 2019-2020 Krystian Stasiowski (sdkrystian at gmail dot com) 4 | 5 | Distributed under the Boost Software License, Version 1.0. (See accompanying 6 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | Official repository: https://github.com/boostorg/static_string 9 | ] 10 | 11 | [library Boost.StaticString 12 | [id static_string] 13 | [quickbook 1.6] 14 | [copyright 2019 - 2020 Krystian Stasiowski] 15 | [copyright 2016 - 2019 Vinnie Falco] 16 | [purpose String Library] 17 | [license 18 | Distributed under the Boost Software License, Version 1.0. 19 | (See accompanying file LICENSE_1_0.txt or copy at 20 | [@http://www.boost.org/LICENSE_1_0.txt]) 21 | ] 22 | [authors [Stasiowski, Krystian], [Falco, Vinnie]] 23 | [category template] 24 | [category generic] 25 | ] 26 | 27 | [template mdash[] '''— '''] 28 | [template indexterm1[term1] ''''''[term1]''''''] 29 | [template indexterm2[term1 term2] ''''''[term1]''''''[term2]''''''] 30 | 31 | [template path_link[path name] ''''''[name]''''''] 32 | [template include_file[path][^<''''''[path]''''''>]] 33 | 34 | [def __InputIterator__ [@https://en.cppreference.com/w/cpp/named_req/InputIterator ['InputIterator]]] 35 | [def __UnaryPredicate__ [@https://en.cppreference.com/w/cpp/named_req/Predicate ['Predicate]]] 36 | 37 | [/-----------------------------------------------------------------------------] 38 | 39 | [heading Introduction] 40 | 41 | This library provides a dynamically resizable string of characters with 42 | compile-time fixed capacity and contiguous embedded storage in which the 43 | characters are placed within the string object itself. Its API closely 44 | resembles that of `std::string`. 45 | 46 | [/-----------------------------------------------------------------------------] 47 | 48 | [heading Motivation] 49 | 50 | A fixed capacity string is useful when: 51 | 52 | * Memory allocation is not possible, e.g., embedded environments without a free 53 | store, where only a stack and the static memory segment are available. 54 | * Memory allocation imposes an unacceptable performance penalty. 55 | e.g., with respect to latency. 56 | * Allocation of objects with complex lifetimes in the static-memory 57 | segment is required. 58 | * A dynamically-resizable string is required within `constexpr` functions. 59 | * The storage location of the static_vector elements is required to be 60 | within the string object itself (e.g. to support `memcpy` for serialization 61 | purposes). 62 | 63 | [/-----------------------------------------------------------------------------] 64 | 65 | [heading Requirements] 66 | 67 | The library is usable in two different modes: standalone and Boost dependent. This library defaults to Boost dependent mode; standalone mode is opt-in through the use of a configuration macro. 68 | 69 | When in Boost dependent mode, the library requires the use of at least C++11, in addition to Boost.Core, Boost.Utility, and Boost.ContainerHash. In standalone mode, C++17 is required but no libraries except for the standard library are needed. 70 | 71 | [/-----------------------------------------------------------------------------] 72 | 73 | [heading Design] 74 | 75 | The over-arching design goal is to resemble the interface and behavior of 76 | `std::string` as much as possible. When any operation would exceed the 77 | maximum allowed size of the string, `std::length_error` is thrown if exceptions are enabled. All 78 | algorithms which throw exceptions provide the strong exception safety 79 | guarantee. This is intended to be a drop in replacement for `std::string`. 80 | 81 | The API of `static_string` only diverges from `std::string` in few places, 82 | one of which is the addition of the `subview` function, for which this implementation 83 | returns a string view instead of `static_string`, 84 | and certain functions that will never throw are marked as `noexcept`, which diverges from 85 | those of `std::string`. The available overloads for `static_string` are identical to those 86 | of `std::string`. 87 | 88 | [/-----------------------------------------------------------------------------] 89 | 90 | [heading Iterators] 91 | 92 | The iterator invalidation rules differ from those of `std::string`: 93 | 94 | * Moving a `static_string` invalidates all iterators 95 | * Swapping two `static_string`s invalidates all iterators 96 | 97 | [/-----------------------------------------------------------------------------] 98 | 99 | [heading Optimizations] 100 | 101 | Depending on the character type and size used for a specialization of `static_string`, certain optimizations are used to reduce the size of the class type. Given the name of a specialization of the form `basic_static_string`: 102 | 103 | * If `N` is 0, then the class has no non-static data members. Given two objects `a` and `b` of type `basic_static_string<0, T, Traits>` and `static_string<0, U, Traits>` respectively, the pointer value returned by `data()` will be the same if `T` and `U` are the same. 104 | 105 | * Otherwise, the type of the member used to store the size of the `static_string` will be the smallest standard unsigned integer type that can represent the value `N`. 106 | 107 | [/-----------------------------------------------------------------------------] 108 | 109 | [heading Configuration] 110 | 111 | Certain features can be enabled and disabled though defining configuration macros. The macros and the associated feature they control are: 112 | 113 | * `BOOST_STATIC_STRING_STANDALONE`: When defined, the library is put into standalone mode. 114 | 115 | [/-----------------------------------------------------------------------------] 116 | 117 | [heading Acknowledgments] 118 | 119 | Thanks to [@https://github.com/K-ballo Agustín Bergé], [@https://github.com/pdimov Peter Dimov], [@https://github.com/glenfe Glen Fernandes], and [@https://github.com/LeonineKing1199 Christian Mazakas] for their constant feedback and guidance during the development of this library. 120 | 121 | The development of this library is sponsored by [@https://cppalliance.org The C++ Alliance]. 122 | 123 | [/-----------------------------------------------------------------------------] 124 | 125 | [heading Reference] 126 | 127 | Defined in namespace `boost::static_strings`: 128 | 129 | [link static_string.ref.boost__static_strings__basic_static_string `basic_static_string`] 130 | 131 | [/-----------------------------------------------------------------------------] 132 | 133 | [section:ref Reference] 134 | [include reference.qbk] 135 | [endsect] 136 | 137 | [/-----------------------------------------------------------------------------] 138 | 139 | [xinclude index.xml] -------------------------------------------------------------------------------- /.drone.star: -------------------------------------------------------------------------------- 1 | # Use, modification, and distribution are 2 | # subject to the Boost Software License, Version 1.0. (See accompanying 3 | # file LICENSE.txt) 4 | # 5 | # Copyright (c) 2020 Rene Rivera 6 | # Copyright (c) 2022 Alan de Freitas 7 | # Copyright (c) 2022-2025 Alexander Grund 8 | 9 | # For Drone CI we use the Starlark scripting language to reduce duplication. 10 | # As the yaml syntax for Drone CI is rather limited. 11 | 12 | # Base environment for all jobs 13 | globalenv={'B2_VARIANT': 'release'} 14 | 15 | # Wrapper function to apply the globalenv to all jobs 16 | def job( 17 | # job specific environment options 18 | env={}, 19 | **kwargs): 20 | real_env = dict(globalenv) 21 | real_env.update(env) 22 | return job_impl(env=real_env, **kwargs) 23 | 24 | def main(ctx): 25 | return [ 26 | job(compiler='clang-3.8', cxxstd='11,14', os='ubuntu-16.04'), 27 | job(compiler='clang-3.9', cxxstd='11,14', os='ubuntu-18.04'), 28 | job(compiler='clang-4.0', cxxstd='11,14', os='ubuntu-18.04'), 29 | job(compiler='clang-5.0', cxxstd='11,14,1z', os='ubuntu-18.04'), 30 | job(compiler='clang-6.0', cxxstd='11,14,17', os='ubuntu-18.04'), 31 | job(compiler='clang-7', cxxstd='11,14,17', os='ubuntu-18.04'), 32 | job(compiler='clang-8', cxxstd='11,14,17,2a', os='ubuntu-18.04'), 33 | job(compiler='clang-9', cxxstd='11,14,17,2a', os='ubuntu-18.04'), 34 | job(compiler='clang-10', cxxstd='11,14,17,2a', os='ubuntu-18.04'), 35 | job(compiler='clang-11', cxxstd='11,14,17,2a', os='ubuntu-22.04'), 36 | job(compiler='clang-12', cxxstd='11,14,17,20', os='ubuntu-22.04'), 37 | job(compiler='clang-13', cxxstd='11,14,17,20,2b', os='ubuntu-22.04'), 38 | job(compiler='clang-14', cxxstd='11,14,17,20,2b', os='ubuntu-22.04'), 39 | job(compiler='clang-15', cxxstd='11,14,17,20,2b', os='ubuntu-22.04', add_llvm=True, 40 | env={'B2_CXXFLAGS': '-Werror'}), 41 | job(name='Clang 15 standalone', compiler='clang-15', cxxstd='17,20,2b', os='ubuntu-22.04', add_llvm=True, 42 | env={'B2_CXXFLAGS': '-Werror', 'B2_DEFINES': 'BOOST_STATIC_STRING_STANDALONE'}), 43 | 44 | job(compiler='gcc-4.8', cxxstd='11', os='ubuntu-16.04'), 45 | job(compiler='gcc-4.9', cxxstd='11', os='ubuntu-16.04'), 46 | job(compiler='gcc-5', cxxstd='11,14,1z', os='ubuntu-18.04'), 47 | job(compiler='gcc-6', cxxstd='11,14,1z', os='ubuntu-18.04'), 48 | job(compiler='gcc-7', cxxstd='11,14,1z', os='ubuntu-18.04'), 49 | job(compiler='gcc-8', cxxstd='11,14,17,2a', os='ubuntu-18.04'), 50 | job(compiler='gcc-9', cxxstd='11,14,17,2a', os='ubuntu-18.04'), 51 | job(compiler='gcc-10', cxxstd='11,14,17,20', os='ubuntu-22.04'), 52 | job(compiler='gcc-11', cxxstd='11,14,17,20,2b', os='ubuntu-22.04'), 53 | job(compiler='gcc-12', cxxstd='11,14,17,20,2b', os='ubuntu-22.04'), 54 | 55 | job(name='Coverage', buildtype='codecov', buildscript='codecov_coveralls', env={'LCOV_BRANCH_COVERAGE': 1, "COVERALLS_REPO_TOKEN": {"from_secret": "coveralls_repo_token"}}, 56 | compiler='gcc-8', cxxstd='11,14,17,2a', os='ubuntu-18.04'), 57 | # Sanitizers 58 | job(name='ASAN', asan=True, 59 | compiler='gcc-12', cxxstd='11,14,17,20', os='ubuntu-22.04'), 60 | job(name='UBSAN', ubsan=True, 61 | compiler='gcc-12', cxxstd='11,14,17,20', os='ubuntu-22.04'), 62 | job(name='TSAN', tsan=True, 63 | compiler='gcc-12', cxxstd='11,14,17,20', os='ubuntu-22.04'), 64 | job(name='Clang 14 w/ sanitizers', asan=True, ubsan=True, 65 | compiler='clang-14', cxxstd='11,14,17,20', os='ubuntu-22.04'), 66 | job(name='Clang 11 libc++ w/ sanitizers', asan=True, ubsan=True, # libc++-11 is the latest working with ASAN: https://github.com/llvm/llvm-project/issues/59432 67 | compiler='clang-11', cxxstd='11,14,17,20', os='ubuntu-20.04', stdlib='libc++', install='libc++-11-dev libc++abi-11-dev'), 68 | job(name='Valgrind', valgrind=True, 69 | compiler='clang-6.0', cxxstd='11,14,1z', os='ubuntu-18.04', install='libc6-dbg libc++-dev libstdc++-8-dev'), 70 | 71 | # libc++ 72 | job(compiler='clang-6.0', cxxstd='11,14,17,2a', os='ubuntu-18.04', stdlib='libc++', install='libc++-dev libc++abi-dev'), 73 | job(compiler='clang-7', cxxstd='11,14,17,2a', os='ubuntu-20.04', stdlib='libc++', install='libc++-7-dev libc++abi-7-dev'), 74 | job(compiler='clang-8', cxxstd='11,14,17,2a', os='ubuntu-20.04', stdlib='libc++', install='libc++-8-dev libc++abi-8-dev'), 75 | job(compiler='clang-9', cxxstd='11,14,17,2a', os='ubuntu-20.04', stdlib='libc++', install='libc++-9-dev libc++abi-9-dev'), 76 | job(compiler='clang-10', cxxstd='11,14,17,20', os='ubuntu-20.04', stdlib='libc++', install='libc++-10-dev libc++abi-10-dev'), 77 | job(compiler='clang-11', cxxstd='11,14,17,20', os='ubuntu-20.04', stdlib='libc++', install='libc++-11-dev libc++abi-11-dev'), 78 | job(compiler='clang-12', cxxstd='11,14,17,20', os='ubuntu-22.04', stdlib='libc++', install='libc++-12-dev libc++abi-12-dev libunwind-12-dev'), 79 | job(compiler='clang-13', cxxstd='11,14,17,20', os='ubuntu-22.04', stdlib='libc++', install='libc++-13-dev libc++abi-13-dev'), 80 | job(compiler='clang-14', cxxstd='11,14,17,20', os='ubuntu-22.04', stdlib='libc++', install='libc++-14-dev libc++abi-14-dev'), 81 | job(compiler='clang-15', cxxstd='11,14,17,20', os='ubuntu-22.04', stdlib='libc++', install='libc++-15-dev libc++abi-15-dev', add_llvm=True), 82 | 83 | # FreeBSD 84 | job(compiler='clang-10', cxxstd='11,14,17,20', os='freebsd-13.1'), 85 | job(compiler='clang-15', cxxstd='11,14,17,20', os='freebsd-13.1'), 86 | job(compiler='gcc-11', cxxstd='11,14,17,20', os='freebsd-13.1', linkflags='-Wl,-rpath=/usr/local/lib/gcc11'), 87 | # OSX 88 | job(compiler='clang', cxxstd='11,14,17,2a', os='osx-xcode-10.1'), 89 | job(compiler='clang', cxxstd='11,14,17,2a', os='osx-xcode-10.3'), 90 | job(compiler='clang', cxxstd='11,14,17,2a', os='osx-xcode-11.1'), 91 | job(compiler='clang', cxxstd='11,14,17,2a', os='osx-xcode-11.7'), 92 | job(compiler='clang', cxxstd='11,14,17,2a', os='osx-xcode-12'), 93 | job(compiler='clang', cxxstd='11,14,17,20', os='osx-xcode-12.5.1'), 94 | job(compiler='clang', cxxstd='11,14,17,20', os='osx-xcode-13.0'), 95 | job(compiler='clang', cxxstd='11,14,17,20', os='osx-xcode-13.4.1'), 96 | job(compiler='clang', cxxstd='11,14,17,20,2b', os='osx-xcode-14.0'), 97 | job(compiler='clang', cxxstd='11,14,17,20,2b', os='osx-xcode-14.3.1'), 98 | job(compiler='clang', cxxstd='11,14,17,20,2b', os='osx-xcode-15.0.1'), 99 | # ARM64 100 | job(compiler='clang-12', cxxstd='11,14,17,20', os='ubuntu-20.04', arch='arm64', add_llvm=True), 101 | job(compiler='gcc-11', cxxstd='11,14,17,20', os='ubuntu-20.04', arch='arm64'), 102 | # S390x 103 | job(compiler='clang-12', cxxstd='11,14,17,20', os='ubuntu-20.04', arch='s390x', add_llvm=True), 104 | job(compiler='gcc-11', cxxstd='11,14,17,20', os='ubuntu-20.04', arch='s390x'), 105 | # Windows 106 | job(compiler='msvc-14.0', cxxstd=None, os='windows', env={'B2_DONT_EMBED_MANIFEST': 1}), 107 | job(compiler='msvc-14.1', cxxstd=None, os='windows'), 108 | job(compiler='msvc-14.2', cxxstd=None, os='windows'), 109 | job(compiler='msvc-14.3', cxxstd=None, os='windows'), 110 | job(compiler='msvc-14.0', cxxstd='14,17,20', os='windows', env={'B2_DONT_EMBED_MANIFEST': 1}), 111 | job(compiler='msvc-14.1', cxxstd='14,17,20', os='windows'), 112 | job(compiler='msvc-14.2', cxxstd='14,17,20', os='windows'), 113 | job(compiler='msvc-14.3', cxxstd='14,17,20,latest', os='windows'), 114 | ] 115 | 116 | # from https://github.com/boostorg/boost-ci 117 | load("@boost_ci//ci/drone/:functions.star", "linux_cxx", "windows_cxx", "osx_cxx", "freebsd_cxx", "job_impl") 118 | -------------------------------------------------------------------------------- /include/boost/static_string/config.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 3 | // Copyright (c) 2019-2020 Krystian Stasiowski (sdkrystian at gmail dot com) 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | // 8 | // Official repository: https://github.com/boostorg/static_string 9 | // 10 | 11 | #ifndef BOOST_STATIC_STRING_CONFIG_HPP 12 | #define BOOST_STATIC_STRING_CONFIG_HPP 13 | 14 | // Are we dependent on Boost? 15 | // #define BOOST_STATIC_STRING_STANDALONE 16 | 17 | #include 18 | 19 | // detect 32/64 bit 20 | #if UINTPTR_MAX == UINT64_MAX 21 | #define BOOST_STATIC_STRING_ARCH 64 22 | #elif UINTPTR_MAX == UINT32_MAX 23 | #define BOOST_STATIC_STRING_ARCH 32 24 | #else 25 | #error Unknown or unsupported architecture, please open an issue 26 | #endif 27 | 28 | // Can we have deduction guides? 29 | #if __cpp_deduction_guides >= 201703L 30 | #define BOOST_STATIC_STRING_USE_DEDUCT 31 | #endif 32 | 33 | // Include if we can 34 | #ifdef __has_include 35 | #if __has_include() 36 | #include 37 | #endif 38 | #endif 39 | 40 | // Can we use __has_builtin? 41 | #ifdef __has_builtin 42 | #define BOOST_STATIC_STRING_HAS_BUILTIN(arg) __has_builtin(arg) 43 | #else 44 | #define BOOST_STATIC_STRING_HAS_BUILTIN(arg) 0 45 | #endif 46 | 47 | // Can we use is_constant_evaluated? 48 | #if __cpp_lib_is_constant_evaluated >= 201811L 49 | #define BOOST_STATIC_STRING_IS_CONST_EVAL std::is_constant_evaluated() 50 | #elif BOOST_STATIC_STRING_HAS_BUILTIN(__builtin_is_constant_evaluated) 51 | #define BOOST_STATIC_STRING_IS_CONST_EVAL __builtin_is_constant_evaluated() 52 | #endif 53 | 54 | // Check for an attribute 55 | #if defined(__has_cpp_attribute) 56 | #define BOOST_STATIC_STRING_CHECK_FOR_ATTR(x) __has_cpp_attribute(x) 57 | #elif defined(__has_attribute) 58 | #define BOOST_STATIC_STRING_CHECK_FOR_ATTR(x) __has_attribute(x) 59 | #else 60 | #define BOOST_STATIC_STRING_CHECK_FOR_ATTR(x) 0 61 | #endif 62 | 63 | // Decide which attributes we can use 64 | #define BOOST_STATIC_STRING_UNLIKELY 65 | #define BOOST_STATIC_STRING_NODISCARD 66 | #define BOOST_STATIC_STRING_NORETURN 67 | #define BOOST_STATIC_STRING_NO_NORETURN 68 | // unlikely 69 | #if BOOST_STATIC_STRING_CHECK_FOR_ATTR(unlikely) 70 | #undef BOOST_STATIC_STRING_UNLIKELY 71 | #define BOOST_STATIC_STRING_UNLIKELY [[unlikely]] 72 | #endif 73 | // nodiscard 74 | #if BOOST_STATIC_STRING_CHECK_FOR_ATTR(nodiscard) 75 | #undef BOOST_STATIC_STRING_NODISCARD 76 | #define BOOST_STATIC_STRING_NODISCARD [[nodiscard]] 77 | #elif defined(_MSC_VER) && _MSC_VER >= 1700 78 | #undef BOOST_STATIC_STRING_NODISCARD 79 | #define BOOST_STATIC_STRING_NODISCARD _Check_return_ 80 | #elif defined(__GNUC__) || defined(__clang__) 81 | #undef BOOST_STATIC_STRING_NODISCARD 82 | #define BOOST_STATIC_STRING_NODISCARD __attribute__((warn_unused_result)) 83 | #endif 84 | // noreturn 85 | #if BOOST_STATIC_STRING_CHECK_FOR_ATTR(noreturn) 86 | #undef BOOST_STATIC_STRING_NORETURN 87 | #undef BOOST_STATIC_STRING_NO_NORETURN 88 | #define BOOST_STATIC_STRING_NORETURN [[noreturn]] 89 | #elif defined(_MSC_VER) 90 | #undef BOOST_STATIC_STRING_NORETURN 91 | #undef BOOST_STATIC_STRING_NO_NORETURN 92 | #define BOOST_STATIC_STRING_NORETURN __declspec(noreturn) 93 | #elif defined(__GNUC__) || defined(__clang__) 94 | #undef BOOST_STATIC_STRING_NORETURN 95 | #undef BOOST_STATIC_STRING_NO_NORETURN 96 | #define BOOST_STATIC_STRING_NORETURN __attribute__((__noreturn__)) 97 | #endif 98 | 99 | // _MSVC_LANG isn't avaliable until after VS2015 100 | #if defined(_MSC_VER) && _MSC_VER < 1910L 101 | // The constexpr support in this version is effectively that of 102 | // c++11, so we treat it as such 103 | #define BOOST_STATIC_STRING_STANDARD_VERSION 201103L 104 | #elif defined(_MSVC_LANG) 105 | // MSVC doesn't define __cplusplus by default 106 | #define BOOST_STATIC_STRING_STANDARD_VERSION _MSVC_LANG 107 | #else 108 | #define BOOST_STATIC_STRING_STANDARD_VERSION __cplusplus 109 | #endif 110 | 111 | // Decide what level of constexpr we can use 112 | #define BOOST_STATIC_STRING_CPP20_CONSTEXPR 113 | #define BOOST_STATIC_STRING_CPP17_CONSTEXPR 114 | #define BOOST_STATIC_STRING_CPP14_CONSTEXPR 115 | #define BOOST_STATIC_STRING_CPP11_CONSTEXPR 116 | #if BOOST_STATIC_STRING_STANDARD_VERSION >= 202002L 117 | #define BOOST_STATIC_STRING_CPP20 118 | #undef BOOST_STATIC_STRING_CPP20_CONSTEXPR 119 | #define BOOST_STATIC_STRING_CPP20_CONSTEXPR constexpr 120 | #endif 121 | #if BOOST_STATIC_STRING_STANDARD_VERSION >= 201703L 122 | #define BOOST_STATIC_STRING_CPP17 123 | #undef BOOST_STATIC_STRING_CPP17_CONSTEXPR 124 | #define BOOST_STATIC_STRING_CPP17_CONSTEXPR constexpr 125 | #endif 126 | #if BOOST_STATIC_STRING_STANDARD_VERSION >= 201402L 127 | #define BOOST_STATIC_STRING_CPP14 128 | #undef BOOST_STATIC_STRING_CPP14_CONSTEXPR 129 | #define BOOST_STATIC_STRING_CPP14_CONSTEXPR constexpr 130 | #endif 131 | #if BOOST_STATIC_STRING_STANDARD_VERSION >= 201103L 132 | #define BOOST_STATIC_STRING_CPP11 133 | #undef BOOST_STATIC_STRING_CPP11_CONSTEXPR 134 | #define BOOST_STATIC_STRING_CPP11_CONSTEXPR constexpr 135 | #endif 136 | 137 | // Boost and non-Boost versions of utilities 138 | #ifndef BOOST_STATIC_STRING_STANDALONE 139 | #ifndef BOOST_STATIC_STRING_THROW 140 | #define BOOST_STATIC_STRING_THROW(ex) BOOST_THROW_EXCEPTION(ex) 141 | #endif 142 | #ifndef BOOST_STATIC_STRING_ASSERT 143 | #define BOOST_STATIC_STRING_ASSERT(cond) BOOST_ASSERT(cond) 144 | #endif 145 | #else 146 | #ifndef BOOST_STATIC_STRING_THROW 147 | #define BOOST_STATIC_STRING_THROW(ex) throw ex 148 | #endif 149 | #ifndef BOOST_STATIC_STRING_ASSERT 150 | #define BOOST_STATIC_STRING_ASSERT(cond) assert(cond) 151 | #endif 152 | #endif 153 | 154 | #ifndef BOOST_STATIC_STRING_STANDALONE 155 | #include 156 | #include 157 | #include 158 | #include 159 | #include 160 | #include 161 | 162 | #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) || \ 163 | defined(BOOST_STATIC_STRING_CXX17_STRING_VIEW) 164 | #include 165 | #define BOOST_STATIC_STRING_HAS_STD_STRING_VIEW 166 | #endif 167 | #else 168 | #include 169 | #include 170 | 171 | #if defined(__has_include) 172 | # if !__has_include() 173 | # define BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW 174 | # endif 175 | /* 176 | * Replicate the logic from Boost.Config 177 | */ 178 | // GNU libstdc++3: 179 | #elif defined(__GLIBCPP__) || defined(__GLIBCXX__) 180 | # if ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 70100) || (__cplusplus <= 201402L) 181 | # define BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW 182 | # endif 183 | // libc++: 184 | #elif defined(_LIBCPP_VERSION) 185 | # if (_LIBCPP_VERSION < 4000) || (__cplusplus <= 201402L) 186 | # define BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW 187 | # endif 188 | // MSVC uses logic from catch all for BOOST_NO_CXX17_HDR_STRING_VIEW 189 | // catch all: 190 | #elif !defined(_YVALS) && !defined(_CPPLIB_VER) 191 | # if (!defined(__has_include) || (__cplusplus < 201700)) 192 | # define BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW 193 | # elif !__has_include() 194 | # define BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW 195 | # endif 196 | #endif 197 | 198 | #if !defined(BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW) || \ 199 | defined(BOOST_STATIC_STRING_CXX17_STRING_VIEW) 200 | #include 201 | #define BOOST_STATIC_STRING_HAS_STD_STRING_VIEW 202 | #endif 203 | #endif 204 | 205 | // Compiler bug prevents constexpr from working with clang 4.x and 5.x 206 | // if it is detected, we disable constexpr. 207 | #if (BOOST_STATIC_STRING_STANDARD_VERSION >= 201402L && \ 208 | BOOST_STATIC_STRING_STANDARD_VERSION < 201703L) && \ 209 | defined(__clang__) && \ 210 | ((__clang_major__ == 4) || (__clang_major__ == 5)) 211 | // This directive works on clang 212 | #warning "C++14 constexpr is not supported in clang 4.x and 5.x due to a compiler bug." 213 | #ifdef BOOST_STATIC_STRING_CPP14 214 | #undef BOOST_STATIC_STRING_CPP14 215 | #endif 216 | #undef BOOST_STATIC_STRING_CPP14_CONSTEXPR 217 | #define BOOST_STATIC_STRING_CPP14_CONSTEXPR 218 | #endif 219 | 220 | // This is for compiler/library configurations 221 | // that cannot use the library comparison function 222 | // objects at all in constant expresssions. In these 223 | // cases, we use whatever will make more constexpr work. 224 | #if defined(__clang__) && \ 225 | (defined(__GLIBCXX__) || defined(_MSC_VER)) 226 | #define BOOST_STATIC_STRING_NO_PTR_COMP_FUNCTIONS 227 | #endif 228 | 229 | // In gcc-5, we cannot use throw expressions in a 230 | // constexpr function. However, we have a workaround 231 | // for this using constructors. Also, non-static member 232 | // functions that return the class they are a member of 233 | // causes an ICE during constant evaluation. 234 | #if defined(__GNUC__) && (__GNUC__== 5) && \ 235 | defined(BOOST_STATIC_STRING_CPP14) 236 | #define BOOST_STATIC_STRING_GCC5_BAD_CONSTEXPR 237 | #endif 238 | 239 | #ifndef BOOST_STATIC_STRING_STANDALONE 240 | #if ! defined(BOOST_NO_CWCHAR) && ! defined(BOOST_NO_SWPRINTF) 241 | #define BOOST_STATIC_STRING_HAS_WCHAR 242 | #endif 243 | #else 244 | #ifndef __has_include 245 | // If we don't have __has_include in standalone, 246 | // we will assume that exists. 247 | #define BOOST_STATIC_STRING_HAS_WCHAR 248 | #elif __has_include() 249 | #define BOOST_STATIC_STRING_HAS_WCHAR 250 | #endif 251 | #endif 252 | 253 | #ifdef BOOST_STATIC_STRING_HAS_WCHAR 254 | #include 255 | #endif 256 | 257 | // Define the basic string_view type used by the library 258 | // Conversions to and from other available string_view types 259 | // are still defined. 260 | #if !defined(BOOST_STATIC_STRING_STANDALONE) || \ 261 | defined(BOOST_STATIC_STRING_HAS_STD_STRING_VIEW) 262 | #define BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW 263 | namespace boost { 264 | namespace static_strings { 265 | 266 | /// The type of `basic_string_view` used by the library 267 | template 268 | using basic_string_view = 269 | #ifndef BOOST_STATIC_STRING_STANDALONE 270 | boost::basic_string_view; 271 | #else 272 | std::basic_string_view; 273 | #endif 274 | } // static_strings 275 | } // boost 276 | #endif 277 | 278 | #if defined(__cpp_lib_to_string) && __cpp_lib_to_string >= 202306L // std::to_[w]string() redefined in terms of std::format() 279 | #define BOOST_STATIC_STRING_USE_STD_FORMAT 280 | #endif 281 | 282 | #if defined(__GNUC__) && (__GNUC__ >= 5) && (__GNUC__ <= 10) && !defined(__clang__) 283 | // Workaround for GCC complaining about nested classes being private. 284 | #define BOOST_STATIC_STRING_GCC_NESTED_CLASS_WORKAROUND public: 285 | #else 286 | #define BOOST_STATIC_STRING_GCC_NESTED_CLASS_WORKAROUND 287 | #endif 288 | 289 | // GCC 9 incorrectly rejects the pointer equality comparison in 290 | // ptr_in_range() in constant expressions. GCC 10 and later handle 291 | // it correctly. 292 | // 293 | // Clang 3.7 and 9-19 have the same issue. 294 | #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ == 9)) \ 295 | || (defined(__clang__) && ((__clang_major__ == 3 && __clang_minor__ == 7) || ((__clang_major__ >= 9) && (__clang_major__ <= 19)))) 296 | #define BOOST_STATIC_STRING_CONSTEXPR_PTR_CMP_BROKEN 297 | #endif 298 | 299 | #endif 300 | -------------------------------------------------------------------------------- /example/static_cstring/static_cstring.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2025 Gennaro Prota (gennaro dot prota at gmail dot com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // Official repository: https://github.com/boostorg/static_string 8 | // 9 | 10 | #ifndef BOOST_STATIC_STRING_STATIC_CSTRING_HPP 11 | #define BOOST_STATIC_STRING_STATIC_CSTRING_HPP 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace boost { 24 | namespace static_strings { 25 | 26 | namespace detail { 27 | 28 | // Primary template: No remaining-capacity trick; uses traits::length() for length. 29 | template 30 | class static_cstring_base 31 | { 32 | public: 33 | using traits_type = Traits; 34 | using value_type = CharT; 35 | using size_type = std::size_t; 36 | 37 | value_type data_[N + 1]{}; 38 | 39 | constexpr size_type get_size() const noexcept 40 | { 41 | return traits_type::length(data_); 42 | } 43 | 44 | constexpr void set_size(size_type sz) noexcept 45 | { 46 | data_[sz] = value_type{}; 47 | } 48 | 49 | // Defaulted comparisons for structural type support. 50 | constexpr bool operator==(const static_cstring_base&) const noexcept = default; 51 | constexpr auto operator<=>(const static_cstring_base&) const noexcept = default; 52 | }; 53 | 54 | // Specialization for N <= UCHAR_MAX: Uses remaining-capacity trick. 55 | template 56 | class static_cstring_base 57 | { 58 | public: 59 | using traits_type = Traits; 60 | using value_type = CharT; 61 | using size_type = std::size_t; 62 | 63 | value_type data_[N + 1]{}; 64 | 65 | constexpr size_type get_size() const noexcept 66 | { 67 | return N - static_cast(data_[N]); 68 | } 69 | 70 | constexpr void set_size(size_type sz) noexcept 71 | { 72 | data_[sz] = value_type{}; 73 | data_[N] = static_cast(N - sz); 74 | } 75 | 76 | // Defaulted comparisons for structural type support. 77 | constexpr bool operator==(const static_cstring_base&) const noexcept = default; 78 | constexpr auto operator<=>(const static_cstring_base&) const noexcept = default; 79 | }; 80 | 81 | } // namespace detail 82 | 83 | template> 84 | class basic_static_cstring 85 | : public detail::static_cstring_base 86 | { 87 | public: 88 | using base = detail::static_cstring_base; 89 | using base::data_; 90 | using base::get_size; 91 | using base::set_size; 92 | 93 | // Member types 94 | using traits_type = Traits; 95 | using value_type = CharT; 96 | using size_type = std::size_t; 97 | using difference_type = std::ptrdiff_t; 98 | using reference = value_type&; 99 | using const_reference = const value_type&; 100 | using pointer = value_type*; 101 | using const_pointer = const value_type*; 102 | using iterator = pointer; 103 | using const_iterator = const_pointer; 104 | 105 | static constexpr size_type npos = static_cast(-1); 106 | static constexpr size_type static_capacity = N; 107 | 108 | // Constructors. 109 | constexpr basic_static_cstring() noexcept 110 | { 111 | set_size(0); 112 | } 113 | 114 | constexpr basic_static_cstring(const CharT* s) 115 | { 116 | assign(s); 117 | } 118 | 119 | constexpr basic_static_cstring(const CharT* s, size_type count) 120 | { 121 | assign(s, count); 122 | } 123 | 124 | constexpr basic_static_cstring(size_type count, CharT ch) 125 | { 126 | assign(count, ch); 127 | } 128 | 129 | template 130 | constexpr basic_static_cstring(const CharT (&arr)[M]) 131 | { 132 | static_assert(M <= N + 1, "String literal too long for static_cstring"); 133 | assign(arr, M - 1); 134 | } 135 | 136 | constexpr size_type size() const noexcept 137 | { 138 | return get_size(); 139 | } 140 | 141 | constexpr size_type length() const noexcept 142 | { 143 | return size(); 144 | } 145 | 146 | constexpr bool empty() const noexcept 147 | { 148 | return data_[0] == value_type{}; 149 | } 150 | 151 | static constexpr size_type max_size() noexcept 152 | { 153 | return N; 154 | } 155 | 156 | static constexpr size_type capacity() noexcept 157 | { 158 | return N; 159 | } 160 | 161 | // Element access. 162 | constexpr reference operator[](size_type pos) noexcept 163 | { 164 | return data_[pos]; 165 | } 166 | 167 | constexpr const_reference operator[](size_type pos) const noexcept 168 | { 169 | return data_[pos]; 170 | } 171 | 172 | constexpr reference at(size_type pos) 173 | { 174 | if (pos >= size()) 175 | { 176 | throw std::out_of_range("static_cstring::at"); 177 | } 178 | return data_[pos]; 179 | } 180 | 181 | constexpr const_reference at(size_type pos) const 182 | { 183 | if (pos >= size()) 184 | { 185 | throw std::out_of_range("static_cstring::at"); 186 | } 187 | return data_[pos]; 188 | } 189 | 190 | constexpr reference front() noexcept 191 | { 192 | BOOST_STATIC_STRING_ASSERT(!empty()); 193 | return data_[0]; 194 | } 195 | 196 | constexpr const_reference front() const noexcept 197 | { 198 | BOOST_STATIC_STRING_ASSERT(!empty()); 199 | return data_[0]; 200 | } 201 | 202 | constexpr reference back() noexcept 203 | { 204 | BOOST_STATIC_STRING_ASSERT(!empty()); 205 | return data_[size() - 1]; 206 | } 207 | 208 | constexpr const_reference back() const noexcept 209 | { 210 | BOOST_STATIC_STRING_ASSERT(!empty()); 211 | return data_[size() - 1]; 212 | } 213 | 214 | constexpr pointer data() noexcept 215 | { 216 | return data_; 217 | } 218 | 219 | constexpr const_pointer data() const noexcept 220 | { 221 | return data_; 222 | } 223 | 224 | constexpr const_pointer c_str() const noexcept 225 | { 226 | return data_; 227 | } 228 | 229 | // Iterators. 230 | constexpr iterator begin() noexcept 231 | { 232 | return data_; 233 | } 234 | 235 | constexpr const_iterator begin() const noexcept 236 | { 237 | return data_; 238 | } 239 | 240 | constexpr const_iterator cbegin() const noexcept 241 | { 242 | return data_; 243 | } 244 | 245 | constexpr iterator end() noexcept 246 | { 247 | return data_ + size(); 248 | } 249 | 250 | constexpr const_iterator end() const noexcept 251 | { 252 | return data_ + size(); 253 | } 254 | 255 | constexpr const_iterator cend() const noexcept 256 | { 257 | return data_ + size(); 258 | } 259 | 260 | // Modifiers. 261 | constexpr void clear() noexcept 262 | { 263 | set_size(0); 264 | } 265 | 266 | constexpr basic_static_cstring& assign(const CharT* s) 267 | { 268 | return assign(s, traits_type::length(s)); 269 | } 270 | 271 | constexpr basic_static_cstring& assign(const CharT* s, size_type count) 272 | { 273 | if (count > N) 274 | { 275 | throw std::length_error("static_cstring::assign"); 276 | } 277 | traits_type::copy(data_, s, count); 278 | set_size(count); 279 | return *this; 280 | } 281 | 282 | constexpr basic_static_cstring& assign(size_type count, CharT ch) 283 | { 284 | if (count > N) 285 | { 286 | throw std::length_error("static_cstring::assign"); 287 | } 288 | traits_type::assign(data_, count, ch); 289 | set_size(count); 290 | return *this; 291 | } 292 | 293 | constexpr basic_static_cstring& operator=(const CharT* s) 294 | { 295 | return assign(s); 296 | } 297 | 298 | constexpr void push_back(CharT ch) 299 | { 300 | const size_type sz = size(); 301 | if (sz >= N) 302 | { 303 | throw std::length_error("static_cstring::push_back"); 304 | } 305 | data_[sz] = ch; 306 | set_size(sz + 1); 307 | } 308 | 309 | constexpr void pop_back() noexcept 310 | { 311 | BOOST_STATIC_STRING_ASSERT(!empty()); 312 | set_size(size() - 1); 313 | } 314 | 315 | constexpr basic_static_cstring& append(const CharT* s) 316 | { 317 | return append(s, traits_type::length(s)); 318 | } 319 | 320 | constexpr basic_static_cstring& append(const CharT* s, size_type count) 321 | { 322 | const size_type sz = size(); 323 | if (sz + count > N) 324 | { 325 | throw std::length_error("static_cstring::append"); 326 | } 327 | traits_type::copy(data_ + sz, s, count); 328 | set_size(sz + count); 329 | return *this; 330 | } 331 | 332 | constexpr basic_static_cstring& append(size_type count, CharT ch) 333 | { 334 | const size_type sz = size(); 335 | if (sz + count > N) 336 | { 337 | throw std::length_error("static_cstring::append"); 338 | } 339 | traits_type::assign(data_ + sz, count, ch); 340 | set_size(sz + count); 341 | return *this; 342 | } 343 | 344 | constexpr basic_static_cstring& operator+=(const CharT* s) 345 | { 346 | return append(s); 347 | } 348 | 349 | constexpr basic_static_cstring& operator+=(CharT ch) 350 | { 351 | push_back(ch); 352 | return *this; 353 | } 354 | 355 | // Comparisons. 356 | constexpr int compare(const basic_static_cstring& other) const noexcept 357 | { 358 | const size_type lhs_sz = size(); 359 | const size_type rhs_sz = other.size(); 360 | const int result = traits_type::compare(data_, other.data_, (std::min)(lhs_sz, rhs_sz)); 361 | 362 | return result != 0 363 | ? result 364 | : lhs_sz < rhs_sz 365 | ? -1 366 | : lhs_sz > rhs_sz 367 | ? 1 368 | : 0; 369 | } 370 | 371 | constexpr int compare(const CharT* s) const noexcept 372 | { 373 | return compare(basic_static_cstring(s)); 374 | } 375 | 376 | // Conversions. 377 | constexpr operator std::basic_string_view() const noexcept 378 | { 379 | return {data_, size()}; 380 | } 381 | 382 | std::basic_string str() const 383 | { 384 | return {data_, size()}; 385 | } 386 | 387 | // Swap. 388 | constexpr void swap(basic_static_cstring& other) noexcept 389 | { 390 | basic_static_cstring tmp = *this; 391 | *this = other; 392 | other = tmp; 393 | } 394 | 395 | // Defaulted comparisons for structural type (C++20). 396 | constexpr bool operator==(const basic_static_cstring&) const noexcept = default; 397 | constexpr auto operator<=>(const basic_static_cstring&) const noexcept = default; 398 | }; 399 | 400 | #if defined(BOOST_STATIC_STRING_USE_DEDUCT) 401 | 402 | // Deduction guide. 403 | template 404 | basic_static_cstring(const CharT(&)[N]) -> basic_static_cstring; 405 | 406 | #endif 407 | 408 | // Comparison with const CharT*. 409 | template 410 | constexpr bool operator==(const basic_static_cstring& lhs, 411 | const CharT* rhs) noexcept 412 | { 413 | return lhs.compare(rhs) == 0; 414 | } 415 | 416 | template 417 | constexpr bool operator==(const CharT* lhs, 418 | const basic_static_cstring& rhs) noexcept 419 | { 420 | return rhs.compare(lhs) == 0; 421 | } 422 | 423 | // Stream output. 424 | template 425 | std::basic_ostream& operator<<(std::basic_ostream& os, 426 | const basic_static_cstring& str) 427 | { 428 | return os << str.c_str(); 429 | } 430 | 431 | // Alias templates. 432 | template 433 | using static_cstring = basic_static_cstring; 434 | 435 | template 436 | using static_wcstring = basic_static_cstring; 437 | 438 | } 439 | } 440 | 441 | #endif 442 | -------------------------------------------------------------------------------- /test/constexpr_tests.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019-2020 Krystian Stasiowski (sdkrystian at gmail dot com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // Official repository: https://github.com/boostorg/static_string 8 | // 9 | 10 | #include 11 | 12 | #include 13 | 14 | namespace boost { 15 | namespace static_strings { 16 | 17 | // char_traits aren't fully constexpr until c++20 18 | #ifdef BOOST_STATIC_STRING_CPP14 19 | struct cxper_char_traits 20 | { 21 | using char_type = char; 22 | using int_type = int; 23 | using state_type = std::mbstate_t; 24 | 25 | static constexpr void assign(char_type& a, const char_type& b) noexcept 26 | { 27 | a = b; 28 | } 29 | 30 | static constexpr bool eq(char_type a, char_type b) noexcept 31 | { 32 | return a == b; 33 | } 34 | 35 | static constexpr bool lt(char_type a, char_type b) noexcept 36 | { 37 | return a < b; 38 | } 39 | 40 | static constexpr int compare(const char_type* a, const char_type* b, std::size_t n) 41 | { 42 | for (; n--; ++a, ++b) 43 | { 44 | if(lt(*a, *b)) 45 | return 1; 46 | else if(lt(*b, *a)) 47 | return -1; 48 | } 49 | return 0; 50 | } 51 | 52 | static constexpr std::size_t length(const char_type* s) 53 | { 54 | auto ptr = s; 55 | while (!eq(*ptr, char_type())) 56 | ++ptr; 57 | return ptr - s; 58 | } 59 | 60 | static constexpr const char_type* find(const char_type* s, std::size_t n, const char_type& ch) 61 | { 62 | for (; n--; ++s) 63 | { 64 | if (eq(*s, ch)) 65 | return s; 66 | } 67 | return nullptr; 68 | } 69 | 70 | static constexpr char_type* move(char_type* dest, const char_type* src, std::size_t n) 71 | { 72 | // This implementation does not handle overlapping ranges where 73 | // dest > src. A correct implementation would need to detect this 74 | // case and copy backwards, but detecting overlap requires pointer 75 | // comparisons that many of the tested compiles (incorrectly) refuse 76 | // in constant expressions. 77 | // 78 | // Since cxper_char_traits is only used for testing constexpr 79 | // functionality and the tests do not exercise overlapping moves 80 | // where dest > src, this simple forward copy is sufficient. 81 | return copy(dest, src, n); 82 | } 83 | 84 | static constexpr char_type* copy(char_type* dest, const char_type* src, std::size_t n) 85 | { 86 | for (auto ptr = dest; n--;) 87 | assign(*ptr++, *src++); 88 | return dest; 89 | } 90 | 91 | static constexpr char_type* assign(char_type* dest, std::size_t n, char_type ch) 92 | { 93 | for (auto ptr = dest; n--;) 94 | assign(*ptr++, ch); 95 | return dest; 96 | } 97 | }; 98 | #else 99 | using cxper_char_traits = std::char_traits; 100 | #endif 101 | using cstatic_string = basic_static_string<50, char, cxper_char_traits>; 102 | 103 | inline 104 | constexpr 105 | bool 106 | testConstantEvaluation() 107 | { 108 | #ifdef BOOST_STATIC_STRING_CPP20 109 | 110 | // Check construction in a constexpr context 111 | constexpr basic_static_string s("hello"); 112 | static_assert(s.size() == 5); 113 | static_assert(s.static_capacity == 5); 114 | static_assert(s == "hello"); 115 | 116 | // Check assignment in a constexpr context 117 | constexpr auto s2 = 118 | []() 119 | { 120 | basic_static_string s("hello"); 121 | s = "world"; 122 | return s; 123 | }(); 124 | static_assert(s2 == "world"); 125 | 126 | // c++20 constexpr tests 127 | cstatic_string a; 128 | cstatic_string b(1, 'a'); 129 | cstatic_string(b, 0); 130 | cstatic_string(b, 0, 1); 131 | cstatic_string("a", 1); 132 | cstatic_string("a"); 133 | cstatic_string{b}; 134 | cstatic_string({'a'}); 135 | 136 | // assignment 137 | a = b; 138 | a = "a"; 139 | a = 'a'; 140 | a = {'a'}; 141 | 142 | // assign 143 | a.assign(b); 144 | a.assign(b, 0, 1); 145 | a.assign("a", 1); 146 | a.assign("a"); 147 | a.assign(b.begin(), b.end()); 148 | a.assign({'a'}); 149 | a.assign(1, 'a'); 150 | 151 | // element access 152 | { 153 | auto j = a.at(0); 154 | static_cast(j); 155 | } 156 | { 157 | auto j = a[0]; 158 | static_cast(j); 159 | } 160 | { 161 | auto j = a.front(); 162 | static_cast(j); 163 | } 164 | { 165 | auto j = a.back(); 166 | static_cast(j); 167 | } 168 | a.data(); 169 | a.c_str(); 170 | a.begin(); 171 | a.cbegin(); 172 | a.end(); 173 | a.cend(); 174 | 175 | // reverse iterators 176 | a.rbegin(); 177 | a.crbegin(); 178 | a.rend(); 179 | a.crend(); 180 | 181 | // capacity and size 182 | cstatic_string().size(); 183 | // this is potentially marked nodiscard 184 | static_cast(cstatic_string().empty()); 185 | cstatic_string().length(); 186 | cstatic_string().max_size(); 187 | cstatic_string().capacity(); 188 | 189 | // clear 190 | a.clear(); 191 | 192 | // insert 193 | a.insert(a.begin(), 1, 'a'); 194 | a.insert(0, a.begin()); 195 | a.insert(0, a.begin(), 1); 196 | a.insert(a.begin(), 'a'); 197 | a.insert(a.begin(), {'a'}); 198 | 199 | // erase 200 | a.erase(0, 1); 201 | a.erase(a.begin()); 202 | a.erase(a.begin(), a.end()); 203 | 204 | // push 205 | a.push_back('a'); 206 | a.pop_back(); 207 | 208 | // append 209 | a.append(1, 'a'); 210 | a.append("a", 1); 211 | a.append("a"); 212 | a.append(a.begin(), a.end()); 213 | a.append({'a'}); 214 | 215 | // append operator 216 | a += 'a'; 217 | a += "a"; 218 | a += {'a'}; 219 | 220 | // compare 221 | a.compare(b); 222 | a.compare(0, 1, b); 223 | a.compare(0, 1, b, 0, 1); 224 | a.compare("a"); 225 | a.compare(0, 1, "a"); 226 | a.compare(0, 1, "a", 1); 227 | 228 | a.substr(0); 229 | 230 | #ifdef BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW 231 | // subview 232 | a.subview(0); 233 | #endif 234 | 235 | // copy 236 | char k[20]{}; 237 | a.copy(k, 1, 0); 238 | 239 | // resize 240 | a.resize(1); 241 | a.resize(1, 'a'); 242 | 243 | // swap 244 | a.swap(b); 245 | 246 | // replace 247 | a.replace(0, 1, a); 248 | a.replace(0, 1, a, 0, 1); 249 | a.replace(0, 1, a.data(), 1); 250 | a.replace(0, 1, a.data()); 251 | a.replace(0, 1, 1, 'a'); 252 | a.replace(a.begin(), a.end(), a); 253 | a.replace(a.begin(), a.end(), a.data(), 1); 254 | a.replace(a.begin(), a.end(), a.data()); 255 | a.replace(a.begin(), a.end(), 1, 'a'); 256 | a.replace(a.begin(), a.end(), a.begin(), a.end()); 257 | a.replace(a.begin(), a.end(), {'a'}); 258 | 259 | #if defined(BOOST_STATIC_STRING_IS_CONST_EVAL) \ 260 | && !defined(BOOST_STATIC_STRING_CONSTEXPR_PTR_CMP_BROKEN) 261 | a.clear(); 262 | a.replace(a.begin(), a.end(), "a"); 263 | a.replace(a.begin(), a.end(), "a", 1); 264 | #endif 265 | 266 | // find 267 | a.find(a); 268 | a.find("a", 0, 1); 269 | a.find("a", 0); 270 | a.find('a', 0); 271 | 272 | // rfind 273 | a.rfind(a); 274 | a.rfind("a", 0, 1); 275 | a.rfind("a", 0); 276 | a.rfind('a', 0); 277 | 278 | // find_first_of 279 | a.find_first_of(a); 280 | a.find_first_of("a", 0, 1); 281 | a.find_first_of("a", 0); 282 | a.find_first_of('a', 0); 283 | 284 | // find_first_not_of 285 | a.find_first_not_of(a); 286 | a.find_first_not_of("a", 0, 1); 287 | a.find_first_not_of("a", 0); 288 | a.find_first_not_of('a', 0); 289 | 290 | // starts_with 291 | a.starts_with('a'); 292 | a.starts_with("a"); 293 | 294 | // ends_with 295 | a.ends_with('a'); 296 | a.ends_with("a"); 297 | 298 | return true; 299 | #elif defined(BOOST_STATIC_STRING_CPP17) 300 | //c++17 constexpr tests 301 | 302 | // ctors 303 | cstatic_string a; 304 | cstatic_string b(1, 'a'); 305 | cstatic_string(b, 0); 306 | cstatic_string(b, 0, 1); 307 | cstatic_string("a", 1); 308 | cstatic_string("a"); 309 | cstatic_string{b}; 310 | cstatic_string({'a'}); 311 | 312 | // assignment 313 | a = b; 314 | a = "a"; 315 | a = 'a'; 316 | a = {'a'}; 317 | 318 | // assign 319 | a.assign(b); 320 | a.assign(b, 0, 1); 321 | a.assign("a", 1); 322 | a.assign("a"); 323 | a.assign(b.begin(), b.end()); 324 | a.assign({'a'}); 325 | a.assign(1, 'a'); 326 | 327 | // element access 328 | { 329 | auto j = a.at(0); 330 | static_cast(j); 331 | } 332 | { 333 | auto j = a[0]; 334 | static_cast(j); 335 | } 336 | { 337 | auto j = a.front(); 338 | static_cast(j); 339 | } 340 | { 341 | auto j = a.back(); 342 | static_cast(j); 343 | } 344 | a.data(); 345 | a.c_str(); 346 | a.begin(); 347 | a.cbegin(); 348 | a.end(); 349 | a.cend(); 350 | 351 | // reverse iterators 352 | //{ 353 | // auto j = a.rbegin(); 354 | //} 355 | //{ 356 | // auto j = a.crbegin(); 357 | //} 358 | //{ 359 | // auto j = a.rend(); 360 | //} 361 | //{ 362 | // auto j = a.crend(); 363 | //} 364 | 365 | // capacity and size 366 | cstatic_string().size(); 367 | // this is potentially marked nodiscard 368 | static_cast(cstatic_string().empty()); 369 | cstatic_string().length(); 370 | cstatic_string().max_size(); 371 | cstatic_string().capacity(); 372 | 373 | // clear 374 | a.clear(); 375 | 376 | // insert 377 | a.insert(a.begin(), 1, 'a'); 378 | a.insert(0, a.begin()); 379 | a.insert(0, a.begin(), 1); 380 | a.insert(a.begin(), 'a'); 381 | a.insert(a.begin(), {'a'}); 382 | 383 | // erase 384 | a.erase(0, 1); 385 | a.erase(a.begin()); 386 | a.erase(a.begin(), a.end()); 387 | 388 | // push 389 | a.push_back('a'); 390 | a.pop_back(); 391 | 392 | // append 393 | a.append(1, 'a'); 394 | a.append("a", 1); 395 | a.append("a"); 396 | a.append(a.begin(), a.end()); 397 | a.append({'a'}); 398 | 399 | // append operator 400 | a += 'a'; 401 | a += "a"; 402 | a += {'a'}; 403 | 404 | // compare 405 | a.compare(b); 406 | a.compare(0, 1, b); 407 | a.compare(0, 1, b, 0, 1); 408 | a.compare("a"); 409 | a.compare(0, 1, "a"); 410 | a.compare(0, 1, "a", 1); 411 | 412 | // substr 413 | // in gcc 5, a constexpr non-static member function returning the class 414 | // is a member of causes an ICE 415 | #ifndef BOOST_STATIC_STRING_GCC5_BAD_CONSTEXPR 416 | a.substr(0); 417 | #endif 418 | 419 | #ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW 420 | // subview 421 | a.subview(0); 422 | #endif 423 | 424 | // copy 425 | char k[20]{}; 426 | a.copy(k, 1, 0); 427 | 428 | // resize 429 | a.resize(1); 430 | a.resize(1, 'a'); 431 | 432 | // swap 433 | a.swap(b); 434 | 435 | // replace 436 | a.replace(0, 1, a); 437 | a.replace(0, 1, a, 0, 1); 438 | a.replace(0, 1, a.data(), 1); 439 | a.replace(0, 1, a.data()); 440 | a.replace(0, 1, 1, 'a'); 441 | a.replace(a.begin(), a.end(), a); 442 | a.replace(a.begin(), a.end(), a.data(), 1); 443 | a.replace(a.begin(), a.end(), a.data()); 444 | a.replace(a.begin(), a.end(), 1, 'a'); 445 | a.replace(a.begin(), a.end(), a.begin(), a.end()); 446 | a.replace(a.begin(), a.end(), {'a'}); 447 | 448 | #if defined(BOOST_STATIC_STRING_IS_CONST_EVAL) \ 449 | && !defined(BOOST_STATIC_STRING_CONSTEXPR_PTR_CMP_BROKEN) 450 | a.clear(); 451 | a.replace(a.begin(), a.end(), "a"); 452 | a.replace(a.begin(), a.end(), "a", 1); 453 | #endif 454 | 455 | // find 456 | a.find(a); 457 | a.find("a", 0, 1); 458 | a.find("a", 0); 459 | a.find('a', 0); 460 | 461 | // rfind 462 | a.rfind(a); 463 | a.rfind("a", 0, 1); 464 | a.rfind("a", 0); 465 | a.rfind('a', 0); 466 | 467 | // find_first_of 468 | a.find_first_of(a); 469 | a.find_first_of("a", 0, 1); 470 | a.find_first_of("a", 0); 471 | a.find_first_of('a', 0); 472 | 473 | // find_first_not_of 474 | a.find_first_not_of(a); 475 | a.find_first_not_of("a", 0, 1); 476 | a.find_first_not_of("a", 0); 477 | a.find_first_not_of('a', 0); 478 | 479 | // starts_with 480 | a.starts_with('a'); 481 | a.starts_with("a"); 482 | 483 | // ends_with 484 | a.ends_with('a'); 485 | a.ends_with("a"); 486 | 487 | return true; 488 | #elif defined(BOOST_STATIC_STRING_CPP14) 489 | // c++14 constexpr tests 490 | 491 | // ctors 492 | cstatic_string a; 493 | cstatic_string b(1, 'a'); 494 | cstatic_string(b, 0); 495 | cstatic_string(b, 0, 1); 496 | cstatic_string("a", 1); 497 | cstatic_string("a"); 498 | cstatic_string{b}; 499 | cstatic_string({'a'}); 500 | 501 | // assignment 502 | a = b; 503 | a = "a"; 504 | a = 'a'; 505 | a = {'a'}; 506 | 507 | // assign 508 | a.assign(b); 509 | a.assign(b, 0, 1); 510 | a.assign("a", 1); 511 | a.assign("a"); 512 | a.assign(b.begin(), b.end()); 513 | a.assign({'a'}); 514 | a.assign(1, 'a'); 515 | 516 | // element access 517 | { 518 | auto j = a.at(0); 519 | static_cast(j); 520 | } 521 | { 522 | auto j = a[0]; 523 | static_cast(j); 524 | } 525 | { 526 | auto j = a.front(); 527 | static_cast(j); 528 | } 529 | { 530 | auto j = a.back(); 531 | static_cast(j); 532 | } 533 | a.data(); 534 | a.c_str(); 535 | a.begin(); 536 | a.cbegin(); 537 | a.end(); 538 | a.cend(); 539 | 540 | // capacity and size 541 | cstatic_string().size(); 542 | // this is potentially marked nodiscard 543 | static_cast(cstatic_string().empty()); 544 | cstatic_string().length(); 545 | cstatic_string().max_size(); 546 | cstatic_string().capacity(); 547 | 548 | // clear 549 | a.clear(); 550 | 551 | // insert 552 | a.insert(a.begin(), 1, 'a'); 553 | a.insert(0, a.begin()); 554 | a.insert(0, a.begin(), 1); 555 | a.insert(a.begin(), 'a'); 556 | a.insert(a.begin(), {'a'}); 557 | 558 | // erase 559 | a.erase(0, 1); 560 | a.erase(a.begin()); 561 | a.erase(a.begin(), a.end()); 562 | 563 | // push 564 | a.push_back('a'); 565 | a.pop_back(); 566 | 567 | // append 568 | a.append(1, 'a'); 569 | a.append("a", 1); 570 | a.append("a"); 571 | a.append(a.begin(), a.end()); 572 | a.append({'a'}); 573 | 574 | // append operator 575 | a += 'a'; 576 | a += "a"; 577 | a += {'a'}; 578 | 579 | // compare 580 | a.compare(b); 581 | a.compare(0, 1, b); 582 | a.compare(0, 1, b, 0, 1); 583 | a.compare("a"); 584 | a.compare(0, 1, "a"); 585 | a.compare(0, 1, "a", 1); 586 | 587 | // substr 588 | // in gcc 5, a constexpr non-static member function returning the class 589 | // is a member of causes an ICE 590 | #ifndef BOOST_STATIC_STRING_GCC5_BAD_CONSTEXPR 591 | a.substr(0, 1); 592 | #endif 593 | 594 | // subview 595 | a.subview(0); 596 | 597 | // copy 598 | char k[20]{}; 599 | a.copy(k, 1, 0); 600 | 601 | // resize 602 | a.resize(1); 603 | a.resize(1, 'a'); 604 | 605 | // swap 606 | a.swap(b); 607 | 608 | // replace 609 | a.replace(0, 1, a); 610 | a.replace(0, 1, a, 0, 1); 611 | a.replace(0, 1, a.data(), 1); 612 | a.replace(0, 1, a.data()); 613 | a.replace(0, 1, 1, 'a'); 614 | a.replace(a.begin(), a.end(), a); 615 | a.replace(a.begin(), a.end(), a.data(), 1); 616 | a.replace(a.begin(), a.end(), a.data()); 617 | a.replace(a.begin(), a.end(), 1, 'a'); 618 | a.replace(a.begin(), a.end(), a.begin(), a.end()); 619 | a.replace(a.begin(), a.end(), {'a'}); 620 | 621 | #if defined(BOOST_STATIC_STRING_IS_CONST_EVAL) \ 622 | && !defined(BOOST_STATIC_STRING_CONSTEXPR_PTR_CMP_BROKEN) 623 | a.clear(); 624 | a.replace(a.begin(), a.end(), "a"); 625 | a.replace(a.begin(), a.end(), "a", 1); 626 | #endif 627 | 628 | // find 629 | a.find(a); 630 | a.find("a", 0, 1); 631 | a.find("a", 0); 632 | a.find('a', 0); 633 | 634 | // rfind 635 | a.rfind(a); 636 | a.rfind("a", 0, 1); 637 | a.rfind("a", 0); 638 | a.rfind('a', 0); 639 | 640 | // find_first_of 641 | a.find_first_of(a); 642 | a.find_first_of("a", 0, 1); 643 | a.find_first_of("a", 0); 644 | a.find_first_of('a', 0); 645 | 646 | // find_first_not_of 647 | a.find_first_not_of(a); 648 | a.find_first_not_of("a", 0, 1); 649 | a.find_first_not_of("a", 0); 650 | a.find_first_not_of('a', 0); 651 | 652 | // starts_with 653 | a.starts_with('a'); 654 | a.starts_with("a"); 655 | 656 | // ends_with 657 | a.ends_with('a'); 658 | a.ends_with("a"); 659 | return true; 660 | #elif defined(BOOST_STATIC_STRING_CPP11) 661 | // c++11 constexpr tests 662 | return (cstatic_string().size() + 663 | cstatic_string().length() + 664 | cstatic_string().max_size() + 665 | cstatic_string().capacity()) != 0 && 666 | cstatic_string().empty(); 667 | #endif 668 | } 669 | 670 | #if __cpp_nontype_template_args >= 201911L 671 | 672 | template X> 673 | struct nttp_primary 674 | { 675 | static constexpr bool value = false; 676 | }; 677 | 678 | template<> 679 | struct nttp_primary<"test string"> 680 | { 681 | static constexpr bool value = true; 682 | }; 683 | 684 | static_assert(!nttp_primary<"random string">::value, 685 | "structural equality broken"); 686 | 687 | static_assert(nttp_primary<"test string">::value, 688 | "structural equality broken"); 689 | 690 | #endif 691 | 692 | } // static_strings 693 | } // boost 694 | -------------------------------------------------------------------------------- /example/static_cstring/static_cstring_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2025 Gennaro Prota (gennaro dot prota at gmail dot com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // Official repository: https://github.com/boostorg/static_string 8 | // 9 | 10 | #include "static_cstring.hpp" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace boost { 21 | namespace static_strings { 22 | 23 | static 24 | void 25 | testCStringSizeGuarantee() 26 | { 27 | // Core guarantee: sizeof is exactly N + 1 (no size member). 28 | static_assert(sizeof(static_cstring<0>) == 1, ""); 29 | static_assert(sizeof(static_cstring<1>) == 2, ""); 30 | static_assert(sizeof(static_cstring<10>) == 11, ""); 31 | static_assert(sizeof(static_cstring<63>) == 64, ""); 32 | static_assert(sizeof(static_cstring<64>) == 65, ""); 33 | static_assert(sizeof(static_cstring<127>) == 128, ""); 34 | static_assert(sizeof(static_cstring) == (UCHAR_MAX + 1), ""); 35 | static_assert(sizeof(static_cstring) == (UCHAR_MAX + 2), ""); 36 | static_assert(sizeof(static_cstring<1000>) == 1001, ""); 37 | } 38 | 39 | static 40 | void 41 | testCStringRemainingCapacityTrick() 42 | { 43 | // Test the remaining-capacity optimization for N <= UCHAR_MAX. 44 | 45 | // Full capacity: Last byte is both null terminator AND remaining == 0. 46 | { 47 | static_cstring<5> full("12345"); 48 | BOOST_TEST(full.size() == 5); 49 | BOOST_TEST(full.capacity() == 5); 50 | BOOST_TEST(full.data()[5] == '\0'); 51 | BOOST_TEST(std::strcmp(full.c_str(), "12345") == 0); 52 | } 53 | 54 | // Partial fill: Null terminator at position size, remaining at position N. 55 | { 56 | static_cstring<10> partial("Hi"); 57 | BOOST_TEST(partial.size() == 2); 58 | BOOST_TEST(partial.capacity() == 10); 59 | BOOST_TEST(partial.data()[2] == '\0'); 60 | BOOST_TEST(static_cast(partial.data()[10]) == 8); 61 | } 62 | 63 | // Empty string. 64 | { 65 | static_cstring<10> empty; 66 | BOOST_TEST(empty.size() == 0); 67 | BOOST_TEST(empty.capacity() == 10); 68 | BOOST_TEST(empty.data()[0] == '\0'); 69 | BOOST_TEST(static_cast(empty.data()[10]) == 10); 70 | } 71 | 72 | // Edge case: N == UCHAR_MAX (max for our trick). 73 | { 74 | static_cstring large; 75 | large.assign(100, 'x'); 76 | BOOST_TEST(large.size() == 100); 77 | BOOST_TEST(large.capacity() == UCHAR_MAX); 78 | BOOST_TEST(static_cast(large.data()[UCHAR_MAX]) == (UCHAR_MAX - large.size())); 79 | } 80 | } 81 | 82 | template 83 | struct CStringTypeTraits 84 | { 85 | static_assert(std::is_trivially_copyable::value); 86 | static_assert(std::is_trivially_copy_constructible::value); 87 | static_assert(std::is_trivially_move_constructible::value); 88 | static_assert(std::is_trivially_copy_assignable::value); 89 | static_assert(std::is_trivially_move_assignable::value); 90 | static_assert(std::is_trivially_destructible::value); 91 | }; 92 | 93 | static 94 | void 95 | testCStringTypeTraits() 96 | { 97 | { 98 | using S = static_cstring<0>; 99 | CStringTypeTraits< S > check; 100 | static_cast(check); 101 | } 102 | { 103 | using S = static_cstring<63>; 104 | CStringTypeTraits< S > check; 105 | static_cast(check); 106 | } 107 | { 108 | using S = static_cstring<300>; 109 | CStringTypeTraits< S > check; 110 | static_cast(check); 111 | } 112 | } 113 | 114 | static 115 | void 116 | testCStringConstruct() 117 | { 118 | // Default construction. 119 | { 120 | static_cstring<1> s; 121 | BOOST_TEST(s.empty()); 122 | BOOST_TEST(s.size() == 0); 123 | BOOST_TEST(s == ""); 124 | BOOST_TEST(*s.end() == 0); 125 | } 126 | 127 | // Construct with count and char. 128 | { 129 | static_cstring<4> s1(3, 'x'); 130 | BOOST_TEST(!s1.empty()); 131 | BOOST_TEST(s1.size() == 3); 132 | BOOST_TEST(s1 == "xxx"); 133 | BOOST_TEST(*s1.end() == 0); 134 | BOOST_TEST_THROWS( 135 | (static_cstring<2>(3, 'x')), 136 | std::length_error); 137 | } 138 | 139 | // Construct from a C string. 140 | { 141 | static_cstring<5> s1("12345"); 142 | BOOST_TEST(s1.size() == 5); 143 | BOOST_TEST(s1 == "12345"); 144 | BOOST_TEST(*s1.end() == 0); 145 | BOOST_TEST_THROWS( 146 | (static_cstring<4>("12345")), 147 | std::length_error); 148 | } 149 | 150 | // Construct from a C string with count. 151 | { 152 | static_cstring<5> s1("UVXYZ", 3); 153 | BOOST_TEST(s1 == "UVX"); 154 | BOOST_TEST(*s1.end() == 0); 155 | } 156 | 157 | // Copy construction. 158 | { 159 | static_cstring<5> s1("12345"); 160 | static_cstring<5> s2(s1); 161 | BOOST_TEST(s2 == "12345"); 162 | BOOST_TEST(*s2.end() == 0); 163 | } 164 | } 165 | 166 | static 167 | void 168 | testCStringAssignment() 169 | { 170 | // assign(size_type count, CharT ch). 171 | BOOST_TEST(static_cstring<3>{}.assign(1, '*') == "*"); 172 | BOOST_TEST(static_cstring<3>{}.assign(3, '*') == "***"); 173 | BOOST_TEST(static_cstring<3>{"abc"}.assign(3, '*') == "***"); 174 | BOOST_TEST_THROWS(static_cstring<1>{"a"}.assign(2, '*'), std::length_error); 175 | 176 | // assign(CharT const* s, size_type count). 177 | BOOST_TEST(static_cstring<3>{}.assign("abc", 3) == "abc"); 178 | BOOST_TEST(static_cstring<3>{"*"}.assign("abc", 3) == "abc"); 179 | BOOST_TEST_THROWS(static_cstring<1>{}.assign("abc", 3), std::length_error); 180 | 181 | // assign(CharT const* s). 182 | BOOST_TEST(static_cstring<3>{}.assign("abc") == "abc"); 183 | BOOST_TEST(static_cstring<3>{"*"}.assign("abc") == "abc"); 184 | BOOST_TEST_THROWS(static_cstring<1>{}.assign("abc"), std::length_error); 185 | 186 | // operator=(const CharT* s). 187 | { 188 | static_cstring<3> s1; 189 | s1 = "123"; 190 | BOOST_TEST(s1 == "123"); 191 | BOOST_TEST(*s1.end() == 0); 192 | static_cstring<1> s2; 193 | BOOST_TEST_THROWS( 194 | s2 = "123", 195 | std::length_error); 196 | } 197 | 198 | // Copy assignment. 199 | { 200 | static_cstring<3> s1("123"); 201 | static_cstring<3> s2; 202 | s2 = s1; 203 | BOOST_TEST(s2 == "123"); 204 | BOOST_TEST(*s2.end() == 0); 205 | } 206 | } 207 | 208 | static 209 | void 210 | testCStringElements() 211 | { 212 | using ccs3 = static_cstring<3> const; 213 | 214 | // at(size_type pos). 215 | BOOST_TEST(static_cstring<3>{"abc"}.at(0) == 'a'); 216 | BOOST_TEST(static_cstring<3>{"abc"}.at(2) == 'c'); 217 | BOOST_TEST_THROWS(static_cstring<3>{""}.at(0), std::out_of_range); 218 | BOOST_TEST_THROWS(static_cstring<3>{"abc"}.at(4), std::out_of_range); 219 | 220 | // at(size_type pos) const. 221 | BOOST_TEST(ccs3{"abc"}.at(0) == 'a'); 222 | BOOST_TEST(ccs3{"abc"}.at(2) == 'c'); 223 | BOOST_TEST_THROWS(ccs3{""}.at(0), std::out_of_range); 224 | 225 | // operator[](size_type pos). 226 | BOOST_TEST(static_cstring<3>{"abc"}[0] == 'a'); 227 | BOOST_TEST(static_cstring<3>{"abc"}[2] == 'c'); 228 | BOOST_TEST(static_cstring<3>{"abc"}[3] == 0); 229 | BOOST_TEST(static_cstring<3>{""}[0] == 0); 230 | 231 | // front() / back(). 232 | BOOST_TEST(static_cstring<3>{"abc"}.front() == 'a'); 233 | BOOST_TEST(static_cstring<3>{"abc"}.back() == 'c'); 234 | 235 | // data() / c_str(). 236 | { 237 | static_cstring<3> s("123"); 238 | BOOST_TEST(std::memcmp(s.data(), "123", 3) == 0); 239 | BOOST_TEST(std::memcmp(s.c_str(), "123\0", 4) == 0); 240 | } 241 | 242 | // Modification through element access. 243 | { 244 | static_cstring<5> s("12345"); 245 | s[1] = '_'; 246 | BOOST_TEST(s == "1_345"); 247 | s.front() = 'A'; 248 | BOOST_TEST(s == "A_345"); 249 | s.back() = 'Z'; 250 | BOOST_TEST(s == "A_34Z"); 251 | } 252 | } 253 | 254 | static 255 | void 256 | testCStringIterators() 257 | { 258 | { 259 | static_cstring<3> s; 260 | BOOST_TEST(std::distance(s.begin(), s.end()) == 0); 261 | s = "123"; 262 | BOOST_TEST(std::distance(s.begin(), s.end()) == 3); 263 | } 264 | { 265 | static_cstring<3> const s("123"); 266 | BOOST_TEST(std::distance(s.begin(), s.end()) == 3); 267 | BOOST_TEST(std::distance(s.cbegin(), s.cend()) == 3); 268 | } 269 | 270 | // Iteration. 271 | { 272 | static_cstring<5> s("hello"); 273 | std::string result; 274 | for (const char c : s) 275 | { 276 | result += c; 277 | } 278 | BOOST_TEST(result == "hello"); 279 | } 280 | } 281 | 282 | static 283 | void 284 | testCStringCapacity() 285 | { 286 | // empty(). 287 | BOOST_TEST(static_cstring<0>{}.empty()); 288 | BOOST_TEST(static_cstring<1>{}.empty()); 289 | BOOST_TEST(!static_cstring<1>{"a"}.empty()); 290 | 291 | // size(). 292 | BOOST_TEST(static_cstring<0>{}.size() == 0); 293 | BOOST_TEST(static_cstring<1>{"a"}.size() == 1); 294 | BOOST_TEST(static_cstring<5>{"abc"}.size() == 3); 295 | 296 | // length(). 297 | BOOST_TEST(static_cstring<0>{}.length() == 0); 298 | BOOST_TEST(static_cstring<3>{"abc"}.length() == 3); 299 | 300 | // max_size(). 301 | BOOST_TEST(static_cstring<0>{}.max_size() == 0); 302 | BOOST_TEST(static_cstring<5>{"abc"}.max_size() == 5); 303 | 304 | // capacity(). 305 | BOOST_TEST(static_cstring<0>{}.capacity() == 0); 306 | BOOST_TEST(static_cstring<5>{"abc"}.capacity() == 5); 307 | } 308 | 309 | static 310 | void 311 | testCStringClear() 312 | { 313 | static_cstring<3> s("123"); 314 | BOOST_TEST(!s.empty()); 315 | s.clear(); 316 | BOOST_TEST(s.empty()); 317 | BOOST_TEST(s.size() == 0); 318 | BOOST_TEST(*s.end() == 0); 319 | BOOST_TEST(s == ""); 320 | } 321 | 322 | static 323 | void 324 | testCStringPushPop() 325 | { 326 | // push_back(). 327 | { 328 | static_cstring<5> s("abc"); 329 | s.push_back('d'); 330 | BOOST_TEST(s == "abcd"); 331 | BOOST_TEST(s.size() == 4); 332 | BOOST_TEST(*s.end() == 0); 333 | 334 | s.push_back('e'); 335 | BOOST_TEST(s == "abcde"); 336 | BOOST_TEST(s.size() == 5); 337 | 338 | BOOST_TEST_THROWS(s.push_back('f'), std::length_error); 339 | } 340 | 341 | // pop_back(). 342 | { 343 | static_cstring<5> s("abcde"); 344 | s.pop_back(); 345 | BOOST_TEST(s == "abcd"); 346 | BOOST_TEST(s.size() == 4); 347 | BOOST_TEST(*s.end() == 0); 348 | 349 | s.pop_back(); 350 | s.pop_back(); 351 | s.pop_back(); 352 | s.pop_back(); 353 | BOOST_TEST(s.empty()); 354 | } 355 | } 356 | 357 | static 358 | void 359 | testCStringAppend() 360 | { 361 | // append(const CharT* s). 362 | { 363 | static_cstring<12> s("Hello"); 364 | s.append(", World"); 365 | BOOST_TEST(s == "Hello, World"); 366 | BOOST_TEST(*s.end() == 0); 367 | } 368 | { 369 | static_cstring<5> s("abc"); 370 | BOOST_TEST_THROWS(s.append("def"), std::length_error); 371 | } 372 | 373 | // append(const CharT* s, size_type count) 374 | { 375 | static_cstring<10> s("abc"); 376 | s.append("defgh", 3); 377 | BOOST_TEST(s == "abcdef"); 378 | BOOST_TEST(*s.end() == 0); 379 | } 380 | 381 | // append(size_type count, CharT ch) 382 | { 383 | static_cstring<10> s("abc"); 384 | s.append(3, 'x'); 385 | BOOST_TEST(s == "abcxxx"); 386 | BOOST_TEST(*s.end() == 0); 387 | BOOST_TEST_THROWS(s.append(5, 'y'), std::length_error); 388 | } 389 | 390 | // operator+=() 391 | { 392 | static_cstring<10> s("abc"); 393 | s += "def"; 394 | BOOST_TEST(s == "abcdef"); 395 | s += 'g'; 396 | BOOST_TEST(s == "abcdefg"); 397 | BOOST_TEST(*s.end() == 0); 398 | } 399 | } 400 | 401 | static 402 | void 403 | testCStringComparison() 404 | { 405 | // operator==() / operator!=(). 406 | { 407 | static_cstring<10> a("abc"); 408 | static_cstring<10> b("abc"); 409 | static_cstring<10> c("abd"); 410 | 411 | BOOST_TEST(a == b); 412 | BOOST_TEST(!(a == c)); 413 | BOOST_TEST(a != c); 414 | BOOST_TEST(!(a != b)); 415 | } 416 | 417 | // operator<(), <=(), >(), >=(). 418 | { 419 | static_cstring<10> a("abc"); 420 | static_cstring<10> b("abd"); 421 | 422 | BOOST_TEST(a < b); 423 | BOOST_TEST(a <= b); 424 | BOOST_TEST(a <= a); 425 | BOOST_TEST(b > a); 426 | BOOST_TEST(b >= a); 427 | BOOST_TEST(b >= b); 428 | } 429 | 430 | // Comparison with CharT const*. 431 | { 432 | static_cstring<10> s("hello"); 433 | BOOST_TEST(s == "hello"); 434 | BOOST_TEST("hello" == s); 435 | BOOST_TEST(s != "world"); 436 | BOOST_TEST("world" != s); 437 | } 438 | 439 | // compare(). 440 | { 441 | static_cstring<10> s("abc"); 442 | BOOST_TEST(s.compare("abc") == 0); 443 | BOOST_TEST(s.compare("abd") < 0); 444 | BOOST_TEST(s.compare("abb") > 0); 445 | } 446 | } 447 | 448 | static 449 | void 450 | testCStringConversion() 451 | { 452 | // operator string_view(). 453 | { 454 | static_cstring<10> s("hello"); 455 | std::string_view sv = s; 456 | BOOST_TEST(sv == "hello"); 457 | BOOST_TEST(sv.size() == 5); 458 | } 459 | 460 | // str(). 461 | { 462 | static_cstring<10> s("hello"); 463 | std::string str = s.str(); 464 | BOOST_TEST(str == "hello"); 465 | BOOST_TEST(str.size() == 5); 466 | } 467 | } 468 | 469 | static 470 | void 471 | testCStringStream() 472 | { 473 | static_cstring<10> s("hello"); 474 | std::ostringstream oss; 475 | oss << s; 476 | BOOST_TEST(oss.str() == "hello"); 477 | } 478 | 479 | static 480 | void 481 | testCStringSwap() 482 | { 483 | static_cstring<10> a("hello"); 484 | static_cstring<10> b("world"); 485 | 486 | a.swap(b); 487 | 488 | BOOST_TEST(a == "world"); 489 | BOOST_TEST(b == "hello"); 490 | } 491 | 492 | static 493 | void 494 | testCStringConstexpr() 495 | { 496 | // constexpr construction and operations. 497 | constexpr static_cstring<10> ce("test"); 498 | static_assert(ce.size() == 4, ""); 499 | static_assert(ce[0] == 't', ""); 500 | static_assert(ce[1] == 'e', ""); 501 | static_assert(ce[2] == 's', ""); 502 | static_assert(ce[3] == 't', ""); 503 | static_assert(!ce.empty(), ""); 504 | static_assert(ce.max_size() == 10, ""); 505 | static_assert(ce.capacity() == 10, ""); 506 | 507 | constexpr static_cstring<5> ce_empty; 508 | static_assert(ce_empty.empty(), ""); 509 | static_assert(ce_empty.size() == 0, ""); 510 | } 511 | 512 | // Helper struct to test NTTP. 513 | template 514 | struct NTTPHelper 515 | { 516 | static constexpr std::size_t size() noexcept 517 | { 518 | return S.size(); 519 | } 520 | 521 | static constexpr const char* c_str() noexcept 522 | { 523 | return S.c_str(); 524 | } 525 | }; 526 | 527 | static 528 | void 529 | testCStringNTTP() 530 | { 531 | // Test non-type template parameter usage (C++20). 532 | 533 | // Test size deduction from string literals. 534 | BOOST_TEST(NTTPHelper<"hello">::size() == 5); 535 | BOOST_TEST(NTTPHelper<"">::size() == 0); 536 | BOOST_TEST(NTTPHelper<"test">::size() == 4); 537 | 538 | // Test that different strings create different types 539 | constexpr bool same_type = std::is_same_v< 540 | NTTPHelper<"hello">, 541 | NTTPHelper<"hello">>; 542 | BOOST_TEST(same_type); 543 | 544 | constexpr bool different_type = !std::is_same_v< 545 | NTTPHelper<"hello">, 546 | NTTPHelper<"world">>; 547 | BOOST_TEST(different_type); 548 | 549 | // Test constexpr access. 550 | constexpr std::size_t len = NTTPHelper<"constexpr">::size(); 551 | static_assert(len == 9, ""); 552 | } 553 | 554 | static 555 | void 556 | testCStringPODUsage() 557 | { 558 | // Test usage in POD types (the original motivation). 559 | struct UserRecord 560 | { 561 | int id; 562 | static_cstring<63> name; 563 | unsigned int flags; 564 | }; 565 | 566 | static_assert(sizeof(static_cstring<63>) == 64, ""); 567 | static_assert(std::is_trivially_copyable::value, ""); 568 | 569 | UserRecord user{}; 570 | user.id = 42; 571 | user.name = "Alice"; 572 | user.flags = 0xFF; 573 | 574 | BOOST_TEST(user.id == 42); 575 | BOOST_TEST(user.name.size() == 5); 576 | BOOST_TEST(user.name == "Alice"); 577 | BOOST_TEST(user.flags == 0xFF); 578 | 579 | // Copy the struct. 580 | UserRecord copy = user; 581 | BOOST_TEST(copy.name == "Alice"); 582 | 583 | // memcpy() should work. 584 | UserRecord memcpy_dest; 585 | std::memcpy(&memcpy_dest, &user, sizeof(UserRecord)); 586 | BOOST_TEST(memcpy_dest.name == "Alice"); 587 | } 588 | 589 | static 590 | void 591 | testCStringLargeCapacity() 592 | { 593 | // Test strings with N > UCHAR_MAX (no remaining-capacity trick). 594 | { 595 | static_cstring<300> s; 596 | BOOST_TEST(s.empty()); 597 | BOOST_TEST(s.size() == 0); 598 | 599 | s = "This is a test string"; 600 | BOOST_TEST(s.size() == 21); 601 | BOOST_TEST(s == "This is a test string"); 602 | 603 | s.clear(); 604 | BOOST_TEST(s.empty()); 605 | } 606 | 607 | // Large string operations. 608 | { 609 | static_cstring<500> s; 610 | s.assign(400, 'x'); 611 | BOOST_TEST(s.size() == 400); 612 | BOOST_TEST(s[0] == 'x'); 613 | BOOST_TEST(s[399] == 'x'); 614 | BOOST_TEST(*s.end() == 0); 615 | } 616 | } 617 | 618 | static 619 | void 620 | testCStringWideChar() 621 | { 622 | // Test with wchar_t. 623 | { 624 | static_wcstring<10> ws; 625 | BOOST_TEST(ws.empty()); 626 | BOOST_TEST(ws.size() == 0); 627 | } 628 | 629 | { 630 | static_wcstring<10> ws(L"hello"); 631 | BOOST_TEST(ws.size() == 5); 632 | BOOST_TEST(ws[0] == L'h'); 633 | BOOST_TEST(ws[4] == L'o'); 634 | BOOST_TEST(*ws.end() == 0); 635 | } 636 | } 637 | 638 | int 639 | runTests() 640 | { 641 | testCStringSizeGuarantee(); 642 | testCStringRemainingCapacityTrick(); 643 | testCStringTypeTraits(); 644 | testCStringConstruct(); 645 | testCStringAssignment(); 646 | testCStringElements(); 647 | testCStringIterators(); 648 | testCStringCapacity(); 649 | testCStringClear(); 650 | testCStringPushPop(); 651 | testCStringAppend(); 652 | testCStringComparison(); 653 | testCStringConversion(); 654 | testCStringStream(); 655 | testCStringSwap(); 656 | testCStringConstexpr(); 657 | testCStringNTTP(); 658 | testCStringPODUsage(); 659 | testCStringLargeCapacity(); 660 | testCStringWideChar(); 661 | 662 | return report_errors(); 663 | } 664 | } 665 | } 666 | 667 | int 668 | main() 669 | { 670 | return boost::static_strings::runTests(); 671 | } 672 | --------------------------------------------------------------------------------