From 24137dbca5668b2ea1f1a6ce1032fd35546ee7a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Musia=C5=82?=
<111433005+SpectraL519@users.noreply.github.com>
Date: Sun, 24 Mar 2024 17:59:50 +0100
Subject: [PATCH] YT-CPPAP-1: Repository cleanup and preparation for version
1.1
- Reorganized the project folder structure to use more descriptive names
- Improved formatting scripts to enumerate the formatted files and run clang-format check with the `--check` flag
- Modified the `install_clang_format_17.sh` script to install both `clang-17` and `clang-format-17` toolchains
- Added a format checking workflow
- Modified the `g++` and `clang++` workflows to properly set both C and C++ comilers with CMake
- Added the change log
---
.clang-format | 62 +-
.github/workflows/clang.yaml | 15 +-
.github/workflows/format.yaml | 25 +
.github/workflows/gpp.yaml | 5 +-
.github/workflows/test.yaml | 8 +-
README.md | 85 ++-
change_log.md | 33 +
example/.gitignore | 1 -
example/CMakeLists.txt | 2 +-
example/{src => source}/convert_numbers.cpp | 17 +-
example/{src => source}/merge_files.cpp | 15 +-
example/{src => source}/power.cpp | 11 +-
example/{src => source}/verbosity.cpp | 14 +-
format/unix_like.sh | 4 -
format/win.ps1 | 2 -
include/ap/argument_parser.hpp | 628 +++++++-----------
scripts/env/install_clang17_toolchain.sh | 17 +
scripts/format/unix.sh | 35 +
scripts/format/windows.ps1 | 37 ++
test/CMakeLists.txt | 2 +-
test/include/argument_parser_test_fixture.hpp | 20 +-
.../optional_argument_test_fixture.hpp | 42 +-
.../positional_argument_test_fixture.hpp | 38 +-
test/{src => source}/test_argument_name.cpp | 7 +-
.../test_argument_parser_add_argument.cpp | 83 +--
.../test_argument_parser_info.cpp | 8 +-
.../test_argument_parser_parse_args.cpp | 176 ++---
test/{src => source}/test_boolean.cpp | 6 +-
test/{src => source}/test_nargs_range.cpp | 7 +-
.../test_optional_argument.cpp | 181 ++---
.../test_positional_argument.cpp | 153 +----
31 files changed, 699 insertions(+), 1040 deletions(-)
create mode 100644 .github/workflows/format.yaml
create mode 100644 change_log.md
delete mode 100644 example/.gitignore
rename example/{src => source}/convert_numbers.cpp (71%)
rename example/{src => source}/merge_files.cpp (74%)
rename example/{src => source}/power.cpp (78%)
rename example/{src => source}/verbosity.cpp (85%)
delete mode 100755 format/unix_like.sh
delete mode 100644 format/win.ps1
create mode 100644 scripts/env/install_clang17_toolchain.sh
create mode 100644 scripts/format/unix.sh
create mode 100644 scripts/format/windows.ps1
rename test/{src => source}/test_argument_name.cpp (98%)
rename test/{src => source}/test_argument_parser_add_argument.cpp (61%)
rename test/{src => source}/test_argument_parser_info.cpp (96%)
rename test/{src => source}/test_argument_parser_parse_args.cpp (81%)
rename test/{src => source}/test_boolean.cpp (76%)
rename test/{src => source}/test_nargs_range.cpp (98%)
rename test/{src => source}/test_optional_argument.cpp (64%)
rename test/{src => source}/test_positional_argument.cpp (59%)
diff --git a/.clang-format b/.clang-format
index b7614ae..626e8fc 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,6 +1,6 @@
---
Language: Cpp
-Standard: Latest
+Standard: c++20
DisableFormat: false
@@ -8,69 +8,41 @@ DisableFormat: false
IndentWidth: 4
TabWidth: 4
UseTab: Never
-ColumnLimit: 80
+ColumnLimit: 100
ContinuationIndentWidth: 4
# Alignment options
AlignAfterOpenBracket: BlockIndent
AlignArrayOfStructures: Right
-AlignConsecutiveAssignments:
- Enabled: false
- AcrossEmptyLines: false
- AcrossComments: false
- AlignCompound: false
- PadOperators: false
-AlignConsecutiveBitFields:
- Enabled: false
- AcrossEmptyLines: false
- AcrossComments: false
- AlignCompound: false
- PadOperators: false
-AlignConsecutiveDeclarations:
- Enabled: false
- AcrossEmptyLines: false
- AcrossComments: false
- AlignCompound: false
- PadOperators: false
-AlignConsecutiveMacros:
- Enabled: false
- AcrossEmptyLines: false
- AcrossComments: false
- AlignCompound: false
- PadOperators: false
+AlignConsecutiveAssignments: false
+AlignConsecutiveBitFields: false
+AlignConsecutiveDeclarations: false
+AlignConsecutiveMacros: false
AlignConsecutiveShortCaseStatements:
- Enabled: true
- AcrossEmptyLines: true
- AcrossComments: true
- AlignCaseColons: false
+ Enabled: false
AlignEscapedNewlines: Left
AlignOperands: AlignAfterOperator
-AlignTrailingComments:
- Kind: Always
- OverEmptyLines: 0
+AlignTrailingComments: false
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: true
-AllowShortFunctionsOnASingleLine: Inline
+AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
-AllowShortLambdasOnASingleLine: Inline
+AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
-BreakAfterAttributes: Leave
-BreakAfterJavaFieldAnnotations: true
-BreakArrays: false
+BreakAfterAttributes: Never
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakBeforeConceptDeclarations: Always
-BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
@@ -123,14 +95,14 @@ ShortNamespaceLines: 0
IndentAccessModifiers: false
AccessModifierOffset: -4
-ConstructorInitializerIndentWidth: 4
+ConstructorInitializerIndentWidth: 0
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
PackConstructorInitializers: NextLine
-SeparateDefinitionBlocks: Leave
+SeparateDefinitionBlocks: Always
-IndentCaseBlocks: true
-IndentCaseLabels: true
+IndentCaseBlocks: false
+IndentCaseLabels: false
IndentWrappedFunctionNames: false
LambdaBodyIndentation: Signature
@@ -154,7 +126,7 @@ SpaceAfterLogicalNot: true
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
-SpaceBeforeCaseColon: true
+SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeParens: Custom
@@ -164,7 +136,7 @@ SpaceBeforeParensOptions:
AfterFunctionDeclarationName: false
AfterFunctionDefinitionName: false
AfterIfMacros: false
- AfterOverloadedOperator: true
+ AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml
index d7bd54b..dce6066 100644
--- a/.github/workflows/clang.yaml
+++ b/.github/workflows/clang.yaml
@@ -3,9 +3,6 @@ on:
push:
branches:
- '*'
- pull_request:
- branches:
- - master
jobs:
build:
@@ -16,14 +13,20 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
+ - name: Prepare
+ shell: bash
+ run: |
+ sudo bash ./scripts/env/install_clang17_toolchain.sh
+ continue-on-error: false
+
- name: Build
shell: bash
env:
- CC: clang-14
- CXX: clang++-14
+ CC: clang-17
+ CXX: clang++-17
run: |
cd example
- cmake -B build -DCMAKE_CXX_COMPILER=clang++-14
+ cmake -B build -DCMAKE_CXX_COMPILER=clang++-17 -DCMAKE_C_COMPILER=clang-17
cd build
make
continue-on-error: false
diff --git a/.github/workflows/format.yaml b/.github/workflows/format.yaml
new file mode 100644
index 0000000..262e684
--- /dev/null
+++ b/.github/workflows/format.yaml
@@ -0,0 +1,25 @@
+name: format
+on:
+ push:
+ branches:
+ - '*'
+
+jobs:
+ build:
+ name: Test code formatting
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Prepare
+ shell: bash
+ run: |
+ sudo bash ./scripts/env/install_clang17_toolchain.sh
+ continue-on-error: false
+
+ - name: Test formatting
+ shell: bash
+ run: |
+ bash ./scripts/format/unix.sh --check
diff --git a/.github/workflows/gpp.yaml b/.github/workflows/gpp.yaml
index 8a327c9..d561f21 100644
--- a/.github/workflows/gpp.yaml
+++ b/.github/workflows/gpp.yaml
@@ -3,9 +3,6 @@ on:
push:
branches:
- '*'
- pull_request:
- branches:
- - master
jobs:
build:
@@ -23,7 +20,7 @@ jobs:
CXX: g++-11
run: |
cd example
- cmake -B build -DCMAKE_CXX_COMPILER=g++-11
+ cmake -B build -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_C_COMPILER=gcc-11
cd build
make
continue-on-error: false
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 8532e7a..8bd374a 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -3,9 +3,6 @@ on:
push:
branches:
- '*'
- pull_request:
- branches:
- - master
jobs:
build_and_test:
@@ -17,9 +14,12 @@ jobs:
uses: actions/checkout@v2
- name: Prepare
+ env:
+ CC: gcc-11
+ CXX: g++-11
run: |
cd test
- cmake -B build -DCMAKE_CXX_COMPILER=g++-11
+ cmake -B build -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_C_COMPILER=gcc-11
continue-on-error: false
- name: Build test executable
diff --git a/README.md b/README.md
index 74c7cad..a0af400 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,7 @@ Command-line argument parser for C++20
[![g++](https://github.com/SpectraL519/cpp-ap/actions/workflows/gpp.yaml/badge.svg)](https://github.com/SpectraL519/cpp-ap/actions/workflows/g++)
[![clang++](https://github.com/SpectraL519/cpp-ap/actions/workflows/clang.yaml/badge.svg)](https://github.com/SpectraL519/cpp-ap/actions/workflows/clang++)
[![test](https://github.com/SpectraL519/cpp-ap/actions/workflows/test.yaml/badge.svg)](https://github.com/SpectraL519/cpp-ap/actions/workflows/test)
+[![format](https://github.com/SpectraL519/cpp-ap/actions/workflows/format.yaml/badge.svg)](https://github.com/SpectraL519/cpp-ap/actions/workflows/format)
@@ -34,11 +35,12 @@ The `CPP-AP` library does not require installing any additional tools or heavy l
* [Parsing arguments](#parsing-arguments)
* [Examples](#examples)
* [Dev notes](#dev-notes)
- * [Requirements](#requirements)
* [Building and testing](#building-and-testing)
+ * [Formatting](#formatting)
* [Documentation](#documentation)
* [Compiler support](#compiler-support)
* [Licence](#licence)
+* [Change log](change_log.md)
@@ -410,7 +412,7 @@ Open your terminal in the project's example directory:
cd /example
```
-The examples' source files are in the `/example/src` directory.
+The examples' source files are in the `/example/source` directory.
> **Note:** Each source file is a sepparate example.
@@ -437,55 +439,74 @@ The compiled binaries will appear in the `/example/build/bin` dire
## Dev notes
-#### Requirements:
- * Supported compiler (check compiler support [here](#compiler-support))
- * clang-format-17 ([ubuntu download tutorial](https://ubuntuhandbook.org/index.php/2023/09/how-to-install-clang-17-or-16-in-ubuntu-22-04-20-04/amp/?fbclid=IwAR1ZfJpoiitjwn8aMlKVWpFdkYmUqtaQwraJBju09v1gtc0jQANTgVeCuMY))
+### Building and testing:
-
+First build the testing executable:
-#### Building and testing:
+```shell
+cd /test/
+cmake -B build
+cd build
+make
+```
-1. Build the testing executable:
+or alternatively:
- ```shell
- cd /test/
- cmake -B build
- cd build
- make
- ```
+```shell
+cd /test/
+mkdir build && cd build
+cmake ..
+make
+```
- or
+> **NOTE:** Building on Windows - use the `-G "Unix Makefiles"` option when running CMake to build a GNU Make project instead of a default Visual Studio project.
- ```shell
- cd /test/
- mkdir build && cd build
- cmake ..
- make
- ```
+Run the tests:
-2. Run tests
+> **NOTE:** The test executable is generated in the `/test/build` directory.
+
+* All tests:
- Run all tests:
```shell
- cd /test/build
./test
```
- Run a single test suite:
+* A single test suite:
+
```shell
./test -ts=""
```
> **Note**: Test suites in the project have the same name as the files they're in.
-3. Tips and tricks:
+
- * Changing the CMake generator:
+### Formatting
- If you wish for CMake to generate a different type of project, use the `-G` option, e.g. (building a Make project on Windows instead of a VS project):
- ```
- cmake -G "Unix Makefiles"
- ```
+> **NOTE:** To ensure new line encoding compatibility the project uses unix new line encoding.
+>
+> This can be set using the `git config --global core.autocrlf true` command.
+> More details can be found [here](https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings)
+
+> **NOTE:** The project uses `clang-format-17`.
+>
+> To install this tool on ubuntu run `sudo bash ./scripts/env/install_clang17_toolchain.sh`.
+>
+> On windows you can download the LLVM package from the official LLVM [GitHub release page](https://github.com/llvm/llvm-project/releases/tag/llvmorg-17.0.1)
+
+To format the code use run the following:
+
+```shell
+# Unix platforms
+./scripts/format/unix.sh
+```
+
+```shell
+# Windows: powershell
+./scripts/format/windows.ps1
+```
+
+To run a forrmat check use the scripts mentioned above with a `--check` flag.
@@ -511,6 +532,8 @@ The documentation for this project can be generated using Doxygen:
As of now the project supports the **GNU G++** and **Clang++** compilers with `C++20` support on Linux and Windows.
+> **NOTE:** To build the project using clang you will need to install the `clang-17` toolchain using the script or website mentioned in the [Formatting](#formatting) section.
+
diff --git a/change_log.md b/change_log.md
new file mode 100644
index 0000000..b09d6e4
--- /dev/null
+++ b/change_log.md
@@ -0,0 +1,33 @@
+# CPP-AP : Change log
+
+### Version 1.0
+
+* Initial version of `argument_parser.hpp` with corresponding tests
+* Initial versions of `.clang-format` and `Doxyfile` configuration files
+* Formatting scripts:
+ * Unix: `format/unix_like.sh`
+ * Windows `format/win.ps1`
+* Example programs:
+ * convert_number
+ * merge_files
+ * power
+ * verbosity
+* Github workflows:
+ * g++
+ * clang++
+ * test
+* MIT Licence
+
+
+
+
+### Version 1.1
+
+* Added `change_log.md`
+* Reorganized project folder strucure:
+ * Renamed folders `src` to `source`
+ * Moved formatting scripts to `scripts/format/`
+* Aligned the `.clang-format` configuration file
+* Added the `install_clang17_toolchain.sh` env script
+* Added the `format` workflow
+* Switched from the `` to the `` library for all current container operations
diff --git a/example/.gitignore b/example/.gitignore
deleted file mode 100644
index 8fce603..0000000
--- a/example/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-data/
diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt
index eeb5d80..7db437b 100644
--- a/example/CMakeLists.txt
+++ b/example/CMakeLists.txt
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.12)
project(cpp-ap-examples)
# Structure
-set(SOURCE_DIR "src")
+set(SOURCE_DIR "source")
set(INCLUDE_DIRS "include" "../include")
set(BINARY_DIR "bin")
set(EXECUTABLE_DIR "bin")
diff --git a/example/src/convert_numbers.cpp b/example/source/convert_numbers.cpp
similarity index 71%
rename from example/src/convert_numbers.cpp
rename to example/source/convert_numbers.cpp
index ebf5fb6..21ee5c9 100644
--- a/example/src/convert_numbers.cpp
+++ b/example/source/convert_numbers.cpp
@@ -3,21 +3,18 @@
#include
#include
-
int main(int argc, char* argv[]) {
ap::argument_parser parser;
parser.program_name("convert numbers")
- .program_description("shows the correct way of using dthe choices parameter")
- .default_optional_arguments({ap::default_argument::optional::help});
+ .program_description("shows the correct way of using dthe choices parameter")
+ .default_optional_arguments({ ap::default_argument::optional::help });
- parser.add_optional_argument("number", "n")
- .nargs(ap::nargs::any())
- .help("positive integer value");
+ parser.add_optional_argument("number", "n").nargs(ap::nargs::any()).help("positive integer value");
parser.add_optional_argument("base", "b")
- .required()
- .default_value("dec")
- .choices({"bin", "dec", "hex"})
- .help("output number format base");
+ .required()
+ .default_value("dec")
+ .choices({ "bin", "dec", "hex" })
+ .help("output number format base");
try {
parser.parse_args(argc, argv);
diff --git a/example/src/merge_files.cpp b/example/source/merge_files.cpp
similarity index 74%
rename from example/src/merge_files.cpp
rename to example/source/merge_files.cpp
index 48b846b..eed1c2a 100644
--- a/example/src/merge_files.cpp
+++ b/example/source/merge_files.cpp
@@ -1,17 +1,18 @@
#include
-#include
#include
+#include
#include
-
int main(int argc, char* argv[]) {
ap::argument_parser parser;
parser.program_name("merge files")
- .program_description("shows the correct way of using default arguments")
- .default_optional_arguments({ap::default_argument::optional::help,
- ap::default_argument::optional::multi_input,
- ap::default_argument::optional::output});
+ .program_description("shows the correct way of using default arguments")
+ .default_optional_arguments(
+ { ap::default_argument::optional::help,
+ ap::default_argument::optional::multi_input,
+ ap::default_argument::optional::output }
+ );
try {
parser.parse_args(argc, argv);
@@ -30,7 +31,7 @@ int main(int argc, char* argv[]) {
const auto output_file_name = parser.value("output");
std::ofstream output_file(output_file_name);
- if (!output_file.is_open())
+ if (not output_file.is_open())
throw std::runtime_error("Cannot open file: " + output_file_name);
for (const auto& input_file_name : input_file_name_list) {
diff --git a/example/src/power.cpp b/example/source/power.cpp
similarity index 78%
rename from example/src/power.cpp
rename to example/source/power.cpp
index 2d9c4f6..2cc3499 100644
--- a/example/src/power.cpp
+++ b/example/source/power.cpp
@@ -1,21 +1,18 @@
#include
-#include
#include
+#include
int main(int argc, char* argv[]) {
// create the parser class instance
ap::argument_parser parser;
- parser.program_name("power calculator")
- .program_description("calculates the value of an expression: base & exponent");
+ parser.program_name("power calculator").program_description("calculates the value of an expression: base & exponent");
// add arguments
parser.add_positional_argument("base").help("the exponentation base value");
- parser.add_optional_argument("exponent", "e")
- .nargs(ap::nargs::any())
- .help("the exponent value");
+ parser.add_optional_argument("exponent", "e").nargs(ap::nargs::any()).help("the exponent value");
- parser.default_optional_arguments({ap::default_argument::optional::help});
+ parser.default_optional_arguments({ ap::default_argument::optional::help });
// parse command-line arguments
try {
diff --git a/example/src/verbosity.cpp b/example/source/verbosity.cpp
similarity index 85%
rename from example/src/verbosity.cpp
rename to example/source/verbosity.cpp
index 9a63aa6..c100a0e 100644
--- a/example/src/verbosity.cpp
+++ b/example/source/verbosity.cpp
@@ -3,12 +3,9 @@
#include
#include
-
namespace {
-enum class verbosity_level : uint16_t {
- low, mid, high
-};
+enum class verbosity_level : uint16_t { low, mid, high };
std::istream& operator>>(std::istream& input, verbosity_level& v) {
uint16_t value;
@@ -53,16 +50,13 @@ void print_msg(const verbosity_level verbosity) {
} // namespace
-
int main(int argc, char* argv[]) {
ap::argument_parser parser;
- parser
- .program_name("verbosity level")
+ parser.program_name("verbosity level")
.program_description("shows the correct way of using enums as a parser argument type")
- .default_optional_arguments({ap::default_argument::optional::help});
+ .default_optional_arguments({ ap::default_argument::optional::help });
- parser
- .add_optional_argument("verbosity_level", "v")
+ parser.add_optional_argument("verbosity_level", "v")
.default_value(verbosity_level::low)
.implicit_value(verbosity_level::mid)
.nargs(1);
diff --git a/format/unix_like.sh b/format/unix_like.sh
deleted file mode 100755
index a1bafb3..0000000
--- a/format/unix_like.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-# Recursively find .hpp files and format them with clang-format
-find . -type f -name "*.hpp" -o -name "*.cpp" -exec clang-format -i {} \;
diff --git a/format/win.ps1 b/format/win.ps1
deleted file mode 100644
index e8e365d..0000000
--- a/format/win.ps1
+++ /dev/null
@@ -1,2 +0,0 @@
-# Recursively find .hpp files and format them with clang-format
-Get-ChildItem -Recurse -Include *.hpp, *.cpp | ForEach-Object { clang-format -i $_.FullName }
diff --git a/include/ap/argument_parser.hpp b/include/ap/argument_parser.hpp
index 37492bf..dfc9416 100644
--- a/include/ap/argument_parser.hpp
+++ b/include/ap/argument_parser.hpp
@@ -36,7 +36,6 @@ SOFTWARE.
#pragma once
-#include
#include
#include
#include
@@ -45,13 +44,14 @@ SOFTWARE.
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
#include
-#include
#ifdef AP_TESTING
@@ -68,7 +68,6 @@ namespace ap {
class argument_parser;
-
/// @brief Template type validation utility.
namespace utility {
@@ -77,8 +76,7 @@ namespace utility {
* @tparam T Type to check.
*/
template
-concept readable =
- requires(T value, std::istream& input_stream) { input_stream >> value; };
+concept readable = requires(T value, std::istream& input_stream) { input_stream >> value; };
/**
* @brief The concept is satisfied when `T` is readable, copy constructible and assignable.
@@ -86,8 +84,7 @@ concept readable =
*/
template
concept valid_argument_value_type =
- readable and
- std::copy_constructible and std::assignable_from;
+ readable and std::copy_constructible and std::assignable_from;
/**
* @brief The concept is satisfied when `T` is comparable using the equality operator `==`.
@@ -108,7 +105,6 @@ inline constexpr bool is_valid_type_v = std::disjunction_v_default;
}
@@ -154,7 +155,7 @@ class range {
* @param n The value count to check.
* @return Ordering relationship between the count and the range.
*/
- [[nodiscard]] std::weak_ordering contains(const range::count_type n) const {
+ [[nodiscard]] std::weak_ordering contains(const range::count_type n) const noexcept {
if (not (this->_nlow.has_value() or this->_nhigh.has_value()))
return std::weak_ordering::equivalent;
@@ -169,18 +170,16 @@ class range {
}
if (this->_nlow.has_value())
- return (n < this->_nlow.value()) ? std::weak_ordering::less
- : std::weak_ordering::equivalent;
+ return (n < this->_nlow.value()) ? std::weak_ordering::less : std::weak_ordering::equivalent;
- return (n > this->_nhigh.value()) ? std::weak_ordering::greater
- : std::weak_ordering::equivalent;
+ return (n > this->_nhigh.value()) ? std::weak_ordering::greater : std::weak_ordering::equivalent;
}
- friend range at_least(const count_type);
- friend range more_than(const count_type);
- friend range less_than(const count_type);
- friend range up_to(const count_type);
- friend range any();
+ friend range at_least(const count_type) noexcept;
+ friend range more_than(const count_type) noexcept;
+ friend range less_than(const count_type) noexcept;
+ friend range up_to(const count_type) noexcept;
+ friend range any() noexcept;
private:
/**
@@ -189,7 +188,7 @@ class range {
* @param nhigh The optional upper bound of the range.
*/
range(const std::optional nlow, const std::optional nhigh)
- : _nlow(nlow), _nhigh(nhigh) {}
+ : _nlow(nlow), _nhigh(nhigh) {}
std::optional _nlow;
std::optional _nhigh;
@@ -203,7 +202,7 @@ class range {
* @param n The lower bound.
* @return Built `range` class instance.
*/
-[[nodiscard]] inline range at_least(const range::count_type n) {
+[[nodiscard]] inline range at_least(const range::count_type n) noexcept {
return range(n, std::nullopt);
}
@@ -212,7 +211,7 @@ class range {
* @param n The lower bound.
* @return Built `range` class instance.
*/
-[[nodiscard]] inline range more_than(const range::count_type n) {
+[[nodiscard]] inline range more_than(const range::count_type n) noexcept {
return range(n + 1, std::nullopt);
}
@@ -221,7 +220,7 @@ class range {
* @param n The upper bound
* @return Built `range` class instance.
*/
-[[nodiscard]] inline range less_than(const range::count_type n) {
+[[nodiscard]] inline range less_than(const range::count_type n) noexcept {
return range(std::nullopt, n - 1);
}
@@ -230,7 +229,7 @@ class range {
* @param n The upper bound
* @return Built `range` class instance.
*/
-[[nodiscard]] inline range up_to(const range::count_type n) {
+[[nodiscard]] inline range up_to(const range::count_type n) noexcept {
return range(std::nullopt, n);
}
@@ -238,13 +237,12 @@ class range {
* @brief `range` class builder function. Creates a range [0, inf].
* @return Built `range` class instance.
*/
-[[nodiscard]] inline range any() {
+[[nodiscard]] inline range any() noexcept {
return range(std::nullopt, std::nullopt);
}
} // namespace nargs
-
/// @brief Defines valued argument action traits.
struct valued_action {
template
@@ -288,41 +286,40 @@ using action_variant_type =
* @return True if the held action is a void action.
*/
template
-[[nodiscard]] inline bool is_void_action(const action_variant_type& action) {
+[[nodiscard]] inline bool is_void_action(const action_variant_type& action) noexcept {
return std::holds_alternative>(action);
}
} // namespace detail
-/// @brief Default argument action.
+/// @brief Returns a default argument action.
template
-detail::callable_type default_action{ [](T&) {} };
+detail::callable_type default_action() noexcept {
+ return [](T&) {};
+}
-/// @brief Predefined action for file name handling arguments. Checks whether a file with the given name exists.
-inline detail::callable_type check_file_exists_action{
- [](std::string& file_path) {
+/// @brief Returns a predefined action for file name handling arguments. Checks whether a file with the given name exists.
+inline detail::callable_type check_file_exists_action() noexcept {
+ return [](std::string& file_path) {
if (not std::filesystem::exists(file_path)) {
std::cerr << "[ERROR] : File " + file_path + " does not exists!";
std::exit(EXIT_FAILURE);
}
- }
-};
+ };
+}
// TODO: on_flag_action
} // namespace action
-
/// @brief Internal argument handling utility.
namespace argument::detail {
/// @brief Structure holding the argument name.
struct argument_name {
- /// @brief Default constructor (deleted).
argument_name() = delete;
-
- /// @brief Assignment operator for argument_name (deleted).
argument_name& operator=(const argument_name&) = delete;
+ argument_name& operator=(argument_name&&) = delete;
/// @brief Copy constructor
argument_name(const argument_name&) = default;
@@ -352,7 +349,7 @@ struct argument_name {
* @param other The argument_name instance to compare with.
* @return Equality of argument names.
*/
- inline bool operator==(const argument_name& other) const {
+ bool operator==(const argument_name& other) const noexcept {
return this->name == other.name;
}
@@ -361,15 +358,15 @@ struct argument_name {
* @param name The string view to compare with.
* @return Equality of names comparison (either full or short name).
*/
- inline bool operator==(std::string_view name) const {
- return name == this->name or
- (this->short_name and name == this->short_name.value());
+ bool operator==(std::string_view name) const noexcept {
+ return name == this->name or (this->short_name and name == this->short_name.value());
}
/// @brief Get a string representation of the argument_name.
- [[nodiscard]] inline std::string str() const {
- return this->short_name ? ("[" + this->name + "," + this->short_name.value() + "]")
- : ("[" + this->name + "]");
+ [[nodiscard]] std::string str() const noexcept {
+ return this->short_name
+ ? ("[" + this->name + "," + this->short_name.value() + "]")
+ : ("[" + this->name + "]");
}
/**
@@ -378,7 +375,7 @@ struct argument_name {
* @param arg_name The argument name to be inserted into the stream.
* @return The modified output stream.
*/
- friend std::ostream& operator<<(std::ostream& os, const argument_name& arg_name) {
+ friend std::ostream& operator<<(std::ostream& os, const argument_name& arg_name) noexcept {
os << arg_name.str();
return os;
}
@@ -398,10 +395,10 @@ class argument_interface {
* @param msg The help message to set.
* @return Reference to the argument_interface.
*/
- virtual argument_interface& help(std::string_view) = 0;
+ virtual argument_interface& help(std::string_view) noexcept = 0;
/// @return True if the argument is optional, false otherwise.
- virtual bool is_optional() const = 0;
+ virtual bool is_optional() const noexcept = 0;
/// @brief Destructor for argument_interface.
virtual ~argument_interface() = default;
@@ -412,7 +409,7 @@ class argument_interface {
* @param argument The argument_interface to output.
* @return The output stream.
*/
- friend std::ostream& operator<<(std::ostream& os, const argument_interface& argument) {
+ friend std::ostream& operator<<(std::ostream& os, const argument_interface& argument) noexcept {
os << argument.name() << " : ";
const auto& argument_help_msg = argument.help();
os << (argument_help_msg ? argument_help_msg.value() : "[ostream(argument)] TODO: msg");
@@ -423,25 +420,25 @@ class argument_interface {
protected:
/// @return Reference to the name of the argument.
- virtual const argument_name& name() const = 0;
+ virtual const argument_name& name() const noexcept = 0;
/// @return True if the argument is required, false otherwise
- virtual bool is_required() const = 0;
+ virtual bool is_required() const noexcept = 0;
/// @return True if bypassing the required status is enabled for the argument, false otherwise.
- virtual bool bypass_required_enabled() const = 0;
+ virtual bool bypass_required_enabled() const noexcept = 0;
/// @return Optional help message for the argument.
- virtual const std::optional& help() const = 0;
+ virtual const std::optional& help() const noexcept = 0;
/// @brief Mark the argument as used.
- virtual void set_used() = 0;
+ virtual void set_used() noexcept = 0;
/// @return True if the argument has been used, false otherwise.
- virtual bool is_used() const = 0;
+ virtual bool is_used() const noexcept = 0;
/// @return The number of times the positional argument is used.
- virtual std::size_t nused() const = 0;
+ virtual std::size_t nused() const noexcept = 0;
/**
* @brief Set the value for the argument.
@@ -451,16 +448,16 @@ class argument_interface {
virtual argument_interface& set_value(const std::string&) = 0;
/// @return True if the argument has a value, false otherwise.
- virtual bool has_value() const = 0;
+ virtual bool has_value() const noexcept = 0;
/// @return True if the argument has parsed values., false otherwise.
- virtual bool has_parsed_values() const = 0;
+ virtual bool has_parsed_values() const noexcept = 0;
/// @return The ordering relationship of argument range.
- virtual std::weak_ordering nvalues_in_range() const = 0;
+ virtual std::weak_ordering nvalues_in_range() const noexcept = 0;
/// @return Reference to the stored value of the argument.
- virtual const std::any& value() const = 0;
+ virtual const std::any& value() const noexcept = 0;
/// @return Reference to the vector of parsed values of the argument.
virtual const std::vector& values() const = 0;
@@ -468,7 +465,6 @@ class argument_interface {
} // namespace argument::detail
-
/**
* @brief Base class for exceptions thrown by the argument parser.
*
@@ -481,11 +477,9 @@ class argument_parser_error : public std::runtime_error {
* @brief Constructor for the argument_parser_error class.
* @param message A descriptive error message providing information about the exception.
*/
- explicit argument_parser_error(const std::string& message)
- : std::runtime_error(message) {}
+ explicit argument_parser_error(const std::string& message) : std::runtime_error(message) {}
};
-
/// @brief Namespace containing custom exception classes for argument parser errors.
namespace error {
@@ -501,17 +495,15 @@ class value_already_set_error : public argument_parser_error {
};
/// @brief Exception thrown when the value provided for an argument cannot be parsed.
-class invalid_value_error : public argument_parser_error{
+class invalid_value_error : public argument_parser_error {
public:
/**
* @brief Constructor for the invalid_value_error class.
* @param arg_name The name of the argument for which the value parsing failed.
* @param value The value that failed to parse.
*/
- explicit invalid_value_error(
- const argument::detail::argument_name& arg_name, const std::string& value
- ) : argument_parser_error(
- "Cannot parse value `" + value + "` for argument " + arg_name.str()) {}
+ explicit invalid_value_error(const argument::detail::argument_name& arg_name, const std::string& value)
+ : argument_parser_error("Cannot parse value `" + value + "` for argument " + arg_name.str()) {}
};
/// @brief Exception thrown when the provided value is not in the choices for an argument.
@@ -522,10 +514,9 @@ class invalid_choice_error : public argument_parser_error {
* @param arg_name The name of the argument for which the value is not in choices.
* @param value The value that is not in the allowed choices.
*/
- explicit invalid_choice_error(
- const argument::detail::argument_name& arg_name, const std::string& value
- ) : argument_parser_error(
- "Value `" + value + "` is not a valid choice for argument " + arg_name.str()) {}
+ explicit invalid_choice_error(const argument::detail::argument_name& arg_name, const std::string& value)
+ : argument_parser_error("Value `" + value + "` is not a valid choice for argument " + arg_name.str()) {
+ }
};
/// @brief Exception thrown when there is a collision in argument names.
@@ -543,11 +534,10 @@ class argument_name_used_error : public argument_parser_error {
* @param given_arg_name The name of the argument causing the collision.
* @param given_arg_name_short The short name of the argument causing the collision.
*/
- explicit argument_name_used_error(
- const std::string_view& given_arg_name, const std::string_view& given_arg_name_short
- ) : argument_parser_error(
- "Given name " +
- argument::detail::argument_name(given_arg_name, given_arg_name_short).str() + " already used") {}
+ explicit argument_name_used_error(const std::string_view& given_arg_name, const std::string_view& given_arg_name_short)
+ : argument_parser_error(
+ "Given name " + argument::detail::argument_name(given_arg_name, given_arg_name_short).str() + " already used"
+ ) {}
};
/// @brief Exception thrown when an argument with a specific name is not found.
@@ -569,10 +559,10 @@ class invalid_value_type_error : public argument_parser_error {
* @param arg_name The name of the argument that had invalid value type.
* @param given_arg_type The type information that failed to cast.
*/
- explicit invalid_value_type_error(
- const argument::detail::argument_name& arg_name, const std::type_info& given_arg_type
- ) : argument_parser_error(
- "Invalid value type specified for argument " + arg_name.str() + " - " + given_arg_type.name()) {}
+ explicit invalid_value_type_error(const argument::detail::argument_name& arg_name, const std::type_info& given_arg_type)
+ : argument_parser_error(
+ "Invalid value type specified for argument " + arg_name.str() + " - " + given_arg_type.name()
+ ) {}
};
/// @brief Exception thrown when a required argument is not parsed.
@@ -606,10 +596,8 @@ class invalid_nvalues_error : public argument_parser_error {
* @param arg_name The name of the argument for which the error occurred.
* @return The error message.
*/
- [[nodiscard]] static std::string msg(
- const std::weak_ordering ordering, const argument::detail::argument_name& arg_name
- ) {
- if(std::is_lt(ordering))
+ [[nodiscard]] static std::string msg(const std::weak_ordering ordering, const argument::detail::argument_name& arg_name) {
+ if (std::is_lt(ordering))
return "Too few values provided for optional argument " + arg_name.str();
else
return "Too many values provided for optional argument " + arg_name.str();
@@ -620,15 +608,12 @@ class invalid_nvalues_error : public argument_parser_error {
* @param ordering The result of the weak_ordering comparison.
* @param arg_name The name of the argument for which the error occurred.
*/
- explicit invalid_nvalues_error(
- const std::weak_ordering ordering, const argument::detail::argument_name& arg_name
- ) : argument_parser_error(invalid_nvalues_error::msg(ordering, arg_name)) {}
+ explicit invalid_nvalues_error(const std::weak_ordering ordering, const argument::detail::argument_name& arg_name)
+ : argument_parser_error(invalid_nvalues_error::msg(ordering, arg_name)) {}
};
} // namespace error
-
-
/// @brief Namespace containing classes and utilities for handling command-line arguments.
namespace argument {
@@ -656,7 +641,7 @@ class positional_argument : public detail::argument_interface {
* @param short_name The short name of the positional argument (optional).
*/
positional_argument(std::string_view name, std::string_view short_name)
- : _name(name, short_name) {}
+ : _name(name, short_name) {}
/// @brief Destructor for positional argument.
~positional_argument() = default;
@@ -666,7 +651,7 @@ class positional_argument : public detail::argument_interface {
* @param other Another positional_argument for comparison.
* @return Result of equality
*/
- inline bool operator==(const positional_argument& other) const {
+ bool operator==(const positional_argument& other) const noexcept {
return this->_name == other._name;
}
@@ -675,7 +660,7 @@ class positional_argument : public detail::argument_interface {
* @param help_msg The help message to set.
* @return Reference to the positional_argument.
*/
- inline positional_argument& help(std::string_view help_msg) override {
+ positional_argument& help(std::string_view help_msg) noexcept override {
this->_help_msg = help_msg;
return *this;
}
@@ -686,8 +671,9 @@ class positional_argument : public detail::argument_interface {
* @return Reference to the positional_argument.
* @note Requires T to be equality comparable.
*/
- inline positional_argument& choices(const std::vector& choices)
- requires(utility::equality_comparable) {
+ positional_argument& choices(const std::vector& choices) noexcept
+ requires(utility::equality_comparable)
+ {
this->_choices = choices;
return *this;
}
@@ -700,14 +686,16 @@ class positional_argument : public detail::argument_interface {
* @return Reference to the positional_argument.
*/
template F>
- inline positional_argument& action(F&& action) {
+ positional_argument& action(F&& action) noexcept {
using callable_type = ap::action::detail::callable_type;
this->_action = std::forward(action);
return *this;
}
/// @return True if the positional argument is optional., false if required.
- [[nodiscard]] inline bool is_optional() const override { return this->_optional; }
+ [[nodiscard]] bool is_optional() const noexcept override {
+ return this->_optional;
+ }
/// @brief Friend class declaration for access by argument_parser.
@@ -722,22 +710,22 @@ class positional_argument : public detail::argument_interface {
private:
/// @return Reference the name of the positional argument.
- [[nodiscard]] inline const detail::argument_name& name() const override {
+ [[nodiscard]] const detail::argument_name& name() const noexcept override {
return this->_name;
}
/// @return Optional help message for the positional argument.
- [[nodiscard]] inline const std::optional& help() const override {
+ [[nodiscard]] const std::optional& help() const noexcept override {
return this->_help_msg;
}
/// @return True if the positional argument is required, false otherwise
- [[nodiscard]] inline bool is_required() const override {
+ [[nodiscard]] bool is_required() const noexcept override {
return this->_required;
}
/// @return True if bypassing the required status is enabled for the positional argument, false otherwise.
- [[nodiscard]] inline bool bypass_required_enabled() const override {
+ [[nodiscard]] bool bypass_required_enabled() const noexcept override {
return this->_bypass_required;
}
@@ -745,15 +733,15 @@ class positional_argument : public detail::argument_interface {
* @brief Mark the positional argument as used.
* @note Not required for positional arguments.
*/
- void set_used() override {}
+ void set_used() noexcept override {}
/// @return True if the positional argument is used, false otherwise.
- [[nodiscard]] inline bool is_used() const override {
+ [[nodiscard]] bool is_used() const noexcept override {
return this->_value.has_value();
}
/// @return The number of times the positional argument is used.
- [[nodiscard]] inline std::size_t nused() const override {
+ [[nodiscard]] std::size_t nused() const noexcept override {
return static_cast(this->_value.has_value());
}
@@ -783,28 +771,27 @@ class positional_argument : public detail::argument_interface {
}
/// @return True if the positional argument has a value, false otherwise.
- [[nodiscard]] inline bool has_value() const override {
+ [[nodiscard]] bool has_value() const noexcept override {
return this->_value.has_value();
}
/// @return True if the positional argument has parsed values, false otherwise.
- [[nodiscard]] inline bool has_parsed_values() const override {
+ [[nodiscard]] bool has_parsed_values() const noexcept override {
return this->_value.has_value();
}
/// @return Ordering relationship of positional argument range.
- [[nodiscard]] inline std::weak_ordering nvalues_in_range() const override {
- return this->_value.has_value() ? std::weak_ordering::equivalent
- : std::weak_ordering::less;
+ [[nodiscard]] std::weak_ordering nvalues_in_range() const noexcept override {
+ return this->_value.has_value() ? std::weak_ordering::equivalent : std::weak_ordering::less;
}
/// @brief Get the stored value of the positional argument.
- [[nodiscard]] inline const std::any& value() const override {
+ [[nodiscard]] const std::any& value() const noexcept override {
return this->_value;
}
/// @return Reference to the vector of parsed values for the positional argument.
- [[nodiscard]] inline const std::vector& values() const override {
+ [[nodiscard]] const std::vector& values() const override {
throw std::logic_error("Positional argument " + this->_name.name + "has only 1 value.");
}
@@ -813,16 +800,15 @@ class positional_argument : public detail::argument_interface {
* @param choice The value to check against choices.
* @return True if the choice valid, false otherwise.
*/
- [[nodiscard]] inline bool _is_valid_choice(const value_type& choice) const {
- return this->_choices.empty() or
- std::find(this->_choices.begin(), this->_choices.end(), choice) != this->_choices.end();
+ [[nodiscard]] bool _is_valid_choice(const value_type& choice) const noexcept {
+ return this->_choices.empty() or std::ranges::find(this->_choices, choice) != this->_choices.end();
}
/**
* @brief Apply the specified action to the value of the positional argument.
* @param value The value to apply the action to.
*/
- void _apply_action(value_type& value) const {
+ void _apply_action(value_type& value) const noexcept {
namespace action = ap::action::detail;
if (action::is_void_action(this->_action))
std::get>(this->_action)(value);
@@ -832,14 +818,15 @@ class positional_argument : public detail::argument_interface {
using action_type = ap::action::detail::action_variant_type;
- static constexpr bool _optional{false};
+ static constexpr bool _optional = false;
const detail::argument_name _name;
std::optional _help_msg;
- static constexpr bool _required{true}; ///< Positional arguments are required by default.
- static constexpr bool _bypass_required{false}; ///< Bypassing required status is defaultly not allowed for positional arguments.
+ static constexpr bool _required = true; ///< Positional arguments are required by default.
+ static constexpr bool _bypass_required =
+ false; ///< Bypassing required status is defaultly not allowed for positional arguments.
std::vector _choices; ///< Vector of valid choices for the positional argument.
- action_type _action{ap::action::default_action}; ///< Action associated with the positional argument.
+ action_type _action = ap::action::default_action(); ///< Action associated with the positional argument.
std::any _value; ///< Stored value of the positional argument.
@@ -871,7 +858,7 @@ class optional_argument : public detail::argument_interface {
* @param short_name The short name of the optional argument (optional).
*/
optional_argument(std::string_view name, std::string_view short_name)
- : _name(name, short_name) {}
+ : _name(name, short_name) {}
/// @brief Destructor for optional_argument.
~optional_argument() = default;
@@ -881,7 +868,7 @@ class optional_argument : public detail::argument_interface {
* @param other The optional_argument to compare with.
* @return Equality of comparison.
*/
- inline bool operator==(const optional_argument& other) const {
+ bool operator==(const optional_argument& other) const noexcept {
return this->_name == other._name;
}
@@ -890,7 +877,7 @@ class optional_argument : public detail::argument_interface {
* @param help_msg The help message to set.
* @return Reference to the optional_argument.
*/
- inline optional_argument& help(std::string_view help_msg) override {
+ optional_argument& help(std::string_view help_msg) noexcept override {
this->_help_msg = help_msg;
return *this;
}
@@ -899,7 +886,7 @@ class optional_argument : public detail::argument_interface {
* @brief Mark the optional argument as required.
* @return Reference to the optional_argument.
*/
- inline optional_argument& required() {
+ optional_argument& required() noexcept {
this->_required = true;
return *this;
}
@@ -908,7 +895,7 @@ class optional_argument : public detail::argument_interface {
* @brief Enable bypassing the required status for the optional argument.
* @return Reference to the optional_argument.
*/
- inline optional_argument& bypass_required() {
+ optional_argument& bypass_required() noexcept {
this->_bypass_required = true;
return *this;
}
@@ -918,7 +905,7 @@ class optional_argument : public detail::argument_interface {
* @param range The nargs range to set.
* @return Reference to the optional_argument.
*/
- inline optional_argument& nargs(const ap::nargs::range& range) {
+ optional_argument& nargs(const ap::nargs::range& range) noexcept {
this->_nargs_range = range;
return *this;
}
@@ -928,7 +915,7 @@ class optional_argument : public detail::argument_interface {
* @param count The count for nargs range.
* @return Reference to the optional_argument.
*/
- inline optional_argument& nargs(const count_type count) {
+ optional_argument& nargs(const count_type count) noexcept {
this->_nargs_range = ap::nargs::range(count);
return *this;
}
@@ -939,7 +926,7 @@ class optional_argument : public detail::argument_interface {
* @param nhigh The upper bound for nargs range.
* @return Reference to the optional_argument.
*/
- inline optional_argument& nargs(const count_type nlow, const count_type nhigh) {
+ optional_argument& nargs(const count_type nlow, const count_type nhigh) noexcept {
this->_nargs_range = ap::nargs::range(nlow, nhigh);
return *this;
}
@@ -952,7 +939,7 @@ class optional_argument : public detail::argument_interface {
* @return Reference to the optional_argument.
*/
template F>
- inline optional_argument& action(F&& action) {
+ optional_argument& action(F&& action) noexcept {
using callable_type = ap::action::detail::callable_type;
this->_action = std::forward(action);
return *this;
@@ -964,8 +951,9 @@ class optional_argument : public detail::argument_interface {
* @return Reference to the optional_argument.
* @note Requires T to be equality comparable.
*/
- inline optional_argument& choices(const std::vector& choices)
- requires(utility::equality_comparable) {
+ optional_argument& choices(const std::vector& choices) noexcept
+ requires(utility::equality_comparable)
+ {
this->_choices = choices;
return *this;
}
@@ -975,7 +963,7 @@ class optional_argument : public detail::argument_interface {
* @param default_value The default value to set.
* @return Reference to the optional_argument.
*/
- optional_argument& default_value(const value_type& default_value) {
+ optional_argument& default_value(const value_type& default_value) noexcept {
this->_default_value = default_value;
return *this;
}
@@ -985,13 +973,15 @@ class optional_argument : public detail::argument_interface {
* @param implicit_value The implicit value to set.
* @return Reference to the optional_argument.
*/
- optional_argument& implicit_value(const value_type& implicit_value) {
+ optional_argument& implicit_value(const value_type& implicit_value) noexcept {
this->_implicit_value = implicit_value;
return *this;
}
/// @return True if argument is optional, false otherwise.
- [[nodiscard]] inline bool is_optional() const override { return this->_optional; }
+ [[nodiscard]] bool is_optional() const noexcept override {
+ return this->_optional;
+ }
/// @brief Friend class declaration for access by argument_parser.
friend class ::ap::argument_parser;
@@ -1005,37 +995,37 @@ class optional_argument : public detail::argument_interface {
private:
/// @return Reference to the name of the optional argument.
- [[nodiscard]] inline const detail::argument_name& name() const override {
+ [[nodiscard]] const detail::argument_name& name() const noexcept override {
return this->_name;
}
/// @return Reference to the optional help message for the optional argument.
- [[nodiscard]] inline const std::optional& help() const override {
+ [[nodiscard]] const std::optional& help() const noexcept override {
return this->_help_msg;
}
/// @return True if the optional argument is required, false otherwise.
- [[nodiscard]] inline bool is_required() const override {
+ [[nodiscard]] bool is_required() const noexcept override {
return this->_required;
}
/// @return True if bypassing the required status is enabled for the optional argument, false otherwise.
- [[nodiscard]] inline bool bypass_required_enabled() const override {
+ [[nodiscard]] bool bypass_required_enabled() const noexcept override {
return this->_bypass_required;
}
/// @brief Mark the optional argument as used.
- void set_used() override {
+ void set_used() noexcept override {
this->_nused++;
}
/// @return True if the optional argument is used, false otherwise.
- [[nodiscard]] inline bool is_used() const override {
+ [[nodiscard]] bool is_used() const noexcept override {
return this->_nused > 0;
}
/// @return The number of times the optional argument is used.
- [[nodiscard]] inline std::size_t nused() const override {
+ [[nodiscard]] std::size_t nused() const noexcept override {
return this->_nused;
}
@@ -1065,17 +1055,17 @@ class optional_argument : public detail::argument_interface {
}
/// @return True if the optional argument has a value, false otherwise.
- [[nodiscard]] inline bool has_value() const override {
+ [[nodiscard]] bool has_value() const noexcept override {
return this->has_parsed_values() or this->_has_predefined_value();
}
/// @return True if parsed values are available for the optional argument, false otherwise.
- [[nodiscard]] inline bool has_parsed_values() const override {
+ [[nodiscard]] bool has_parsed_values() const noexcept override {
return not this->_values.empty();
}
/// @return ordering relationship of optional argument range.
- [[nodiscard]] std::weak_ordering nvalues_in_range() const override {
+ [[nodiscard]] std::weak_ordering nvalues_in_range() const noexcept override {
if (not this->_nargs_range)
return std::weak_ordering::equivalent;
@@ -1086,23 +1076,22 @@ class optional_argument : public detail::argument_interface {
}
/// @return Reference to the stored value of the optional argument.
- [[nodiscard]] inline const std::any& value() const override {
+ [[nodiscard]] const std::any& value() const noexcept override {
return this->_values.empty() ? this->_predefined_value() : this->_values.front();
}
/// @return Reference to the vector of parsed values for the optional argument.
- [[nodiscard]] inline const std::vector& values() const override {
+ [[nodiscard]] const std::vector& values() const override {
return this->_values;
}
/// @return True if the optional argument has a predefined value, false otherwise.
- [[nodiscard]] inline bool _has_predefined_value() const {
- return this->_default_value.has_value() or
- (this->is_used() and this->_implicit_value.has_value());
+ [[nodiscard]] bool _has_predefined_value() const noexcept {
+ return this->_default_value.has_value() or (this->is_used() and this->_implicit_value.has_value());
}
/// @return Reference to the predefined value of the optional argument.
- [[nodiscard]] inline const std::any& _predefined_value() const {
+ [[nodiscard]] const std::any& _predefined_value() const noexcept {
return this->is_used() ? this->_implicit_value : this->_default_value;
}
@@ -1111,16 +1100,15 @@ class optional_argument : public detail::argument_interface {
* @param choice The value to check against choices.
* @return True if choice is valid, false otherwise.
*/
- [[nodiscard]] inline bool _is_valid_choice(const value_type& choice) const {
- return this->_choices.empty() or
- std::find(this->_choices.begin(), this->_choices.end(), choice) != this->_choices.end();
+ [[nodiscard]] bool _is_valid_choice(const value_type& choice) const noexcept {
+ return this->_choices.empty() or std::ranges::find(this->_choices, choice) != this->_choices.end();
}
/**
* @brief Apply the specified action to the value of the optional argument.
* @param value The value to apply the action to.
*/
- void _apply_action(value_type& value) const {
+ void _apply_action(value_type& value) const noexcept {
namespace action = ap::action::detail;
if (action::is_void_action(this->_action))
std::get>(this->_action)(value);
@@ -1130,19 +1118,19 @@ class optional_argument : public detail::argument_interface {
using action_type = ap::action::detail::action_variant_type;
- static constexpr bool _optional{true};
+ static constexpr bool _optional = true;
const detail::argument_name _name;
std::optional _help_msg;
- bool _required{false};
- bool _bypass_required{false};
+ bool _required = false;
+ bool _bypass_required = false;
std::optional _nargs_range;
- action_type _action{ap::action::default_action}; ///< Action associated with the opitonal argument.
+ action_type _action = ap::action::default_action(); ///< Action associated with the opitonal argument.
std::vector _choices; ///< Vector of valid choices for the optional argument.
std::any _default_value;
std::any _implicit_value;
- std::size_t _nused{0u}; ///< Number of used optional arguments.
+ std::size_t _nused = 0u; ///< Number of used optional arguments.
std::vector _values; ///< Vector holding parsed values for the optional argument.
std::stringstream _ss; ///< Stringstream used for parsing values.
@@ -1150,42 +1138,27 @@ class optional_argument : public detail::argument_interface {
} // namespace argument
-
/// @brief Namespace containing default argument types.
namespace default_argument {
/// @brief Enum class representing positional arguments.
-enum class positional : uint8_t {
- input,
- output
-};
+enum class positional : uint8_t { input, output };
/// @brief Enum class representing optional arguments.
-enum class optional : uint8_t {
- help,
- input,
- output,
- multi_input,
- multi_output
-};
+enum class optional : uint8_t { help, input, output, multi_input, multi_output };
} // namespace default_argument
-
/// @brief Main argument parser class.
class argument_parser {
public:
/// @brief Default constructor.
argument_parser() = default;
- /// @brief Deleted copy constructor.
argument_parser(const argument_parser&) = delete;
-
- /// @brief Deleted move constructor.
argument_parser(argument_parser&&) = delete;
-
- /// @brief Deleted copy assignment operator.
argument_parser& operator=(const argument_parser&) = delete;
+ argument_parser& operator=(argument_parser&&) = delete;
/// @brief Destructor for the argument parser.
~argument_parser() = default;
@@ -1195,7 +1168,7 @@ class argument_parser {
* @param name The name of the program.
* @return Reference to the argument parser.
*/
- inline argument_parser& program_name(std::string_view name) {
+ argument_parser& program_name(std::string_view name) noexcept {
this->_program_name = name;
return *this;
}
@@ -1205,7 +1178,7 @@ class argument_parser {
* @param description The description of the program.
* @return Reference to the argument parser.
*/
- inline argument_parser& program_description(std::string_view description) {
+ argument_parser& program_description(std::string_view description) noexcept {
this->_program_description = description;
return *this;
}
@@ -1215,9 +1188,8 @@ class argument_parser {
* @param args Vector of default positional argument categories.
* @return Reference to the argument parser.
*/
- inline argument_parser& default_positional_arguments(
- const std::vector& args
- ) {
+ argument_parser& default_positional_arguments(const std::vector& args
+ ) noexcept {
for (const auto arg : args)
this->_add_default_positional_argument(arg);
return *this;
@@ -1228,9 +1200,7 @@ class argument_parser {
* @param args Vector of default optional argument categories.
* @return Reference to the argument parser.
*/
- inline argument_parser& default_optional_arguments(
- const std::vector& args
- ) {
+ argument_parser& default_optional_arguments(const std::vector& args) noexcept {
for (const auto arg : args)
this->_add_default_optional_argument(arg);
return *this;
@@ -1249,10 +1219,8 @@ class argument_parser {
if (this->_is_arg_name_used(name))
throw error::argument_name_used_error(name);
- this->_positional_args.push_back(
- std::make_unique>(name));
- return static_cast&>(
- *this->_positional_args.back());
+ this->_positional_args.push_back(std::make_unique>(name));
+ return static_cast&>(*this->_positional_args.back());
}
/**
@@ -1263,18 +1231,14 @@ class argument_parser {
* @return Reference to the added positional argument.
*/
template
- argument::positional_argument& add_positional_argument(
- std::string_view name, std::string_view short_name
- ) {
+ argument::positional_argument& add_positional_argument(std::string_view name, std::string_view short_name) {
// TODO: check forbidden characters
if (this->_is_arg_name_used(name, short_name))
throw error::argument_name_used_error(name, short_name);
- this->_positional_args.push_back(
- std::make_unique>(name, short_name));
- return static_cast&>(
- *this->_positional_args.back());
+ this->_positional_args.push_back(std::make_unique>(name, short_name));
+ return static_cast&>(*this->_positional_args.back());
}
/**
@@ -1308,8 +1272,7 @@ class argument_parser {
if (this->_is_arg_name_used(name, short_name))
throw error::argument_name_used_error(name, short_name);
- this->_optional_args.push_back(
- std::make_unique>(name, short_name));
+ this->_optional_args.push_back(std::make_unique>(name, short_name));
return static_cast&>(*this->_optional_args.back());
}
@@ -1322,9 +1285,9 @@ class argument_parser {
template
argument::optional_argument& add_flag(std::string_view name) {
return this->add_optional_argument(name)
- .default_value(not StoreImplicitly)
- .implicit_value(StoreImplicitly)
- .nargs(0);
+ .default_value(not StoreImplicitly)
+ .implicit_value(StoreImplicitly)
+ .nargs(0);
}
/**
@@ -1335,13 +1298,11 @@ class argument_parser {
* @return Reference to the added boolean flag argument.
*/
template
- argument::optional_argument& add_flag(
- std::string_view name, std::string_view short_name
- ) {
+ argument::optional_argument& add_flag(std::string_view name, std::string_view short_name) {
return this->add_optional_argument(name, short_name)
- .default_value(not StoreImplicitly)
- .implicit_value(StoreImplicitly)
- .nargs(0);
+ .default_value(not StoreImplicitly)
+ .implicit_value(StoreImplicitly)
+ .nargs(0);
}
/**
@@ -1364,7 +1325,7 @@ class argument_parser {
* @param arg_name The name of the argument.
* @return True if the argument has a value, false otherwise.
*/
- bool has_value(std::string_view arg_name) const {
+ bool has_value(std::string_view arg_name) const noexcept {
const auto arg_opt = this->_get_argument(arg_name);
return arg_opt ? arg_opt->get().has_value() : false; // TODO: throw
}
@@ -1374,9 +1335,9 @@ class argument_parser {
* @param arg_name The name of the argument.
* @return The count of times the argument has been used.
*/
- std::size_t count(std::string_view arg_name) const {
+ std::size_t count(std::string_view arg_name) const noexcept {
const auto arg_opt = this->_get_argument(arg_name);
- return arg_opt ? arg_opt->get().nused() : 0u; // TODO: throw
+ return arg_opt ? arg_opt->get().nused() : 0ull; // TODO: throw
}
/**
@@ -1392,7 +1353,7 @@ class argument_parser {
throw error::argument_not_found_error(arg_name);
try {
- T value{std::any_cast(arg_opt->get().value())};
+ T value = std::any_cast(arg_opt->get().value());
return value;
}
catch (const std::bad_any_cast& err) {
@@ -1416,16 +1377,14 @@ class argument_parser {
try {
if (not arg.has_parsed_values() and arg.has_value())
- return std::vector{std::any_cast(arg.value())};
-
- const auto& arg_values = arg.values();
+ return std::vector{ std::any_cast(arg.value()) };
std::vector values;
- std::transform(
- std::begin(arg_values),
- std::end(arg_values),
- std::back_inserter(values),
- [] (const std::any& value) { return std::any_cast(value); }
+ std::ranges::copy(
+ std::views::transform(
+ arg.values(), [](const std::any& value) { return std::any_cast(value); }
+ ),
+ std::back_inserter(values)
);
return values;
}
@@ -1440,7 +1399,7 @@ class argument_parser {
* @param parser The argument parser to print.
* @return The modified output stream.
*/
- friend std::ostream& operator<<(std::ostream& os, const argument_parser& parser) {
+ friend std::ostream& operator<<(std::ostream& os, const argument_parser& parser) noexcept {
if (parser._program_name)
os << parser._program_name.value() << std::endl;
@@ -1466,18 +1425,17 @@ class argument_parser {
* @brief Add default positional argument based on the specified category.
* @param arg The default positional argument category.
*/
- void _add_default_positional_argument(const default_argument::positional arg) {
+ void _add_default_positional_argument(const default_argument::positional arg) noexcept {
switch (arg) {
- case default_argument::positional::input:
- this->add_positional_argument("input")
- .action(ap::action::check_file_exists_action)
- .help("Input file path");
- break;
-
- case default_argument::positional::output:
- this->add_positional_argument("output")
- .help("Output file path");
- break;
+ case default_argument::positional::input:
+ this->add_positional_argument("input")
+ .action(ap::action::check_file_exists_action())
+ .help("Input file path");
+ break;
+
+ case default_argument::positional::output:
+ this->add_positional_argument("output").help("Output file path");
+ break;
}
}
@@ -1485,43 +1443,35 @@ class argument_parser {
* @brief Add default optional argument based on the specified category.
* @param arg The default optional argument category.
*/
- void _add_default_optional_argument(const default_argument::optional arg) {
+ void _add_default_optional_argument(const default_argument::optional arg) noexcept {
switch (arg) {
- case default_argument::optional::help:
- this->add_flag("help", "h")
- .bypass_required()
- .help("Display help message");
- break;
-
- case default_argument::optional::input:
- this->add_optional_argument("input", "i")
- .required()
- .nargs(1)
- .action(ap::action::check_file_exists_action)
- .help("Input file path");
- break;
-
- case default_argument::optional::output:
- this->add_optional_argument("output", "o")
- .required()
- .nargs(1)
- .help("Output file path");
- break;
-
- case default_argument::optional::multi_input:
- this->add_optional_argument("input", "i")
- .required()
- .nargs(ap::nargs::at_least(1))
- .action(ap::action::check_file_exists_action)
- .help("Input files paths");
- break;
-
- case default_argument::optional::multi_output:
- this->add_optional_argument("output", "o")
- .required()
- .nargs(ap::nargs::at_least(1))
- .help("Output files paths");
- break;
+ case default_argument::optional::help:
+ this->add_flag("help", "h").bypass_required().help("Display help message");
+ break;
+
+ case default_argument::optional::input:
+ this->add_optional_argument("input", "i")
+ .required()
+ .nargs(1)
+ .action(ap::action::check_file_exists_action())
+ .help("Input file path");
+ break;
+
+ case default_argument::optional::output:
+ this->add_optional_argument("output", "o").required().nargs(1).help("Output file path");
+ break;
+
+ case default_argument::optional::multi_input:
+ this->add_optional_argument("input", "i")
+ .required()
+ .nargs(ap::nargs::at_least(1))
+ .action(ap::action::check_file_exists_action())
+ .help("Input files paths");
+ break;
+
+ case default_argument::optional::multi_output:
+ this->add_optional_argument("output", "o").required().nargs(ap::nargs::at_least(1)).help("Output files paths");
+ break;
}
}
@@ -1539,9 +1489,8 @@ class argument_parser {
* @param discriminator Type discriminator (flag or value).
* @param value The value of the argument.
*/
- cmd_argument(
- const type_discriminator discriminator, const std::string& value
- ) : discriminator(discriminator), value(value) {}
+ cmd_argument(const type_discriminator discriminator, const std::string& value)
+ : discriminator(discriminator), value(value) {}
~cmd_argument() = default;
@@ -1550,9 +1499,8 @@ class argument_parser {
* @param other Another cmd_argument to compare with.
* @return Boolean statement of equality comparison.
*/
- inline bool operator==(const cmd_argument& other) const {
- return this->discriminator == other.discriminator and
- this->value == other.value;
+ bool operator==(const cmd_argument& other) const noexcept {
+ return this->discriminator == other.discriminator and this->value == other.value;
}
type_discriminator discriminator;
@@ -1563,8 +1511,7 @@ class argument_parser {
using cmd_argument_list_iterator = typename cmd_argument_list::const_iterator;
using argument_ptr_type = std::unique_ptr;
- using argument_opt_type =
- std::optional>;
+ using argument_opt_type = std::optional>;
using argument_list_type = std::vector;
using argument_list_iterator_type = typename argument_list_type::iterator;
using argument_list_const_iterator_type = typename argument_list_type::const_iterator;
@@ -1575,12 +1522,8 @@ class argument_parser {
* @param name The name of the argument.
* @return Argument predicate based on the provided name.
*/
- [[nodiscard]] inline argument_predicate_type _name_eq_predicate(
- const std::string_view& name
- ) const {
- return [&name](const argument_ptr_type& arg) {
- return name == arg->name();
- };
+ [[nodiscard]] argument_predicate_type _name_eq_predicate(const std::string_view& name) const noexcept {
+ return [&name](const argument_ptr_type& arg) { return name == arg->name(); };
}
/**
@@ -1589,9 +1532,9 @@ class argument_parser {
* @param short_name The short name of the argument.
* @return Argument predicate based on the provided name and short name.
*/
- [[nodiscard]] inline argument_predicate_type _name_eq_predicate(
+ [[nodiscard]] argument_predicate_type _name_eq_predicate(
const std::string_view& name, const std::string_view& short_name
- ) const {
+ ) const noexcept {
return [&name, &short_name](const argument_ptr_type& arg) {
return name == arg->name() or short_name == arg->name();
};
@@ -1602,13 +1545,13 @@ class argument_parser {
* @param name The name of the argument.
* @return True if the argument name is already used, false otherwise.
*/
- [[nodiscard]] bool _is_arg_name_used(const std::string_view& name) const {
+ [[nodiscard]] bool _is_arg_name_used(const std::string_view& name) const noexcept {
const auto predicate = this->_name_eq_predicate(name);
- if (this->_const_find_positional(predicate) != this->_positional_args.end())
+ if (std::ranges::find_if(this->_positional_args, predicate) != this->_positional_args.end())
return true;
- if (this->_const_find_optional(predicate) != this->_optional_args.end())
+ if (std::ranges::find_if(this->_optional_args, predicate) != this->_optional_args.end())
return true;
return false;
@@ -1620,15 +1563,13 @@ class argument_parser {
* @param short_name The short name of the argument.
* @return True if the argument name or short name is already used, false otherwise.
*/
- [[nodiscard]] bool _is_arg_name_used(
- const std::string_view& name, const std::string_view& short_name
- ) const {
+ [[nodiscard]] bool _is_arg_name_used(const std::string_view& name, const std::string_view& short_name) const noexcept {
const auto predicate = this->_name_eq_predicate(name, short_name);
- if (this->_const_find_positional(predicate) != this->_positional_args.end())
+ if (std::ranges::find_if(this->_positional_args, predicate) != this->_positional_args.end())
return true;
- if (this->_const_find_optional(predicate) != this->_optional_args.end())
+ if (std::ranges::find_if(this->_optional_args, predicate) != this->_optional_args.end())
return true;
return false;
@@ -1640,7 +1581,7 @@ class argument_parser {
* @param argv Array of command-line argument strings.
* @return List of preprocessed command-line arguments.
*/
- [[nodiscard]] cmd_argument_list _preprocess_input(int argc, char* argv[]) const {
+ [[nodiscard]] cmd_argument_list _preprocess_input(int argc, char* argv[]) const noexcept {
if (argc < 2)
return cmd_argument_list{};
@@ -1651,10 +1592,10 @@ class argument_parser {
std::string value = argv[i];
if (this->_is_flag(value)) {
this->_strip_flag_prefix(value);
- args.push_back(cmd_argument{cmd_argument::type_discriminator::flag, value});
+ args.push_back(cmd_argument{ cmd_argument::type_discriminator::flag, value });
}
else {
- args.push_back(cmd_argument{cmd_argument::type_discriminator::value, value});
+ args.push_back(cmd_argument{ cmd_argument::type_discriminator::value, value });
}
}
@@ -1666,7 +1607,7 @@ class argument_parser {
* @param arg The argument value.
* @return True if the argument is a flag, false otherwise.
*/
- [[nodiscard]] bool _is_flag(const std::string& arg) const {
+ [[nodiscard]] bool _is_flag(const std::string& arg) const noexcept {
if (arg.starts_with(this->_flag_prefix))
return this->_is_arg_name_used(arg.substr(this->_flag_prefix_length));
@@ -1680,7 +1621,7 @@ class argument_parser {
* @brief Remove the flag prefix from the argument.
* @param arg The argument to strip the prefix from.
*/
- void _strip_flag_prefix(std::string& arg) const {
+ void _strip_flag_prefix(std::string& arg) const noexcept {
if (arg.starts_with(this->_flag_prefix))
arg.erase(0, this->_flag_prefix_length);
else
@@ -1702,9 +1643,7 @@ class argument_parser {
* @param cmd_args The list of command-line arguments.
* @param cmd_it Iterator for iterating through command-line arguments.
*/
- void _parse_positional_args(
- const cmd_argument_list& cmd_args, cmd_argument_list_iterator& cmd_it
- ) {
+ void _parse_positional_args(const cmd_argument_list& cmd_args, cmd_argument_list_iterator& cmd_it) noexcept {
// TODO: align tests
for (const auto& pos_arg : this->_positional_args) {
if (cmd_it == cmd_args.end())
@@ -1723,15 +1662,13 @@ class argument_parser {
* @param cmd_args The list of command-line arguments.
* @param cmd_it Iterator for iterating through command-line arguments.
*/
- void _parse_optional_args(
- const cmd_argument_list& cmd_args, cmd_argument_list_iterator& cmd_it
- ) {
+ void _parse_optional_args(const cmd_argument_list& cmd_args, cmd_argument_list_iterator& cmd_it) {
std::optional> curr_opt_arg;
while (cmd_it != cmd_args.end()) {
if (cmd_it->discriminator == cmd_argument::type_discriminator::flag) {
auto opt_arg_it =
- this->_find_optional(this->_name_eq_predicate(cmd_it->value));
+ std::ranges::find_if(this->_optional_args, this->_name_eq_predicate(cmd_it->value));
if (opt_arg_it == this->_optional_args.end())
throw error::argument_not_found_error(cmd_it->value);
@@ -1754,13 +1691,10 @@ class argument_parser {
* @brief Check if optional arguments can bypass the required arguments.
* @return True if optional arguments can bypass required arguments, false otherwise.
*/
- [[nodiscard]] inline bool _bypass_required_args() const {
- return std::any_of(
- std::cbegin(this->_optional_args), std::cend(this->_optional_args),
- [](const argument_ptr_type& arg) {
- return arg->is_used() and arg->bypass_required_enabled();
- }
- );
+ [[nodiscard]] bool _bypass_required_args() const noexcept {
+ return std::any_of(std::cbegin(this->_optional_args), std::cend(this->_optional_args), [](const argument_ptr_type& arg) {
+ return arg->is_used() and arg->bypass_required_enabled();
+ });
}
/// @brief Check if all required positional and optional arguments are used.
@@ -1794,15 +1728,15 @@ class argument_parser {
* @param name The name of the argument.
* @return The argument with the specified name, if found; otherwise, std::nullopt.
*/
- argument_opt_type _get_argument(const std::string_view& name) const {
+ argument_opt_type _get_argument(const std::string_view& name) const noexcept {
const auto predicate = this->_name_eq_predicate(name);
- if (auto pos_arg_it = this->_const_find_positional(predicate);
+ if (auto pos_arg_it = std::ranges::find_if(this->_positional_args, predicate);
pos_arg_it != this->_positional_args.end()) {
return std::ref(**pos_arg_it);
}
- if (auto opt_arg_it = this->_const_find_optional(predicate);
+ if (auto opt_arg_it = std::ranges::find_if(this->_optional_args, predicate);
opt_arg_it != this->_optional_args.end()) {
return std::ref(**opt_arg_it);
}
@@ -1810,64 +1744,16 @@ class argument_parser {
return std::nullopt;
}
- /**
- * @brief Find a positional argument based on the provided predicate.
- * @param predicate The predicate for finding the argument.
- * @return Iterator to the found positional argument.
- */
- [[nodiscard]] inline argument_list_iterator_type _find_positional(
- const argument_predicate_type& predicate
- ) {
- return std::find_if(
- std::begin(this->_positional_args), std::end(this->_positional_args), predicate);
- }
-
- /**
- * @brief Find an optional argument based on the provided predicate.
- * @param predicate The predicate for finding the argument.
- * @return Iterator to the found optional argument.
- */
- [[nodiscard]] inline argument_list_iterator_type _find_optional(
- const argument_predicate_type& predicate
- ) {
- return std::find_if(
- std::begin(this->_optional_args), std::end(this->_optional_args), predicate);
- }
-
- /**
- * @brief Find a positional argument based on the provided predicate (const version).
- * @param predicate The predicate for finding the argument.
- * @return Iterator to the found positional argument.
- */
- [[nodiscard]] inline argument_list_const_iterator_type _const_find_positional(
- const argument_predicate_type& predicate
- ) const {
- return std::find_if(
- std::cbegin(this->_positional_args), std::cend(this->_positional_args), predicate);
- }
-
- /**
- * @brief Find an optional argument based on the provided predicate (const version).
- * @param predicate The predicate for finding the argument.
- * @return Iterator to the found optional argument.
- */
- [[nodiscard]] inline argument_list_const_iterator_type _const_find_optional(
- const argument_predicate_type& predicate
- ) const {
- return std::find_if(
- std::cbegin(this->_optional_args), std::cend(this->_optional_args), predicate);
- }
-
std::optional _program_name;
std::optional _program_description;
argument_list_type _positional_args;
argument_list_type _optional_args;
- static constexpr uint8_t _flag_prefix_char_length{1u};
- static constexpr uint8_t _flag_prefix_length{2u};
- static constexpr char _flag_prefix_char{'-'};
- const std::string _flag_prefix{"--"}; // not static constexpr because of ubuntu :(
+ static constexpr uint8_t _flag_prefix_char_length = 1u;
+ static constexpr uint8_t _flag_prefix_length = 2u;
+ static constexpr char _flag_prefix_char = '-';
+ const std::string _flag_prefix = "--"; // not static constexpr because of ubuntu gcc implementation :(
};
} // namespace ap
diff --git a/scripts/env/install_clang17_toolchain.sh b/scripts/env/install_clang17_toolchain.sh
new file mode 100644
index 0000000..97d07b4
--- /dev/null
+++ b/scripts/env/install_clang17_toolchain.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+if command -v clang-17 &>/dev/null && command -v clang-format-17 &>/dev/null; then
+ echo "clang-17 toolchain already installed!"
+ exit 0
+fi
+
+echo "Adding LLVM apt repository"
+wget -q -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - >/dev/null 2>&1
+echo | sudo add-apt-repository "deb http://apt.llvm.org/$(lsb_release -sc)/ llvm-toolchain-$(lsb_release -sc)-17 main" &>/dev/null 2>&1
+
+echo "Updating package list"
+sudo apt update &>/dev/null 2>&1
+
+echo "Installing clang-17 toolchain"
+sudo apt install clang-17 clang-format-17 -y &>/dev/null 2>&1
+echo "Success!"
diff --git a/scripts/format/unix.sh b/scripts/format/unix.sh
new file mode 100644
index 0000000..f7873f9
--- /dev/null
+++ b/scripts/format/unix.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+format_check=false
+if [[ "$1" == "--check" ]]; then
+ format_check=true
+fi
+
+run_clang_format() {
+ local file="$1"
+ if [[ "$format_check" == true ]]; then
+ clang-format-17 --dry-run --Werror "$file"
+ else
+ clang-format-17 -i "$file"
+ fi
+}
+
+# Count the number of files to format
+file_count=$(find . -type f \( -name "*.hpp" -o -name "*.cpp" \) ! -path "*/build/*" | wc -l)
+if [[ "$format_check" == true ]]; then
+ echo "Files to check: $file_count"
+else
+ echo "Files to format: $file_count"
+fi
+echo
+
+# Iterate over the files and run format/check
+file_number=0
+find . -type f \( -name "*.hpp" -o -name "*.cpp" \) ! -path "*/build/*" -print0 | while IFS= read -r -d '' file; do
+ ((file_number++))
+ echo "[$file_number/$file_count] $file"
+ run_clang_format "$file"
+done
+
+echo
+echo "Done!"
diff --git a/scripts/format/windows.ps1 b/scripts/format/windows.ps1
new file mode 100644
index 0000000..ab07c53
--- /dev/null
+++ b/scripts/format/windows.ps1
@@ -0,0 +1,37 @@
+$formatCheck = $false
+if ($args[0] -eq "--check") {
+ $formatCheck = $true
+}
+
+function Run-Clang-Format {
+ param (
+ [string]$filePath,
+ [bool]$check
+ )
+
+ if ($check) {
+ clang-format --dry-run --Werror $filePath
+ }
+ else {
+ clang-format -i $filePath
+ }
+}
+
+# Get the list of files to format
+$files = Get-ChildItem -Recurse -Include *.hpp, *.cpp | Where-Object { $_.DirectoryName -notmatch "\\build\\" }
+
+# Count the number of files to format
+$fileCount = $files.Count
+Write-Host "Total files to format: $fileCount"
+Write-Host
+
+# Iterate over the files and run format/check
+$fileNumber = 0
+foreach ($file in $files) {
+ $fileNumber++
+ Write-Host "[$fileNumber/$fileCount] $($file.FullName)"
+ Run-Clang-Format -filePath $file.FullName -check $formatCheck
+}
+
+Write-Host
+Write-Host "Done!"
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index db4e883..8c9af97 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.12)
project(cpp-ap-test)
# Structure
-set(SOURCE_DIRS "src" "app")
+set(SOURCE_DIRS "source" "app")
set(INCLUDE_DIRS "include" "../include")
set(BINARY_DIR ".")
set(EXECUTABLE_DIR ".")
diff --git a/test/include/argument_parser_test_fixture.hpp b/test/include/argument_parser_test_fixture.hpp
index 0c24899..0b7cffb 100644
--- a/test/include/argument_parser_test_fixture.hpp
+++ b/test/include/argument_parser_test_fixture.hpp
@@ -35,9 +35,7 @@ struct argument_parser_test_fixture {
return "test_value_" + std::to_string(i);
}
- [[nodiscard]] std::size_t get_args_length(
- std::size_t num_args, std::size_t args_split
- ) const {
+ [[nodiscard]] std::size_t get_args_length(std::size_t num_args, std::size_t args_split) const {
return args_split + 2 * (num_args - args_split);
}
@@ -86,9 +84,7 @@ struct argument_parser_test_fixture {
return argument_name("test_arg_" + std::to_string(i), "ta_" + std::to_string(i));
}
- void add_arguments(
- ap::argument_parser& parser, std::size_t num_args, std::size_t args_split
- ) const {
+ void add_arguments(ap::argument_parser& parser, std::size_t num_args, std::size_t args_split) const {
for (std::size_t i = 0; i < args_split; i++) { // positional args
const auto arg_name = prepare_arg_name(i);
parser.add_positional_argument(arg_name.name, arg_name.short_name.value());
@@ -100,21 +96,17 @@ struct argument_parser_test_fixture {
}
}
- [[nodiscard]] cmd_argument_list prepare_cmd_arg_list(
- std::size_t num_args, std::size_t args_split
- ) const {
+ [[nodiscard]] cmd_argument_list prepare_cmd_arg_list(std::size_t num_args, std::size_t args_split) const {
cmd_argument_list cmd_args;
cmd_args.reserve(get_args_length(num_args, args_split));
for (std::size_t i = 0; i < args_split; i++) { // positional args
- cmd_args.push_back(cmd_argument{
- cmd_argument::type_discriminator::value, prepare_arg_value(i)});
+ cmd_args.push_back(cmd_argument{ cmd_argument::type_discriminator::value, prepare_arg_value(i) });
}
for (std::size_t i = args_split; i < num_args; i++) { // optional args
cmd_args.push_back(cmd_argument{
- cmd_argument::type_discriminator::flag, prepare_arg_name(i).name});
- cmd_args.push_back(cmd_argument{
- cmd_argument::type_discriminator::value, prepare_arg_value(i)});
+ cmd_argument::type_discriminator::flag, prepare_arg_name(i).name });
+ cmd_args.push_back(cmd_argument{ cmd_argument::type_discriminator::value, prepare_arg_value(i) });
}
return cmd_args;
diff --git a/test/include/optional_argument_test_fixture.hpp b/test/include/optional_argument_test_fixture.hpp
index 84a2f7e..636a6ae 100644
--- a/test/include/optional_argument_test_fixture.hpp
+++ b/test/include/optional_argument_test_fixture.hpp
@@ -6,8 +6,8 @@
#include
-using ap::argument::detail::argument_name;
using ap::argument::optional_argument;
+using ap::argument::detail::argument_name;
using ap::utility::valid_argument_value_type;
namespace ap_testing {
@@ -20,82 +20,68 @@ struct optional_argument_test_fixture {
using value_type = typename optional_argument::value_type;
template
- inline void sut_set_used(optional_argument& sut) const {
+ void sut_set_used(optional_argument& sut) const {
return sut.set_used();
}
template
- inline bool sut_is_used(const optional_argument& sut) const {
+ bool sut_is_used(const optional_argument& sut) const {
return sut.is_used();
}
template
- inline std::size_t sut_get_nused(const optional_argument& sut) const {
+ std::size_t sut_get_nused(const optional_argument& sut) const {
return sut.nused();
}
template
- inline optional_argument& sut_set_value(
- optional_argument& sut, const std::string& str_value
- ) const {
+ optional_argument& sut_set_value(optional_argument& sut, const std::string& str_value) const {
sut.set_used();
return sut.set_value(str_value);
}
template
- inline optional_argument& sut_set_choices(
- optional_argument& sut, const std::vector>& choices
- ) const {
+ optional_argument& sut_set_choices(optional_argument& sut, const std::vector>& choices) const {
return sut.choices(choices);
}
template
- [[nodiscard]] inline bool sut_has_value(const optional_argument& sut) const {
+ [[nodiscard]] bool sut_has_value(const optional_argument& sut) const {
return sut.has_value();
}
template
- [[nodiscard]] inline bool sut_has_parsed_values(const optional_argument& sut) const {
+ [[nodiscard]] bool sut_has_parsed_values(const optional_argument& sut) const {
return sut.has_parsed_values();
}
template
- [[nodiscard]] inline std::weak_ordering sut_nvalues_in_range(
- const optional_argument& sut
- ) const {
+ [[nodiscard]] std::weak_ordering sut_nvalues_in_range(const optional_argument& sut) const {
return sut.nvalues_in_range();
}
template
- [[nodiscard]] inline const std::any& sut_get_value(
- const optional_argument& sut
- ) const {
+ [[nodiscard]] const std::any& sut_get_value(const optional_argument& sut) const {
return sut.value();
}
template
- [[nodiscard]] inline const std::vector& sut_get_values(
- const optional_argument& sut
- ) const {
+ [[nodiscard]] const std::vector& sut_get_values(const optional_argument& sut) const {
return sut.values();
}
template
- [[nodiscard]] inline const argument_name& sut_get_name(
- const optional_argument& sut
- ) const {
+ [[nodiscard]] const argument_name& sut_get_name(const optional_argument& sut) const {
return sut.name();
}
template
- [[nodiscard]] inline bool sut_is_required(const optional_argument& sut) const {
+ [[nodiscard]] bool sut_is_required(const optional_argument& sut) const {
return sut.is_required();
}
template
- [[nodiscard]] inline const std::optional& sut_get_help(
- const optional_argument& sut
- ) const {
+ [[nodiscard]] const std::optional& sut_get_help(const optional_argument& sut) const {
return sut.help();
}
};
diff --git a/test/include/positional_argument_test_fixture.hpp b/test/include/positional_argument_test_fixture.hpp
index 354c7f2..f3eec25 100644
--- a/test/include/positional_argument_test_fixture.hpp
+++ b/test/include/positional_argument_test_fixture.hpp
@@ -6,8 +6,8 @@
#include
-using ap::argument::detail::argument_name;
using ap::argument::positional_argument;
+using ap::argument::detail::argument_name;
using ap::utility::valid_argument_value_type;
namespace ap_testing {
@@ -20,74 +20,62 @@ struct positional_argument_test_fixture {
using value_type = typename positional_argument::value_type;
template
- [[nodiscard]] inline const argument_name& sut_get_name(
- const positional_argument& sut
- ) const {
+ [[nodiscard]] const argument_name& sut_get_name(const positional_argument& sut) const {
return sut.name();
}
template
- [[nodiscard]] inline bool sut_is_required(const positional_argument& sut) const {
+ [[nodiscard]] bool sut_is_required(const positional_argument& sut) const {
return sut.is_required();
}
template
- [[nodiscard]] inline const std::optional& sut_get_help(
- const positional_argument& sut
- ) const {
+ [[nodiscard]] const std::optional& sut_get_help(const positional_argument& sut) const {
return sut.help();
}
template
- [[nodiscard]] inline bool sut_is_used(const positional_argument& sut) const {
+ [[nodiscard]] bool sut_is_used(const positional_argument& sut) const {
return sut.is_used();
}
template
- [[nodiscard]] inline std::size_t sut_get_nused(const positional_argument& sut) const {
+ [[nodiscard]] std::size_t sut_get_nused(const positional_argument& sut) const {
return sut.nused();
}
template
- [[nodiscard]] inline bool sut_has_value(const positional_argument& sut) const {
+ [[nodiscard]] bool sut_has_value(const positional_argument& sut) const {
return sut.has_value();
}
template
- [[nodiscard]] inline bool sut_has_parsed_values(const positional_argument& sut) const {
+ [[nodiscard]] bool sut_has_parsed_values(const positional_argument& sut) const {
return sut.has_parsed_values();
}
template
- inline positional_argument& sut_set_value(
- positional_argument& sut, const std::string& str_value
- ) const {
+ positional_argument& sut_set_value(positional_argument& sut, const std::string& str_value) const {
return sut.set_value(str_value);
}
template
- inline positional_argument& sut_set_choices(
- positional_argument& sut, const std::vector>& choices
- ) const {
+ positional_argument& sut_set_choices(positional_argument& sut, const std::vector>& choices) const {
return sut.choices(choices);
}
template
- [[nodiscard]] inline std::weak_ordering sut_nvalues_in_range(
- const positional_argument& sut
- ) const {
+ [[nodiscard]] std::weak_ordering sut_nvalues_in_range(const positional_argument& sut) const {
return sut.nvalues_in_range();
}
template
- [[nodiscard]] inline const std::any& sut_get_value(
- const positional_argument& sut
- ) const {
+ [[nodiscard]] const std::any& sut_get_value(const positional_argument& sut) const {
return sut.value();
}
template
- inline const std::vector