diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f11b28..7630338 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,18 +13,18 @@ jobs: matrix: os: [macos-15, ubuntu-24.04, windows-latest] type: [Debug, Release] - compiler: [cl, clang++, g++] + compiler: [cl, clang++, g++-14] exclude: - os: macos-15 compiler: cl - os: macos-15 - compiler: g++ + compiler: clang++ - os: ubuntu-24.04 compiler: cl - os: windows-latest compiler: clang++ - os: windows-latest - compiler: g++ + compiler: g++-14 steps: - uses: actions/checkout@v5 @@ -82,7 +82,7 @@ jobs: - uses: actions/checkout@v5 - name: CMake configure - run: cmake -Bbuild -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS=-fsanitize=address,undefined,leak -DCMAKE_EXE_LINKER_FLAGS=-fsanitize=address,undefined,leak + run: cmake -Bbuild -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_CXX_FLAGS=-fsanitize=address,undefined,leak -DCMAKE_EXE_LINKER_FLAGS=-fsanitize=address,undefined,leak - name: CMake build run: cmake --build build --parallel --target run-unit-test @@ -114,7 +114,7 @@ jobs: sudo apt install -y valgrind - name: CMake configure - run: cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ + run: cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 - name: CMake build run: cmake --build build --parallel --target unittest @@ -136,14 +136,14 @@ jobs: sudo apt install -y lcov - name: CMake configure - run: cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_EXE_LINKER_FLAGS=--coverage + run: cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_EXE_LINKER_FLAGS=--coverage - name: CMake build run: cmake --build build --parallel --target run-unit-test - name: Generate coverage run: | - lcov --directory build --capture --output-file coverage.info --ignore-errors mismatch + lcov --directory build --capture --gcov-tool gcov-14 --output-file coverage.info --ignore-errors mismatch lcov --list coverage.info lcov --extract coverage.info --output-file argparse.info *argparse.hpp lcov --list argparse.info diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c27540..0ff552c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE include/) -target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20) +target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_23) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) enable_testing() diff --git a/README.md b/README.md index bfc693b..f237c23 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This is a C++ implementation of Python's `argparse` module. The aim is to cover ## Dependencies -C++ argparse is a header-only library, so its setup is minimal. It has no external dependencies and only uses STL. Since it uses `std::ranges` and some other features, it requires C++20 compiler and standard library. +C++ argparse is a header-only library, so its setup is minimal. It has no external dependencies and only uses STL. Since it uses `std::ranges` and some other features, it requires C++23 compiler and standard library. In case of need, [v3.1.0](https://github.com/kkarbowiak/cpp-argparse/releases/tag/v3.1.0) is the latest release that still compiles in C++20 mode. C++ argparse uses CMake internally, but you don't have to. Just put the [argparse.hpp](https://github.com/kkarbowiak/cpp-argparse/releases/latest/download/argparse.hpp) header somewhere and point your build system to it. diff --git a/include/argparse.hpp b/include/argparse.hpp index 43445f8..331daef 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -14,10 +14,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -91,12 +92,12 @@ namespace argparse inline auto operator|(Handle lhs, Handle rhs) -> Handle { - return static_cast(static_cast(lhs) | static_cast(rhs)); + return static_cast(std::to_underlying(lhs) | std::to_underlying(rhs)); } inline auto operator&(Handle lhs, Handle rhs) -> int { - return static_cast(lhs) & static_cast(rhs); + return std::to_underlying(lhs) & std::to_underlying(rhs); } template @@ -256,7 +257,7 @@ namespace argparse { if (m_handle & Handle::help) { - std::cout << format_help() << std::endl; + std::println("{}", format_help()); std::exit(EXIT_SUCCESS); } @@ -266,7 +267,7 @@ namespace argparse { if (m_handle & Handle::version) { - std::cout << format_version() << std::endl; + std::println("{}", format_version()); std::exit(EXIT_SUCCESS); } @@ -276,8 +277,8 @@ namespace argparse { if (m_handle & Handle::errors) { - std::cout << e.what() << '\n'; - std::cout << format_help() << std::endl; + std::println("{}", e.what()); + std::println("{}", format_help()); std::exit(EXIT_FAILURE); } @@ -394,19 +395,8 @@ namespace argparse static auto join(std::ranges::view auto strings, std::string_view separator) -> std::string { - auto result = std::string(); - - for (auto const & string : strings | std::views::take(1)) - { - result += string; - } - for (auto const & string : strings | std::views::drop(1)) - { - result += separator; - result += string; - } - - return result; + auto const joined = std::ranges::fold_left_first(strings, [=](auto l, auto const & r) { l += separator; l += r; return std::move(l); }); + return joined.value_or(std::string()); } static auto parse_optional_arguments(std::ranges::view auto arguments, Tokens & tokens) -> void @@ -578,9 +568,10 @@ namespace argparse auto transform(std::vector const & values) const -> std::any override { - auto const transformation = values - | std::views::transform([](auto const & value) { return std::any_cast(value); }); - return std::any(std::vector(transformation.begin(), transformation.end())); + return std::any( + values + | std::views::transform([](auto const & value) { return std::any_cast(value); }) + | std::ranges::to()); } auto append(std::any const & value, std::any & values) const -> void override @@ -1353,7 +1344,7 @@ namespace argparse { if (name[1] != '-') { - if (it->m_token.starts_with("-") && !it->m_token.starts_with("--") && it->m_token.find(name[1]) != std::string::npos) + if (it->m_token.starts_with("-") && !it->m_token.starts_with("--") && it->m_token.contains(name[1])) { return name; } @@ -1883,10 +1874,7 @@ namespace argparse if (argument.has_nargs_number()) { - for (auto n = 0u; n < argument.get_nargs_number(); n++) - { - result += " " + formatted_arg; - } + result += std::ranges::fold_left(std::views::repeat(" " + formatted_arg, argument.get_nargs_number()), std::string(), std::plus()); } else { diff --git a/test/exit/CMakeLists.txt b/test/exit/CMakeLists.txt index e7422ec..ac09b87 100644 --- a/test/exit/CMakeLists.txt +++ b/test/exit/CMakeLists.txt @@ -5,7 +5,7 @@ target_sources(app PRIVATE main.cpp) -target_compile_features(app PRIVATE cxx_std_20) +target_compile_features(app PRIVATE cxx_std_23) target_compile_options(app PRIVATE $<$,$>: -Wall -Wextra -Wmisleading-indentation -Wunused diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index d4fff1b..a909b74 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -25,7 +25,7 @@ target_link_libraries(unittest PRIVATE cpp-argparse doctest) -target_compile_features(unittest PRIVATE cxx_std_20) +target_compile_features(unittest PRIVATE cxx_std_23) target_compile_options(unittest PRIVATE $<$,$>: -Wall -Wextra -Wmisleading-indentation -Wunused diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index 2401ed0..559b11c 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -36,7 +36,7 @@ set(targets foreach(target ${targets}) add_executable(${target}) target_sources(${target} PRIVATE ${target}.cpp) - target_compile_features(${target} PRIVATE cxx_std_20) + target_compile_features(${target} PRIVATE cxx_std_23) target_compile_options(${target} PRIVATE $<$,$>: -Wall -Wextra -Wmisleading-indentation -Wunused