├── .clang-format ├── .clang-tidy ├── .clangd ├── .github ├── filters.yml └── workflows │ ├── bootstrap_vcpkg │ └── action.yml │ ├── conan_setup │ └── action.yml │ ├── docs_pusher.yml │ ├── merge_checker.yml │ ├── pr_checker.yml │ └── release_builder.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── ci ├── calculate_test_coverage.sh ├── conan_test_project │ ├── CMakeLists.txt │ ├── conanfile.py │ └── main.cpp ├── create_badge_url.sh ├── old_coverage ├── package_test_project │ ├── CMakeLists.txt │ └── vcpkg.json ├── vcpkg_package_updater.ps1 ├── vcpkg_package_updater.sh └── vcpkg_test_project │ ├── CMakeLists.txt │ ├── main.cpp │ └── vcpkg.json ├── cmake ├── build_types │ ├── ast.cmake │ ├── death_test.cmake │ ├── documentation.cmake │ ├── documentation_script.cmake │ ├── library.cmake │ ├── unit_test.cmake │ └── unit_test_coverage.cmake ├── ccache.cmake ├── clang-format.cmake ├── clang-tidy.cmake ├── config.cmake ├── copyright_checker.cmake ├── package │ ├── arg_router-config.cmake.in │ └── install.cmake ├── path_prefixer.cmake ├── sanitizers.cmake ├── translation_generator │ ├── translation_generator.cmake │ └── translation_generator_script.cmake ├── triplets │ └── x86-linux.cmake └── versioning │ ├── version.cmake │ └── version.hpp.in ├── copyright_header.txt ├── docs ├── Doxyfile ├── header.html └── related_pages │ ├── architecture.doxy │ ├── configuration.doxy │ ├── error_handling.doxy │ ├── examples.doxy │ ├── help.doxy │ ├── images │ ├── node_relationships.dia │ └── node_relationships.svg │ ├── nodes.doxy │ ├── policies.doxy │ └── validation.doxy ├── examples ├── CMakeLists.txt ├── c++17 │ ├── CMakeLists.txt │ ├── basic_cat │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── custom_policy_and_node │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── just_cats │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── launcher │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── runtime_node_enable │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── simple │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── simple_ml │ │ ├── CMakeLists.txt │ │ └── main.cpp │ └── simple_ml_gen │ │ ├── CMakeLists.txt │ │ └── main.cpp ├── c++20 │ ├── CMakeLists.txt │ ├── basic_cat │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── custom_policy_and_node │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── just_cats │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── launcher │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── runtime_node_enable │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── simple │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── simple_ml │ │ ├── CMakeLists.txt │ │ └── main.cpp │ └── simple_ml_gen │ │ ├── CMakeLists.txt │ │ └── main.cpp └── resources │ └── simple_ml_gen │ ├── en_GB.toml │ ├── fr.toml │ └── ja.toml ├── include └── arg_router │ ├── algorithm.hpp │ ├── arg.hpp │ ├── arg_router.hpp │ ├── basic_types.hpp │ ├── config.hpp │ ├── counting_flag.hpp │ ├── dependency │ ├── alias_group.hpp │ ├── detail.hpp │ └── one_of.hpp │ ├── exception.hpp │ ├── flag.hpp │ ├── forwarding_arg.hpp │ ├── help.hpp │ ├── list.hpp │ ├── literals.hpp │ ├── math.hpp │ ├── mode.hpp │ ├── multi_arg.hpp │ ├── multi_arg_base.hpp │ ├── multi_lang │ ├── iso_locale.hpp │ ├── root.hpp │ ├── root_wrapper.hpp │ ├── string_selector.hpp │ └── translation.hpp │ ├── parsing │ ├── dynamic_token_adapter.hpp │ ├── global_parser.hpp │ ├── parse_target.hpp │ ├── parsing.hpp │ ├── pre_parse_data.hpp │ ├── token_type.hpp │ └── unknown_argument_handling.hpp │ ├── policy │ ├── alias.hpp │ ├── colour_help_formatter.hpp │ ├── custom_parser.hpp │ ├── default_help_formatter.hpp │ ├── default_value.hpp │ ├── dependent.hpp │ ├── description.hpp │ ├── display_name.hpp │ ├── error_name.hpp │ ├── exception_translator.hpp │ ├── flatten_help.hpp │ ├── long_name.hpp │ ├── min_max_count.hpp │ ├── min_max_value.hpp │ ├── multi_stage_value.hpp │ ├── no_result_value.hpp │ ├── none_name.hpp │ ├── policy.hpp │ ├── program_addendum.hpp │ ├── program_intro.hpp │ ├── program_name.hpp │ ├── program_version.hpp │ ├── required.hpp │ ├── router.hpp │ ├── runtime_enable.hpp │ ├── short_form_expander.hpp │ ├── short_name.hpp │ ├── token_end_marker.hpp │ ├── validator.hpp │ ├── validator_rule_utilities.hpp │ └── value_separator.hpp │ ├── positional_arg.hpp │ ├── root.hpp │ ├── traits.hpp │ ├── tree_node.hpp │ ├── tree_node_fwd.hpp │ ├── utility │ ├── compile_time_optional.hpp │ ├── compile_time_string.hpp │ ├── dynamic_string_view.hpp │ ├── exception_formatter.hpp │ ├── result.hpp │ ├── string_to_policy.hpp │ ├── string_view_ops.hpp │ ├── terminal.hpp │ ├── tree_recursor.hpp │ ├── tuple_iterator.hpp │ ├── type_hash.hpp │ ├── unsafe_any.hpp │ ├── utf8.hpp │ ├── utf8 │ │ ├── code_point.hpp │ │ ├── double_width.hpp │ │ ├── grapheme_cluster_break.hpp │ │ ├── levenshtein_distance.hpp │ │ ├── line_break.hpp │ │ ├── whitespace.hpp │ │ └── zero_width.hpp │ └── win_api.hpp │ └── version.hpp ├── scripts ├── copyright_checker.py ├── pre-commit └── unicode_table_generators.py ├── test ├── .clang-tidy ├── CMakeLists.txt ├── algorithm_test.cpp ├── allocator_test.cpp ├── arg_test.cpp ├── counting_flag_same_prefix_test.cpp ├── counting_flag_test.cpp ├── dependency │ ├── alias_group_test.cpp │ └── one_of_test.cpp ├── flag_same_prefix_test.cpp ├── flag_test.cpp ├── forwarding_arg_test.cpp ├── help_test.cpp ├── list_test.cpp ├── main_test.cpp ├── math_test.cpp ├── mode_test.cpp ├── multi_arg_test.cpp ├── multi_lang │ ├── iso_locale_test.cpp │ ├── root_test.cpp │ ├── root_wrapper_test.cpp │ └── string_selector_test.cpp ├── parsing │ ├── dynamic_token_adapter_test.cpp │ ├── global_parser_test.cpp │ ├── parse_target_test.cpp │ ├── parsing_test.cpp │ └── pre_parse_data_test.cpp ├── policy │ ├── alias_test.cpp │ ├── colour_help_formatter_test.cpp │ ├── custom_parser_test.cpp │ ├── default_help_formatter_test.cpp │ ├── default_value_test.cpp │ ├── dependent_test.cpp │ ├── description_test.cpp │ ├── display_name_test.cpp │ ├── error_name_test.cpp │ ├── exception_translator_test.cpp │ ├── long_name_test.cpp │ ├── min_max_count_test.cpp │ ├── min_max_value_ct_test.cpp │ ├── min_max_value_t_test.cpp │ ├── required_test.cpp │ ├── router_test.cpp │ ├── runtime_enable_test.cpp │ ├── short_form_expander_test.cpp │ ├── short_name_test.cpp │ ├── token_end_marker_test.cpp │ ├── validator_rule_utilities_test.cpp │ ├── validator_test.cpp │ └── value_separator_test.cpp ├── positional_arg_test.cpp ├── root_test.cpp ├── root_tests │ ├── basic_test.cpp │ ├── death_test.cpp │ ├── positional_arg_test.cpp │ ├── top_level_test.cpp │ └── variable_length_test.cpp ├── test_helpers.cpp ├── test_helpers.hpp ├── test_printers.hpp ├── traits_test.cpp ├── translation_generator_test.cpp ├── tree_node_test.cpp └── utility │ ├── compile_time_optional_test.cpp │ ├── compile_time_string_test.cpp │ ├── dynamic_string_view_test.cpp │ ├── exception_formatter_test.cpp │ ├── result_test.cpp │ ├── string_to_policy_test.cpp │ ├── string_view_ops_test.cpp │ ├── tree_recursor_test.cpp │ ├── type_hash_test.cpp │ ├── unsafe_any_test.cpp │ ├── utf8 │ ├── code_point_test.cpp │ ├── grapheme_cluster_break_test.cpp │ ├── levenshtein_distance_test.cpp │ └── line_break_test.cpp │ └── utf8_test.cpp └── vcpkg.json /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Chromium 4 | AccessModifierOffset: -4 5 | AllowAllArgumentsOnNextLine: false 6 | AllowAllConstructorInitializersOnNextLine: false 7 | AllowShortBlocksOnASingleLine: Empty 8 | AllowShortCaseLabelsOnASingleLine: true 9 | AlwaysBreakBeforeMultilineStrings: false 10 | BinPackArguments: false 11 | BreakBeforeBraces: Linux 12 | BreakBeforeTernaryOperators: false 13 | BreakConstructorInitializers: AfterColon 14 | BreakInheritanceList: AfterColon 15 | ColumnLimit: 100 16 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 17 | IndentCaseLabels: false 18 | IndentPPDirectives: AfterHash 19 | IndentWidth: 4 20 | PointerAlignment: Left 21 | QualifierAlignment: Left 22 | ReferenceAlignment: Pointer 23 | ReflowComments: true 24 | SortUsingDeclarations: false 25 | SpacesInContainerLiterals: false 26 | Standard: Latest 27 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: 2 | '-*,boost-*,clang-*,google-build-explicit-make-pair,google-build-namespaces,google-default-arguments,google-explicit-constructor,google-global-names-in-headers,google-objc-*,google-readability-*,google-runtime-*,google-upgrade-googletest-case,hicpp-avoid-*,hicpp-braces-around-statements,hicpp-deprecated-headers,hicpp-exception-baseclass,hicpp-explicit-conversions,hicpp-function-size,hicpp-invalid-access-moved,hicpp-member-init,hicpp-move-const-arg,hicpp-multiway-paths-covered,hicpp-named-parameter,hicpp-new-delete-operators,hicpp-no-*,hicpp-noexcept-move,hicpp-special-member-functions,hicpp-static-assert,hicpp-undelegated-constructor,hicpp-use-*,hicpp-vararg,llvm-else-after-return,llvm-include-order,llvm-namespace-comment,llvm-prefer-*,llvm-qualified-auto,llvm-twine-local,misc-definitions-in-headers,misc-misleading-*,misc-misplaced-const,misc-new-delete-overloads,misc-non-copyable-objects,misc-redundant-expression,misc-static-assert,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,misc-uniqueptr-reset-release,misc-unused-*,modernize-avoid-*,modernize-concat-nested-namespaces,modernize-deprecated-*,modernize-loop-convert,modernize-make-*,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-*,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-emplace,modernize-use-equals-*,modernize-use-nodiscard,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-transparent-functors,modernize-use-uncaught-exceptions,modernize-use-using,performance-*,portability-*,readability-avoid-const-params-in-decls,readability-braces-around-statements,readability-const-return-type,readability-container-*,readability-convert-member-functions-to-static,readability-delete-null-pointer,readability-duplicate-include,readability-else-after-return,readability-function-size,readability-identifier-naming,readability-inconsistent-declaration-parameter-name,readability-isolate-declaration,readability-magic-numbers,readability-make-member-function-const,readability-misleading-indentation,readability-misplaced-array-index,readability-named-parameter,readability-non-const-parameter,readability-qualified-auto,readability-redundant-*,readability-simplify-*,readability-static-*,readability-string-compare,readability-suspicious-call-argument,readability-uniqueptr-delete-release' 3 | FormatStyle: 'file' 4 | HeaderFilterRegex: \.hpp$ 5 | CheckOptions: 6 | - key: readability-magic-numbers.IgnoredIntegerValues 7 | value: '0;1;2;3;4;10' 8 | -------------------------------------------------------------------------------- /.clangd: -------------------------------------------------------------------------------- 1 | Hover: 2 | ShowAKA: Yes 3 | InlayHints: 4 | Enabled: Yes 5 | ParameterNames: No 6 | DeducedTypes: Yes 7 | Diagnostics: 8 | UnusedIncludes: None 9 | -------------------------------------------------------------------------------- /.github/filters.yml: -------------------------------------------------------------------------------- 1 | pr_checker: 2 | - ".github/workflows/pr_checker.yml" 3 | - ".github/workflows/bootstrap_vcpkg/action.yml" 4 | 5 | merge_checker: 6 | - ".github/workflows/merge_checker.yml" 7 | - ".github/workflows/bootstrap_vcpkg/action.yml" 8 | 9 | docs_pusher: 10 | - ".github/workflows/docs_pusher.yml" 11 | - ".github/workflows/bootstrap_vcpkg/action.yml" 12 | 13 | ci: &ci 14 | - "scripts/copyright_checker.py" 15 | - "ci/calculate_test_coverage.sh" 16 | - "ci/create_badge_url.sh" 17 | 18 | source: &source 19 | - *ci 20 | - "include/**" 21 | - "CMakeLists.txt" 22 | - "cmake/**" 23 | - "vcpkg.json" 24 | - ".gitmodules" 25 | - ".clang-format" 26 | - ".clang-tidy" 27 | 28 | source_tests_and_examples: 29 | - *source 30 | - "test/**" 31 | - "examples/**" 32 | - "ci/package_test_project/**" 33 | 34 | docs: 35 | - "cmake/build_types/documentation*" 36 | - "docs/**" 37 | - "README.md" 38 | 39 | vcpkg_test_project: 40 | - "ci/vcpkg_test_project/**" 41 | 42 | conan_test_project: 43 | - ".github/workflows/conan_setup/action.yml" 44 | - "ci/conan_test_project/**" -------------------------------------------------------------------------------- /.github/workflows/bootstrap_vcpkg/action.yml: -------------------------------------------------------------------------------- 1 | name: Bootstrap vcpkg and Configure NuGet 2 | description: Bootsraps vcpkg with disabled metrics, and configures NuGet as a bianry cache 3 | 4 | inputs: 5 | token: 6 | description: "GitHub password token" 7 | required: true 8 | 9 | runs: 10 | using: "composite" 11 | steps: 12 | - name: Configure env vars 13 | shell: bash 14 | run: | 15 | echo "NUGET_SOURCE_URL=https://nuget.pkg.github.com/cmannett85/index.json" >> $GITHUB_ENV 16 | echo "VCPKG_BINARY_SOURCES=clear;nuget,vcpkg-cache,readwrite" >> $GITHUB_ENV 17 | 18 | - name: Bootstrap vcpkg to build the NuGet client on Linux and MacOS 19 | if: runner.os != 'Windows' 20 | shell: bash 21 | run: | 22 | cd ${{ github.workspace }} 23 | ./external/vcpkg/bootstrap-vcpkg.sh -disableMetrics 24 | 25 | - name: Bootstrap vcpkg to build the NuGet client on Windows 26 | if: runner.os == 'Windows' 27 | shell: pwsh 28 | run: | 29 | cd ${{ github.workspace }} 30 | ./external/vcpkg/bootstrap-vcpkg.bat -disableMetrics 31 | 32 | - name: Configure NuGet client on Linux and MacOS 33 | if: runner.os != 'Windows' 34 | shell: bash 35 | run: | 36 | mono `./external/vcpkg/vcpkg fetch nuget | tail -n 1` \ 37 | sources add \ 38 | -source ${{ env.NUGET_SOURCE_URL }} \ 39 | -storepasswordincleartext \ 40 | -name "vcpkg-cache" \ 41 | -username "cmannett85" \ 42 | -password "${{ inputs.token }}" 43 | mono `./external/vcpkg/vcpkg fetch nuget | tail -n 1` \ 44 | setapikey "${{ inputs.token }}" \ 45 | -source ${{ env.NUGET_SOURCE_URL }} 46 | 47 | - name: Configure NuGet client on Windows 48 | if: runner.os == 'Windows' 49 | shell: pwsh 50 | run: | 51 | [array] $output = ./external/vcpkg/vcpkg.exe fetch nuget 52 | & $output[-1] sources add -source ${{ env.NUGET_SOURCE_URL }} -storepasswordincleartext -name "vcpkg-cache" -username "cmannett85" -password "${{ inputs.token }}" 53 | & $output[-1] setapikey "${{ inputs.token }}" -source ${{ env.NUGET_SOURCE_URL }} 54 | -------------------------------------------------------------------------------- /.github/workflows/conan_setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Installs and configures Conan 2 | description: Installs and configures Conan for a particular C++ version (Linux only) 3 | 4 | inputs: 5 | version: 6 | description: "C++ language version" 7 | build_dir: 8 | description: "Build directory for the Conan test project" 9 | 10 | runs: 11 | using: "composite" 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: actions/setup-python@v4 15 | with: 16 | python-version: '3.x' 17 | 18 | - name: Update packages 19 | shell: bash 20 | run: | 21 | sudo apt update 22 | sudo apt install ninja-build 23 | python -m pip install --upgrade pip conan 24 | 25 | - name: Build Conan profile 26 | shell: bash 27 | run: | 28 | conan profile detect --force 29 | sed -i "s/^compiler.cppstd=.*/compiler.cppstd=${{ inputs.version }}/g" `conan profile path default` 30 | 31 | - name: Build 32 | shell: bash 33 | run: | 34 | conan install ${{ github.workspace }}/ci/conan_test_project --output-folder=${{ inputs.build_dir }} --build=missing 35 | cd ${{ inputs.build_dir }} 36 | cmake ${{ github.workspace }}/ci/conan_test_project/ -G "Ninja" -DCMAKE_TOOLCHAIN_FILE=./build/Release/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release 37 | cmake --build . 38 | -------------------------------------------------------------------------------- /.github/workflows/docs_pusher.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses Doxygen to generate HTML API documentation, which is then 2 | # pushed to the project's GitHub Pages 3 | name: Documentation Generator 4 | 5 | on: 6 | push: 7 | branches: [ main ] 8 | 9 | env: 10 | SKIP_COVERAGE_UPDATE: 1 11 | BUILD_DIR: ${{ github.workspace }}/build 12 | 13 | jobs: 14 | # Skip jobs based on what files have changed 15 | changes: 16 | runs-on: ubuntu-latest 17 | permissions: 18 | pull-requests: read 19 | outputs: 20 | docs_pusher: ${{ steps.filter.outputs.docs_pusher }} 21 | source_tests_and_examples: ${{ steps.filter.outputs.source_tests_and_examples }} 22 | docs: ${{ steps.filter.outputs.docs }} 23 | steps: 24 | - uses: actions/checkout@v3 25 | - uses: dorny/paths-filter@v2 26 | id: filter 27 | with: 28 | initial-fetch-depth: 2 29 | filters: .github/filters.yml 30 | 31 | documentation: 32 | runs-on: ubuntu-latest 33 | needs: changes 34 | if: | 35 | needs.changes.outputs.docs_pusher == 'true' || 36 | needs.changes.outputs.source_tests_and_examples == 'true' || 37 | needs.changes.outputs.docs == 'true' 38 | 39 | steps: 40 | - uses: actions/checkout@v3 41 | with: 42 | submodules: true 43 | 44 | - name: Update packages 45 | run: | 46 | sudo apt update 47 | sudo apt install lcov ninja-build doxygen graphviz 48 | 49 | - uses: ./.github/workflows/bootstrap_vcpkg 50 | with: 51 | token: "${{ secrets.GITHUB_TOKEN }}" 52 | 53 | - name: Generate API documentation and build Unit Tests 54 | timeout-minutes: 30 55 | run: | 56 | mkdir -p ${{ env.BUILD_DIR }} 57 | cd ${{ env.BUILD_DIR }} 58 | cmake ${{ github.workspace }} -G "Ninja" -DCMAKE_CXX_COMPILER=clang++-14 -DDEATH_TEST_PARALLEL=2 59 | cmake --build . --target documentation arg_router_test_coverage 60 | 61 | - name: Run unit tests to generate coverage data 62 | timeout-minutes: 30 63 | run: | 64 | cd ${{ env.BUILD_DIR }}/test 65 | ./arg_router_test_coverage -l test_suite 66 | 67 | - name: Generate coverage report 68 | run: | 69 | cd ${{ github.workspace }}/ci 70 | ./calculate_test_coverage.sh ${{ env.BUILD_DIR }} 71 | cd ${{ env.BUILD_DIR }} 72 | genhtml arg_router.info --no-function-coverage --title "arg_router Unit Test Code Coverage" --legend --highlight --output-directory gcov_html 73 | cp -rf ./gcov_html ${GITHUB_WORKSPACE}/docs/doxygen/html/ 74 | 75 | - name: Deploy 76 | uses: peaceiris/actions-gh-pages@v3 77 | with: 78 | github_token: ${{ secrets.GITHUB_TOKEN }} 79 | publish_dir: ./docs/doxygen/html 80 | -------------------------------------------------------------------------------- /.github/workflows/release_builder.yml: -------------------------------------------------------------------------------- 1 | # This workflow publishes a release when a version tag is pushed 2 | name: Release Builder 3 | 4 | on: 5 | push: 6 | tags: 7 | - 'v*' 8 | 9 | env: 10 | BUILD_DIR: ${{ github.workspace }}/build 11 | TAG_VERSION: ${{ github.ref }} 12 | 13 | jobs: 14 | create_release: 15 | runs-on: ubuntu-22.04 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | with: 20 | fetch-depth: 1 21 | 22 | - name: Get commit message and percent-encode 23 | id: commit_msg 24 | run: | 25 | MSG=$(git show -s --format=%s%n%n%b $(git log -2 --pretty=%H | tail -n 1)) 26 | echo $MSG 27 | MSG="${MSG//'%'/'%25'}" 28 | MSG="${MSG//$'\n'/'%0A'}" 29 | MSG="${MSG//$'\r'/'%0D'}" 30 | echo "commit_msg=${MSG}" >> $GITHUB_OUTPUT 31 | 32 | - name: Build release 33 | run: | 34 | mkdir -p ${{ env.BUILD_DIR }} 35 | cd ${{ env.BUILD_DIR }} 36 | cmake ${{ github.workspace }} -DINSTALLATION_ONLY=ON 37 | cmake --build . --target package 38 | 39 | - name: Check versions match 40 | id: version_check 41 | run: | 42 | cd ${{ env.BUILD_DIR }} 43 | VERSION=`cut -c 12- <<< "${{ env.TAG_VERSION }}"` 44 | FILENAME="arg_router-${VERSION}" 45 | test -e ${FILENAME}.zip 46 | echo "filename=${FILENAME}" >> $GITHUB_OUTPUT 47 | 48 | - name: Test Deb install 49 | run: | 50 | cd ${{ env.BUILD_DIR }} 51 | sudo apt install ./${{ steps.version_check.outputs.filename }}.deb 52 | test -e /usr/include/arg_router 53 | sudo apt remove arg_router 54 | ! test -e /usr/include/arg_router 55 | 56 | - name: Create GitHub release entry 57 | id: create_release 58 | uses: softprops/action-gh-release@v0.1.15 59 | with: 60 | tag_name: ${{ env.TAG_VERSION }} 61 | name: arg_router ${{ env.TAG_VERSION }} 62 | body: ${{ steps.commit_msg.outputs.commit_msg }} 63 | draft: false 64 | prerelease: false 65 | fail_on_unmatched_files: true 66 | files: | 67 | ${{ env.BUILD_DIR }}/${{ steps.version_check.outputs.filename }}.zip 68 | ${{ env.BUILD_DIR }}/${{ steps.version_check.outputs.filename }}.deb 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Death test main (modified by tests) 2 | test/death_test/main_*.cpp 3 | 4 | # Generated docs 5 | docs/doxygen 6 | docs/README_API.md 7 | 8 | # IDE cruft 9 | build/ 10 | out/ 11 | *.creator.user 12 | *.txt.user 13 | .vscode/ 14 | .vs/ 15 | target/ 16 | CMakeSettings.json 17 | .cache/ 18 | CMakeUserPresets.json 19 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vcpkg"] 2 | path = external/vcpkg 3 | url = https://github.com/Microsoft/vcpkg.git 4 | [submodule "external/doxygen-awesome-css"] 5 | path = external/doxygen-awesome-css 6 | url = https://github.com/jothepro/doxygen-awesome-css.git 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /ci/calculate_test_coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Copyright (C) 2022-2023 by Camden Mannett. 4 | ### Distributed under the Boost Software License, Version 1.0. 5 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | 7 | # Run from inside the /ci folder. 8 | # - First argument is the top-level build directory and is required 9 | # - Second argument is optional, and defined the gcov tool (defaults to llvm-gcov-14) 10 | if [ -z "$1" ]; then 11 | echo "Must pass build directory" 12 | exit 1 13 | fi 14 | 15 | BUILD_DIR=$1 16 | DEFAULT_TOOL_NAME="llvm-gcov-14" 17 | TOOL=${2:-"${BUILD_DIR}/${DEFAULT_TOOL_NAME}"} 18 | SKIP_UPDATE="${SKIP_COVERAGE_UPDATE:-1}" 19 | 20 | SRC_PATH=${PWD} 21 | OLD_COVERAGE="$(cat ./old_coverage)" 22 | 23 | # llvm-cov needs a gcov arg to be used with lcov, but lcov doesn't accept it, so we need to create 24 | # a script that emulates it 25 | cd ${BUILD_DIR} 26 | if [[ "${TOOL}" == *"${DEFAULT_TOOL_NAME}"* ]]; then 27 | rm ${TOOL} 28 | SCRIPT_TEXT="#!/usr/bin/env bash\nexec llvm-cov-14 gcov \"\$@\"" 29 | echo -e ${SCRIPT_TEXT} >> ${TOOL} 30 | chmod a+x ${TOOL} 31 | fi 32 | 33 | lcov -d ./test/CMakeFiles/arg_router_test_coverage.dir \ 34 | -c -o temp.info --gcov-tool ${TOOL} 35 | lcov --remove temp.info "/usr/include/*" \ 36 | --remove temp.info "*/vcpkg_installed/*" \ 37 | --remove temp.info "*/arg_router/test/*" \ 38 | --output-file arg_router.info 39 | 40 | NEW_COVERAGE="$(lcov --summary arg_router.info | awk 'NR==3 {print $2+0}')" 41 | DIFF=$(echo "$NEW_COVERAGE - $OLD_COVERAGE" | bc); 42 | echo "New coverage: ${NEW_COVERAGE}%, previous coverage: ${OLD_COVERAGE}%, diff: ${DIFF}" 43 | if (( $(echo "${DIFF} < -1.0" | bc -l) )); then 44 | echo "Coverage drop too great (>1%)" 45 | exit 1 46 | fi 47 | 48 | if [ "${SKIP_UPDATE}" = "0" ]; then 49 | # Write the new value back to the cache 50 | echo ${NEW_COVERAGE} > ${SRC_PATH}/old_coverage 51 | fi 52 | -------------------------------------------------------------------------------- /ci/conan_test_project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | cmake_minimum_required(VERSION 3.18) 6 | 7 | project(conan_test_project 8 | LANGUAGES CXX) 9 | 10 | find_package(arg_router REQUIRED) 11 | 12 | add_executable(conan_test_project "main.cpp") 13 | target_link_libraries(conan_test_project PUBLIC arg_router::arg_router) 14 | -------------------------------------------------------------------------------- /ci/conan_test_project/conanfile.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2023 by Camden Mannett. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | import os 6 | 7 | from conan import ConanFile 8 | from conan.tools.cmake import CMake, cmake_layout 9 | from conan.tools.build import can_run 10 | 11 | 12 | class TestPackageConan(ConanFile): 13 | settings = "os", "compiler", "build_type", "arch" 14 | generators = "CMakeDeps", "CMakeToolchain" 15 | 16 | def requirements(self): 17 | self.requires("arg_router/[>=1.3.0]") 18 | 19 | def build(self): 20 | cmake = CMake(self) 21 | cmake.configure() 22 | cmake.build() 23 | 24 | def layout(self): 25 | cmake_layout(self) 26 | 27 | def test(self): 28 | if can_run(self): 29 | cmd = os.path.join(self.cpp.build.bindir, 30 | "conan_test_project") + " --help" 31 | self.run(cmd, env="conanrun") 32 | -------------------------------------------------------------------------------- /ci/conan_test_project/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include 6 | 7 | namespace ar = arg_router; 8 | namespace arp = ar::policy; 9 | 10 | #if (__cplusplus >= 202002L) 11 | using namespace ar::literals; 12 | 13 | int main(int argc, char* argv[]) 14 | { 15 | ar::root(arp::validation::default_validator, 16 | ar::help("help"_S, 17 | "h"_S, 18 | "Display this help and exit"_S, 19 | arp::program_name_t{"just-cats"_S}, 20 | arp::program_intro_t{"Prints cats!"_S}, 21 | arp::program_addendum_t{"An example program for arg_router."_S}), 22 | ar::flag("cat"_S, "English cat"_S, arp::router{[](bool) { 23 | std::cout << "cat" << std::endl; 24 | }}), 25 | ar::flag("猫"_S, // 26 | arp::description_t{"日本語の猫"_S}, 27 | arp::router{[](bool) { std::cout << "猫" << std::endl; }}), 28 | ar::flag("🐱"_S, // 29 | arp::description_t{"Emoji cat"_S}, 30 | arp::router{[](bool) { std::cout << "🐱" << std::endl; }}), 31 | ar::flag("แมว"_S, // 32 | "แมวไทย"_S, 33 | arp::router{[](bool) { std::cout << "แมว" << std::endl; }}), 34 | ar::flag("кіт"_S, // 35 | "український кіт"_S, 36 | arp::router{[](bool) { std::cout << "кіт" << std::endl; }})) 37 | .parse(argc, argv); 38 | 39 | return EXIT_SUCCESS; 40 | } 41 | #else 42 | int main(int argc, char* argv[]) 43 | { 44 | ar::root(arp::validation::default_validator, 45 | ar::help(S_("help"){}, 46 | S_('h'){}, 47 | S_("Display this help and exit"){}, 48 | arp::program_name, 49 | arp::program_intro, 50 | arp::program_addendum), 51 | ar::flag(S_("cat"){}, // 52 | S_("English cat"){}, 53 | arp::router{[](bool) { std::cout << "cat" << std::endl; }}), 54 | ar::flag(S_("猫"){}, // 55 | arp::description, 56 | arp::router{[](bool) { std::cout << "猫" << std::endl; }}), 57 | ar::flag(S_("🐱"){}, // 58 | arp::description, 59 | arp::router{[](bool) { std::cout << "🐱" << std::endl; }}), 60 | ar::flag(S_("แมว"){}, // 61 | S_("แมวไทย"){}, 62 | arp::router{[](bool) { std::cout << "แมว" << std::endl; }}), 63 | ar::flag(S_("кіт"){}, // 64 | S_("український кіт"){}, 65 | arp::router{[](bool) { std::cout << "кіт" << std::endl; }})) 66 | .parse(argc, argv); 67 | 68 | return EXIT_SUCCESS; 69 | } 70 | #endif 71 | -------------------------------------------------------------------------------- /ci/create_badge_url.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Copyright (C) 2022-2023 by Camden Mannett. 4 | ### Distributed under the Boost Software License, Version 1.0. 5 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | 7 | ESCAPE=0 8 | if [ "$1" == "-e" ]; then 9 | ESCAPE=1 10 | fi 11 | 12 | # Creates a shields.io badge URL for the unit test coverage 13 | COVERAGE="$(cat ./ci/old_coverage)" 14 | COLOUR="brightgreen" 15 | if (( $(echo "$COVERAGE < 50" | bc -l) )); then 16 | COLOUR="red" 17 | elif (( $(echo "$COVERAGE < 60" | bc -l) )); then 18 | COLOUR="orange" 19 | elif (( $(echo "$COVERAGE < 70" | bc -l) )); then 20 | COLOUR="yellow" 21 | elif (( $(echo "$COVERAGE < 80" | bc -l) )); then 22 | COLOUR="yellowgreen" 23 | elif (( $(echo "$COVERAGE < 90" | bc -l) )); then 24 | COLOUR="green" 25 | fi 26 | 27 | if [ "$ESCAPE" == "0" ]; then 28 | echo "https://img.shields.io/badge/Unit_Test_Coverage-${COVERAGE}%25-${COLOUR}" 29 | else 30 | echo "https:\/\/img\.shields\.io\/badge\/Unit_Test_Coverage-${COVERAGE}%25-${COLOUR}" 31 | fi 32 | -------------------------------------------------------------------------------- /ci/old_coverage: -------------------------------------------------------------------------------- 1 | 97.2 2 | -------------------------------------------------------------------------------- /ci/package_test_project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | cmake_minimum_required(VERSION 3.18) 6 | 7 | option(DISABLE_VCPKG "Disable vcpkg" OFF) 8 | 9 | set(ROOT_DIR "${CMAKE_SOURCE_DIR}/../..") 10 | if (NOT DISABLE_VCPKG) 11 | set(CMAKE_TOOLCHAIN_FILE "${ROOT_DIR}/external/vcpkg/scripts/buildsystems/vcpkg.cmake") 12 | endif() 13 | 14 | project(package_test_project 15 | LANGUAGES CXX) 16 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 17 | 18 | find_package(arg_router REQUIRED) 19 | 20 | arg_router_translation_generator( 21 | SOURCES "${ROOT_DIR}/examples/resources/simple_ml_gen/en_GB.toml" 22 | "${ROOT_DIR}/examples/resources/simple_ml_gen/fr.toml" 23 | "${ROOT_DIR}/examples/resources/simple_ml_gen/ja.toml" 24 | OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/translations/" 25 | TARGET translation_package_test_project 26 | ) 27 | 28 | # Default to C++20 29 | if(NOT DEFINED CMAKE_CXX_STANDARD) 30 | set(CMAKE_CXX_STANDARD "20") 31 | endif() 32 | 33 | add_executable(package_test_project 34 | $, 35 | "${ROOT_DIR}/examples/c++17/simple_ml_gen/main.cpp" , 36 | "${ROOT_DIR}/examples/c++20/simple_ml_gen/main.cpp" > 37 | ${translation_files} 38 | "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg.json") 39 | 40 | target_link_libraries(package_test_project PUBLIC arg_router::arg_router) 41 | set_target_properties(package_test_project PROPERTIES CXX_EXTENSIONS OFF) 42 | add_dependencies(package_test_project translation_package_test_project) 43 | target_include_directories(package_test_project PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") 44 | 45 | set(EXTRA_FLAGS -Werror -Wall -Wextra) 46 | if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") 47 | set(EXTRA_FLAGS /W4 /Z7 /GR- /permissive-) 48 | 49 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 50 | set(EXTRA_FLAGS ${EXTRA_FLAGS} /clang:-fconstexpr-steps=10000000) 51 | endif() 52 | endif() 53 | target_compile_options(package_test_project PRIVATE ${EXTRA_FLAGS}) 54 | -------------------------------------------------------------------------------- /ci/package_test_project/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "package-test-project", 3 | "version": "0.0.2", 4 | "dependencies": [ 5 | "boost-lexical-cast", 6 | "boost-mp11" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /ci/vcpkg_package_updater.ps1: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | # If you see 'vcpkg_package_updater.ps1 cannot be loaded because running scripts is disabled on this system', 6 | # set the following in Powershell first: 7 | # Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass 8 | 9 | # If you see 'gpg: skipped "xxxxxxx": No secret key', it is because their is no GPG program 10 | # associated with Git. Add this: 11 | # git config --global gpg.program "c:/Program Files (x86)/GnuPG/bin/gpg.exe" 12 | 13 | # If a REF hash is provided, check that it is valid 14 | param([string]$ref_hash = '') 15 | if ($ref_hash -and $ref_hash -notmatch '^[0-9a-f]{40}$') { 16 | Write-Host 'Invalid REF hash' 17 | exit 1 18 | } 19 | 20 | $root_dir = "$PSScriptRoot\.." 21 | 22 | # Use the version in the Doxyfile 23 | Select-String -Path $root_dir\docs\Doxyfile -Pattern '^PROJECT_NUMBER = (.*)$' ` 24 | | ForEach-Object { Set-Variable -name 'version' -Value $_.matches[0].groups[1].value } 25 | 26 | # Create a new branch at vcpkg HEAD. Wipe out any previous changes 27 | Set-Location $root_dir\external\vcpkg 28 | git checkout master 29 | git reset --hard origin/master 30 | git fetch 31 | git checkout -b vcpkg_$version 32 | 33 | # Update the versions 34 | (Get-Content -ReadCount 0 ports/arg-router/vcpkg.json) ` 35 | -replace '^ "version": "[0-9]+\.[0-9]+\.[0-9]+",$', " `"version`": `"$version`"," ` 36 | | Set-Content ports/arg-router/vcpkg.json 37 | .\vcpkg format-manifest ports/arg-router/vcpkg.json 38 | git add ports/arg-router/vcpkg.json 39 | git commit -m "[arg-router] Update to v$version" 40 | .\vcpkg x-add-version arg-router 41 | 42 | # If this run is for a test build, then update the REF entry to the specified hash 43 | if ($ref_hash) { 44 | (Get-Content -ReadCount 0 ports/arg-router/portfile.cmake) ` 45 | -replace '^ REF v.*$', " REF $ref_hash" ` 46 | | Set-Content ports/arg-router/portfile.cmake 47 | } 48 | 49 | # Manually build the test package, this will fail due to an incorrect SHA but we need it to for 50 | # vcpkg to give us the correct one 51 | Set-Location $root_dir\ci\vcpkg_test_project 52 | New-Item -Path . -Name 'build' -ItemType 'directory' 53 | Set-Location .\build 54 | [array] $sha_output = cmake -G 'Ninja' ` 55 | -DVCPKG_TARGET_TRIPLET=x64-windows-static ` 56 | -DCMAKE_CXX_STANDARD=20 ` 57 | -B . -S .. 2>&1 ` 58 | | Out-String 59 | 60 | # Update the SHA value in the portfile, and the ref if this run is for a test build 61 | Set-Location $root_dir\external\vcpkg 62 | Select-String -Pattern 'Actual hash: (.*)' -InputObject $sha_output ` 63 | | ForEach-Object { Set-Variable -name 'new_sha' -Value $_.matches[0].groups[1].value.Trim() } 64 | (Get-Content -ReadCount 0 ports/arg-router/portfile.cmake) ` 65 | -replace '^ SHA512 [0-9a-f]{128}$', " SHA512 $new_sha" ` 66 | | Set-Content ports/arg-router/portfile.cmake 67 | 68 | # Re-run the build to confirm 69 | Write-Host "Testing project against updated vcpkg..." 70 | Set-Location $root_dir\ci\vcpkg_test_project\build 71 | cmake -G 'Ninja' ` 72 | -DVCPKG_TARGET_TRIPLET=x64-windows-static ` 73 | -DCMAKE_CXX_STANDARD=20 ` 74 | -B . -S .. 75 | cmake --build . 76 | 77 | Set-Location .. 78 | Remove-Item -Path .\build -Recurse -Force 79 | 80 | # Update the version hash for the SHA update 81 | Set-Location $root_dir\external\vcpkg 82 | git add ports\arg-router\portfile.cmake 83 | git commit -m "WIP" 84 | .\vcpkg x-add-version arg-router --overwrite-version 85 | -------------------------------------------------------------------------------- /ci/vcpkg_package_updater.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Copyright (C) 2023 by Camden Mannett. 4 | ### Distributed under the Boost Software License, Version 1.0. 5 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | 7 | # If a REF hash is provided, check that it is valid 8 | ref_hash="" 9 | if [ ! -z "$1" ]; then 10 | if [[ ! "$1" =~ ^[0-9a-f]{40}$ ]]; then 11 | echo "Invalid REF hash" 12 | exit 1 13 | fi 14 | ref_hash="$1" 15 | fi 16 | 17 | root_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )/../ 18 | 19 | # Use the version in the Doxyfile 20 | version=`sed -n -e 's/^PROJECT_NUMBER = \(.*\)$/\1/p' ${root_dir}/docs/Doxyfile` 21 | 22 | # Create a new branch at vcpkg HEAD. Wipe out any previous changes 23 | cd ${root_dir}/external/vcpkg 24 | git checkout master 25 | git reset --hard origin/master 26 | git fetch 27 | git checkout -b vcpkg_${version} 28 | 29 | # Update the versions 30 | sed -ri "s/^ \"version\": \"[0-9]+\.[0-9]+\.[0-9]+\",$/ \"version\": \"${version}\",/" ports/arg-router/vcpkg.json 31 | ./vcpkg format-manifest ports/arg-router/vcpkg.json 32 | git add ports/arg-router/vcpkg.json 33 | git commit -m "[arg-router] Update to v${version}" 34 | ./vcpkg x-add-version arg-router 35 | 36 | # If this run is for a test build, then update the REF entry to the specified hash 37 | if [ ! -z "$ref_hash" ]; then 38 | sed -ri "s/^ REF v.*$/ REF ${ref_hash}/" ports/arg-router/portfile.cmake 39 | fi 40 | 41 | # Manually build the test package, this will fail due to an incorrect SHA but we need it to for 42 | # vcpkg to give us the correct one 43 | cd ${root_dir}/ci/vcpkg_test_project 44 | mkdir build 45 | cd ./build 46 | set +e 47 | sha_output=`cmake -G "Ninja" -DCMAKE_CXX_STANDARD=20 -B . -S .. 2>&1` 48 | set -e 49 | 50 | # Update the SHA value in the portfile, and the ref if this run is for a test build 51 | cd ${root_dir}/external/vcpkg 52 | new_sha=`echo "$sha_output" | sed -n -e 's/^Actual hash: \(.*\)$/\1/p'` 53 | sed -ri "s/^ SHA512 [0-9a-f]{128}$/ SHA512 ${new_sha}/" ports/arg-router/portfile.cmake 54 | 55 | # Re-run the build to confirm 56 | echo "Testing project against updated vcpkg..." 57 | cd ${root_dir}/ci/vcpkg_test_project/build 58 | cmake -G "Ninja" -DCMAKE_CXX_STANDARD=20 -B . -S .. 59 | cmake --build . 60 | cd .. 61 | rm -rf ./build 62 | 63 | # Update the version hash for the SHA update 64 | cd ${root_dir}/external/vcpkg 65 | git add ports/arg-router/portfile.cmake 66 | git commit -m "WIP" 67 | ./vcpkg x-add-version arg-router --overwrite-version 68 | -------------------------------------------------------------------------------- /ci/vcpkg_test_project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | cmake_minimum_required(VERSION 3.18) 6 | 7 | set(ROOT_DIR "${CMAKE_SOURCE_DIR}/../..") 8 | set(CMAKE_TOOLCHAIN_FILE "${ROOT_DIR}/external/vcpkg/scripts/buildsystems/vcpkg.cmake") 9 | 10 | project(vcpkg_test_project 11 | LANGUAGES CXX) 12 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 13 | 14 | find_package(arg_router REQUIRED) 15 | 16 | add_executable(vcpkg_test_project 17 | "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg.json") 19 | 20 | target_link_libraries(vcpkg_test_project PUBLIC arg_router::arg_router) 21 | target_compile_features(vcpkg_test_project PUBLIC cxx_std_20) 22 | set_target_properties(vcpkg_test_project PROPERTIES CXX_EXTENSIONS OFF) 23 | 24 | if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") 25 | target_compile_options(vcpkg_test_project PRIVATE /Zc:__cplusplus /W4 /Z7 /GR- /permissive-) 26 | else() 27 | target_compile_options(vcpkg_test_project PRIVATE -Werror -Wall -Wextra) 28 | endif() 29 | -------------------------------------------------------------------------------- /ci/vcpkg_test_project/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include 6 | 7 | namespace ar = arg_router; 8 | namespace arp = ar::policy; 9 | using namespace ar::literals; 10 | 11 | int main(int argc, char* argv[]) 12 | { 13 | ar::root(arp::validation::default_validator, 14 | ar::help("help"_S, 15 | "h"_S, 16 | "Display this help and exit"_S, 17 | arp::program_name_t{"just-cats"_S}, 18 | arp::program_intro_t{"Prints cats!"_S}, 19 | arp::program_addendum_t{"An example program for arg_router."_S}), 20 | ar::flag("cat"_S, "English cat"_S, arp::router{[](bool) { 21 | std::cout << "cat" << std::endl; 22 | }}), 23 | ar::flag("猫"_S, // 24 | arp::description_t{"日本語の猫"_S}, 25 | arp::router{[](bool) { std::cout << "猫" << std::endl; }}), 26 | ar::flag("🐱"_S, // 27 | arp::description_t{"Emoji cat"_S}, 28 | arp::router{[](bool) { std::cout << "🐱" << std::endl; }}), 29 | ar::flag("แมว"_S, // 30 | "แมวไทย"_S, 31 | arp::router{[](bool) { std::cout << "แมว" << std::endl; }}), 32 | ar::flag("кіт"_S, // 33 | "український кіт"_S, 34 | arp::router{[](bool) { std::cout << "кіт" << std::endl; }})) 35 | .parse(argc, argv); 36 | 37 | return EXIT_SUCCESS; 38 | } 39 | -------------------------------------------------------------------------------- /ci/vcpkg_test_project/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vcpkg-test-project", 3 | "version": "0.0.1", 4 | "dependencies": [ 5 | "arg-router" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /cmake/build_types/ast.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | function(create_ast_target) 6 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") 7 | cmake_parse_arguments(ARG "" "TARGET" "SOURCES" ${ARGN}) 8 | if (NOT ARG_TARGET) 9 | message(FATAL_ERROR "Target not defined") 10 | endif() 11 | if (NOT ARG_SOURCES) 12 | message(FATAL_ERROR "Sources not defined") 13 | endif() 14 | 15 | add_executable(${ARG_TARGET} EXCLUDE_FROM_ALL ${ARG_SOURCES}) 16 | target_compile_features(${ARG_TARGET} PUBLIC cxx_std_20) 17 | set_target_properties(${ARG_TARGET} PROPERTIES CXX_EXTENSIONS OFF) 18 | target_include_directories(${ARG_TARGET} PUBLIC "${CMAKE_SOURCE_DIR}/include") 19 | target_compile_options(${ARG_TARGET} PRIVATE -Xclang -ast-print -fsyntax-only) 20 | else() 21 | message(STATUS "Skipping AST targets as they are only for Clang compilers") 22 | endif() 23 | endfunction() 24 | -------------------------------------------------------------------------------- /cmake/build_types/death_test.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | path_prefixer(DEATH_TEST_DIR 6 | death_test 7 | ) 8 | file(MAKE_DIRECTORY ${DEATH_TEST_DIR}) 9 | 10 | function(create_death_test NUM) 11 | # Make the death_test main stub to appease CMake, it'll get destroyed on first use 12 | set(DEATH_TEST_SRC 13 | "${DEATH_TEST_DIR}/main_${NUM}.cpp" 14 | ) 15 | file(TOUCH ${DEATH_TEST_SRC}) 16 | 17 | set(TARGET_NAME "arg_router_death_test_${NUM}") 18 | add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL ${DEATH_TEST_SRC}) 19 | target_link_libraries(${TARGET_NAME} PRIVATE arg_router) 20 | 21 | target_compile_features(${TARGET_NAME} PUBLIC cxx_std_20) 22 | set_target_properties(${TARGET_NAME} PROPERTIES CXX_EXTENSIONS OFF) 23 | target_compile_definitions(${TARGET_NAME} PRIVATE DEATH_TEST_BUILD) 24 | 25 | configure_test_build(${TARGET_NAME}) 26 | endfunction() 27 | 28 | math(EXPR STOP_INDEX "${DEATH_TEST_PARALLEL}-1") 29 | foreach(NUM RANGE ${STOP_INDEX}) 30 | create_death_test(${NUM}) 31 | endforeach() 32 | -------------------------------------------------------------------------------- /cmake/build_types/documentation.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | path_prefixer(DOCS_SOURCES 6 | cmake/build_types/documentation_script.cmake 7 | docs/Doxyfile 8 | docs/related_pages/architecture.doxy 9 | docs/related_pages/configuration.doxy 10 | docs/related_pages/examples.doxy 11 | docs/related_pages/help.doxy 12 | docs/related_pages/images/node_relationships.dia 13 | docs/related_pages/images/node_relationships.svg 14 | docs/related_pages/nodes.doxy 15 | docs/related_pages/policies.doxy 16 | docs/related_pages/validation.doxy 17 | README.md 18 | ) 19 | 20 | path_prefixer(README_API_PATH 21 | docs/README_API.md 22 | ) 23 | 24 | set(DOCS_COMMAND 25 | "${CMAKE_COMMAND}" 26 | -DROOT="${CMAKE_CURRENT_SOURCE_DIR}" 27 | -P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_types/documentation_script.cmake" 28 | ) 29 | 30 | add_custom_target(documentation 31 | COMMAND ${DOCS_COMMAND} 32 | SOURCES ${DOCS_SOURCES} 33 | ) 34 | 35 | # We have to touch the generated API readme because CPack configuration will fail if it is not 36 | # there. set_source_files_properties cannot be used in a script so that's set here too 37 | file(TOUCH ${README_API_PATH}) 38 | set_source_files_properties(${README_API_PATH} PROPERTIES GENERATED TRUE) 39 | -------------------------------------------------------------------------------- /cmake/build_types/documentation_script.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | # Can't use find_package as it tries to create a target which is not allowed in script mode 6 | find_program( 7 | DOXYGEN_EXECUTABLE 8 | NAMES doxygen 9 | PATHS 10 | "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\doxygen_is1;Inno Setup: App Path]/bin" 11 | /Applications/Doxygen.app/Contents/Resources 12 | /Applications/Doxygen.app/Contents/MacOS 13 | /Applications/Utilities/Doxygen.app/Contents/Resources 14 | /Applications/Utilities/Doxygen.app/Contents/MacOS 15 | DOC "Doxygen documentation generation tool (http://www.doxygen.org)" 16 | REQUIRED 17 | ) 18 | 19 | set(API_MD_PATH "${ROOT}/README.md") 20 | set(NEW_API_MD_PATH "${ROOT}/docs/README_API.md") 21 | 22 | file(READ ${API_MD_PATH} MD_DATA) 23 | 24 | # Remove the badges, by simply removing the first couple of lines 25 | string(FIND "${MD_DATA}" "\n\n" NL_IDX) 26 | if(${NL_IDX} EQUAL -1) 27 | message(FATAL "Cannot find README.md first newline") 28 | endif() 29 | math(EXPR NL_IDX "${NL_IDX} + 2") 30 | string(SUBSTRING "${MD_DATA}" ${NL_IDX} -1 UPDATED_MD_DATA) 31 | 32 | if(NOT "${MD_DATA}" STREQUAL "${UPDATED_MD_DATA}") 33 | message(STATUS "Updating Doxygen README.md") 34 | file(WRITE ${NEW_API_MD_PATH} "${UPDATED_MD_DATA}") 35 | else() 36 | message(STATUS "README.md up to date") 37 | endif() 38 | 39 | execute_process( 40 | COMMAND "${DOXYGEN_EXECUTABLE}" "${ROOT}/docs/Doxyfile" 41 | WORKING_DIRECTORY "${ROOT}/docs" 42 | RESULT_VARIABLE DOXYGEN_RESULT 43 | ERROR_VARIABLE DOXY_ERROR_STRING 44 | ) 45 | 46 | if(NOT ${DOXYGEN_RESULT} EQUAL 0) 47 | message(FATAL_ERROR "Doxygen generation failed: ${DOXY_ERROR_STRING}") 48 | endif() 49 | -------------------------------------------------------------------------------- /cmake/build_types/library.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | add_library(arg_router INTERFACE ${HEADERS}) 6 | target_link_libraries(arg_router INTERFACE 7 | Boost::boost 8 | $<$:nonstd::span-lite> 9 | ) 10 | 11 | target_include_directories(arg_router AFTER INTERFACE 12 | $ 13 | $ # /include 14 | ) 15 | 16 | if(NOT INSTALLATION_ONLY) 17 | add_dependencies(arg_router clangformat) 18 | endif() 19 | -------------------------------------------------------------------------------- /cmake/build_types/unit_test_coverage.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | # Translation generator unit test input files 6 | include("${CMAKE_SOURCE_DIR}/cmake/translation_generator/translation_generator.cmake") 7 | arg_router_translation_generator( 8 | SOURCES "${CMAKE_SOURCE_DIR}/examples/resources/simple_ml_gen/en_GB.toml" 9 | "${CMAKE_SOURCE_DIR}/examples/resources/simple_ml_gen/ja.toml" 10 | OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/translations/" 11 | TARGET translation_arg_router_test_coverage 12 | ) 13 | 14 | add_executable(arg_router_test_coverage EXCLUDE_FROM_ALL ${TEST_HEADERS} ${TEST_SRCS}) 15 | add_dependencies( 16 | arg_router_test_coverage 17 | translation_arg_router_test_coverage 18 | clangformat_test arg_router) 19 | 20 | set_target_properties(arg_router_test_coverage PROPERTIES CXX_EXTENSIONS OFF) 21 | target_compile_definitions(arg_router_test_coverage PRIVATE 22 | UNIT_TEST_BUILD 23 | AR_REPO_PATH="${CMAKE_SOURCE_DIR}" 24 | UNIT_TEST_BIN_DIR="${CMAKE_CURRENT_BINARY_DIR}" 25 | ) 26 | 27 | # Default to C++20 28 | if(NOT DEFINED CMAKE_CXX_STANDARD) 29 | target_compile_features(arg_router_test_coverage PUBLIC cxx_std_20) 30 | endif() 31 | 32 | configure_test_build(arg_router_test_coverage --coverage) 33 | add_clangtidy_to_target(arg_router_test_coverage) 34 | add_santizers_to_target(arg_router_test_coverage) 35 | 36 | target_include_directories(arg_router_test_coverage 37 | PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" 38 | ) 39 | 40 | target_link_libraries(arg_router_test_coverage 41 | PRIVATE arg_router 42 | PUBLIC Boost::filesystem 43 | PUBLIC Threads::Threads 44 | ) 45 | 46 | target_link_options(arg_router_test_coverage 47 | PRIVATE --coverage 48 | ) 49 | -------------------------------------------------------------------------------- /cmake/ccache.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | if (BUILD_UNIT_TESTS_AND_EXAMPLES) 6 | find_program(CCACHE_PROGRAM ccache) 7 | if(CCACHE_PROGRAM AND NOT (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")) 8 | message(STATUS "Found ccache") 9 | set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") 10 | endif() 11 | endif() -------------------------------------------------------------------------------- /cmake/clang-format.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | if(ENABLE_CLANG_FORMAT_CHECKS) 6 | find_program(CLANG_FORMAT clang-format REQUIRED) 7 | message(STATUS "Found clang-format at ${CLANG_FORMAT}") 8 | endif() 9 | 10 | # Creates a clang-format target, or an empty target if ENABLE_CLANG_FORMAT_CHECKS is off. This 11 | # target will fail the build if the formatting is incorrect 12 | function(create_clangformat_target) 13 | cmake_parse_arguments(ARGS "" "NAME" "SOURCES" ${ARGN}) 14 | 15 | if(ENABLE_CLANG_FORMAT_CHECKS) 16 | add_custom_target(${ARGS_NAME} 17 | COMMENT "Running clang-format checks for ${ARGS_NAME}" 18 | COMMAND "${CLANG_FORMAT}" --style=file --dry-run --Werror ${ARGS_SOURCES} 19 | SOURCES "${CMAKE_SOURCE_DIR}/.clang-format" ${ARGS_SOURCES} 20 | ) 21 | else() 22 | add_custom_target(${ARGS_NAME}) 23 | endif() 24 | endfunction() 25 | -------------------------------------------------------------------------------- /cmake/clang-tidy.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | # Add a clang-tidy pass to the given target, if ENABLE_CLANG_TIDY is ON 6 | function(add_clangtidy_to_target TARGET) 7 | if(ENABLE_CLANG_TIDY) 8 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") 9 | message(STATUS "Enabling clang-tidy for ${TARGET}") 10 | set_target_properties(${TARGET} PROPERTIES CXX_CLANG_TIDY 11 | "clang-tidy;-p=${CMAKE_BINARY_DIR}") 12 | else() 13 | message(STATUS "Skipping clang-tidy as it is only for Clang compilers") 14 | endif() 15 | endif() 16 | endfunction() 17 | -------------------------------------------------------------------------------- /cmake/config.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | set(MAX_CTS_SIZE 128 6 | CACHE STRING "Maximum compile_time_string size, defaults to 128") 7 | add_compile_definitions(AR_MAX_CTS_SIZE=${MAX_CTS_SIZE}) 8 | 9 | set(LONG_PREFIX "--" 10 | CACHE STRING "Long flag or argument prefix, defaults to '--'") 11 | add_compile_definitions(AR_LONG_PREFIX="${LONG_PREFIX}") 12 | 13 | set(SHORT_PREFIX "-" 14 | CACHE STRING "Short flag or argument prefix, defaults to '-'") 15 | add_compile_definitions(AR_SHORT_PREFIX="${SHORT_PREFIX}") 16 | 17 | set(ALLOCATOR "std::allocator" 18 | CACHE STRING "Container allocator, defaults to std::allocator") 19 | add_compile_definitions(AR_ALLOCATOR=${ALLOCATOR}) 20 | 21 | set(UTF8_TRAILING_WINDOW_SIZE 16 22 | CACHE STRING "Trailing window size for grapheme cluster and line break algorithms, defaults to 16") 23 | add_compile_definitions(AR_UTF8_TRAILING_WINDOW_SIZE=${UTF8_TRAILING_WINDOW_SIZE}) 24 | 25 | set(DISABLE_CPP20_STRINGS false 26 | CACHE STRING "Disable the use of C++20-style compile-time strings") 27 | add_compile_definitions(AR_DISABLE_CPP20_STRINGS=${DISABLE_CPP20_STRINGS}) 28 | -------------------------------------------------------------------------------- /cmake/copyright_checker.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | find_package (Python3 REQUIRED COMPONENTS Interpreter) 6 | 7 | execute_process(COMMAND "${Python3_EXECUTABLE}" 8 | "${CMAKE_SOURCE_DIR}/scripts/copyright_checker.py" 9 | presence 10 | "${CMAKE_SOURCE_DIR}" 11 | RESULT_VARIABLE COPYRIGHT_PASS) 12 | if (NOT COPYRIGHT_PASS EQUAL 0) 13 | message(FATAL_ERROR "Copyright check failure") 14 | endif() 15 | -------------------------------------------------------------------------------- /cmake/package/arg_router-config.cmake.in: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | @PACKAGE_INIT@ 6 | 7 | # Prevent multiple inclusion 8 | if (DEFINED span-lite_FOUND) 9 | return() 10 | endif() 11 | 12 | include(CMakeFindDependencyMacro) 13 | find_dependency(Boost @BOOST_VERSION@) 14 | 15 | find_package(span-lite QUIET) 16 | if (NOT span-lite_FOUND) 17 | message(STATUS "span-lite package not found, you will need to compile against C++20 or higher") 18 | endif() 19 | 20 | include("${CMAKE_CURRENT_LIST_DIR}/arg_router.cmake") 21 | include("${CMAKE_CURRENT_LIST_DIR}/translation_generator.cmake") 22 | set_and_check(arg_router_INCLUDE_DIRS "@PACKAGE_INSTALL_BASE_DIR@") 23 | 24 | check_required_components(arg_router) 25 | -------------------------------------------------------------------------------- /cmake/package/install.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | include(CMakePackageConfigHelpers) 6 | 7 | set(INSTALL_BASE_DIR "include") 8 | set(INSTALL_AR_DIR "${INSTALL_BASE_DIR}/arg_router") 9 | set(CONFIG_FILE "${CMAKE_BINARY_DIR}/cmake/package/arg_router-config.cmake") 10 | set(CONFIG_VERSION_FILE "${CMAKE_BINARY_DIR}/cmake/package/arg_router-config-version.cmake") 11 | set(TRANSLATION_GENERATOR_FILES 12 | "${CMAKE_SOURCE_DIR}/cmake/translation_generator/translation_generator.cmake" 13 | "${CMAKE_SOURCE_DIR}/cmake/translation_generator/translation_generator_script.cmake") 14 | set(AR_CMAKE_PACKAGE_DIR "share/arg_router" 15 | CACHE STRING "Installation suffix of CMake package config files, defaults to share/arg_router") 16 | 17 | install(TARGETS arg_router 18 | EXPORT AR_TARGETS) 19 | install(EXPORT AR_TARGETS 20 | FILE arg_router.cmake 21 | NAMESPACE arg_router:: 22 | DESTINATION "${AR_CMAKE_PACKAGE_DIR}") 23 | 24 | configure_package_config_file("${CMAKE_SOURCE_DIR}/cmake/package/arg_router-config.cmake.in" 25 | ${CONFIG_FILE} 26 | INSTALL_DESTINATION "${AR_CMAKE_PACKAGE_DIR}" 27 | PATH_VARS INSTALL_BASE_DIR) 28 | write_basic_package_version_file(${CONFIG_VERSION_FILE} 29 | COMPATIBILITY SameMajorVersion 30 | ARCH_INDEPENDENT) 31 | 32 | install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/arg_router" 33 | DESTINATION ${INSTALL_BASE_DIR}) 34 | install(FILES "${CMAKE_SOURCE_DIR}/README.md" 35 | "${CMAKE_SOURCE_DIR}/LICENSE" 36 | DESTINATION ${INSTALL_AR_DIR}) 37 | install(FILES "${CONFIG_FILE}" 38 | "${CONFIG_VERSION_FILE}" 39 | ${TRANSLATION_GENERATOR_FILES} 40 | DESTINATION ${AR_CMAKE_PACKAGE_DIR}) 41 | 42 | # CPack package configuration 43 | set(CPACK_PACKAGE_VENDOR "Camden Mannett") 44 | set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE) 45 | set(CPACK_RESOURCE_FILE_README ${CMAKE_SOURCE_DIR}/docs/README_API.md) 46 | set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CMAKE_PROJECT_VERSION}") 47 | set(CPACK_GENERATOR ZIP DEB) 48 | # .deb specific 49 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_VENDOR}) 50 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-dev (>= ${BOOST_VERSION})") 51 | include(CPack) 52 | -------------------------------------------------------------------------------- /cmake/path_prefixer.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | function(path_prefixer VAR) 6 | foreach(SOURCE ${ARGN}) 7 | list(APPEND NEW_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}") 8 | endforeach() 9 | 10 | set(${VAR} "${NEW_SOURCES}" PARENT_SCOPE) 11 | endfunction() 12 | -------------------------------------------------------------------------------- /cmake/sanitizers.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | function(add_santizers_to_target TARGET) 6 | if(ENABLE_SANITIZERS) 7 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") 8 | message(STATUS "Enabling santizers for ${TARGET}") 9 | target_compile_options(${TARGET} PRIVATE 10 | -fsanitize=address 11 | -fsanitize=undefined 12 | -fno-omit-frame-pointer 13 | ) 14 | target_link_options(${TARGET} PRIVATE 15 | -fsanitize=address 16 | -fsanitize=undefined 17 | ) 18 | else() 19 | message(STATUS "Skipping sanitizers as they are only for Clang compilers") 20 | endif() 21 | endif() 22 | endfunction() 23 | -------------------------------------------------------------------------------- /cmake/translation_generator/translation_generator.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | function(arg_router_translation_generator) 6 | set(single_value_args OUTPUT_DIR TARGET) 7 | set(multi_value_args SOURCES) 8 | cmake_parse_arguments(ARGS "" "${single_value_args}" "${multi_value_args}" ${ARGN}) 9 | 10 | if (NOT DEFINED ARGS_SOURCES) 11 | message(FATAL_ERROR "Translation generator requires at least one source file") 12 | endif() 13 | if (NOT DEFINED ARGS_OUTPUT_DIR) 14 | message(FATAL_ERROR "Translation generator output directory must be set, typically CMAKE_CURRENT_BINARY_DIR") 15 | endif() 16 | if (NOT DEFINED ARGS_TARGET) 17 | message(FATAL_ERROR "Translation generator requires a target output variable") 18 | endif() 19 | 20 | # The script file is always in the dir as this file 21 | get_filename_component(this_file_path "${CMAKE_CURRENT_FUNCTION_LIST_FILE}" DIRECTORY) 22 | set(script_path "${this_file_path}/translation_generator_script.cmake") 23 | 24 | add_custom_target(${ARGS_TARGET} 25 | COMMAND ${CMAKE_COMMAND} 26 | "-DSOURCES=${ARGS_SOURCES}" 27 | -DOUTPUT_DIR=${ARGS_OUTPUT_DIR} 28 | -P ${script_path} 29 | SOURCES ${ARGS_SOURCES} 30 | ${script_path} 31 | VERBATIM) 32 | 33 | # set_source_files_properties cannot be used in a script so that's set here 34 | foreach(source ${ARGS_SOURCES}) 35 | get_filename_component(language_id "${source}" NAME_WLE) 36 | set(output_file "${ARGS_OUTPUT_DIR}/${language_id}.hpp") 37 | 38 | target_sources(${ARGS_TARGET} PRIVATE "${output_file}") 39 | set_source_files_properties("${output_file}" PROPERTIES GENERATED TRUE) 40 | endforeach() 41 | endfunction() 42 | -------------------------------------------------------------------------------- /cmake/triplets/x86-linux.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | set(VCPKG_TARGET_ARCHITECTURE x86) 6 | set(VCPKG_CRT_LINKAGE dynamic) 7 | set(VCPKG_LIBRARY_LINKAGE static) 8 | 9 | set(VCPKG_CMAKE_SYSTEM_NAME Linux) 10 | -------------------------------------------------------------------------------- /cmake/versioning/version.cmake: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | message(STATUS "Project revision: ${CMAKE_PROJECT_VERSION}") 6 | 7 | # Update the version in version.hpp 8 | path_prefixer(VERSION_FILE 9 | include/arg_router/version.hpp 10 | ) 11 | set(VERSION_FILE_TMP 12 | "${CMAKE_BINARY_DIR}/cmake/versioning/version.hpp.tmp" 13 | ) 14 | configure_file( 15 | "${CMAKE_SOURCE_DIR}/cmake/versioning/version.hpp.in" 16 | ${VERSION_FILE_TMP} 17 | ) 18 | 19 | file(READ ${VERSION_FILE} VERSION_FILE_DATA) 20 | file(READ ${VERSION_FILE_TMP} VERSION_FILE_TMP_DATA) 21 | if(NOT "${VERSION_FILE_TMP_DATA}" STREQUAL "${VERSION_FILE_DATA}") 22 | message(STATUS "Updating version.hpp library version") 23 | file(RENAME ${VERSION_FILE_TMP} ${VERSION_FILE}) 24 | endif() 25 | 26 | # Update the project version in the Doxyfile 27 | file(READ "${CMAKE_SOURCE_DIR}/docs/Doxyfile" DOXYFILE_DATA) 28 | string( 29 | REGEX REPLACE 30 | "PROJECT_NUMBER = [0-9]*\\.[0-9]*\\.[0-9]*" 31 | "PROJECT_NUMBER = ${CMAKE_PROJECT_VERSION}" 32 | UPDATED_DOXYFILE_DATA 33 | "${DOXYFILE_DATA}" 34 | ) 35 | 36 | # Escape any semi-colons otherwise CMake will treat the string as an array of strings 37 | string( 38 | REPLACE ";" "\;" 39 | UPDATED_DOXYFILE_DATA 40 | "${UPDATED_DOXYFILE_DATA}" 41 | ) 42 | 43 | if(NOT "${DOXYFILE_DATA}" STREQUAL "${UPDATED_DOXYFILE_DATA}") 44 | message(STATUS "Updating Doxyfile library version") 45 | file(WRITE "${CMAKE_SOURCE_DIR}/docs/Doxyfile" ${UPDATED_DOXYFILE_DATA}) 46 | endif() 47 | 48 | # Update the version in vcpkg.json 49 | file(READ "${CMAKE_SOURCE_DIR}/vcpkg.json" VCPKG_JSON_DATA) 50 | string( 51 | REGEX REPLACE 52 | "\"version-string\": \"[0-9]*\\.[0-9]*\\.[0-9]*\"" 53 | "\"version-string\": \"${CMAKE_PROJECT_VERSION}\"" 54 | UPDATED_VCPKG_JSON_DATA 55 | "${VCPKG_JSON_DATA}" 56 | ) 57 | 58 | if(NOT "${VCPKG_JSON_DATA}" STREQUAL "${UPDATED_VCPKG_JSON_DATA}") 59 | message(STATUS "Updating vcpkg.json library version") 60 | file(WRITE "${CMAKE_SOURCE_DIR}/vcpkg.json" ${UPDATED_VCPKG_JSON_DATA}) 61 | endif() 62 | -------------------------------------------------------------------------------- /cmake/versioning/version.hpp.in: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | /** @file 8 | * 9 | * This file is automatically generated by the build system, do not manually modify it. If you need 10 | * to change the template, it is located in arg_router/cmake/versioning/version.hpp.in 11 | */ 12 | 13 | namespace arg_router 14 | { 15 | /** Library version as a SymVers-style string. 16 | */ 17 | constexpr auto version_string = "${CMAKE_PROJECT_VERSION}"; 18 | } // namespace arg_router 19 | -------------------------------------------------------------------------------- /copyright_header.txt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | -------------------------------------------------------------------------------- /docs/header.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | $projectname: $title 13 | 14 | $title 15 | 16 | 17 | 18 | $treeview 19 | $search 20 | $mathjax 21 | 22 | $extrastylesheet 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 | 34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 51 | 52 | 53 | 54 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
44 |
$projectname 45 |  $projectnumber 47 |
48 | 49 |
$projectbrief
50 |
55 |
$projectbrief
56 |
$searchbox
67 |
68 | 69 | -------------------------------------------------------------------------------- /docs/related_pages/configuration.doxy: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | namespace arg_router 6 | { 7 | /** @page configuration Configuration 8 | * @tableofcontents 9 | * 10 | * There are a few core parts of arg_router that are configurable as compile defines, most are 11 | * accessible globally (in a more C++ friendly way) in the @ref config namespace. All are available 12 | * as CMake cache variables, minus the "AR_" prefix. 13 | * 14 | * AR_MAX_CTS_SIZE when using C++17 or if AR_DISABLE_CPP20_STRINGS=true is the 15 | * maximum size an argument to S_ can be, it defaults to 128. Increasing the size won't 16 | * increase your program size, but will increase the build time. 17 | * 18 | * AR_LONG_PREFIX is the character string that defines the prefix of long-form token 19 | * labels e.g. "--help". It defaults to two hyphens. If redefining, this must have the same or more 20 | * characters than AR_SHORT_PREFIX. 21 | * 22 | * AR_SHORT_PREFIX is the character string that defines the prefix of short-form 23 | * token labels e.g. "-h". It defaults to one hyphen. It must have one character in it. 24 | * 25 | * AR_ALLOCATOR sets the allocator for all allocating types in arg_router (e.g. 26 | * std::vector, std::string, etc.). It defaults to std::allocator, i.e. 27 | * heap allocation. 28 | * 29 | * AR_UTF8_TRAILING_WINDOW_SIZE sets the Trailing window size for the grapheme cluster and 30 | * line break algorithms, defaults to 16. Each entry in the trailing window is a break property of 31 | * a grapheme cluster ("user-perceived character"), not a byte. 32 | * 33 | * AR_DISABLE_CPP20_STRINGS is a boolean value that forcibly disables C++20 compile-time 34 | * string support when set to true. 35 | */ 36 | } 37 | -------------------------------------------------------------------------------- /docs/related_pages/examples.doxy: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | /** List of example source files. 6 | * 7 | * @example c++17/basic_cat/main.cpp 8 | * @example c++17/custom_policy_and_node/main.cpp 9 | * @example c++17/just_cats/main.cpp 10 | * @example c++17/launcher/main.cpp 11 | * @example c++17/runtime_node_enable/main.cpp 12 | * @example c++17/simple/main.cpp 13 | * @example c++17/simple_ml/main.cpp 14 | * @example c++17/simple_ml_gen/main.cpp 15 | * 16 | * @example c++20/basic_cat/main.cpp 17 | * @example c++20/custom_policy_and_node/main.cpp 18 | * @example c++20/just_cats/main.cpp 19 | * @example c++20/launcher/main.cpp 20 | * @example c++20/runtime_node_enable/main.cpp 21 | * @example c++20/simple/main.cpp 22 | * @example c++20/simple_ml/main.cpp 23 | * @example c++20/simple_ml_gen/main.cpp 24 | */ 25 | -------------------------------------------------------------------------------- /docs/related_pages/images/node_relationships.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmannett85/arg_router/e04ed2ba211b714f3ac5484258716773e5f290c8/docs/related_pages/images/node_relationships.dia -------------------------------------------------------------------------------- /docs/related_pages/validation.doxy: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | namespace arg_router 6 | { 7 | /** @page validation Validation 8 | * @tableofcontents 9 | * 10 | * As noted in the Architectural Overview, the node's perform as much validation of their 11 | * configuration as possible, but that @em typically does not include validation of the 12 | * @em relationships with other nodes and policies. 13 | * 14 | * To achieve that we use a validator policy that attaches to the root node and checks the entire 15 | * parse tree upon construction (which is always after all child nodes and policies). 16 | * 17 | * @section validation_validator Validator 18 | * The validator that ships with arg_router is policy::validation::validator. It's a complicated bit 19 | * of machinery but from a user's point of view, it is just a list of @em rules that apply to each 20 | * policy and tree_node derived type. Each rule has a predicate that is used to match against the 21 | * validated policy or node type, and a collection of @em conditions that all have to be met by the 22 | * validated type in order for a static_assert @b not to fire. 23 | * 24 | * The rules, defined by policy::validation::rule and policy::validation::rule_q, are a template 25 | * parameter pack of policy::validation::validator and so can be modified without having to write 26 | * your own validator from scratch. The standard configured validator i.e. a validator with the 27 | * rules defined for all the arg_router types, is policy::validation::default_validator. 28 | * 29 | * @section validation_rules Rules 30 | * As noted above, each rule starts with a predicate that 'selects' that rule as applying to the 31 | * validated type. Let's look at an example from policy::validation::default_validator: 32 | * @code 33 | * rule_q, 34 | must_not_have_policies> 38 | * @endcode 39 | * 40 | * policy::validation::common_rules::despecialised_any_of_rule is a quoted metafunction that 41 | * evaluates to true if the validated type matches one of the despecialised types in its argument 42 | * list. In this case we're just checking that it matches flag_t. 43 | * 44 | * As the name suggests, policy::validation::must_not_have_policies checks that the validated type 45 | * does not use any of the policies listed in its template parameters. 46 | */ 47 | } -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | include("${CMAKE_SOURCE_DIR}/cmake/build_types/ast.cmake") 6 | 7 | function(configure_example_build TARGET) 8 | if (MSVC_FRONTEND) 9 | set(EXTRA_FLAGS /Zc:__cplusplus /W4 /Z7 /GR- /permissive- /bigobj /wd4996) 10 | 11 | # /MT by default as it simplifies the running of the examples 12 | set_property(TARGET ${TARGET} PROPERTY 13 | MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") 14 | 15 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 16 | set(EXTRA_FLAGS ${EXTRA_FLAGS} /clang:-fconstexpr-steps=10000000) 17 | endif() 18 | else() 19 | set(EXTRA_FLAGS -Werror -Wall -Wextra -fno-rtti -Wno-deprecated-declarations) 20 | endif() 21 | target_compile_options(${TARGET} PRIVATE ${EXTRA_FLAGS}) 22 | endfunction() 23 | 24 | message(STATUS "Configuring examples") 25 | add_subdirectory(c++17) 26 | 27 | if(BUILD_CPP20_EXAMPLES) 28 | add_subdirectory(c++20) 29 | endif() 30 | -------------------------------------------------------------------------------- /examples/c++17/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | add_custom_target(cpp17_examples) 6 | 7 | add_subdirectory(basic_cat) 8 | add_subdirectory(custom_policy_and_node) 9 | add_subdirectory(just_cats) 10 | add_subdirectory(launcher) 11 | add_subdirectory(runtime_node_enable) 12 | add_subdirectory(simple) 13 | add_subdirectory(simple_ml) 14 | add_subdirectory(simple_ml_gen) 15 | -------------------------------------------------------------------------------- /examples/c++17/basic_cat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_basic_cat 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_basic_cat "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_basic_cat clangformat_example_basic_cat) 12 | 13 | target_compile_features(example_basic_cat PUBLIC cxx_std_17) 14 | set_target_properties(example_basic_cat PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_basic_cat PRIVATE arg_router) 16 | 17 | configure_example_build(example_basic_cat) 18 | add_clangtidy_to_target(example_basic_cat) 19 | 20 | add_dependencies(cpp17_examples example_basic_cat) 21 | -------------------------------------------------------------------------------- /examples/c++17/custom_policy_and_node/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_custom_policy_and_node 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_custom_policy_and_node "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_custom_policy_and_node clangformat_example_custom_policy_and_node) 12 | 13 | target_compile_features(example_custom_policy_and_node PUBLIC cxx_std_17) 14 | set_target_properties(example_custom_policy_and_node PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_custom_policy_and_node PRIVATE arg_router) 16 | 17 | configure_example_build(example_custom_policy_and_node) 18 | add_clangtidy_to_target(example_custom_policy_and_node) 19 | 20 | add_dependencies(cpp17_examples example_custom_policy_and_node) 21 | -------------------------------------------------------------------------------- /examples/c++17/just_cats/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_just_cats 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_just_cats "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_just_cats clangformat_example_just_cats) 12 | 13 | target_compile_features(example_just_cats PUBLIC cxx_std_17) 14 | set_target_properties(example_just_cats PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_just_cats PRIVATE arg_router) 16 | 17 | configure_example_build(example_just_cats) 18 | add_clangtidy_to_target(example_just_cats) 19 | 20 | add_dependencies(cpp17_examples example_just_cats) 21 | -------------------------------------------------------------------------------- /examples/c++17/just_cats/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include 6 | 7 | namespace ar = arg_router; 8 | namespace arp = ar::policy; 9 | 10 | int main(int argc, char* argv[]) 11 | { 12 | ar::root(arp::validation::default_validator, 13 | ar::help(S_("help"){}, 14 | S_('h'){}, 15 | S_("Display this help and exit"){}, 16 | arp::program_name, 17 | arp::program_intro, 18 | arp::program_addendum), 19 | ar::flag(S_("cat"){}, // 20 | S_("English cat"){}, 21 | arp::router{[](bool) { std::cout << "cat" << std::endl; }}), 22 | ar::flag(S_("猫"){}, // 23 | arp::description, 24 | arp::router{[](bool) { std::cout << "猫" << std::endl; }}), 25 | ar::flag(S_("🐱"){}, // 26 | arp::description, 27 | arp::router{[](bool) { std::cout << "🐱" << std::endl; }}), 28 | ar::flag(S_("แมว"){}, // 29 | S_("แมวไทย"){}, 30 | arp::router{[](bool) { std::cout << "แมว" << std::endl; }}), 31 | ar::flag(S_("кіт"){}, // 32 | S_("український кіт"){}, 33 | arp::router{[](bool) { std::cout << "кіт" << std::endl; }})) 34 | .parse(argc, argv); 35 | 36 | return EXIT_SUCCESS; 37 | } 38 | -------------------------------------------------------------------------------- /examples/c++17/launcher/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | set(Boost_USE_MULTITHREADED ON) 6 | find_package(Boost ${BOOST_VERSION} REQUIRED COMPONENTS 7 | filesystem 8 | ) 9 | 10 | create_clangformat_target( 11 | NAME clangformat_example_launcher 12 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 13 | ) 14 | 15 | add_executable(example_launcher "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 16 | add_dependencies(example_launcher clangformat_example_launcher) 17 | 18 | target_compile_features(example_launcher PUBLIC cxx_std_17) 19 | set_target_properties(example_launcher PROPERTIES CXX_EXTENSIONS OFF) 20 | target_link_libraries(example_launcher 21 | PRIVATE arg_router 22 | PUBLIC Boost::filesystem 23 | ) 24 | 25 | configure_example_build(example_launcher) 26 | add_clangtidy_to_target(example_launcher) 27 | 28 | add_dependencies(cpp17_examples example_launcher) 29 | -------------------------------------------------------------------------------- /examples/c++17/runtime_node_enable/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_runtime_node_enable 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_runtime_node_enable "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_runtime_node_enable clangformat_example_runtime_node_enable) 12 | 13 | target_compile_features(example_runtime_node_enable PUBLIC cxx_std_17) 14 | set_target_properties(example_runtime_node_enable PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_runtime_node_enable 16 | PRIVATE arg_router 17 | ) 18 | 19 | configure_example_build(example_runtime_node_enable) 20 | add_clangtidy_to_target(example_runtime_node_enable) 21 | 22 | add_dependencies(cpp17_examples example_runtime_node_enable) 23 | -------------------------------------------------------------------------------- /examples/c++17/runtime_node_enable/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include 6 | 7 | namespace ar = arg_router; 8 | namespace arp = ar::policy; 9 | 10 | using namespace ar::literals; 11 | using namespace std::string_view_literals; 12 | 13 | namespace 14 | { 15 | constexpr auto version = "v3.14"sv; 16 | constexpr auto license_env_var = "AR_EXAMPLE_LICENSE"; 17 | } // namespace 18 | 19 | int main(int argc, char* argv[]) 20 | { 21 | const auto advanced = std::getenv(license_env_var) != nullptr; 22 | ar::root( 23 | arp::validation::default_validator, 24 | ar::help(S_("help"){}, 25 | S_('h'){}, 26 | S_("Display this help and exit"){}, 27 | arp::flatten_help, 28 | arp::program_name, 29 | arp::program_version, 30 | arp::program_addendum), 31 | ar::flag(S_("version"){}, 32 | S_("Output version information and exit"){}, 33 | arp::router{[](bool) { 34 | std::cout << version << std::endl; 35 | std::exit(EXIT_SUCCESS); 36 | }}), 37 | ar::mode(S_("advanced"){}, 38 | S_("Advanced features"){}, 39 | ar::flag(S_("feature1"){}, S_("First feature"){}), 40 | // NOLINTNEXTLINE(readability-magic-numbers) 41 | ar::arg(S_("feature2"){}, S_("Second feature"){}, arp::default_value{42}), 42 | arp::router{[](bool f1, int f2) { 43 | std::cout << "F1: " << std::boolalpha << f1 << ", F2: " << f2 << std::endl; 44 | }}, 45 | arp::runtime_enable{advanced}), 46 | ar::mode( 47 | ar::flag(S_("foo"){}, S_("Foo flag"){}, S_('f'){}), 48 | ar::flag(S_("bar"){}, S_("Bar flag"){}, S_('b'){}), 49 | ar::arg(S_("advance-foo"){}, 50 | S_("Licensed foo"){}, 51 | arp::runtime_enable_required{advanced}), 52 | arp::router{[](bool f, bool b, std::string_view advance_foo) { 53 | std::cout << "F: " << std::boolalpha << f << ", B: " << b 54 | << ", Advance-foo: " << advance_foo << std::endl; 55 | }})) 56 | .parse(argc, argv); 57 | 58 | return EXIT_SUCCESS; 59 | } 60 | -------------------------------------------------------------------------------- /examples/c++17/simple/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_simple 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_simple "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_simple clangformat_example_simple) 12 | 13 | target_compile_features(example_simple PUBLIC cxx_std_17) 14 | set_target_properties(example_simple PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_simple PRIVATE arg_router) 16 | 17 | configure_example_build(example_simple) 18 | add_clangtidy_to_target(example_simple) 19 | 20 | add_dependencies(cpp17_examples example_simple) 21 | -------------------------------------------------------------------------------- /examples/c++17/simple/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace ar = arg_router; 11 | namespace arp = ar::policy; 12 | namespace fs = std::filesystem; 13 | 14 | using namespace std::string_view_literals; 15 | using namespace std::string_literals; 16 | using namespace ar::utility::string_view_ops; 17 | 18 | namespace 19 | { 20 | void copy_mode(bool force, fs::path&& dest, std::vector&& srcs) 21 | { 22 | const auto options = force ? fs::copy_options::overwrite_existing : fs::copy_options::none; 23 | 24 | for (const auto& src : srcs) { 25 | fs::copy(src, dest, options); 26 | } 27 | } 28 | 29 | void move_mode(bool force, fs::path&& dest, fs::path&& src) 30 | { 31 | if (force && fs::exists(dest)) { 32 | fs::remove(src); 33 | } 34 | 35 | fs::rename(src, dest); 36 | } 37 | } // namespace 38 | 39 | template <> 40 | struct ar::parser { 41 | [[nodiscard]] static inline fs::path parse(std::string_view arg) { return arg; } 42 | }; 43 | 44 | int main(int argc, char* argv[]) 45 | { 46 | const auto common_args = 47 | ar::list{ar::flag(S_("force"){}, S_('f'){}, S_("Force overwrite existing files"){}), 48 | ar::positional_arg(arp::required, 49 | S_("DST"){}, 50 | S_("Destination directory"){}, 51 | arp::fixed_count<1>)}; 52 | 53 | ar::root(arp::validation::default_validator, 54 | ar::help(S_("help"){}, 55 | S_('h'){}, 56 | S_("Display this help and exit"){}, 57 | arp::program_name, 58 | arp::program_version, 59 | arp::program_intro, 60 | arp::program_addendum, 61 | arp::flatten_help, 62 | arp::colour_help_formatter), 63 | ar::mode(S_("copy"){}, 64 | S_("Copy source files to destination"){}, 65 | common_args, 66 | ar::positional_arg>(arp::required, 67 | S_("SRC"){}, 68 | S_("Source file paths"){}, 69 | arp::min_count<1>), 70 | arp::router{[](bool force, fs::path dest, std::vector srcs) { 71 | copy_mode(force, std::move(dest), std::move(srcs)); 72 | }}), 73 | ar::mode(S_("move"){}, 74 | S_("Move source file to destination"){}, 75 | common_args, 76 | ar::positional_arg(arp::required, 77 | S_("SRC"){}, 78 | S_("Source file path"){}, 79 | arp::fixed_count<1>), 80 | arp::router{[](bool force, fs::path dest, fs::path src) { 81 | move_mode(force, std::move(dest), std::move(src)); 82 | }})) 83 | .parse(argc, argv); 84 | } 85 | -------------------------------------------------------------------------------- /examples/c++17/simple_ml/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_simple_ml 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_simple_ml "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_simple_ml clangformat_example_simple_ml) 12 | 13 | target_compile_features(example_simple_ml PUBLIC cxx_std_17) 14 | set_target_properties(example_simple_ml PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_simple_ml PRIVATE arg_router) 16 | 17 | configure_example_build(example_simple_ml) 18 | add_clangtidy_to_target(example_simple_ml) 19 | 20 | add_dependencies(cpp17_examples example_simple_ml) 21 | -------------------------------------------------------------------------------- /examples/c++17/simple_ml_gen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | include("${CMAKE_SOURCE_DIR}/cmake/translation_generator/translation_generator.cmake") 6 | arg_router_translation_generator( 7 | SOURCES "${CMAKE_SOURCE_DIR}/examples/resources/simple_ml_gen/en_GB.toml" 8 | "${CMAKE_SOURCE_DIR}/examples/resources/simple_ml_gen/fr.toml" 9 | "${CMAKE_SOURCE_DIR}/examples/resources/simple_ml_gen/ja.toml" 10 | OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/translations/" 11 | TARGET translation_example_simple_ml_gen 12 | ) 13 | 14 | create_clangformat_target( 15 | NAME clangformat_example_simple_ml_gen 16 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 17 | ) 18 | 19 | add_executable(example_simple_ml_gen 20 | "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 21 | add_dependencies( 22 | example_simple_ml_gen 23 | translation_example_simple_ml_gen 24 | clangformat_example_simple_ml) 25 | 26 | target_include_directories(example_simple_ml_gen PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") 27 | 28 | target_compile_features(example_simple_ml_gen PUBLIC cxx_std_17) 29 | set_target_properties(example_simple_ml_gen PROPERTIES CXX_EXTENSIONS OFF) 30 | target_link_libraries(example_simple_ml_gen PRIVATE arg_router) 31 | 32 | configure_example_build(example_simple_ml_gen) 33 | add_clangtidy_to_target(example_simple_ml_gen) 34 | 35 | add_dependencies(cpp17_examples example_simple_ml_gen) 36 | -------------------------------------------------------------------------------- /examples/c++20/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | add_custom_target(cpp20_examples) 6 | 7 | add_subdirectory(basic_cat) 8 | add_subdirectory(custom_policy_and_node) 9 | add_subdirectory(just_cats) 10 | add_subdirectory(launcher) 11 | add_subdirectory(runtime_node_enable) 12 | add_subdirectory(simple) 13 | add_subdirectory(simple_ml) 14 | add_subdirectory(simple_ml_gen) 15 | -------------------------------------------------------------------------------- /examples/c++20/basic_cat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_basic_cat_cpp20 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_basic_cat_cpp20 "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_basic_cat_cpp20 clangformat_example_basic_cat_cpp20) 12 | 13 | target_compile_features(example_basic_cat_cpp20 PUBLIC cxx_std_20) 14 | set_target_properties(example_basic_cat_cpp20 PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_basic_cat_cpp20 PRIVATE arg_router) 16 | 17 | configure_example_build(example_basic_cat_cpp20) 18 | add_clangtidy_to_target(example_basic_cat_cpp20) 19 | 20 | add_dependencies(cpp20_examples example_basic_cat_cpp20) 21 | -------------------------------------------------------------------------------- /examples/c++20/custom_policy_and_node/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_custom_policy_and_node_cpp20 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_custom_policy_and_node_cpp20 "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_custom_policy_and_node_cpp20 12 | clangformat_example_custom_policy_and_node_cpp20 13 | ) 14 | 15 | target_compile_features(example_custom_policy_and_node_cpp20 PUBLIC cxx_std_20) 16 | set_target_properties(example_custom_policy_and_node_cpp20 PROPERTIES CXX_EXTENSIONS OFF) 17 | target_link_libraries(example_custom_policy_and_node_cpp20 PRIVATE arg_router) 18 | 19 | configure_example_build(example_custom_policy_and_node_cpp20) 20 | add_clangtidy_to_target(example_custom_policy_and_node_cpp20) 21 | 22 | add_dependencies(cpp20_examples example_custom_policy_and_node_cpp20) 23 | -------------------------------------------------------------------------------- /examples/c++20/just_cats/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_just_cats_cpp20 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_just_cats_cpp20 "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_just_cats_cpp20 clangformat_example_just_cats_cpp20) 12 | 13 | target_compile_features(example_just_cats_cpp20 PUBLIC cxx_std_20) 14 | set_target_properties(example_just_cats_cpp20 PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_just_cats_cpp20 PRIVATE arg_router) 16 | 17 | configure_example_build(example_just_cats_cpp20) 18 | add_clangtidy_to_target(example_just_cats_cpp20) 19 | 20 | add_dependencies(cpp20_examples example_just_cats_cpp20) 21 | -------------------------------------------------------------------------------- /examples/c++20/just_cats/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include 6 | 7 | namespace ar = arg_router; 8 | namespace arp = ar::policy; 9 | using namespace ar::literals; 10 | 11 | int main(int argc, char* argv[]) 12 | { 13 | ar::root(arp::validation::default_validator, 14 | ar::help("help"_S, 15 | "h"_S, 16 | "Display this help and exit"_S, 17 | arp::program_name_t{"just-cats"_S}, 18 | arp::program_intro_t{"Prints cats!"_S}, 19 | arp::program_addendum_t{"An example program for arg_router."_S}), 20 | ar::flag("cat"_S, "English cat"_S, arp::router{[](bool) { 21 | std::cout << "cat" << std::endl; 22 | }}), 23 | ar::flag("猫"_S, // 24 | arp::description_t{"日本語の猫"_S}, 25 | arp::router{[](bool) { std::cout << "猫" << std::endl; }}), 26 | ar::flag("🐱"_S, // 27 | arp::description_t{"Emoji cat"_S}, 28 | arp::router{[](bool) { std::cout << "🐱" << std::endl; }}), 29 | ar::flag("แมว"_S, // 30 | "แมวไทย"_S, 31 | arp::router{[](bool) { std::cout << "แมว" << std::endl; }}), 32 | ar::flag("кіт"_S, // 33 | "український кіт"_S, 34 | arp::router{[](bool) { std::cout << "кіт" << std::endl; }})) 35 | .parse(argc, argv); 36 | 37 | return EXIT_SUCCESS; 38 | } 39 | -------------------------------------------------------------------------------- /examples/c++20/launcher/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | set(Boost_USE_MULTITHREADED ON) 6 | find_package(Boost ${BOOST_VERSION} REQUIRED COMPONENTS 7 | filesystem 8 | ) 9 | 10 | create_clangformat_target( 11 | NAME clangformat_example_launcher_cpp20 12 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 13 | ) 14 | 15 | add_executable(example_launcher_cpp20 "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 16 | add_dependencies(example_launcher_cpp20 clangformat_example_launcher_cpp20) 17 | 18 | target_compile_features(example_launcher_cpp20 PUBLIC cxx_std_20) 19 | set_target_properties(example_launcher_cpp20 PROPERTIES CXX_EXTENSIONS OFF) 20 | target_link_libraries(example_launcher_cpp20 21 | PRIVATE arg_router 22 | PUBLIC Boost::filesystem 23 | ) 24 | 25 | configure_example_build(example_launcher_cpp20) 26 | add_clangtidy_to_target(example_launcher_cpp20) 27 | 28 | add_dependencies(cpp20_examples example_launcher_cpp20) 29 | -------------------------------------------------------------------------------- /examples/c++20/launcher/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace ar = arg_router; 15 | namespace arp = ar::policy; 16 | namespace bp = boost::process; 17 | 18 | using namespace std::literals; 19 | using namespace ar::literals; 20 | using namespace ar::utility::string_view_ops; 21 | 22 | namespace 23 | { 24 | // NOLINTNEXTLINE(*-avoid-c-arrays) 25 | constexpr char version[] = "v3.14"; 26 | 27 | void print_invocs(const std::vector& progs, 28 | const std::vector& args) 29 | { 30 | for (auto prog : progs) { 31 | std::cout << prog; 32 | for (auto arg : args) { 33 | std::cout << " " << arg; 34 | } 35 | std::cout << std::endl; 36 | } 37 | } 38 | 39 | int run_invocs(const std::vector& progs, 40 | const std::vector& args) 41 | { 42 | auto children = std::vector{}; 43 | children.reserve(progs.size()); 44 | for (auto prog : progs) { 45 | auto path = boost::filesystem::path{prog}; 46 | if (!path.has_parent_path()) { 47 | path = bp::search_path(path); 48 | } 49 | children.emplace_back(path, bp::args = args); 50 | } 51 | 52 | auto result = EXIT_SUCCESS; 53 | for (auto& child : children) { 54 | child.wait(); 55 | const auto ec = child.exit_code(); 56 | if (ec > result) { 57 | result = ec; 58 | } 59 | } 60 | 61 | return result; 62 | } 63 | } // namespace 64 | 65 | int main(int argc, char* argv[]) 66 | { 67 | ar::root( 68 | arp::validation::default_validator, 69 | ar::help("help"_S, 70 | "h"_S, 71 | "Display this help and exit"_S, 72 | arp::program_name_t{"launcher"_S}, 73 | arp::program_version>, 74 | arp::program_addendum_t{"An example program for arg_router."_S}), 75 | ar::flag("version"_S, "Output version information and exit"_S, arp::router{[](bool) { 76 | std::cout << &version[0] << std::endl; 77 | std::exit(EXIT_SUCCESS); 78 | }}), 79 | ar::mode( 80 | ar::flag("dry-run"_S, "Just print launch invocations, do not execute them"_S, "d"_S), 81 | ar::positional_arg>(arp::required, 82 | "PROGS"_S, 83 | "Programs to run"_S, 84 | arp::token_end_marker_t{"--"_S}, 85 | arp::min_count<1>), 86 | ar::positional_arg>("ARGS"_S, 87 | "Arguments to pass to programs"_S), 88 | arp::router{[](bool dry_run, 89 | const std::vector& progs, 90 | const std::vector& args) { 91 | if (dry_run) { 92 | print_invocs(progs, args); 93 | return; 94 | } 95 | 96 | exit(run_invocs(progs, args)); 97 | }})) 98 | .parse(argc, argv); 99 | 100 | return EXIT_SUCCESS; 101 | } 102 | -------------------------------------------------------------------------------- /examples/c++20/runtime_node_enable/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_runtime_node_enable_cpp20 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_runtime_node_enable_cpp20 "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_runtime_node_enable_cpp20 clangformat_example_runtime_node_enable_cpp20) 12 | 13 | target_compile_features(example_runtime_node_enable_cpp20 PUBLIC cxx_std_20) 14 | set_target_properties(example_runtime_node_enable_cpp20 PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_runtime_node_enable_cpp20 16 | PRIVATE arg_router 17 | ) 18 | 19 | configure_example_build(example_runtime_node_enable_cpp20) 20 | add_clangtidy_to_target(example_runtime_node_enable_cpp20) 21 | 22 | add_dependencies(cpp20_examples example_runtime_node_enable_cpp20) 23 | -------------------------------------------------------------------------------- /examples/c++20/runtime_node_enable/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include 6 | 7 | namespace ar = arg_router; 8 | namespace arp = ar::policy; 9 | 10 | using namespace ar::literals; 11 | 12 | namespace 13 | { 14 | // NOLINTNEXTLINE(*-avoid-c-arrays) 15 | constexpr char version[] = "v3.14"; 16 | 17 | constexpr auto license_env_var = "AR_EXAMPLE_LICENSE"; 18 | } // namespace 19 | 20 | int main(int argc, char* argv[]) 21 | { 22 | const auto advanced = std::getenv(license_env_var) != nullptr; 23 | ar::root( 24 | arp::validation::default_validator, 25 | ar::help("help"_S, 26 | "h"_S, 27 | "Display this help and exit"_S, 28 | arp::flatten_help, 29 | arp::program_name_t{"runtime_node_enable"_S}, 30 | arp::program_version>, 31 | arp::program_addendum_t{"An example program for arg_router."_S}), 32 | ar::flag("version"_S, "Output version information and exit"_S, arp::router{[](bool) { 33 | std::cout << &version[0] << std::endl; 34 | std::exit(EXIT_SUCCESS); 35 | }}), 36 | ar::mode("advanced"_S, 37 | "Advanced features"_S, 38 | ar::flag("feature1"_S, "First feature"_S), 39 | // NOLINTNEXTLINE(readability-magic-numbers) 40 | ar::arg("feature2"_S, "Second feature"_S, arp::default_value{42}), 41 | arp::router{[](bool f1, int f2) { 42 | std::cout << "F1: " << std::boolalpha << f1 << ", F2: " << f2 << std::endl; 43 | }}, 44 | arp::runtime_enable{advanced}), 45 | ar::mode( 46 | ar::flag("foo"_S, "Foo flag"_S, "f"_S), 47 | ar::flag("bar"_S, "Bar flag"_S, "b"_S), 48 | ar::arg("advance-foo"_S, 49 | "Licensed foo"_S, 50 | arp::runtime_enable_required{advanced}), 51 | arp::router{[](bool f, bool b, std::string_view advance_foo) { 52 | std::cout << "F: " << std::boolalpha << f << ", B: " << b 53 | << ", Advance-foo: " << advance_foo << std::endl; 54 | }})) 55 | .parse(argc, argv); 56 | 57 | return EXIT_SUCCESS; 58 | } 59 | -------------------------------------------------------------------------------- /examples/c++20/simple/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_simple_cpp20 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_simple_cpp20 "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_simple_cpp20 clangformat_example_simple_cpp20) 12 | 13 | target_compile_features(example_simple_cpp20 PUBLIC cxx_std_20) 14 | set_target_properties(example_simple_cpp20 PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_simple_cpp20 PRIVATE arg_router) 16 | 17 | configure_example_build(example_simple_cpp20) 18 | add_clangtidy_to_target(example_simple_cpp20) 19 | 20 | add_dependencies(cpp20_examples example_simple_cpp20) 21 | -------------------------------------------------------------------------------- /examples/c++20/simple/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace ar = arg_router; 11 | namespace arp = ar::policy; 12 | namespace fs = std::filesystem; 13 | 14 | using namespace std::literals; 15 | using namespace ar::literals; 16 | using namespace ar::utility::string_view_ops; 17 | 18 | namespace 19 | { 20 | void copy_mode(bool force, fs::path&& dest, std::vector&& srcs) 21 | { 22 | const auto options = force ? fs::copy_options::overwrite_existing : fs::copy_options::none; 23 | 24 | for (const auto& src : srcs) { 25 | fs::copy(src, dest, options); 26 | } 27 | } 28 | 29 | void move_mode(bool force, fs::path&& dest, fs::path&& src) 30 | { 31 | if (force && fs::exists(dest)) { 32 | fs::remove(src); 33 | } 34 | 35 | fs::rename(src, dest); 36 | } 37 | } // namespace 38 | 39 | template <> 40 | struct ar::parser { 41 | [[nodiscard]] static inline fs::path parse(std::string_view arg) { return arg; } 42 | }; 43 | 44 | int main(int argc, char* argv[]) 45 | { 46 | const auto common_args = 47 | ar::list{ar::flag("force"_S, "f"_S, "Force overwrite existing files"_S), 48 | ar::positional_arg(arp::required, 49 | "DST"_S, 50 | "Destination directory"_S, 51 | arp::fixed_count<1>)}; 52 | 53 | ar::root(arp::validation::default_validator, 54 | ar::help("help"_S, 55 | "h"_S, 56 | "Display this help and exit"_S, 57 | arp::program_name_t{"simple"_S}, 58 | arp::program_version_t{"v0.1"_S}, 59 | arp::program_intro_t{"A simple file copier and mover."_S}, 60 | arp::program_addendum_t{"An example program for arg_router."_S}, 61 | arp::flatten_help, 62 | arp::colour_help_formatter), 63 | ar::mode("copy"_S, 64 | "Copy source files to destination"_S, 65 | common_args, 66 | ar::positional_arg>(arp::required, 67 | "SRC"_S, 68 | "Source file paths"_S, 69 | arp::min_count<1>), 70 | arp::router{[](bool force, fs::path dest, std::vector srcs) { 71 | copy_mode(force, std::move(dest), std::move(srcs)); 72 | }}), 73 | ar::mode("move"_S, 74 | "Move source file to destination"_S, 75 | common_args, 76 | ar::positional_arg(arp::required, 77 | "SRC"_S, 78 | "Source file path"_S, 79 | arp::fixed_count<1>), 80 | arp::router{[](bool force, fs::path dest, fs::path src) { 81 | move_mode(force, std::move(dest), std::move(src)); 82 | }})) 83 | .parse(argc, argv); 84 | } 85 | -------------------------------------------------------------------------------- /examples/c++20/simple_ml/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022-2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | create_clangformat_target( 6 | NAME clangformat_example_simple_ml_cpp20 7 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 8 | ) 9 | 10 | add_executable(example_simple_ml_cpp20 "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 11 | add_dependencies(example_simple_ml_cpp20 clangformat_example_simple_ml_cpp20) 12 | 13 | target_compile_features(example_simple_ml_cpp20 PUBLIC cxx_std_20) 14 | set_target_properties(example_simple_ml_cpp20 PROPERTIES CXX_EXTENSIONS OFF) 15 | target_link_libraries(example_simple_ml_cpp20 PRIVATE arg_router) 16 | 17 | configure_example_build(example_simple_ml_cpp20) 18 | add_clangtidy_to_target(example_simple_ml_cpp20) 19 | 20 | add_dependencies(cpp20_examples example_simple_ml_cpp20) 21 | -------------------------------------------------------------------------------- /examples/c++20/simple_ml_gen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2023 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | include("${CMAKE_SOURCE_DIR}/cmake/translation_generator/translation_generator.cmake") 6 | arg_router_translation_generator( 7 | SOURCES "${CMAKE_SOURCE_DIR}/examples/resources/simple_ml_gen/en_GB.toml" 8 | "${CMAKE_SOURCE_DIR}/examples/resources/simple_ml_gen/fr.toml" 9 | "${CMAKE_SOURCE_DIR}/examples/resources/simple_ml_gen/ja.toml" 10 | OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/translations/" 11 | TARGET translation_example_simple_ml_gen_cpp20 12 | ) 13 | 14 | create_clangformat_target( 15 | NAME clangformat_example_simple_ml_gen_cpp20 16 | SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" 17 | ) 18 | 19 | add_executable(example_simple_ml_gen_cpp20 20 | "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") 21 | add_dependencies( 22 | example_simple_ml_gen_cpp20 23 | translation_example_simple_ml_gen_cpp20 24 | clangformat_example_simple_ml_gen_cpp20) 25 | 26 | target_include_directories(example_simple_ml_gen_cpp20 PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") 27 | 28 | target_compile_features(example_simple_ml_gen_cpp20 PUBLIC cxx_std_20) 29 | set_target_properties(example_simple_ml_gen_cpp20 PROPERTIES CXX_EXTENSIONS OFF) 30 | target_link_libraries(example_simple_ml_gen_cpp20 PRIVATE arg_router) 31 | 32 | configure_example_build(example_simple_ml_gen_cpp20) 33 | add_clangtidy_to_target(example_simple_ml_gen_cpp20) 34 | 35 | add_dependencies(cpp20_examples example_simple_ml_gen_cpp20) 36 | -------------------------------------------------------------------------------- /examples/resources/simple_ml_gen/en_GB.toml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2023 by Camden Mannett. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | force = "force" 6 | force_description = "Force overwrite existing files" 7 | destination = "DST" 8 | destination_description = "Destination directory" 9 | help = "help" 10 | help_description = "Display this help and exit" 11 | program_intro = "A simple file copier and mover." 12 | program_addendum = "An example program for arg_router." 13 | copy = "copy" 14 | copy_description = "Copy source files to destination" 15 | source = "SRC" 16 | sources_description = "Source file paths" 17 | move = "move" 18 | move_description = "Move source file to destination" 19 | source_description = "Source file path" 20 | -------------------------------------------------------------------------------- /examples/resources/simple_ml_gen/fr.toml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2023 by Camden Mannett. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | force = "forcer" 6 | force_description = "Forcer l'écrasement des fichiers existants" 7 | destination = "DST" 8 | destination_description = "Répertoire de destination" 9 | help = "aider" 10 | help_description = "Afficher cette aide et quitter" 11 | program_intro = "Un simple copieur et déménageur de fichiers." 12 | program_addendum = "Un exemple de programme pour arg_router." 13 | copy = "copier" 14 | copy_description = "Copier les fichiers source vers la destination" 15 | source = "SRC" 16 | sources_description = "Chemins des fichiers sources" 17 | move = "déplacer" 18 | move_description = "Déplacer le fichier source vers la destination" 19 | source_description = "Chemin du fichier source" 20 | 21 | [error_code] 22 | unknown_argument = "Argument inconnu" 23 | unhandled_arguments = "Arguments non gérés" 24 | argument_has_already_been_set = "L'argument a déjà été défini" 25 | failed_to_parse = "L'analyse a échoué" 26 | no_arguments_passed = "Aucun argument passé" 27 | minimum_value_not_reached = "Valeur minimale non atteinte" 28 | maximum_value_exceeded = "Valeur maximale dépassée" 29 | minimum_count_not_reached = "Nombre minimum non atteint" 30 | maximum_count_exceeded = "Nombre maximal dépassé" 31 | unknown_argument_with_suggestion = "Argument inconnu : {}. Vouliez-vous dire { }?" 32 | mode_requires_arguments = "Le mode nécessite des arguments" 33 | missing_required_argument = "Argument requis manquant" 34 | too_few_values_for_alias = "Trop peu de valeurs pour l'alias" 35 | dependent_argument_missing = "Argument dépendant manquant (doit être avant le jeton requis sur la ligne de commande)" 36 | one_of_selected_type_mismatch = "Un seul argument d'un \"One Of\" peut être utilisé à la fois" 37 | missing_value_separator = "Attendu un séparateur de valeur" 38 | -------------------------------------------------------------------------------- /examples/resources/simple_ml_gen/ja.toml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2023 by Camden Mannett. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | force = "強制" 6 | force_description = "既存のファイルを強制的に上書きする" 7 | destination = "先" 8 | destination_description = "宛先ディレクトリ" 9 | help = "ヘルプ" 10 | help_description = "このヘルプを表示して終了" 11 | program_intro = "ファイルをコピーおよび移動するためのシンプルなプログラム。" 12 | program_addendum = "「arg_router」のサンプルプログラム。" 13 | copy = "コピー" 14 | copy_description = "ソース ファイルを宛先にコピーする" 15 | source = "出典" 16 | sources_description = "ソース ファイルのパス" 17 | move = "移動" 18 | move_description = "ソース ファイルを宛先に移動する" 19 | source_description = "ソース ファイル パス" 20 | 21 | [error_code] 22 | unknown_argument = "不明な引数" 23 | unhandled_arguments = "未処理の引数" 24 | argument_has_already_been_set = "引数はすでに設定されています" 25 | failed_to_parse = "解析に失敗しました" 26 | no_arguments_passed = "引数が渡されませんでした" 27 | minimum_value_not_reached = "最小値に達していません" 28 | maximum_value_exceeded = "最大値を超えました" 29 | minimum_count_not_reached = "最小数に達していません" 30 | maximum_count_exceeded = "最大数を超えました" 31 | unknown_argument_with_suggestion = "不明な引数 {}。 { } という意味でしたか?" 32 | mode_requires_arguments = "モードには引数が必要です" 33 | missing_required_argument = "必要な引数がありません" 34 | too_few_values_for_alias = "エイリアス値が少なすぎる" 35 | dependent_argument_missing = "従属引数がありません (コマンドラインで必要なトークンの前に置く必要があります)" 36 | one_of_selected_type_mismatch = "一度に許可される「One Of」引数は1つだけです" 37 | missing_value_separator = "値の区切り文字が必要です" 38 | -------------------------------------------------------------------------------- /include/arg_router/arg_router.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/literals.hpp" 8 | #include "arg_router/multi_lang/iso_locale.hpp" 9 | #include "arg_router/multi_lang/root.hpp" 10 | #include "arg_router/multi_lang/root_wrapper.hpp" 11 | #include "arg_router/multi_lang/string_selector.hpp" 12 | #include "arg_router/policy/colour_help_formatter.hpp" 13 | #include "arg_router/policy/custom_parser.hpp" 14 | #include "arg_router/policy/description.hpp" 15 | #include "arg_router/policy/min_max_value.hpp" 16 | #include "arg_router/policy/token_end_marker.hpp" 17 | #include "arg_router/policy/validator.hpp" 18 | #include "arg_router/policy/validator_rule_utilities.hpp" 19 | #include "arg_router/policy/value_separator.hpp" 20 | 21 | /** Namespace for all arg_router types and functions. */ 22 | namespace arg_router 23 | { 24 | 25 | } // namespace arg_router 26 | -------------------------------------------------------------------------------- /include/arg_router/basic_types.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/config.hpp" 8 | 9 | #include 10 | #include 11 | 12 | #if __cplusplus >= 202000L 13 | # include 14 | #else 15 | # define span_CONFIG_CONTRACT_LEVEL_OFF 16 | # include 17 | #endif 18 | 19 | namespace arg_router 20 | { 21 | /** arg_router string. 22 | * 23 | * Same as a std::string, except that it uses the config::allocator. 24 | */ 25 | using string = std::basic_string, config::allocator>; 26 | 27 | /** arg_router ostringstream. 28 | * 29 | * Same as a std::ostringstream, except that it uses the config::allocator. 30 | */ 31 | using ostringstream = 32 | std::basic_ostringstream, config::allocator>; 33 | 34 | /** arg_router vector. 35 | * 36 | * Same as a std::vector, except that it uses the config::allocator. 37 | */ 38 | template 39 | using vector = std::vector>; 40 | 41 | /** An alias for std::span if compiling with >= C++20 support, otherwise 42 | * nonstd::span_lite::span. 43 | */ 44 | #if __cplusplus >= 202000L 45 | template 46 | using span = std::span; 47 | #else 48 | template 49 | using span = nonstd::span_lite::span; 50 | #endif 51 | } // namespace arg_router 52 | -------------------------------------------------------------------------------- /include/arg_router/config.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | /** @file 8 | * 9 | * Preprocessor definitions. These should not be used directly but via the equivalent constants in 10 | * the config namespace. They can be overridden by defining them before the first arg_router 11 | * include in end-user projects, or by setting the equivalent CMake variables in cmake/config.cmake 12 | */ 13 | 14 | // If changing these or adding new ones, reflect those changes in config.cmake 15 | #ifndef AR_MAX_CTS_SIZE 16 | # define AR_MAX_CTS_SIZE 128 17 | #endif 18 | 19 | #ifndef AR_LONG_PREFIX 20 | # define AR_LONG_PREFIX "--" 21 | #endif 22 | 23 | #ifndef AR_SHORT_PREFIX 24 | # define AR_SHORT_PREFIX "-" 25 | #endif 26 | 27 | #ifndef AR_ALLOCATOR 28 | # define AR_ALLOCATOR std::allocator 29 | #endif 30 | 31 | #ifndef AR_UTF8_TRAILING_WINDOW_SIZE 32 | # define AR_UTF8_TRAILING_WINDOW_SIZE 16 33 | #endif 34 | 35 | #ifndef AR_DISABLE_CPP20_STRINGS 36 | # define AR_DISABLE_CPP20_STRINGS false 37 | #endif 38 | 39 | #include "arg_router/utility/utf8.hpp" 40 | 41 | /** Build configuration-defined constants. 42 | * 43 | * There are a few core parts of arg_router that are configurable as compile defines, all are 44 | * available as CMake cache variables too (minus the "AR_" prefix). 45 | */ 46 | namespace arg_router::config 47 | { 48 | /** Long form argument prefix. 49 | * 50 | * UTF-8 supporting. Must be the same or longer than short_prefix (in terms of characters). 51 | */ 52 | constexpr auto long_prefix = std::string_view{AR_LONG_PREFIX}; 53 | 54 | /** Short form argument prefix. 55 | * 56 | * UTF-8 supporting. Must be one characters long. 57 | */ 58 | constexpr auto short_prefix = std::string_view{AR_SHORT_PREFIX}; 59 | 60 | static_assert(utility::utf8::count(short_prefix) == 1, "Short prefix must be one character"); 61 | 62 | static_assert(utility::utf8::count(long_prefix) >= utility::utf8::count(short_prefix), 63 | "Long prefix must be longer or the same as short prefix"); 64 | 65 | /** Allocator for all STL types. 66 | * 67 | * @tparam T Type to allocate for 68 | */ 69 | template 70 | using allocator = AR_ALLOCATOR; 71 | 72 | #if (__cplusplus >= 202002L) && !AR_DISABLE_CPP20_STRINGS 73 | # define AR_ENABLE_CPP20_STRINGS 74 | #endif 75 | 76 | /** There's a bizarre issue that appeared in MSVC 1936 where quoted metafunctions appeared to stop 77 | * working due to the Q::template fn definition not being accepted. 78 | */ 79 | #if (!defined(__clang__) && defined(_MSC_VER) && (_MSC_VER >= 1936)) 80 | # define MSVC_1936_WORKAROUND 1 81 | #endif 82 | } // namespace arg_router::config 83 | -------------------------------------------------------------------------------- /include/arg_router/literals.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/utility/compile_time_string.hpp" 8 | 9 | namespace arg_router::literals 10 | { 11 | #ifdef AR_ENABLE_CPP20_STRINGS 12 | /** String literal to generate a C++20 compile-time string instance. 13 | * 14 | * @tparam S Internal storage type 15 | * @return Compile-time string instance 16 | */ 17 | template 18 | [[nodiscard]] constexpr utility::str operator""_S() noexcept 19 | { 20 | return utility::str{}; 21 | } 22 | #endif 23 | } // namespace arg_router::literals 24 | -------------------------------------------------------------------------------- /include/arg_router/math.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | /** Mathematical functions and types. */ 10 | namespace arg_router::math 11 | { 12 | /** Returns the absolute value of the integer @a value. 13 | * 14 | * This only exists because std::abs(T) is not constexpr. 15 | * @tparam T Integral type 16 | * @param value Input 17 | * @return Absolute value 18 | */ 19 | template 20 | [[nodiscard]] constexpr T abs(T value) noexcept 21 | { 22 | static_assert(std::is_integral_v, "T must be an integral"); 23 | if constexpr (std::is_signed_v) { 24 | return value < T{0} ? -value : value; 25 | } else { 26 | return value; 27 | } 28 | } 29 | 30 | /** Returns the number of digits in @a value. 31 | * 32 | * Basicaly log10(value)+1 but constexpr. 33 | * @tparam T Integral type 34 | * @param value Input 35 | * @return Number of digits. 36 | */ 37 | template 38 | [[nodiscard]] constexpr T num_digits(T value) noexcept 39 | { 40 | static_assert(std::is_integral_v, "T must be an integral"); 41 | 42 | constexpr auto base = T{10}; 43 | 44 | value = abs(value); 45 | auto i = T{1}; 46 | while (value /= base) { 47 | ++i; 48 | } 49 | 50 | return i; 51 | } 52 | 53 | /** Power function. 54 | * 55 | * This only exists because std::power(T) is not constexpr. 56 | * @tparam Base Power base 57 | * @tparam T Integral type 58 | * @param exp Exponent 59 | * @return @a Base raised to the power @a exp 60 | */ 61 | template 62 | [[nodiscard]] constexpr T pow(T exp) noexcept 63 | { 64 | static_assert(std::is_integral_v, "T must be an integral"); 65 | static_assert(Base > 0, "Base must be greater than zero"); 66 | 67 | return exp <= T{0} ? T{1} : Base * pow(exp - T{1}); 68 | } 69 | } // namespace arg_router::math 70 | -------------------------------------------------------------------------------- /include/arg_router/multi_lang/iso_locale.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/basic_types.hpp" 8 | 9 | namespace arg_router::multi_lang 10 | { 11 | /** Converts a locale name (i.e. a string returned by std::locale) into a standardised 12 | * language code format. 13 | * 14 | * The most common locale formats are: 15 | * @code 16 | * _. 17 | * - 18 | * -- 19 | * @endcode 20 | * This function will strip off the encoding if present, and change the dividing character to an 21 | * underscore. For example: 22 | * @code 23 | * iso_country_code("en-US") == "en_US" 24 | * iso_country_code("en_GB.UTF-8") == "en_GB" 25 | * iso_country_code("fr.UTF-8") == "fr" 26 | * iso_country_code("uz-Latn-UZ") == "uz_Latn_UZ" 27 | * @endcode 28 | * An empty string in yields an empty string out. 29 | * 30 | * Typically @a locale_name is under the SSO string size, so allocation doesn't occur. 31 | * 32 | * @param locale_name Local name to standardise 33 | * @return Standardised locale name 34 | */ 35 | inline string iso_locale(std::string_view locale_name) 36 | { 37 | // No need to worry about UTF-8 here as the codes are required to be ASCII 38 | // Start by stripping off the encoding 39 | auto result = string{}; 40 | { 41 | const auto pos = locale_name.find('.'); 42 | result = locale_name.substr(0, pos); 43 | } 44 | 45 | // Change hypens to underscores 46 | for (auto& c : result) { 47 | if (c == '-') { 48 | c = '_'; 49 | } 50 | } 51 | 52 | return result; 53 | } 54 | } // namespace arg_router::multi_lang 55 | -------------------------------------------------------------------------------- /include/arg_router/multi_lang/string_selector.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/utility/compile_time_string.hpp" 8 | 9 | #ifndef AR_ENABLE_CPP20_STRINGS 10 | 11 | # include 12 | 13 | /** @file 14 | */ 15 | 16 | namespace arg_router::multi_lang 17 | { 18 | /** A compile time string container that acts a drop-in replacement for compile_time_string by 19 | * compile-time selection of an element. 20 | * 21 | * @tparam I String index to use 22 | * @tparam S Strings to contain 23 | */ 24 | template 25 | using string_selector = std::tuple_element_t>; 26 | } // namespace arg_router::multi_lang 27 | 28 | # define AR_SM_UNPACK(z, n, var_list) AR_STRING(BOOST_PP_ARRAY_ELEM(n, var_list)) 29 | 30 | /** A multi-language equivalent to S_, only for use within a multi_lang::root call. 31 | * 32 | * Specify the string language variants in the order they are declared in the owning 33 | * multi_lang::root. 34 | * @code 35 | * arp::long_name 36 | * @endcode 37 | * 38 | * @note This has now been superceded by multi_lang::root_t, and will be removed in v2 39 | * 40 | * The macro creates compile_time_string types from the inputs and puts them into a string_selector. 41 | * There is no requirement to use this macro, it's just a convenience. 42 | * @param I Index to select 43 | */ 44 | # define SM_(I, ...) \ 45 | arg_router::multi_lang::string_selector 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/arg_router/multi_lang/translation.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/traits.hpp" 8 | 9 | namespace arg_router::multi_lang 10 | { 11 | /** Used to define compile-time strings for translation. 12 | * 13 | * See multi_lang::root_t for instructions of its use. 14 | * 15 | * @note The unspecialised version will trigger a static_assert failure - all language variants 16 | * known to multi_lang::root_t must be specialised 17 | * 18 | * @tparam LanguageID Language ID type, must match one of the IDs used in the template parameters 19 | * of multi_lang::root_t 20 | */ 21 | template 22 | class translation 23 | { 24 | static_assert(traits::always_false_v, "Unhandled language ID"); 25 | }; 26 | } // namespace arg_router::multi_lang 27 | -------------------------------------------------------------------------------- /include/arg_router/parsing/unknown_argument_handling.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/utility/utf8/levenshtein_distance.hpp" 8 | 9 | namespace arg_router::parsing 10 | { 11 | /** Throws a multi_lang_exception with either a error_code::unknown_argument or a 12 | * error_code::unknown_argument_with_suggestion if the data is available. 13 | * 14 | * @tparam Node Node type throwing the exception 15 | * @param node Node throwing the exception, used as a source for the 16 | * utility::utf8::closest_matching_child_node(const Node& node, parsing::token_type token) 17 | * @param unknown_token The token that caused the exception to be thrown 18 | */ 19 | template 20 | [[noreturn]] void unknown_argument_exception(const Node& node, token_type unknown_token) 21 | { 22 | auto matching_node_and_parents = 23 | utility::utf8::closest_matching_child_node(node, unknown_token); 24 | if (matching_node_and_parents.empty()) { 25 | throw multi_lang_exception{error_code::unknown_argument, unknown_token}; 26 | } 27 | 28 | auto tokens = vector{unknown_token}; 29 | tokens.reserve(matching_node_and_parents.size() + 1); 30 | tokens.insert(tokens.end(), 31 | matching_node_and_parents.rbegin(), 32 | matching_node_and_parents.rend()); 33 | 34 | throw multi_lang_exception{error_code::unknown_argument_with_suggestion, tokens}; 35 | } 36 | } // namespace arg_router::parsing 37 | -------------------------------------------------------------------------------- /include/arg_router/policy/custom_parser.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/parsing/token_type.hpp" 8 | #include "arg_router/policy/policy.hpp" 9 | 10 | #include 11 | #include 12 | 13 | namespace arg_router::policy 14 | { 15 | /** Provides the ability for an argument to have a user-provided value parser. 16 | * 17 | * @tparam T Argument's value type i.e. the type the parser needs to return 18 | */ 19 | template 20 | class custom_parser 21 | { 22 | public: 23 | /** Alias of @a T. */ 24 | using value_type = T; 25 | 26 | /** Parser signature. */ 27 | using parser_type = std::function; 28 | 29 | /** Constructor. 30 | * 31 | * @param p Custom parser 32 | */ 33 | constexpr explicit custom_parser(parser_type p) noexcept : parser_{std::move(p)} {} 34 | 35 | /** Parse @a str to produce an equivalent instance of value_type. 36 | * 37 | * @tparam ValueType Parsed value type, must be implicity convertible from value_type 38 | * @tparam Parents Pack of parent tree nodes in ascending ancestry order 39 | * @param token Token to parse 40 | * @param parents Parents instances pack 41 | * @return Parsed value 42 | * @exception multi_lang_exception Thrown if parsing failed 43 | */ 44 | template 45 | [[nodiscard]] constexpr ValueType parse_phase(std::string_view token, 46 | [[maybe_unused]] const Parents&... parents) const 47 | { 48 | return parser_(token); 49 | } 50 | 51 | private: 52 | parser_type parser_; 53 | }; 54 | 55 | template 56 | struct is_policy> : std::true_type { 57 | }; 58 | } // namespace arg_router::policy 59 | -------------------------------------------------------------------------------- /include/arg_router/policy/default_value.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/config.hpp" 8 | #include "arg_router/policy/policy.hpp" 9 | 10 | namespace arg_router::policy 11 | { 12 | /** Provides a default value for non-required arguments. 13 | * 14 | * @tparam T Value type 15 | */ 16 | template 17 | class default_value 18 | { 19 | public: 20 | /** Alias of @a T. */ 21 | using value_type = T; 22 | 23 | /** Policy priority. */ 24 | constexpr static auto priority = std::size_t{500}; 25 | 26 | /** Constructor 27 | * 28 | * @param value Default value 29 | */ 30 | constexpr explicit default_value(value_type value) noexcept : value_{std::move(value)} {} 31 | 32 | /** Called when the owning node's token (if any) is missing from the command line, this will 33 | * return the default value. 34 | * 35 | * @tparam ValueType Parsed value type, must be implicitly constructible from value_type 36 | * @tparam Parents Pack of parent tree nodes in ascending ancestry order 37 | * @param parents Parents instances pack 38 | * @return Default value 39 | */ 40 | template 41 | [[nodiscard]] constexpr ValueType missing_phase( 42 | [[maybe_unused]] const Parents&... parents) const noexcept 43 | { 44 | return value_; 45 | } 46 | 47 | private: 48 | value_type value_; 49 | }; 50 | 51 | template 52 | struct is_policy> : std::true_type { 53 | }; 54 | } // namespace arg_router::policy 55 | -------------------------------------------------------------------------------- /include/arg_router/policy/description.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Represents the description of a node. 12 | * 13 | * If using C++17 then use the template variable helper with the S_ macro; for C++20 and 14 | * higher, use the constructor directly with a compile-time string literal: 15 | * @code 16 | * constexpr auto a = ar::policy::description; 17 | * constexpr auto b = ar::policy::description_t{"hello"_S}; 18 | * @endcode 19 | * @note Descriptions must not be empty 20 | * @tparam S Compile-time string 21 | */ 22 | template 23 | class description_t 24 | { 25 | public: 26 | /** String type. */ 27 | using string_type = S; 28 | 29 | /** Constructor. 30 | * 31 | * @param str String instance 32 | */ 33 | constexpr explicit description_t([[maybe_unused]] S str = {}) noexcept {} 34 | 35 | /** Returns the description. 36 | * 37 | * @return Description 38 | */ 39 | [[nodiscard]] constexpr static std::string_view description() noexcept { return S::get(); } 40 | 41 | private: 42 | static_assert(!description().empty(), "Descriptions must not be empty"); 43 | }; 44 | 45 | /** Constant variable helper. 46 | * 47 | * @tparam S Compile-time string 48 | */ 49 | template 50 | constexpr auto description = description_t{}; 51 | 52 | template 53 | struct is_policy> : std::true_type { 54 | }; 55 | } // namespace arg_router::policy 56 | -------------------------------------------------------------------------------- /include/arg_router/policy/display_name.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Represents the display name of a node. 12 | * 13 | * A display name is a label given to a node that appears in the help output, but is not used in the 14 | * token parsing. 15 | * 16 | * In the default validator, this policy is not allowed to be used with long_name and short_name - 17 | * as we shouldn't be trying to confuse the user... 18 | * 19 | * If using C++17 then use the template variable helper with the S_ macro; for C++20 and 20 | * higher, use the constructor directly with a compile-time string literal: 21 | * @code 22 | * constexpr auto a = ar::policy::display_name; 23 | * constexpr auto b = ar::policy::display_name_t{"hello"_S}; 24 | * @endcode 25 | * @note Display names must not be empty 26 | * @tparam S Compile-time string 27 | */ 28 | template 29 | class display_name_t 30 | { 31 | public: 32 | /** String type. */ 33 | using string_type = S; 34 | 35 | /** Constructor. 36 | * 37 | * @param str String instance 38 | */ 39 | constexpr explicit display_name_t([[maybe_unused]] S str = {}) noexcept {} 40 | 41 | /** Returns the name. 42 | * 43 | * @return Display name 44 | */ 45 | [[nodiscard]] constexpr static std::string_view display_name() noexcept { return S::get(); } 46 | 47 | private: 48 | static_assert(!display_name().empty(), "Display name must not be empty"); 49 | }; 50 | 51 | /** Constant variable helper. 52 | * 53 | * @tparam S Compile-time string 54 | */ 55 | template 56 | constexpr auto display_name = display_name_t{}; 57 | 58 | template 59 | struct is_policy> : std::true_type { 60 | }; 61 | } // namespace arg_router::policy 62 | -------------------------------------------------------------------------------- /include/arg_router/policy/error_name.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Represents the error name of an argument. 12 | * 13 | * An error name is a label given to a node such that when it throws an error, this label is used 14 | * to represent the node. This policy is typically not for use by users, it is for node 15 | * developers to tune their node's representation in error output. 16 | * 17 | * If using C++17 then use the template variable helper with the S_ macro; for C++20 and 18 | * higher, use the constructor directly with a compile-time string literal: 19 | * @code 20 | * constexpr auto a = ar::policy::error_name; 21 | * constexpr auto b = ar::policy::error_name_t{"hello"_S}; 22 | * @endcode 23 | * @note Error names must not be empty 24 | * @tparam S Compile-time string 25 | */ 26 | template 27 | class error_name_t 28 | { 29 | public: 30 | /** String type. */ 31 | using string_type = S; 32 | 33 | /** Constructor. 34 | * 35 | * @param str String instance 36 | */ 37 | constexpr explicit error_name_t([[maybe_unused]] S str = {}) noexcept {} 38 | 39 | /** Returns the name. 40 | * 41 | * @return Display name 42 | */ 43 | [[nodiscard]] constexpr static std::string_view error_name() noexcept { return S::get(); } 44 | 45 | private: 46 | static_assert(!error_name().empty(), "Error name must not be empty"); 47 | }; 48 | 49 | /** Constant variable helper. 50 | * 51 | * @tparam S Compile-time string 52 | */ 53 | template 54 | constexpr auto error_name = error_name_t{}; 55 | 56 | template 57 | struct is_policy> : std::true_type { 58 | }; 59 | } // namespace arg_router::policy 60 | -------------------------------------------------------------------------------- /include/arg_router/policy/flatten_help.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Used to set a help node to display all command line options in one large tree. 12 | * 13 | * The default behaviour for a help node is to only show the command line options for the specified 14 | * level, this instructs to displsy all the options. 15 | */ 16 | template // This is needed due so it can be used in 17 | struct flatten_help_t { // template template parameters 18 | }; 19 | 20 | /** Constant variable helper. */ 21 | constexpr auto flatten_help = flatten_help_t<>{}; 22 | 23 | template <> 24 | struct is_policy> : std::true_type { 25 | }; 26 | } // namespace arg_router::policy 27 | -------------------------------------------------------------------------------- /include/arg_router/policy/long_name.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Represents the long name of a node. 12 | * 13 | * If using C++17 then use the template variable helper with the S_ macro; for C++20 and 14 | * higher, use the constructor directly with a compile-time string literal: 15 | * @code 16 | * constexpr auto a = ar::policy::long_name; 17 | * constexpr auto b = ar::policy::long_name_t{"hello"_S}; 18 | * @endcode 19 | * @note Long names must be greater than one character and cannot contain any whitespace characters 20 | * @tparam S Compile-time string 21 | */ 22 | template 23 | class long_name_t 24 | { 25 | public: 26 | /** String type. */ 27 | using string_type = S; 28 | 29 | /** Constructor. 30 | * 31 | * @param str String instance 32 | */ 33 | constexpr explicit long_name_t([[maybe_unused]] S str = {}) noexcept {} 34 | 35 | /** Returns the name. 36 | * 37 | * @return Long name 38 | */ 39 | [[nodiscard]] constexpr static std::string_view long_name() noexcept { return S::get(); } 40 | 41 | private: 42 | static_assert(utility::utf8::count(long_name()) > 1, 43 | "Long names must be longer than one character"); 44 | static_assert(!utility::utf8::contains_whitespace(long_name()), 45 | "Long names cannot contain whitespace"); 46 | }; 47 | 48 | /** Constant variable helper. 49 | * 50 | * @tparam S compile_time_string 51 | */ 52 | template 53 | constexpr auto long_name = long_name_t{}; 54 | 55 | template 56 | struct is_policy> : std::true_type { 57 | }; 58 | } // namespace arg_router::policy 59 | -------------------------------------------------------------------------------- /include/arg_router/policy/multi_stage_value.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | #include 10 | #include 11 | 12 | namespace arg_router::policy 13 | { 14 | /** Indicates how a node's parsed value should be merged in some way with the parent's result value. 15 | * 16 | * Node's should derive from this when they appear multiple times non-contiguously in the command 17 | * line. The parent mode-like type will merge, in a user defined way, the values returned by each 18 | * into a single result that will be passed to the routing phase. 19 | * 20 | * An example of this is the counting_flag, it parses a bool but that needs to be added to a total 21 | * count maintained by the parent. This is achieved by having the node's value_type set to 22 | * std::size_t, the parse return type a bool, and this type's merge function increment the total 23 | * count. 24 | * @tparam ResultType Node's value_type 25 | * @tparam ValueType Type returned from the node's parse function 26 | */ 27 | template 28 | class multi_stage_value 29 | { 30 | public: 31 | /** Merge Callable type. */ 32 | using merge_fn = std::function&, ValueType&&)>; 33 | 34 | /** Constructor. 35 | * 36 | * @param fn Merge function object 37 | */ 38 | constexpr explicit multi_stage_value(merge_fn fn) noexcept : fn_{std::move(fn)} {} 39 | 40 | /** Public API to merge the parsed value into the parent's result value. 41 | * 42 | * @param result Parent's result value. If empty, will need initialising 43 | * @param value Parsed value 44 | */ 45 | constexpr void merge(std::optional& result, ValueType&& value) const 46 | { 47 | fn_(result, std::forward(value)); 48 | } 49 | 50 | private: 51 | merge_fn fn_; 52 | }; 53 | 54 | template 55 | struct is_policy> : std::true_type { 56 | }; 57 | 58 | /** Evaulates to true if @a T derives from a multi_stage_value specialisation. 59 | * 60 | * @tparam T Type to test 61 | */ 62 | template 63 | struct has_multi_stage_value { 64 | private: 65 | template 66 | constexpr static std::true_type test(const multi_stage_value*); 67 | 68 | constexpr static std::false_type test(...); 69 | 70 | public: 71 | // NOLINTNEXTLINE(hicpp-vararg) 72 | constexpr static bool value = decltype(test(std::declval()))::value; 73 | }; 74 | 75 | /** Helper variable for has_multi_stage_value. 76 | * 77 | * @tparam T Type to test 78 | */ 79 | template 80 | constexpr bool has_multi_stage_value_v = has_multi_stage_value::value; 81 | } // namespace arg_router::policy 82 | -------------------------------------------------------------------------------- /include/arg_router/policy/no_result_value.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Indicates that a node or derived policy's owning node does not create a return value when 12 | * parsed. 13 | * 14 | * Policies or nodes can derive from this. 15 | */ 16 | template // This is needed due so it can be used in 17 | struct no_result_value { // template template parameters 18 | }; 19 | 20 | /** Evaluates to true if @a T uses no_result_value. 21 | * 22 | * @tparam T Type to test 23 | */ 24 | template 25 | using has_no_result_value = std::is_base_of, T>; 26 | 27 | /** Helper variable for has_no_result_value. 28 | * 29 | * @tparam T Type to test 30 | */ 31 | template 32 | constexpr bool has_no_result_value_v = has_no_result_value::value; 33 | 34 | template <> 35 | struct is_policy> : std::true_type { 36 | }; 37 | } // namespace arg_router::policy 38 | -------------------------------------------------------------------------------- /include/arg_router/policy/none_name.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Represents the name of a node that does not use any token prefix (i.e. 12 | * parsing::prefix_type == none). 13 | * 14 | * The only node that uses this in the library is mode_t. 15 | * 16 | * If using C++17 then use the template variable helper with the S_ macro; for C++20 and 17 | * higher, use the constructor directly with a compile-time string literal: 18 | * @code 19 | * constexpr auto a = ar::policy::none_name; 20 | * constexpr auto b = ar::policy::none_name_t{"hello"_S}; 21 | * @endcode 22 | * @note Display names must not be empty 23 | * @tparam S Compile-time string 24 | */ 25 | template 26 | class none_name_t 27 | { 28 | public: 29 | /** String type. */ 30 | using string_type = S; 31 | 32 | /** Constructor. 33 | * 34 | * @param str String instance 35 | */ 36 | constexpr explicit none_name_t([[maybe_unused]] S str = {}) noexcept {} 37 | 38 | /** Returns the name. 39 | * 40 | * @return None name 41 | */ 42 | [[nodiscard]] constexpr static std::string_view none_name() noexcept { return S::get(); } 43 | 44 | private: 45 | static_assert(utility::utf8::count(none_name()) > 1, 46 | "None names must be longer than one character"); 47 | static_assert(!utility::utf8::contains_whitespace(none_name()), 48 | "None names cannot contain whitespace"); 49 | }; 50 | 51 | /** Constant variable helper. 52 | * 53 | * @tparam S Compile-time string 54 | */ 55 | template 56 | constexpr auto none_name = none_name_t{}; 57 | 58 | template 59 | struct is_policy> : std::true_type { 60 | }; 61 | } // namespace arg_router::policy 62 | -------------------------------------------------------------------------------- /include/arg_router/policy/program_addendum.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Represents the program addendum. 12 | * 13 | * Used by help nodes to display supplementary information (usually) after the argument output. 14 | * 15 | * If using C++17 then use the template variable helper with the S_ macro; for C++20 and 16 | * higher, use the constructor directly with a compile-time string literal: 17 | * @code 18 | * constexpr auto a = ar::policy::program_addendum; 19 | * constexpr auto b = ar::policy::program_addendum_t{"hello"_S}; 20 | * @endcode 21 | * @note Must be greater than one character 22 | * @tparam S Compile-time string 23 | */ 24 | template 25 | class program_addendum_t 26 | { 27 | public: 28 | /** String type. */ 29 | using string_type = S; 30 | 31 | /** Constructor. 32 | * 33 | * @param str String instance 34 | */ 35 | constexpr explicit program_addendum_t([[maybe_unused]] S str = {}) noexcept {} 36 | 37 | /** Returns the program name. 38 | * 39 | * @return Program name 40 | */ 41 | [[nodiscard]] constexpr static std::string_view program_addendum() noexcept { return S::get(); } 42 | 43 | private: 44 | static_assert(utility::utf8::count(program_addendum()) > 1, 45 | "Program addendum must be longer than one character"); 46 | }; 47 | 48 | /** Constant variable helper. 49 | * 50 | * @tparam S Compile-time string 51 | */ 52 | template 53 | constexpr auto program_addendum = program_addendum_t{}; 54 | 55 | template 56 | struct is_policy> : std::true_type { 57 | }; 58 | } // namespace arg_router::policy 59 | -------------------------------------------------------------------------------- /include/arg_router/policy/program_intro.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Represents the program introduction. 12 | * 13 | * Used by help nodes to display a brief description about the program. 14 | * 15 | * If using C++17 then use the template variable helper with the S_ macro; for C++20 and 16 | * higher, use the constructor directly with a compile-time string literal: 17 | * @code 18 | * constexpr auto a = ar::policy::program_intro; 19 | * constexpr auto b = ar::policy::program_intro_t{"hello"_S}; 20 | * @endcode 21 | * @note Must be greater than one character 22 | * @tparam S Compile-time string 23 | */ 24 | template 25 | class program_intro_t 26 | { 27 | public: 28 | /** String type. */ 29 | using string_type = S; 30 | 31 | /** Constructor. 32 | * 33 | * @param str String instance 34 | */ 35 | constexpr explicit program_intro_t([[maybe_unused]] S str = {}) noexcept {} 36 | 37 | /** Returns the program name. 38 | * 39 | * @return Program name 40 | */ 41 | [[nodiscard]] constexpr static std::string_view program_intro() noexcept { return S::get(); } 42 | 43 | private: 44 | static_assert(utility::utf8::count(program_intro()) > 1, 45 | "Program intro must be longer than one character"); 46 | }; 47 | 48 | /** Constant variable helper. 49 | * 50 | * @tparam S Compile-time string 51 | */ 52 | template 53 | constexpr auto program_intro = program_intro_t{}; 54 | 55 | template 56 | struct is_policy> : std::true_type { 57 | }; 58 | } // namespace arg_router::policy 59 | -------------------------------------------------------------------------------- /include/arg_router/policy/program_name.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Represents the program name. 12 | * 13 | * Used by help nodes to produce their output, though in principle can be used by anything that 14 | * wants to. 15 | * 16 | * If using C++17 then use the template variable helper with the S_ macro; for C++20 and 17 | * higher, use the constructor directly with a compile-time string literal: 18 | * @code 19 | * constexpr auto a = ar::policy::program_name; 20 | * constexpr auto b = ar::policy::program_name_t{"hello"_S}; 21 | * @endcode 22 | * @note Names must be greater than one character and cannot contain any whitespace characters 23 | * @tparam S Compile-time string 24 | */ 25 | template 26 | class program_name_t 27 | { 28 | public: 29 | /** String type. */ 30 | using string_type = S; 31 | 32 | /** Constructor. 33 | * 34 | * @param str String instance 35 | */ 36 | constexpr explicit program_name_t([[maybe_unused]] S str = {}) noexcept {} 37 | 38 | /** Returns the program name. 39 | * 40 | * @return Program name 41 | */ 42 | [[nodiscard]] constexpr static std::string_view program_name() noexcept { return S::get(); } 43 | 44 | private: 45 | static_assert(utility::utf8::count(program_name()) > 1, 46 | "Program names must be longer than one character"); 47 | static_assert(!utility::utf8::contains_whitespace(program_name()), 48 | "Program names cannot contain whitespace"); 49 | }; 50 | 51 | /** Constant variable helper. 52 | * 53 | * @tparam S Compile-time string 54 | */ 55 | template 56 | constexpr auto program_name = program_name_t{}; 57 | 58 | template 59 | struct is_policy> : std::true_type { 60 | }; 61 | } // namespace arg_router::policy 62 | -------------------------------------------------------------------------------- /include/arg_router/policy/program_version.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | 9 | namespace arg_router::policy 10 | { 11 | /** Represents the program version string. 12 | * 13 | * Used by help nodes to produce their output, though in principle can be used by anything that 14 | * wants to. 15 | * 16 | * If using C++17 then use the template variable helper with the S_ macro; for C++20 and 17 | * higher, use the constructor directly with a compile-time string literal: 18 | * @code 19 | * constexpr auto a = ar::policy::program_version; 20 | * constexpr auto b = ar::policy::program_version_t{"hello"_S}; 21 | * @endcode 22 | * @tparam S Compile-time string 23 | */ 24 | template 25 | class program_version_t 26 | { 27 | public: 28 | /** String type. */ 29 | using string_type = S; 30 | 31 | /** Constructor. 32 | * 33 | * @param str String instance 34 | */ 35 | constexpr explicit program_version_t([[maybe_unused]] S str = {}) noexcept {} 36 | 37 | /** Returns the program version. 38 | * 39 | * @return Program version 40 | */ 41 | [[nodiscard]] constexpr static std::string_view program_version() noexcept { return S::get(); } 42 | 43 | private: 44 | static_assert(utility::utf8::count(program_version()) > 1, 45 | "Program version string must be longer than one character"); 46 | }; 47 | 48 | /** Constant variable helper. 49 | * 50 | * @tparam S Compile-time string 51 | */ 52 | template 53 | constexpr auto program_version = program_version_t{}; 54 | 55 | template 56 | struct is_policy> : std::true_type { 57 | }; 58 | } // namespace arg_router::policy 59 | -------------------------------------------------------------------------------- /include/arg_router/policy/required.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/exception.hpp" 8 | #include "arg_router/parsing/parsing.hpp" 9 | #include "arg_router/policy/policy.hpp" 10 | 11 | #include 12 | 13 | namespace arg_router::policy 14 | { 15 | /** Used to a mark a command line argument type as required i.e. it is a parse error if the token is 16 | * missing. 17 | */ 18 | template // This is needed due so it can be used in 19 | class required_t // template template parameters 20 | { 21 | public: 22 | /** Policy priority. */ 23 | constexpr static auto priority = std::size_t{450}; 24 | 25 | /** Throw an error. 26 | * 27 | * @tparam ValueType Parsed value type, not used in this method 28 | * @tparam Parents Pack of parent tree nodes in ascending ancestry order 29 | * @param parents Parents instances pack, not used in this method 30 | * @return Nothing, it will throw if called 31 | * @exception multi_lang_exception Thrown if this method is called 32 | */ 33 | template 34 | [[noreturn]] ValueType missing_phase([[maybe_unused]] const Parents&... parents) const 35 | { 36 | static_assert(sizeof...(Parents) >= 1, "Alias requires at least 1 parent"); 37 | 38 | using node_type = boost::mp11::mp_first>; 39 | 40 | throw multi_lang_exception{error_code::missing_required_argument, 41 | parsing::node_token_type()}; 42 | } 43 | }; 44 | 45 | /** Constant variable helper. */ 46 | constexpr auto required = required_t<>{}; 47 | 48 | /** Evaluates to true if @a T is marked as required. 49 | * 50 | * @tparam T Type to test 51 | */ 52 | template 53 | using is_required = std::is_base_of, T>; 54 | 55 | /** Helper variable for is_required. 56 | * 57 | * @tparam T Type to test 58 | */ 59 | template 60 | constexpr bool is_required_v = is_required::value; 61 | 62 | template <> 63 | struct is_policy> : std::true_type { 64 | }; 65 | } // namespace arg_router::policy 66 | -------------------------------------------------------------------------------- /include/arg_router/policy/router.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/exception.hpp" 8 | #include "arg_router/policy/policy.hpp" 9 | 10 | #include 11 | 12 | namespace arg_router::policy 13 | { 14 | /** Provides a Callable that is executed on a successful parse. 15 | * 16 | * @tparam Fn Callable function object type 17 | */ 18 | template 19 | class router 20 | { 21 | public: 22 | /** Callable function object type alias. */ 23 | using callable_type = Fn; 24 | 25 | /** Constructor. 26 | * 27 | * @param f Callable that is executed on a successful parse 28 | */ 29 | constexpr explicit router(Fn f) noexcept : f_{std::move(f)} {} 30 | 31 | /** Executes the result of the parsed command line arguments. 32 | * 33 | * @tparam Args Argument types, must be implicitly convertible to the types in 34 | * callable_args_type, in the order and number specified by callable_args 35 | * @param args Argument values 36 | */ 37 | template 38 | void routing_phase(Args&&... args) const 39 | { 40 | f_(std::forward(args)...); 41 | } 42 | 43 | private: 44 | Fn f_; 45 | }; 46 | 47 | template 48 | struct is_policy> : std::true_type { 49 | }; 50 | } // namespace arg_router::policy 51 | -------------------------------------------------------------------------------- /include/arg_router/policy/short_name.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/policy/policy.hpp" 8 | #include "arg_router/utility/compile_time_string.hpp" 9 | 10 | namespace arg_router::policy 11 | { 12 | /** Represents the short name of a node. 13 | * 14 | * Although this type only accepts a single UTF-8 character, the parser expects it (or the short 15 | * name group it is a part of) to be preceded by the short prefix. 16 | * 17 | * If using C++17 then use the template variable helper with the S_ macro or char; for 18 | * C++20 and higher, use the char variable helper or the constructor directly with a compile-time 19 | * string literal: 20 | * @code 21 | * constexpr auto a = ar::policy::short_name<'h'>; 22 | * constexpr auto b = ar::policy::short_name_utf8; 23 | * constexpr auto c = ar::policy::short_name_t{"h"_S}; 24 | * @endcode 25 | * @tparam S Compile-time string 26 | */ 27 | template 28 | class short_name_t 29 | { 30 | public: 31 | /** String type. */ 32 | using string_type = S; 33 | 34 | /** Constructor. 35 | * 36 | * @param str String instance 37 | */ 38 | constexpr explicit short_name_t([[maybe_unused]] S str = {}) noexcept {} 39 | 40 | /** Returns the name. 41 | * 42 | * @return Short name 43 | */ 44 | [[nodiscard]] constexpr static std::string_view short_name() noexcept { return S::get(); } 45 | 46 | private: 47 | using full_name_type = AR_STRING_SV(config::short_prefix)::append_t; 48 | 49 | static_assert(utility::utf8::count(short_name()) == 1, "Short name must only be one character"); 50 | static_assert(full_name_type::get() != config::long_prefix, 51 | "Short name with short prefix cannot match the long prefix"); 52 | }; 53 | 54 | /** Constant variable helper. 55 | * 56 | * @tparam S Short name character 57 | */ 58 | template 59 | constexpr auto short_name = short_name_t{}; 60 | 61 | /** Constant variable helper that supports UTF-8 code points. 62 | * 63 | * @tparam S Compile-time string 64 | */ 65 | template 66 | constexpr auto short_name_utf8 = short_name_t{}; 67 | 68 | template 69 | struct is_policy> : std::true_type { 70 | }; 71 | } // namespace arg_router::policy 72 | -------------------------------------------------------------------------------- /include/arg_router/tree_node_fwd.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/utility/dynamic_string_view.hpp" 8 | 9 | #include 10 | 11 | namespace arg_router 12 | { 13 | /** Help data for runtime help collect. 14 | * 15 | * arg_router's help system supports compile-time (see @ref help_hdt) and runtime collation via this 16 | * structure. The latter is intended to replace the former as it allows for dynamic filtering and 17 | * other adjustments. 18 | */ 19 | struct runtime_help_data { 20 | utility::dynamic_string_view label; //!< Node name 21 | utility::dynamic_string_view description; //!< Node description 22 | vector children; //!< Child node help data 23 | }; 24 | 25 | template 26 | class tree_node; 27 | 28 | /** Evaulates to true if @a T derives from a tree_node specialisation. 29 | * 30 | * @tparam T Type to test 31 | */ 32 | template 33 | struct is_tree_node { 34 | private: 35 | template 36 | constexpr static std::true_type test(const tree_node*); 37 | 38 | constexpr static std::false_type test(...); 39 | 40 | public: 41 | // NOLINTNEXTLINE(hicpp-vararg) 42 | constexpr static bool value = decltype(test(std::declval()))::value; 43 | }; 44 | 45 | /** Helper variable for is_tree_node. 46 | * 47 | * @tparam T Type to test 48 | */ 49 | template 50 | constexpr bool is_tree_node_v = is_tree_node::value; 51 | } // namespace arg_router 52 | -------------------------------------------------------------------------------- /include/arg_router/utility/string_view_ops.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/basic_types.hpp" 8 | 9 | #include 10 | 11 | /** Namespace for string_view operators. */ 12 | namespace arg_router::utility::string_view_ops 13 | { 14 | /** Concatentation operator between string and string_view. 15 | * 16 | * The returned string uses the library allocator (config::allocator) by default. 17 | * @tparam CharT Character type 18 | * @tparam Traits Character traits 19 | * @tparam Allocator Allocator type 20 | * @param lhs string instance 21 | * @param rhs string_view instance 22 | * @return string of @a lhs and @a rhs concatenated together 23 | */ 24 | template , 26 | typename Allocator = config::allocator> 27 | [[nodiscard]] constexpr std::basic_string operator+( 28 | std::basic_string lhs, 29 | std::basic_string_view rhs) 30 | { 31 | return lhs += rhs; 32 | } 33 | 34 | /** Overload that accepts reversed arguments. 35 | * 36 | * The returned string uses the library allocator (config::allocator) by default. 37 | * @tparam CharT Character type 38 | * @tparam Traits Character traits 39 | * @tparam Allocator Allocator type 40 | * @param lhs string_view instance 41 | * @param rhs string instance 42 | * @return string of @a lhs and @a rhs concatenated together 43 | */ 44 | template , 46 | typename Allocator = config::allocator> 47 | [[nodiscard]] constexpr std::basic_string operator+( 48 | std::basic_string_view lhs, 49 | std::basic_string rhs) 50 | { 51 | rhs.insert(rhs.begin(), lhs.begin(), lhs.end()); 52 | return rhs; 53 | } 54 | 55 | /** Returns a string using two string_views. 56 | * 57 | * The returned string uses the library allocator (config::allocator). 58 | * @tparam CharT Character type 59 | * @tparam Traits Character traits 60 | * @param lhs string_view instance 61 | * @param rhs string instance 62 | * @return string of @a lhs and @a rhs concatenated together 63 | */ 64 | template > 65 | [[nodiscard]] constexpr std::basic_string> operator+( 66 | std::basic_string_view lhs, 67 | std::basic_string_view rhs) 68 | { 69 | return std::basic_string>{lhs} += rhs; 70 | } 71 | } // namespace arg_router::utility::string_view_ops 72 | -------------------------------------------------------------------------------- /include/arg_router/utility/terminal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #if defined(__linux__) || defined(__APPLE__) 10 | # include 11 | #elif _WIN32 12 | # include "arg_router/utility/win_api.hpp" 13 | #endif 14 | 15 | /** Namespace for terminal utilities. */ 16 | namespace arg_router::utility::terminal 17 | { 18 | #ifdef UNIT_TEST_BUILD 19 | extern std::size_t test_columns_value; 20 | #endif 21 | 22 | /** Returns the current number columns in the terminal. 23 | * 24 | * @return Column count 25 | */ 26 | inline std::size_t columns() 27 | { 28 | #ifdef UNIT_TEST_BUILD 29 | return test_columns_value; 30 | #else 31 | # if defined(__linux__) || defined(__APPLE__) 32 | // NOLINTBEGIN(*-member-init, *-vararg) 33 | struct winsize w; 34 | if (::ioctl(0, TIOCGWINSZ, &w) != 0) { 35 | return 0; 36 | } 37 | // NOLINTEND(*-member-init, *-vararg) 38 | return w.ws_col; 39 | # elif _WIN32 40 | CONSOLE_SCREEN_BUFFER_INFO csbi; 41 | if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) { 42 | return 0; 43 | } 44 | return csbi.srWindow.Right - csbi.srWindow.Left + 1; 45 | # endif 46 | #endif 47 | } 48 | } // namespace arg_router::utility::terminal 49 | -------------------------------------------------------------------------------- /include/arg_router/utility/tuple_iterator.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/traits.hpp" 8 | 9 | #include 10 | 11 | /** Namespace for utility types and functions. 12 | */ 13 | namespace arg_router::utility 14 | { 15 | /** Iterates over @a tuple and calls @a f on each element. 16 | * 17 | * @code 18 | * auto t = std::tuple{"hello"s, 42.5, 9}; 19 | * tuple_iterator([](auto i, auto&& v) { 20 | * std::cout << i << ": " << v << std::endl; 21 | * }, t); 22 | * // 0: hello 23 | * // 1: 42.5 24 | * // 2: 9 25 | * @endcode 26 | * @tparam F Callable type 27 | * @tparam Tuple Tuple type 28 | * @param f Callable instance 29 | * @param tuple Tuple instance 30 | * @return Void 31 | */ 32 | template 33 | constexpr std::enable_if_t>> tuple_iterator( 34 | F&& f, 35 | Tuple&& tuple) 36 | { 37 | constexpr auto N = std::tuple_size_v>; 38 | boost::mp11::mp_for_each>([&](auto i) { f(i, std::get(tuple)); }); 39 | } 40 | 41 | /** Iterates over @a pack and calls @a f on each instance within it. 42 | * 43 | * Forwards @a pack into a tuple and uses it to call tuple_iterator(F&&, Tuple&&). 44 | * @tparam F Callable type 45 | * @tparam T Pack types 46 | * @param f Callable instance 47 | * @param pack Instances to iterate over 48 | */ 49 | template 50 | constexpr void tuple_iterator(F&& f, T&&... pack) 51 | { 52 | tuple_iterator(std::forward(f), std::tuple{std::forward(pack)...}); 53 | } 54 | 55 | /** Iterates over @a tuple and passes a nullptr pointer of the tuple element to 56 | * @a f. 57 | * 58 | * @code 59 | * using Tuple = std::tuple; 60 | * tuple_type_iterator([](auto i) { 61 | * using Arg = std::tuple_element_t; 62 | * std::cout << i << ": " << boost::core::demangle(typeid(Arg).name()) 63 | * << std::endl; 64 | * }); 65 | * // 0: std::string 66 | * // 1: double 67 | * // 2: int 68 | * @endcode 69 | * @tparam Tuple Tuple type 70 | * @tparam F Callable type 71 | * @param f Callable instance 72 | * @return Void 73 | */ 74 | template 75 | constexpr std::enable_if_t>> tuple_type_iterator(F&& f) 76 | { 77 | constexpr auto N = std::tuple_size_v>; 78 | boost::mp11::mp_for_each>([&](auto i) { f(i); }); 79 | } 80 | } // namespace arg_router::utility 81 | -------------------------------------------------------------------------------- /include/arg_router/utility/type_hash.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace arg_router::utility 10 | { 11 | /** Hash generation for a type. 12 | * 13 | * This is intended to replace typeid(T).hash_code(), as the use of typeid causes huge 14 | * amounts of class name data to be put into the binary's static data storage - which isn't used! 15 | * 16 | * @note Aliases are resolved by the compiler in a pre-processing stage before this, so 17 | * type_hash() == type_hash() (on a 64bit system) 18 | * 19 | * Anyone reading the implementation will see that this is @em not a hash function, it just takes 20 | * the address of the instantiated function. Originally this used the hash of the 21 | * __PRETTY_FUNCTION__ output and therefore could be used at compile-time. Unfortunately 22 | * that was ruined when C++20 compile-time string support was added, due to a bug in gcc 23 | * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108269) which produced incorrect output when 24 | * std::array was used inside an NTTP. 25 | * @param T Type to generate a hash code for 26 | * @return Hash code of @a T 27 | */ 28 | template 29 | [[nodiscard]] std::size_t type_hash() noexcept 30 | { 31 | return reinterpret_cast(&type_hash); 32 | } 33 | } // namespace arg_router::utility 34 | -------------------------------------------------------------------------------- /include/arg_router/utility/utf8/whitespace.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/utility/utf8/code_point.hpp" 8 | 9 | namespace arg_router::utility::utf8 10 | { 11 | /** Whitespace code points. 12 | * 13 | * Each entry is an inclusive range of code points. 14 | * 15 | * This table is generated using scripts/unicode_table_generators.py from 16 | * http://www.unicode.org/Public/UNIDATA/PropList.txt v14.0.0. 17 | */ 18 | constexpr auto whitespace_table = std::array{{ 19 | {0x000009, 0x00000D}, 20 | {0x000020, 0x000020}, 21 | {0x000085, 0x000085}, 22 | {0x0000A0, 0x0000A0}, 23 | {0x001680, 0x001680}, 24 | {0x002000, 0x00200A}, 25 | {0x002028, 0x002028}, 26 | {0x002029, 0x002029}, 27 | {0x00202F, 0x00202F}, 28 | {0x00205F, 0x00205F}, 29 | {0x003000, 0x003000}, 30 | }}; 31 | } // namespace arg_router::utility::utf8 32 | -------------------------------------------------------------------------------- /include/arg_router/utility/win_api.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | /** @file 8 | * 9 | * Wrapper for including windows.h on Windows platforms. By default NOMINMAX and 10 | * WIN32_LEAN_AND_MEAN is defined before inclusion but these can be disabled by defining 11 | * AR_NO_* before if desired. 12 | */ 13 | 14 | #ifdef _WIN32 15 | # if !defined(AR_NO_NOMINMAX) && !defined(NOMINMAX) 16 | # define NOMINMAX 17 | # endif 18 | 19 | # if !defined(AR_NO_WIN32_LEAN_AND_MEAN) && !defined(WIN32_LEAN_AND_MEAN) 20 | # define WIN32_LEAN_AND_MEAN 21 | # endif 22 | 23 | # include "windows.h" 24 | #endif 25 | -------------------------------------------------------------------------------- /include/arg_router/version.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | /** @file 8 | * 9 | * This file is automatically generated by the build system, do not manually modify it. If you need 10 | * to change the template, it is located in arg_router/cmake/versioning/version.hpp.in 11 | */ 12 | 13 | namespace arg_router 14 | { 15 | /** Library version as a SymVers-style string. 16 | */ 17 | constexpr auto version_string = "1.4.0"; 18 | } // namespace arg_router 19 | -------------------------------------------------------------------------------- /scripts/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2023 by Camden Mannett. 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | 7 | set -e 8 | 9 | # Get list of changes files 10 | readarray -t files <<< `git diff-index --name-only --cached HEAD` 11 | 12 | # Run the copyright checker 13 | python ./scripts/copyright_checker.py date ${files[@]} 14 | 15 | # Run clang-format 16 | source_files=() 17 | for file in "${files[@]}"; do 18 | extension="${file#*.}" 19 | if [ "$extension" = "hpp" ] || [ "$extension" = "cpp" ]; then 20 | source_files+=($file) 21 | fi 22 | done 23 | 24 | if [[ ${#source_files[@]} > 0 ]]; then 25 | clang-format --style=file --dry-run --Werror ${source_files[@]} 26 | fi 27 | -------------------------------------------------------------------------------- /test/.clang-tidy: -------------------------------------------------------------------------------- 1 | # Disable clang-tidy in the test dir - we need to get dirty for the tests! 2 | # The added check is a workaround for this issue: 3 | # https://stackoverflow.com/a/58379342/498437 4 | InheritParentConfig: false 5 | Checks: '-*,misc-definitions-in-headers' 6 | CheckOptions: 7 | - key: HeaderFileExtensions 8 | value: 'x' 9 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### Copyright (C) 2022 by Camden Mannett. 2 | ### Distributed under the Boost Software License, Version 1.0. 3 | ### (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/build_types/unit_test.cmake) 6 | include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/build_types/unit_test_coverage.cmake) 7 | include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/build_types/death_test.cmake) 8 | -------------------------------------------------------------------------------- /test/counting_flag_same_prefix_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #undef AR_LONG_PREFIX 6 | #define AR_LONG_PREFIX "-" 7 | 8 | #include "arg_router/counting_flag.hpp" 9 | #include "arg_router/policy/long_name.hpp" 10 | #include "arg_router/policy/short_name.hpp" 11 | 12 | #include "test_helpers.hpp" 13 | 14 | using namespace arg_router; 15 | using namespace std::string_view_literals; 16 | 17 | BOOST_AUTO_TEST_SUITE(counting_flag_suite) 18 | 19 | BOOST_AUTO_TEST_CASE(no_short_form_expander_test) 20 | { 21 | [[maybe_unused]] auto f = 22 | counting_flag(policy::long_name, policy::short_name<'H'>); 23 | static_assert(f.long_name() == "hello"sv, "Long name test fail"); 24 | static_assert(f.short_name() == "H", "Short name test fail"); 25 | static_assert(f.minimum_count() == 0, "Minimum count test fail"); 26 | static_assert(f.maximum_count() == 0, "Maximum count test fail"); 27 | 28 | static_assert( 29 | boost::mp11::mp_none_of_q::policies_type, 30 | boost::mp11::mp_bind>>::value, 33 | "Expected short_form_expander policy"); 34 | } 35 | 36 | BOOST_AUTO_TEST_SUITE_END() 37 | -------------------------------------------------------------------------------- /test/flag_same_prefix_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #undef AR_LONG_PREFIX 6 | #define AR_LONG_PREFIX "-" 7 | 8 | #include "arg_router/flag.hpp" 9 | #include "arg_router/policy/long_name.hpp" 10 | #include "arg_router/policy/short_name.hpp" 11 | 12 | #include "test_helpers.hpp" 13 | 14 | using namespace arg_router; 15 | using namespace std::string_view_literals; 16 | 17 | BOOST_AUTO_TEST_SUITE(flag_suite) 18 | 19 | BOOST_AUTO_TEST_CASE(no_short_form_expander_test) 20 | { 21 | [[maybe_unused]] auto f = flag(policy::long_name, policy::short_name<'H'>); 22 | static_assert(f.long_name() == "hello"sv, "Long name test fail"); 23 | static_assert(f.short_name() == "H", "Short name test fail"); 24 | static_assert(f.minimum_count() == 0, "Minimum count test fail"); 25 | static_assert(f.maximum_count() == 0, "Maximum count test fail"); 26 | 27 | static_assert( 28 | boost::mp11::mp_none_of_q::policies_type, 29 | boost::mp11::mp_bind>>::value, 32 | "Expected short_form_expander policy"); 33 | } 34 | 35 | BOOST_AUTO_TEST_SUITE_END() 36 | -------------------------------------------------------------------------------- /test/main_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | // Use the header-only version, due to suffering linking issues on CI 6 | #define BOOST_TEST_MODULE arg_router_test Test Suite 7 | #include 8 | -------------------------------------------------------------------------------- /test/math_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/math.hpp" 6 | 7 | #include "test_helpers.hpp" 8 | 9 | using namespace arg_router; 10 | 11 | BOOST_AUTO_TEST_SUITE(math_suite) 12 | 13 | BOOST_AUTO_TEST_CASE(abs_test) 14 | { 15 | static_assert(math::abs(0) == 0); 16 | static_assert(math::abs(42) == 42); 17 | static_assert(math::abs(-0) == 0); 18 | static_assert(math::abs(-42) == 42); 19 | } 20 | 21 | BOOST_AUTO_TEST_CASE(num_digits) 22 | { 23 | static_assert(math::num_digits(0) == 1); 24 | static_assert(math::num_digits(42) == 2); 25 | static_assert(math::num_digits(100) == 3); 26 | static_assert(math::num_digits(4345432) == 7); 27 | static_assert(math::num_digits(-0) == 1); 28 | static_assert(math::num_digits(-42) == 2); 29 | } 30 | 31 | BOOST_AUTO_TEST_CASE(pow) 32 | { 33 | static_assert(math::pow<3>(0) == 1); 34 | static_assert(math::pow<3>(3) == 27); 35 | static_assert(math::pow<10>(3) == 1000); 36 | static_assert(math::pow<10>(-3) == 1); 37 | } 38 | 39 | BOOST_AUTO_TEST_CASE(death_test) 40 | { 41 | test::death_test_compile({{R"( 42 | #include "arg_router/math.hpp" 43 | 44 | using namespace arg_router; 45 | 46 | int main() { 47 | const auto result = math::abs("hello"); 48 | return 0; 49 | } 50 | )", 51 | "T must be an integral", 52 | "abs_must_be_integral_test"}, 53 | { 54 | R"( 55 | #include "arg_router/math.hpp" 56 | 57 | using namespace arg_router; 58 | 59 | int main() { 60 | const auto result = math::num_digits("hello"); 61 | return 0; 62 | } 63 | )", 64 | "T must be an integral", 65 | "num_digits_must_be_integral_test"}, 66 | { 67 | R"( 68 | #include "arg_router/math.hpp" 69 | 70 | using namespace arg_router; 71 | 72 | int main() { 73 | const auto result = math::pow<10>("hello"); 74 | return 0; 75 | } 76 | )", 77 | "T must be an integral", 78 | "pow_must_be_integral_test"}, 79 | { 80 | R"( 81 | #include "arg_router/math.hpp" 82 | 83 | using namespace arg_router; 84 | 85 | int main() { 86 | const auto result = math::pow<-10>(3); 87 | return 0; 88 | } 89 | )", 90 | "Base must be greater than zero", 91 | "pow_base_must_be_positive_test"}}); 92 | } 93 | 94 | BOOST_AUTO_TEST_SUITE_END() 95 | -------------------------------------------------------------------------------- /test/multi_lang/iso_locale_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/multi_lang/iso_locale.hpp" 6 | 7 | #include "test_helpers.hpp" 8 | 9 | using namespace arg_router; 10 | 11 | BOOST_AUTO_TEST_SUITE(multi_lang_suite) 12 | 13 | BOOST_AUTO_TEST_CASE(iso_locale_test) 14 | { 15 | auto f = [](auto input, auto expected) { 16 | const auto result = multi_lang::iso_locale(input); 17 | BOOST_CHECK_EQUAL(result, expected); 18 | }; 19 | 20 | test::data_set(f, 21 | { 22 | std::tuple{"en-US", "en_US"}, 23 | std::tuple{"en_GB.UTF-8", "en_GB"}, 24 | std::tuple{"fr.UTF-8", "fr"}, 25 | std::tuple{"fr", "fr"}, 26 | std::tuple{"POSIX", "POSIX"}, 27 | std::tuple{"C", "C"}, 28 | std::tuple{"", ""}, 29 | }); 30 | } 31 | 32 | BOOST_AUTO_TEST_SUITE_END() 33 | -------------------------------------------------------------------------------- /test/multi_lang/string_selector_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/multi_lang/string_selector.hpp" 6 | 7 | #ifndef AR_ENABLE_CPP20_STRINGS 8 | 9 | # include "test_helpers.hpp" 10 | 11 | using namespace arg_router; 12 | 13 | BOOST_AUTO_TEST_SUITE(multi_lang_suite) 14 | 15 | BOOST_AUTO_TEST_CASE(SM_macro_test) 16 | { 17 | { 18 | using type = SM_(0, "hello", "world"); 19 | static_assert(std::is_same_v, "Test fail"); 20 | } 21 | 22 | { 23 | using type = SM_(1, "hello", "world"); 24 | static_assert(std::is_same_v, "Test fail"); 25 | } 26 | } 27 | 28 | BOOST_AUTO_TEST_SUITE_END() 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /test/parsing/pre_parse_data_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/parsing/pre_parse_data.hpp" 6 | #include "arg_router/tree_node.hpp" 7 | 8 | #include "test_helpers.hpp" 9 | #include "test_printers.hpp" 10 | 11 | using namespace arg_router; 12 | 13 | namespace 14 | { 15 | template 16 | class stub_node : public tree_node 17 | { 18 | public: 19 | using value_type = bool; 20 | 21 | constexpr explicit stub_node(Policies... policies) : 22 | tree_node{std::move(policies)...} 23 | { 24 | } 25 | 26 | template 27 | [[nodiscard]] value_type parse(parsing::parse_target, const Parents&...) const 28 | { 29 | return true; 30 | } 31 | }; 32 | } // namespace 33 | 34 | BOOST_AUTO_TEST_SUITE(parsing_suite) 35 | 36 | BOOST_AUTO_TEST_SUITE(pre_parse_data_suite) 37 | 38 | BOOST_AUTO_TEST_CASE(no_target_constructor_test) 39 | { 40 | auto args = std::vector{{parsing::prefix_type::none, "-f"}, 41 | {parsing::prefix_type::none, "42"}}; 42 | const auto false_validator = [](const auto&...) { return false; }; 43 | 44 | { 45 | auto ppd = parsing::pre_parse_data{args}; 46 | BOOST_CHECK_EQUAL(ppd.args(), args); 47 | BOOST_CHECK(ppd.validator()()); 48 | } 49 | 50 | { 51 | const auto ppd = parsing::pre_parse_data{args}; 52 | BOOST_CHECK_EQUAL(ppd.args(), args); 53 | BOOST_CHECK(ppd.validator()()); 54 | } 55 | 56 | { 57 | auto ppd = parsing::pre_parse_data{args, false_validator}; 58 | BOOST_CHECK_EQUAL(ppd.args(), args); 59 | BOOST_CHECK(!ppd.validator()()); 60 | } 61 | 62 | { 63 | const auto ppd = parsing::pre_parse_data{args, false_validator}; 64 | BOOST_CHECK_EQUAL(ppd.args(), args); 65 | BOOST_CHECK(!ppd.validator()()); 66 | } 67 | } 68 | 69 | BOOST_AUTO_TEST_CASE(target_constructor_test) 70 | { 71 | auto args = std::vector{{parsing::prefix_type::none, "-f"}, 72 | {parsing::prefix_type::none, "42"}}; 73 | auto target_tokens = std::vector{{parsing::prefix_type::none, "hello"}}; 74 | auto node = stub_node{}; 75 | const auto target = parsing::parse_target{target_tokens, node}; 76 | const auto false_validator = [](const auto&...) { return false; }; 77 | 78 | { 79 | auto ppd = parsing::pre_parse_data{args, target}; 80 | BOOST_CHECK_EQUAL(ppd.args(), args); 81 | BOOST_CHECK(ppd.validator()()); 82 | BOOST_CHECK_EQUAL(ppd.target().tokens(), target_tokens); 83 | } 84 | 85 | { 86 | const auto ppd = parsing::pre_parse_data{args, target}; 87 | BOOST_CHECK_EQUAL(ppd.args(), args); 88 | BOOST_CHECK(ppd.validator()()); 89 | BOOST_CHECK_EQUAL(ppd.target().tokens(), target_tokens); 90 | } 91 | 92 | { 93 | auto ppd = parsing::pre_parse_data{args, target, false_validator}; 94 | BOOST_CHECK_EQUAL(ppd.args(), args); 95 | BOOST_CHECK(!ppd.validator()()); 96 | BOOST_CHECK_EQUAL(ppd.target().tokens(), target_tokens); 97 | } 98 | 99 | { 100 | const auto ppd = parsing::pre_parse_data{args, target, false_validator}; 101 | BOOST_CHECK_EQUAL(ppd.args(), args); 102 | BOOST_CHECK(!ppd.validator()()); 103 | BOOST_CHECK_EQUAL(ppd.target().tokens(), target_tokens); 104 | } 105 | } 106 | 107 | BOOST_AUTO_TEST_SUITE_END() 108 | 109 | BOOST_AUTO_TEST_SUITE_END() 110 | -------------------------------------------------------------------------------- /test/policy/custom_parser_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/policy/custom_parser.hpp" 6 | #include "arg_router/tree_node.hpp" 7 | 8 | #include "test_helpers.hpp" 9 | #include "test_printers.hpp" 10 | 11 | using namespace arg_router; 12 | 13 | namespace 14 | { 15 | template 16 | class stub_node : public tree_node 17 | { 18 | public: 19 | constexpr explicit stub_node(Policies... policies) : 20 | tree_node{std::move(policies)...} 21 | { 22 | } 23 | 24 | template 25 | std::optional parse_phase(std::string_view token, const Parents&... parents) const 26 | { 27 | auto result = std::optional{}; 28 | utility::tuple_type_iterator( // 29 | [&](auto i) { 30 | using this_policy = std::tuple_element_t; 31 | if constexpr (policy::has_parse_phase_method_v && 32 | traits::is_specialisation_of_v) { 33 | BOOST_CHECK(!result); 34 | result = this->this_policy::template parse_phase(token, parents...); 35 | } 36 | }); 37 | 38 | return result; 39 | } 40 | }; 41 | } // namespace 42 | 43 | BOOST_AUTO_TEST_SUITE(policy_suite) 44 | 45 | BOOST_AUTO_TEST_SUITE(custom_parser_suite) 46 | 47 | BOOST_AUTO_TEST_CASE(is_policy_test) 48 | { 49 | static_assert(policy::is_policy_v>, "Policy test has failed"); 50 | } 51 | 52 | BOOST_AUTO_TEST_CASE(parse_phase_test) 53 | { 54 | const auto root = stub_node{ 55 | stub_node{policy::custom_parser{[](auto str) { return parser::parse(str); }}}, 56 | stub_node{policy::custom_parser{ 57 | [](auto str) { return parser::parse(str); }}}, 58 | stub_node{}}; 59 | 60 | auto f = [&](auto token, const auto& owner, auto expected_value) { 61 | using value_type = typename std::decay_t::value_type; 62 | const auto result = owner.template parse_phase(token, owner, root); 63 | BOOST_CHECK_EQUAL(result, expected_value); 64 | }; 65 | 66 | test::data_set( 67 | f, 68 | std::tuple{ 69 | std::tuple{"42", std::get<0>(root.children()), std::optional{42}}, 70 | std::tuple{"42", std::get<1>(root.children()), std::optional{"42"}}, 71 | std::tuple{"42", std::get<2>(root.children()), std::optional{}}}); 72 | } 73 | 74 | BOOST_AUTO_TEST_SUITE_END() 75 | 76 | BOOST_AUTO_TEST_SUITE_END() 77 | -------------------------------------------------------------------------------- /test/policy/default_value_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/policy/default_value.hpp" 6 | #include "arg_router/tree_node.hpp" 7 | 8 | #include "test_helpers.hpp" 9 | #include "test_printers.hpp" 10 | 11 | #include 12 | 13 | using namespace arg_router; 14 | using namespace std::string_view_literals; 15 | 16 | namespace 17 | { 18 | template 19 | class stub_node : public tree_node 20 | { 21 | public: 22 | constexpr explicit stub_node(Policies... policies) : 23 | tree_node{std::move(policies)...} 24 | { 25 | } 26 | 27 | template 28 | std::optional missing_phase(const Parents&... parents) const 29 | { 30 | auto result = std::optional{}; 31 | utility::tuple_type_iterator( // 32 | [&](auto i) { 33 | using this_policy = std::tuple_element_t; 34 | if constexpr (policy::has_missing_phase_method_v && 35 | traits::is_specialisation_of_v) { 36 | result = this->this_policy::template missing_phase(parents...); 37 | } 38 | }); 39 | 40 | return result; 41 | } 42 | }; 43 | } // namespace 44 | 45 | BOOST_AUTO_TEST_SUITE(policy_suite) 46 | 47 | BOOST_AUTO_TEST_SUITE(default_value_suite) 48 | 49 | BOOST_AUTO_TEST_CASE(is_policy_test) 50 | { 51 | static_assert(policy::is_policy_v>, "Policy test has failed"); 52 | } 53 | 54 | BOOST_AUTO_TEST_CASE(missing_phase_test) 55 | { 56 | const auto root = stub_node{stub_node{policy::default_value{42}}, 57 | stub_node{policy::default_value{3.14}}, 58 | stub_node{}}; 59 | 60 | auto f = [&](const auto& owner, auto expected_value) { 61 | using value_type = typename std::decay_t::value_type; 62 | const auto result = owner.template missing_phase(owner, root); 63 | BOOST_CHECK_EQUAL(result, expected_value); 64 | }; 65 | 66 | test::data_set(f, 67 | std::tuple{std::tuple{std::get<0>(root.children()), std::optional{42}}, 68 | std::tuple{std::get<1>(root.children()), std::optional{3.14}}, 69 | std::tuple{std::get<2>(root.children()), std::optional{}}}); 70 | } 71 | 72 | BOOST_AUTO_TEST_SUITE_END() 73 | 74 | BOOST_AUTO_TEST_SUITE_END() 75 | -------------------------------------------------------------------------------- /test/policy/description_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/policy/description.hpp" 6 | #include "arg_router/literals.hpp" 7 | 8 | #include "test_helpers.hpp" 9 | 10 | using namespace arg_router; 11 | using namespace arg_router::literals; 12 | 13 | BOOST_AUTO_TEST_SUITE(policy_suite) 14 | 15 | BOOST_AUTO_TEST_SUITE(description_suite) 16 | 17 | BOOST_AUTO_TEST_CASE(is_policy_test) 18 | { 19 | static_assert(policy::is_policy_v>, 20 | "Policy test has failed"); 21 | } 22 | 23 | BOOST_AUTO_TEST_CASE(constructor_and_get_test) 24 | { 25 | const auto hello_str = policy::description; 26 | static_assert(hello_str.description() == "hello"); 27 | 28 | constexpr auto world_str = policy::description_t{AR_STRING("world"){}}; 29 | static_assert(world_str.description() == "world"); 30 | } 31 | 32 | #ifdef AR_ENABLE_CPP20_STRINGS 33 | BOOST_AUTO_TEST_CASE(string_literal_test) 34 | { 35 | const auto world_str = policy::description_t{"world"_S}; 36 | static_assert(world_str.description() == "world"); 37 | } 38 | #endif 39 | 40 | BOOST_AUTO_TEST_SUITE(death_suite) 41 | 42 | BOOST_AUTO_TEST_CASE(empty_test) 43 | { 44 | test::death_test_compile( 45 | R"( 46 | #include "arg_router/policy/description.hpp" 47 | #include "arg_router/utility/compile_time_string.hpp" 48 | int main() { 49 | const auto des = arg_router::policy::description; 50 | return 0; 51 | } 52 | )", 53 | "Descriptions must not be empty"); 54 | } 55 | 56 | BOOST_AUTO_TEST_SUITE_END() 57 | 58 | BOOST_AUTO_TEST_SUITE_END() 59 | 60 | BOOST_AUTO_TEST_SUITE_END() 61 | -------------------------------------------------------------------------------- /test/policy/display_name_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/policy/display_name.hpp" 6 | #include "arg_router/literals.hpp" 7 | 8 | #include "test_helpers.hpp" 9 | 10 | using namespace arg_router; 11 | using namespace arg_router::literals; 12 | 13 | BOOST_AUTO_TEST_SUITE(policy_suite) 14 | 15 | BOOST_AUTO_TEST_SUITE(display_name_suite) 16 | 17 | BOOST_AUTO_TEST_CASE(is_policy_test) 18 | { 19 | static_assert(policy::is_policy_v>, 20 | "Policy test has failed"); 21 | } 22 | 23 | BOOST_AUTO_TEST_CASE(constructor_and_get_test) 24 | { 25 | constexpr auto hello_str = policy::display_name; 26 | static_assert(hello_str.display_name() == "hello"); 27 | 28 | constexpr auto world_str = policy::display_name_t{AR_STRING("world"){}}; 29 | static_assert(world_str.display_name() == "world"); 30 | } 31 | 32 | #ifdef AR_ENABLE_CPP20_STRINGS 33 | BOOST_AUTO_TEST_CASE(string_literal_test) 34 | { 35 | const auto world_str = policy::display_name_t{"world"_S}; 36 | static_assert(world_str.display_name() == "world"); 37 | } 38 | #endif 39 | 40 | BOOST_AUTO_TEST_SUITE(death_suite) 41 | 42 | BOOST_AUTO_TEST_CASE(empty_test) 43 | { 44 | test::death_test_compile( 45 | R"( 46 | #include "arg_router/policy/display_name.hpp" 47 | #include "arg_router/utility/compile_time_string.hpp" 48 | int main() { 49 | const auto des = arg_router::policy::display_name; 50 | return 0; 51 | } 52 | )", 53 | "Display name must not be empty"); 54 | } 55 | 56 | BOOST_AUTO_TEST_SUITE_END() 57 | 58 | BOOST_AUTO_TEST_SUITE_END() 59 | 60 | BOOST_AUTO_TEST_SUITE_END() 61 | -------------------------------------------------------------------------------- /test/policy/error_name_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/policy/error_name.hpp" 6 | #include "arg_router/literals.hpp" 7 | 8 | #include "test_helpers.hpp" 9 | 10 | using namespace arg_router; 11 | using namespace arg_router::literals; 12 | 13 | BOOST_AUTO_TEST_SUITE(policy_suite) 14 | 15 | BOOST_AUTO_TEST_SUITE(error_name_suite) 16 | 17 | BOOST_AUTO_TEST_CASE(is_policy_test) 18 | { 19 | static_assert(policy::is_policy_v>, 20 | "Policy test has failed"); 21 | } 22 | 23 | BOOST_AUTO_TEST_CASE(constructor_and_get_test) 24 | { 25 | constexpr auto hello_str = policy::error_name; 26 | static_assert(hello_str.error_name() == "hello"); 27 | 28 | constexpr auto world_str = policy::error_name_t{AR_STRING("world"){}}; 29 | static_assert(world_str.error_name() == "world"); 30 | } 31 | 32 | #ifdef AR_ENABLE_CPP20_STRINGS 33 | BOOST_AUTO_TEST_CASE(string_literal_test) 34 | { 35 | const auto world_str = policy::error_name_t{"world"_S}; 36 | static_assert(world_str.error_name() == "world"); 37 | } 38 | #endif 39 | 40 | BOOST_AUTO_TEST_SUITE(death_suite) 41 | 42 | BOOST_AUTO_TEST_CASE(empty_test) 43 | { 44 | test::death_test_compile( 45 | R"( 46 | #include "arg_router/policy/error_name.hpp" 47 | #include "arg_router/utility/compile_time_string.hpp" 48 | int main() { 49 | const auto des = arg_router::policy::error_name; 50 | return 0; 51 | } 52 | )", 53 | "Error name must not be empty"); 54 | } 55 | 56 | BOOST_AUTO_TEST_SUITE_END() 57 | 58 | BOOST_AUTO_TEST_SUITE_END() 59 | 60 | BOOST_AUTO_TEST_SUITE_END() 61 | -------------------------------------------------------------------------------- /test/policy/long_name_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/policy/long_name.hpp" 6 | #include "arg_router/literals.hpp" 7 | 8 | #include "test_helpers.hpp" 9 | 10 | using namespace arg_router; 11 | using namespace arg_router::literals; 12 | 13 | BOOST_AUTO_TEST_SUITE(policy_suite) 14 | 15 | BOOST_AUTO_TEST_SUITE(long_name_suite) 16 | 17 | BOOST_AUTO_TEST_CASE(is_policy_test) 18 | { 19 | static_assert(policy::is_policy_v>, 20 | "Policy test has failed"); 21 | } 22 | 23 | BOOST_AUTO_TEST_CASE(constructor_and_get_test) 24 | { 25 | constexpr auto hello_str = policy::long_name; 26 | static_assert(hello_str.long_name() == "hello"); 27 | 28 | constexpr auto three_char_str = policy::long_name; 29 | static_assert(three_char_str.long_name() == "boo"); 30 | 31 | constexpr auto world_str = policy::long_name_t{AR_STRING("world"){}}; 32 | static_assert(world_str.long_name() == "world"); 33 | } 34 | 35 | #ifdef AR_ENABLE_CPP20_STRINGS 36 | BOOST_AUTO_TEST_CASE(string_literal_test) 37 | { 38 | const auto world_str = policy::long_name_t{"world"_S}; 39 | static_assert(world_str.long_name() == "world"); 40 | } 41 | #endif 42 | 43 | BOOST_AUTO_TEST_CASE(death_test) 44 | { 45 | test::death_test_compile({{ 46 | R"( 47 | #include "arg_router/policy/long_name.hpp" 48 | #include "arg_router/utility/compile_time_string.hpp" 49 | int main() { 50 | const auto ln = arg_router::policy::long_name; 51 | return 0; 52 | } 53 | )", 54 | "Long names must be longer than one character", 55 | "empty_test"}, 56 | { 57 | R"( 58 | #include "arg_router/policy/long_name.hpp" 59 | #include "arg_router/utility/compile_time_string.hpp" 60 | int main() { 61 | const auto ln = arg_router::policy::long_name; 62 | return 0; 63 | } 64 | )", 65 | "Long names must be longer than one character", 66 | "single_char_test"}, 67 | { 68 | R"( 69 | #include "arg_router/policy/long_name.hpp" 70 | #include "arg_router/utility/compile_time_string.hpp" 71 | int main() { 72 | const auto ln = arg_router::policy::long_name; 73 | return 0; 74 | } 75 | )", 76 | "Long names cannot contain whitespace", 77 | "space_test"}}); 78 | } 79 | 80 | BOOST_AUTO_TEST_SUITE_END() 81 | 82 | BOOST_AUTO_TEST_SUITE_END() 83 | -------------------------------------------------------------------------------- /test/policy/short_name_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022-2023 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/policy/short_name.hpp" 6 | #include "arg_router/literals.hpp" 7 | 8 | #include "test_helpers.hpp" 9 | 10 | using namespace arg_router; 11 | using namespace arg_router::literals; 12 | 13 | BOOST_AUTO_TEST_SUITE(policy_suite) 14 | 15 | BOOST_AUTO_TEST_SUITE(short_name_suite) 16 | 17 | BOOST_AUTO_TEST_CASE(is_policy_test) 18 | { 19 | static_assert(policy::is_policy_v>>, 20 | "Policy test has failed"); 21 | } 22 | 23 | BOOST_AUTO_TEST_CASE(constructor_and_get_test) 24 | { 25 | constexpr auto c_a = policy::short_name<'a'>; 26 | static_assert(c_a.short_name() == "a"); 27 | 28 | constexpr auto c_4 = policy::short_name<'4'>; 29 | static_assert(c_4.short_name() == "4"); 30 | 31 | constexpr auto s_a = policy::short_name_t{AR_STRING("a"){}}; 32 | static_assert(s_a.short_name() == "a"); 33 | } 34 | 35 | #ifdef AR_ENABLE_CPP20_STRINGS 36 | BOOST_AUTO_TEST_CASE(string_literal_test) 37 | { 38 | const auto s_a = policy::short_name_t{"a"_S}; 39 | static_assert(s_a.short_name() == "a"); 40 | } 41 | #endif 42 | 43 | BOOST_AUTO_TEST_CASE(death_test) 44 | { 45 | test::death_test_compile({{R"( 46 | #include "arg_router/policy/short_name.hpp" 47 | int main() { 48 | const auto ln = arg_router::policy::short_name_utf8; 49 | return 0; 50 | } 51 | )", 52 | "Short name must only be one character", 53 | "short_name_must_be_one_character_test"}, 54 | { 55 | R"( 56 | #include "arg_router/policy/short_name.hpp" 57 | int main() { 58 | const auto ln = arg_router::policy::short_name<'-'>; 59 | return 0; 60 | } 61 | )", 62 | "Short name with short prefix cannot match the long prefix", 63 | "short_name_cannot_start_with_argument_prefix_test"}}); 64 | } 65 | 66 | BOOST_AUTO_TEST_SUITE_END() 67 | 68 | BOOST_AUTO_TEST_SUITE_END() 69 | -------------------------------------------------------------------------------- /test/test_printers.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #pragma once 6 | 7 | #include "arg_router/parsing/parsing.hpp" 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace arg_router 15 | { 16 | namespace parsing 17 | { 18 | inline std::ostream& operator<<(std::ostream& stream, prefix_type prefix) 19 | { 20 | return stream << to_string(prefix); 21 | } 22 | 23 | inline std::ostream& operator<<(std::ostream& stream, const token_type& token) 24 | { 25 | return stream << to_string(token); 26 | } 27 | 28 | inline std::ostream& operator<<(std::ostream& stream, pre_parse_action action) 29 | { 30 | switch (action) { 31 | case pre_parse_action::skip_node: return stream << "skip_node"; 32 | case pre_parse_action::valid_node: return stream << "valid_node"; 33 | case pre_parse_action::skip_node_but_use_sub_targets: 34 | return stream << "skip_node_but_use_sub_targets"; 35 | default: return stream << ""; 36 | } 37 | } 38 | 39 | inline std::ostream& operator<<(std::ostream& stream, pre_parse_result result) 40 | { 41 | if (result.has_error()) { 42 | return stream << ""; 43 | } 44 | 45 | return stream << result.extract(); 46 | } 47 | } // namespace parsing 48 | 49 | template 50 | std::ostream& operator<<(std::ostream& stream, span v) 51 | { 52 | stream << "{"; 53 | for (auto&& item : v) { 54 | stream << item << ","; 55 | } 56 | return stream << "}"; 57 | } 58 | 59 | inline std::ostream& operator<<(std::ostream& stream, error_code ec) 60 | { 61 | return stream << static_cast>(ec); 62 | } 63 | } // namespace arg_router 64 | 65 | // Naughty, but only used in the test code 66 | namespace std 67 | { 68 | template 69 | ostream& operator<<(ostream& stream, const optional& o) 70 | { 71 | if (o) { 72 | return stream << *o; 73 | } 74 | return stream << "{}"; 75 | } 76 | 77 | template 78 | ostream& operator<<(ostream& stream, const vector& v) 79 | { 80 | stream << "{"; 81 | for (auto&& item : v) { 82 | stream << item << ","; 83 | } 84 | return stream << "}"; 85 | } 86 | } // namespace std 87 | -------------------------------------------------------------------------------- /test/traits_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/traits.hpp" 6 | 7 | #include "test_helpers.hpp" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace arg_router; 14 | using namespace std::string_view_literals; 15 | 16 | BOOST_AUTO_TEST_SUITE(traits_suite) 17 | 18 | BOOST_AUTO_TEST_CASE(is_tuple_like_test) 19 | { 20 | static_assert(traits::is_tuple_like_v>, "Fail"); 21 | static_assert(traits::is_tuple_like_v>, "Fail"); 22 | static_assert(!traits::is_tuple_like_v, "Fail"); 23 | static_assert(!traits::is_tuple_like_v, "Fail"); 24 | } 25 | 26 | BOOST_AUTO_TEST_CASE(is_specialisation_test) 27 | { 28 | struct test { 29 | }; 30 | 31 | static_assert(traits::is_specialisation_v>, "Fail"); 32 | static_assert(traits::is_specialisation_v>, "Fail"); 33 | static_assert(traits::is_specialisation_v, "Fail"); 34 | static_assert(traits::is_specialisation_v>, "Fail"); 35 | 36 | static_assert(!traits::is_specialisation_v, "Fail"); 37 | static_assert(!traits::is_specialisation_v, "Fail"); 38 | } 39 | 40 | BOOST_AUTO_TEST_CASE(is_specialisation_of_test) 41 | { 42 | static_assert(traits::is_specialisation_of_v, std::vector>, "Fail"); 43 | 44 | static_assert(!traits::is_specialisation_of_v, std::basic_string_view>, 45 | "Fail"); 46 | static_assert(!traits::is_specialisation_of_v, std::deque>, "Fail"); 47 | static_assert(!traits::is_specialisation_of_v, "Fail"); 48 | } 49 | 50 | BOOST_AUTO_TEST_CASE(is_same_when_despecialised_test) 51 | { 52 | static_assert(traits::is_same_when_despecialised_v, std::vector>, "Fail"); 53 | static_assert(traits::is_same_when_despecialised_v, std::vector>, 54 | "Fail"); 55 | 56 | static_assert(!traits::is_same_when_despecialised_v, std::deque>, "Fail"); 57 | static_assert(!traits::is_same_when_despecialised_v, int>, "Fail"); 58 | static_assert(!traits::is_same_when_despecialised_v>, "Fail"); 59 | static_assert(!traits::is_same_when_despecialised_v, "Fail"); 60 | } 61 | 62 | BOOST_AUTO_TEST_CASE(integral_constant_test) 63 | { 64 | static_assert(std::is_same_v::value_type, int>, "Fail"); 65 | static_assert(traits::integral_constant<-42>::value == -42, "Fail"); 66 | 67 | static_assert( 68 | std::is_same_v::value_type, std::size_t>, 69 | "Fail"); 70 | static_assert(traits::integral_constant::value == 42, "Fail"); 71 | } 72 | 73 | BOOST_AUTO_TEST_SUITE_END() 74 | -------------------------------------------------------------------------------- /test/utility/compile_time_optional_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/utility/compile_time_optional.hpp" 6 | 7 | #include "test_helpers.hpp" 8 | 9 | using namespace std::string_literals; 10 | using namespace arg_router; 11 | 12 | BOOST_AUTO_TEST_SUITE(utility_suite) 13 | 14 | BOOST_AUTO_TEST_SUITE(compile_time_optional_suite) 15 | 16 | BOOST_AUTO_TEST_CASE(constructor_test) 17 | { 18 | constexpr auto cto1 = utility::compile_time_optional{}; 19 | static_assert(cto1.empty, "Failed"); 20 | static_assert(!cto1, "Failed"); 21 | 22 | constexpr auto cto2 = utility::compile_time_optional{42}; 23 | static_assert(!cto2.empty, "Failed"); 24 | static_assert(cto2, "Failed"); 25 | 26 | const auto cto3 = utility::compile_time_optional{"hello"s}; 27 | static_assert(!cto3.empty, "Failed"); 28 | static_assert(cto3, "Failed"); 29 | 30 | const auto val = 42; 31 | auto cto4 = utility::compile_time_optional{std::cref(val)}; 32 | static_assert(!cto4.empty, "Failed"); 33 | static_assert(cto4, "Failed"); 34 | } 35 | 36 | BOOST_AUTO_TEST_CASE(derefence_operator_test) 37 | { 38 | constexpr auto cto1 = utility::compile_time_optional{42}; 39 | static_assert(*cto1 == 42, "Failed"); 40 | 41 | const auto cto2 = utility::compile_time_optional{"hello"s}; 42 | BOOST_CHECK_EQUAL(*cto2, "hello"); 43 | 44 | auto cto3 = utility::compile_time_optional{42}; 45 | *cto3 = 84; 46 | BOOST_CHECK_EQUAL(*cto3, 84); 47 | 48 | auto val = 42; 49 | auto cto4 = utility::compile_time_optional{std::ref(val)}; 50 | *cto4 = 84; 51 | BOOST_CHECK_EQUAL(*cto4, 84); 52 | } 53 | 54 | BOOST_AUTO_TEST_CASE(derefence_to_member_operator_test) 55 | { 56 | const auto cto1 = utility::compile_time_optional{"hello"s}; 57 | BOOST_CHECK_EQUAL(cto1->size(), 5); 58 | 59 | auto val = "hello"s; 60 | auto cto2 = utility::compile_time_optional{std::ref(val)}; 61 | BOOST_CHECK_EQUAL(cto2->size(), 5); 62 | *cto2 += " world"; 63 | BOOST_CHECK_EQUAL(cto2->size(), 11); 64 | } 65 | 66 | BOOST_AUTO_TEST_SUITE_END() 67 | 68 | BOOST_AUTO_TEST_SUITE_END() 69 | -------------------------------------------------------------------------------- /test/utility/string_view_ops_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/utility/string_view_ops.hpp" 6 | 7 | #include "test_helpers.hpp" 8 | 9 | using namespace arg_router; 10 | using namespace utility::string_view_ops; 11 | using namespace std::string_literals; 12 | using namespace std::string_view_literals; 13 | 14 | BOOST_AUTO_TEST_SUITE(string_view_ops_suite) 15 | 16 | BOOST_AUTO_TEST_CASE(concatenation_operator) 17 | { 18 | auto f = [](auto lhs, auto rhs, auto expected) { 19 | const auto result = lhs + rhs; 20 | static_assert( 21 | std::is_same_v, std::decay_t>, 22 | "Result is incorrect type"); 23 | BOOST_CHECK_EQUAL(result, expected); 24 | }; 25 | 26 | test::data_set(f, 27 | std::tuple{ 28 | std::tuple{"hello "s, "world"sv, "hello world"s}, 29 | std::tuple{"hello "sv, "world"s, "hello world"s}, 30 | }); 31 | } 32 | 33 | BOOST_AUTO_TEST_SUITE_END() 34 | -------------------------------------------------------------------------------- /test/utility/type_hash_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 by Camden Mannett. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #include "arg_router/utility/type_hash.hpp" 6 | #include "arg_router/policy/description.hpp" 7 | #include "arg_router/policy/validator.hpp" 8 | 9 | #include "test_helpers.hpp" 10 | 11 | using namespace arg_router; 12 | 13 | namespace 14 | { 15 | using primitive_types = 16 | std::tuple; 17 | } 18 | 19 | BOOST_AUTO_TEST_SUITE(utility_suite) 20 | 21 | BOOST_AUTO_TEST_SUITE(type_hash_suite) 22 | 23 | BOOST_AUTO_TEST_CASE(negative_primitives_test) 24 | { 25 | utility::tuple_type_iterator([](auto i) { 26 | utility::tuple_type_iterator([i](auto j) { 27 | using first_type = std::tuple_element_t; 28 | using second_type = std::tuple_element_t; 29 | 30 | if constexpr (i != j) { 31 | BOOST_CHECK_NE(utility::type_hash(), utility::type_hash()); 32 | } else { 33 | BOOST_CHECK_EQUAL(utility::type_hash(), 34 | utility::type_hash()); 35 | } 36 | }); 37 | }); 38 | } 39 | 40 | BOOST_AUTO_TEST_CASE(positive_primitives_test) 41 | { 42 | utility::tuple_type_iterator([](auto i) { 43 | using primitive_type = std::tuple_element_t; 44 | 45 | BOOST_CHECK_EQUAL(utility::type_hash(), 46 | utility::type_hash()); 47 | }); 48 | } 49 | 50 | BOOST_AUTO_TEST_CASE(node_test) 51 | { 52 | const auto a = root(mode(arg(policy::long_name, 53 | policy::required, 54 | policy::description), 55 | policy::router{[&](auto) {}}), 56 | policy::validation::default_validator); 57 | const auto b = root(mode(arg(policy::long_name, 58 | policy::required, 59 | policy::description), 60 | policy::router{[&](auto) {}}), 61 | policy::validation::default_validator); 62 | 63 | BOOST_CHECK_NE(utility::type_hash(), utility::type_hash()); 64 | BOOST_CHECK_EQUAL(utility::type_hash(), utility::type_hash()); 65 | BOOST_CHECK_EQUAL(utility::type_hash(), utility::type_hash()); 66 | } 67 | 68 | BOOST_AUTO_TEST_CASE(const_test) 69 | { 70 | BOOST_CHECK_NE(utility::type_hash(), utility::type_hash()); 71 | } 72 | 73 | BOOST_AUTO_TEST_CASE(alias_test) 74 | { 75 | using alias_type = std::uint64_t; 76 | BOOST_CHECK_EQUAL(utility::type_hash(), utility::type_hash()); 77 | } 78 | 79 | BOOST_AUTO_TEST_CASE(short_name_test) 80 | { 81 | auto a = flag(policy::short_name<'a'>); 82 | auto b = flag(policy::short_name<'b'>); 83 | BOOST_CHECK_NE(utility::type_hash(), utility::type_hash()); 84 | } 85 | 86 | BOOST_AUTO_TEST_SUITE_END() 87 | 88 | BOOST_AUTO_TEST_SUITE_END() 89 | -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arg-router", 3 | "version": "1.1.0", 4 | "dependencies": [ 5 | { 6 | "name": "boost-asio", 7 | "features": [] 8 | }, 9 | "boost-lexical-cast", 10 | "boost-mp11", 11 | "boost-preprocessor", 12 | "boost-process", 13 | { 14 | "name": "boost-regex", 15 | "features": [] 16 | }, 17 | "boost-test", 18 | "span-lite" 19 | ] 20 | } 21 | --------------------------------------------------------------------------------