diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 21454e5..06dffec 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -4,253 +4,129 @@ name: Continuous Integration Tests on: push: + branches: + - main pull_request: workflow_dispatch: schedule: - cron: '30 15 * * *' jobs: - beman-submodule-test: - runs-on: ubuntu-latest - name: "Check beman submodules for consistency" - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: beman submodule consistency check - run: | - (set -o pipefail; ./infra/tools/beman-submodule/beman-submodule status | grep -qvF '+') + beman-submodule-check: + uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-submodule-check.yml@1.1.0 preset-test: - strategy: - fail-fast: false - matrix: - presets: - - preset: "gcc-debug" - platform: "ubuntu-latest" - - preset: "gcc-release" - platform: "ubuntu-latest" - - preset: "llvm-debug" - platform: "ubuntu-latest" - - preset: "llvm-release" - platform: "ubuntu-latest" - - preset: "appleclang-debug" - platform: "macos-latest" - - preset: "appleclang-release" - platform: "macos-latest" - - preset: "msvc-debug" - platform: "windows-latest" - - preset: "msvc-release" - platform: "windows-latest" - name: "Preset: ${{ matrix.presets.preset }} on ${{ matrix.presets.platform }}" - runs-on: ${{ matrix.presets.platform }} - steps: - - uses: actions/checkout@v4 - - name: Setup build environment - uses: lukka/get-cmake@latest - with: - cmakeVersion: "~3.25.0" - ninjaVersion: "^1.11.1" - - name: Setup MSVC - if: startsWith(matrix.presets.platform, 'windows') - uses: TheMrMilchmann/setup-msvc-dev@v3 - with: - arch: x64 - - name: Run preset - run: cmake --workflow --preset ${{ matrix.presets.preset }} - - gtest-test: - strategy: - fail-fast: false - matrix: - platform: - - description: "Ubuntu GNU" - os: ubuntu-latest - toolchain: "infra/cmake/gnu-toolchain.cmake" - - description: "Ubuntu LLVM" - os: ubuntu-latest - toolchain: "infra/cmake/llvm-toolchain.cmake" - - description: "Windows MSVC" - os: windows-latest - toolchain: "infra/cmake/msvc-toolchain.cmake" - - description: "Macos Appleclang" - os: macos-latest - toolchain: "infra/cmake/appleclang-toolchain.cmake" - cpp_version: [17, 20, 23, 26] - cmake_args: - - description: "Default" - - description: "TSan" - args: "-DBEMAN_BUILDSYS_SANITIZER=TSan" - - description: "MaxSan" - args: "-DBEMAN_BUILDSYS_SANITIZER=MaxSan" - include: - - platform: - description: "Ubuntu GCC" - os: ubuntu-latest - toolchain: "infra/cmake/gnu-toolchain.cmake" - cpp_version: 17 - cmake_args: - description: "Werror" - args: "-DCMAKE_CXX_FLAGS='-Werror=all -Werror=extra'" - - platform: - description: "Ubuntu GCC" - os: ubuntu-latest - toolchain: "infra/cmake/gnu-toolchain.cmake" - cpp_version: 17 - cmake_args: - description: "Dynamic" - args: "-DBUILD_SHARED_LIBS=on" - exclude: - # MSVC does not support thread sanitizer - - platform: - description: "Windows MSVC" - cmake_args: - description: "TSan" - - name: "Unit: - ${{ matrix.platform.description }} - ${{ matrix.cpp_version }} - ${{ matrix.cmake_args.description }}" - runs-on: ${{ matrix.platform.os }} - steps: - - uses: actions/checkout@v4 - - name: Install Ninja - uses: lukka/get-cmake@latest - with: - cmakeVersion: "~3.25.0" - ninjaVersion: "^1.11.1" - - name: Setup MSVC - if: startsWith(matrix.platform.os, 'windows') - uses: TheMrMilchmann/setup-msvc-dev@v3 - with: - arch: x64 - - name: Build and Test - uses: ./.github/actions/cmake-build-test - with: - cpp_version: ${{ matrix.cpp_version }} - toolchain_file: ${{ matrix.platform.toolchain }} - cmake_extra_args: ${{ matrix.cmake_args.args }} - - configuration-test: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - args: - - name: "Disable build testing" - arg: "-DBEMAN_CSTRING_VIEW_BUILD_TESTS=OFF" - - name: "Disable example building" - arg: "-DBEMAN_CSTRING_VIEW_BUILD_EXAMPLES=OFF" - - name: "Disable config-file package creation" - arg: "-DBEMAN_CSTRING_VIEW_INSTALL_CONFIG_FILE_PACKAGE=OFF" - name: "CMake: ${{ matrix.args.name }}" - steps: - - uses: actions/checkout@v4 - - name: Setup build environment - uses: lukka/get-cmake@latest - with: - cmakeVersion: "~3.25.0" - ninjaVersion: "^1.11.1" - - name: Build and Test - uses: ./.github/actions/cmake-build-test - with: - cpp_version: 17 - toolchain_file: "infra/cmake/gnu-toolchain.cmake" - cmake_extra_args: ${{ matrix.args.arg }} - disable_test: true - - compiler-test: - runs-on: ubuntu-24.04 - strategy: - fail-fast: false - matrix: - compilers: - - class: GNU - version: 14 - toolchain: "infra/cmake/gnu-toolchain.cmake" - - class: GNU - version: 13 - toolchain: "infra/cmake/gnu-toolchain.cmake" - - class: GNU - version: 12 - toolchain: "infra/cmake/gnu-toolchain.cmake" - - class: LLVM - version: 20 - toolchain: "infra/cmake/llvm-toolchain.cmake" - - class: LLVM - version: 19 - toolchain: "infra/cmake/llvm-toolchain.cmake" - - class: LLVM - version: 18 - toolchain: "infra/cmake/llvm-toolchain.cmake" - - class: LLVM - version: 17 - toolchain: "infra/cmake/llvm-toolchain.cmake" - name: "Compiler: ${{ matrix.compilers.class }} ${{ matrix.compilers.version }}" - steps: - - uses: actions/checkout@v4 - - name: Setup build environment - uses: lukka/get-cmake@latest - with: - cmakeVersion: "~3.25.0" - ninjaVersion: "^1.11.1" - - name: Install Compiler - id: install-compiler - run: | - sudo add-apt-repository universe - sudo apt-get update - - if [ "${{ matrix.compilers.class }}" = "GNU" ]; then - CC=gcc-${{ matrix.compilers.version }} - CXX=g++-${{ matrix.compilers.version }} - - sudo apt-get install -y $CC - sudo apt-get install -y $CXX - - $CC --version - $CXX --version - else - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo bash llvm.sh ${{ matrix.compilers.version }} - - CC=clang-${{ matrix.compilers.version }} - CXX=clang++-${{ matrix.compilers.version }} - - $CC --version - $CXX --version - fi - - echo "CC=$CC" >> "$GITHUB_OUTPUT" - echo "CXX=$CXX" >> "$GITHUB_OUTPUT" - - name: Build and Test - uses: ./.github/actions/cmake-build-test - with: - cpp_version: 20 - toolchain_file: ${{ matrix.compilers.toolchain }} + uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-preset-test.yml@1.1.0 + with: + matrix_config: > + [ + {"preset": "gcc-debug", "image": "ghcr.io/bemanproject/infra-containers-gcc:latest"}, + {"preset": "gcc-release", "image": "ghcr.io/bemanproject/infra-containers-gcc:latest"}, + {"preset": "llvm-debug", "image": "ghcr.io/bemanproject/infra-containers-clang:latest"}, + {"preset": "llvm-release", "image": "ghcr.io/bemanproject/infra-containers-clang:latest"}, + {"preset": "appleclang-debug", "runner": "macos-latest"}, + {"preset": "appleclang-release", "runner": "macos-latest"}, + {"preset": "msvc-debug", "runner": "windows-latest"}, + {"preset": "msvc-release", "runner": "windows-latest"} + ] + + build-and-test: + uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-build-and-test.yml@1.1.0 + with: + matrix_config: > + { + "gcc": [ + { "versions": ["15"], + "tests": [ + { "cxxversions": ["c++26"], + "tests": [ + { "stdlibs": ["libstdc++"], + "tests": [ + "Debug.Default", "Release.Default", "Release.TSan", + "Release.MaxSan", "Debug.Werror", "Debug.Dynamic", + "Debug.Coverage" + ] + } + ] + }, + { "cxxversions": ["c++23", "c++20"], + "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}] + } + ] + }, + { "versions": ["14", "13"], + "tests": [ + { "cxxversions": ["c++26", "c++23", "c++20"], + "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}] + } + ] + } + ], + "clang": [ + { "versions": ["21"], + "tests": [ + {"cxxversions": ["c++26"], + "tests": [ + { "stdlibs": ["libstdc++", "libc++"], + "tests": [ + "Debug.Default", "Release.Default", "Release.TSan", + "Release.MaxSan", "Debug.Werror", "Debug.Dynamic" + ] + } + ] + }, + { "cxxversions": ["c++23", "c++20"], + "tests": [ + {"stdlibs": ["libstdc++", "libc++"], "tests": ["Release.Default"]} + ] + } + ] + }, + { "versions": ["20", "19", "18"], + "tests": [ + { "cxxversions": ["c++26", "c++23", "c++20"], + "tests": [ + {"stdlibs": ["libstdc++", "libc++"], "tests": ["Release.Default"]} + ] + } + ] + }, + { "versions": ["17"], + "tests": [ + { "cxxversions": ["c++26", "c++23", "c++20"], + "tests": [{"stdlibs": ["libc++"], "tests": ["Release.Default"]}] + }, + { "cxxversions": ["c++20"], + "tests": [{"stdlibs": ["libstdc++"], "tests": ["Release.Default"]}] + } + ] + } + ], + "appleclang": [ + { "versions": ["latest"], + "tests": [ + { "cxxversions": ["c++26", "c++23", "c++20"], + "tests": [{ "stdlibs": ["libc++"], "tests": ["Release.Default"]}] + } + ] + } + ], + "msvc": [ + { "versions": ["latest"], + "tests": [ + { "cxxversions": ["c++23"], + "tests": [ + { "stdlibs": ["stl"], + "tests": ["Debug.Default", "Release.Default", "Release.MaxSan"] + } + ] + } + ] + } + ] + } create-issue-when-fault: - runs-on: ubuntu-latest - needs: [preset-test, gtest-test, configuration-test, compiler-test] + needs: [preset-test, build-and-test] if: failure() && github.event_name == 'schedule' - steps: - # See https://github.com/cli/cli/issues/5075 - - uses: actions/checkout@v4 - - name: Create issue - run: | - issue_num=$(gh issue list -s open -S "[SCHEDULED-BUILD] Build & Test failure" -L 1 --json number | jq 'if length == 0 then -1 else .[0].number end') - - body="**Build-and-Test Failure Report** - - **Time of Failure**: $(date -u '+%B %d, %Y, %H:%M %Z') - - **Commit**: [${{ github.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}) - - **Action Run**: [View logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) - - The scheduled build-and-test triggered by cron has failed. - Please investigate the logs and recent changes associated with this commit or rerun the workflow if you believe this is an error." - - if [[ $issue_num -eq -1 ]]; then - gh issue create --repo ${{ github.repository }} --title "[SCHEDULED-BUILD] Build & Test failure" --body "$body" - else - gh issue comment --repo ${{ github.repository }} $issue_num --body "$body" - fi - env: - GH_TOKEN: ${{ github.token }} + uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-create-issue-when-fault.yml@1.1.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index e69a90f..bbf3777 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 3.25) +cmake_minimum_required(VERSION 3.25...4.2) -set(CMAKE_CXX_STANDARD 23) +if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 20) # NEEDED! for std::type_identity, std::format, std::char8_t, ...! +endif() project( beman.cstring_view # CMake Project Name, which is also the name of the top-level diff --git a/CMakePresets.json b/CMakePresets.json index 483e1a3..4a7b0ae 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -7,7 +7,6 @@ "generator": "Ninja", "binaryDir": "${sourceDir}/build/${presetName}", "cacheVariables": { - "CMAKE_CXX_STANDARD": "20", "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "./infra/cmake/use-fetch-content.cmake" } diff --git a/README.md b/README.md index 319728b..dbd9987 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception --> -![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/dascandy/cstring_view/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/dascandy/cstring_view/actions/workflows/pre-commit.yml/badge.svg) +![Library Status](https://raw.githubusercontent.com/bemanproject/beman/refs/heads/main/images/badges/beman_badge-beman_library_under_development.svg) ![Continuous Integration Tests](https://github.com/bemanproject/cstring_view/actions/workflows/ci_tests.yml/badge.svg) ![Lint Check (pre-commit)](https://github.com/bemanproject/cstring_view/actions/workflows/pre-commit.yml/badge.svg) [![Coverage](https://coveralls.io/repos/github/bemanproject/cstring_view/badge.svg?branch=main) `beman.cstring_view` is a header-only `cstring_view` library. @@ -13,6 +13,10 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception **Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use) +## License + +`beman.exemplar` is licensed under the Apache License v2.0 with LLVM Exceptions. + ## Usage `std::cstring_view` exposes a string\_view like type that is intended for being able to propagate prior knowledge that @@ -39,8 +43,8 @@ Full runnable examples can be found in [`examples/`](examples/). This project requires at least the following to build: -* C++17 -* CMake 3.25 +* A C++ compiler that conforms to the C++17 standard or greater +* CMake 3.25 or later * (Test Only) GoogleTest You can disable building tests by setting cmake option @@ -51,10 +55,10 @@ when configuring the project. This project officially supports: -* GNU GCC Compiler \[version 12-14\] -* LLVM Clang++ Compiler \[version 17-20\] -* AppleClang compiler on Mac OS -* MSVC compiler on Windows +* GCC versions 11–15 +* LLVM Clang++ (with libstdc++ or libc++) versions 17–21 +* AppleClang version 17.0.0 (i.e., the [latest version on GitHub-hosted macOS runners](https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md)) +* MSVC version 19.44.35215.0 (i.e., the [latest version on GitHub-hosted Windows runners](https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md)) > [!NOTE] > @@ -70,7 +74,7 @@ This project officially supports: This project supports [GitHub Codespace](https://github.com/features/codespaces) via [Development Containers](https://containers.dev/), which allows rapid development and instant hacking in your browser. -We recommend you using GitHub codespace to explore this project as this +We recommend using GitHub codespace to explore this project as it requires minimal setup. You can create a codespace for this project by clicking this badge: @@ -89,11 +93,11 @@ GitHub codespaces, please reference [this doc](https://docs.github.com/en/codesp ### Develop locally on your machines
- For Linux based systems + For Linux Beman libraries require [recent versions of CMake](#build-environment), -we advise you to download CMake directly from [CMake's website](https://cmake.org/download/) -or install it via the [Kitware apt library](https://apt.kitware.com/). +we recommend downloading CMake directly from [CMake's website](https://cmake.org/download/) +or installing it with the [Kitware apt library](https://apt.kitware.com/). A [supported compiler](#supported-platforms) should be available from your package manager. Alternatively you could use an install script from official compiler vendors. @@ -120,10 +124,10 @@ you are using.
- For MacOS based systems + For MacOS Beman libraries require [recent versions of CMake](#build-environment). -You can use [`Homebrew`](https://brew.sh/) to install the latest major version of CMake. +Use [`Homebrew`](https://brew.sh/) to install the latest version of CMake. ```bash brew install cmake @@ -175,28 +179,31 @@ cmake --workflow --preset gcc-debug Generally, there are two kinds of presets, `debug` and `release`. The `debug` presets are designed to aid development, so it has debugging -instrumentation enabled and as many sanitizers turned on as possible. +instrumentation enabled and many sanitizers enabled. > [!NOTE] > -> The set of sanitizer supports are different across compilers. -> You can checkout the exact set of compiler arguments by looking at the toolchain -> files under the [`cmake`](cmake/) directory. +> The sanitizers that are enabled vary from compiler to compiler. +> See the toolchain files under ([`cmake`](cmake/)) to determine the exact configuration used for each preset. -The `release` presets are designed for use in production environments, -thus they have the highest optimization turned on (e.g. `O3`). +The `release` presets are designed for production use, and +consequently have the highest optimization turned on (e.g. `O3`). ### Configure and Build Manually -While [CMake Presets](#configure-and-build-the-project-using-cmake-presets) are -convenient, you might want to set different configuration or compiler arguments -than any provided preset supports. +If the presets are not suitable for your use-case, a traditional CMake +invocation will provide more configurability. To configure, build and test the project with extra arguments, you can run this set of commands. ```bash -cmake -B build -S . -DCMAKE_CXX_STANDARD=20 # Your extra arguments here. +cmake \ + -B build \ + -S . \ + -DCMAKE_CXX_STANDARD=20 \ + -DCMAKE_PREFIX_PATH=$PWD/infra/cmake \ + # Your extra arguments here. cmake --build build ctest --test-dir build ``` diff --git a/examples/example.cpp b/examples/example.cpp index 5811bc2..a5c71f0 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -7,6 +7,7 @@ using namespace std::literals; using namespace beman::literals; +#if __cpp_impl_three_way_comparison >= 201907L std::string_view to_string(std::strong_ordering order) { if (order == std::strong_ordering::equal) { return "equal"; @@ -21,6 +22,7 @@ std::string_view to_string(std::strong_ordering order) { return "internal error"; } } +#endif int main() { std::string s = "hello world"; @@ -39,7 +41,9 @@ int main() { std::cout << ("hello"_csv != "goodbye"sv) << "\n"; std::cout << ("hello"_csv != "goodbye"_csv) << "\n"; std::cout << (z0 == z1) << "\n"; +#if __cpp_impl_three_way_comparison >= 201907L std::cout << to_string(z0 <=> z1) << "\n"; +#endif std::cout << z0[z0.size()] * 1 << "\n"; std::cout << z0.c_str() << "\n"; std::cout << "\"" << empty << "\"\n"; @@ -61,7 +65,9 @@ int main() { std::cout << (L"hello"_csv != L"goodbye"sv) << "\n"; std::cout << (L"hello"_csv != L"goodbye"_csv) << "\n"; std::cout << (wz0 == wz1) << "\n"; +#if __cpp_impl_three_way_comparison >= 201907L std::cout << to_string(wz0 <=> wz1) << "\n"; +#endif std::cout << wz0[wz0.size()] * 1 << "\n"; std::wcout << std::format(L"{}\n", wz0.c_str()); std::wcout << std::format(L"\"{}\"\n", wempty); diff --git a/include/beman/cstring_view/cstring_view.hpp b/include/beman/cstring_view/cstring_view.hpp index e71da41..172014b 100644 --- a/include/beman/cstring_view/cstring_view.hpp +++ b/include/beman/cstring_view/cstring_view.hpp @@ -7,6 +7,7 @@ #include #include #include +#include // for std::type_identity_t #include #include @@ -31,9 +32,13 @@ constexpr bool operator==(basic_cstring_view std::type_identity_t> y) noexcept; template + +#if __cpp_impl_three_way_comparison >= 201907L constexpr auto operator<=>(basic_cstring_view x, std::type_identity_t> y) noexcept; +#endif + // [cstring.view.io], inserters and extractors template std::basic_ostream& operator<<(std::basic_ostream& os, @@ -110,7 +115,7 @@ class basic_cstring_view { // [cstring.view.cons], construction and assignment constexpr basic_cstring_view() noexcept : size_() { - static const charT empty_string[1]{}; + // XXX static const charT empty_string[1]{}; data_ = std::data(empty_string); } constexpr basic_cstring_view(const basic_cstring_view&) noexcept = default; @@ -313,6 +318,8 @@ class basic_cstring_view { private: const_pointer data_; // exposition only size_type size_; // exposition only + + static constexpr charT empty_string[1]{}; // NOLINT }; inline namespace literals {