From 8bf639de56a8958c8ccb06c430900aa95e2a62bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Brachais?= Date: Thu, 1 Aug 2024 11:31:46 +0200 Subject: [PATCH] Light all-around fixes --- .github/workflows/cmake-multi-platform.yml | 5 +- .gitignore | 2 + README.md | 6 +- cpptools/CMakeLists.txt | 32 +++++--- cpptools/cli/argument_parsing.hpp | 12 +++ cpptools/cli/input.hpp | 90 +++++++++++----------- cpptools/cpptools.config.cpp | 1 + cpptools/exception/parameter_exception.hpp | 2 +- cpptools/utility/string.cpp | 34 ++++---- tests/CMakeLists.txt | 6 +- 10 files changed, 111 insertions(+), 79 deletions(-) create mode 100644 cpptools/cpptools.config.cpp diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index f21a025..fd82631 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -65,11 +65,8 @@ jobs: -S ${{ github.workspace }} - name: Build - # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} - name: Test working-directory: ${{ steps.strings.outputs.build-output-dir }} - # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest --build-config ${{ matrix.build_type }} + run: ctest --build-config ${{ matrix.build_type }} --test-dir tests diff --git a/.gitignore b/.gitignore index 56a1f1c..cd95654 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,7 @@ .vscode build* compile_commands.json +cpptools/cpptools.cpp +cpptools/_internal/debug_macros.hpp cpptools/_internal/debug_macros.hpp cpptools/_internal/undef_debug_macros.hpp \ No newline at end of file diff --git a/README.md b/README.md index 46e68ac..eb76bf8 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,11 @@ on at present. > **The unit tests for stuff in `cli` fail: _file "xxx" not found_.** -Copy folder `resources` (located in folder `tests`) next to the unit tests executable. CMake should be doing that as post-build task, so if you're encountering that problem as part of building through CMake, please file an issue. +Make sure you're running the test executable through CTest. If for some reason +you need to run the test executable manually, make sure that folder `resources` +(located in folder `tests`) is copied next to the unit tests executable. CMake +should be doing that as a post-build task though, so if you're encountering that +problem as part of building through CMake, please file an issue. [tree]: https://github.com/deqyra/CppTools/blob/master/cpptools/container [ranges]: https://github.com/deqyra/CppTools/blob/master/cpptools/utility/ranges.hpp diff --git a/cpptools/CMakeLists.txt b/cpptools/CMakeLists.txt index 6187de0..b72faf2 100644 --- a/cpptools/CMakeLists.txt +++ b/cpptools/CMakeLists.txt @@ -5,13 +5,7 @@ set( CPPTOOLS_TEMPLATE_CONFIG_FILE "${CMAKE_CURRENT_LIST_DIR}/../cmake/cpptools- set( CPPTOOLS_OUTPUT_CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/cpptools-config.cmake" ) set( CPPTOOLS_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/cpptools-config-version.cmake" ) -# Compile library -add_library( cpptools_objects OBJECT - _internal/assume.hpp - _internal/debug_log.hpp - _internal/debug_macros.hpp - _internal/undef_debug_macros.hpp - _internal/utility_macros.hpp +set( CPPTOOLS_HEADERS cli/argument_parsing.hpp cli/command.hpp cli/command_sequence.hpp @@ -34,7 +28,6 @@ add_library( cpptools_objects OBJECT exception/lookup_exception.hpp math/sine_generator.hpp thread/interruptible.hpp - thread/worker.cpp thread/worker.hpp utility/bitwise_enum_ops.hpp utility/clamped_value.hpp @@ -47,7 +40,6 @@ add_library( cpptools_objects OBJECT utility/monitored_value.hpp utility/predicate.hpp utility/ranges.hpp - utility/string.cpp utility/string.hpp utility/to_string.hpp utility/type_traits.hpp @@ -57,6 +49,28 @@ add_library( cpptools_objects OBJECT utility/detail/range_base.hpp ) +set( CPPTOOLS_INCLUDE_HEADERS "" ) + +foreach( HEADER ${CPPTOOLS_HEADERS} ) + set( CPPTOOLS_INCLUDE_HEADERS "${CPPTOOLS_INCLUDE_HEADERS}\n#include \"${HEADER}\"") +endforeach() + +# Trick to force compilation of inline definitions located in headers +configure_file( cpptools.config.cpp ${CMAKE_CURRENT_LIST_DIR}/cpptools.cpp ) + +# Compile library +add_library( cpptools_objects OBJECT + cpptools.cpp + _internal/assume.hpp + _internal/debug_log.hpp + _internal/debug_macros.hpp + _internal/undef_debug_macros.hpp + _internal/utility_macros.hpp + ${CPPTOOLS_HEADERS} + thread/worker.cpp + utility/string.cpp +) + set( CPPTOOLS_ENABLE_DEBUG $ ) target_include_directories( cpptools_objects diff --git a/cpptools/cli/argument_parsing.hpp b/cpptools/cli/argument_parsing.hpp index 6140ffa..af2d275 100644 --- a/cpptools/cli/argument_parsing.hpp +++ b/cpptools/cli/argument_parsing.hpp @@ -221,6 +221,18 @@ class basic_argument_value_map { return *this; } + operator std::basic_string_view() { + return at(0); + } + + [[nodiscard]] constexpr decltype(auto) operator[](this auto&& self, std::size_t idx) noexcept { + return self._values[idx]; + } + + [[nodiscard]] constexpr decltype(auto) at(this auto&& self, std::size_t idx) { + return self._values.at(idx); + } + [[nodiscard]] constexpr auto begin(this auto&& self) noexcept { return self._values.begin(); } diff --git a/cpptools/cli/input.hpp b/cpptools/cli/input.hpp index 8b0549d..323a47f 100644 --- a/cpptools/cli/input.hpp +++ b/cpptools/cli/input.hpp @@ -9,68 +9,66 @@ #include "streams.hpp" -namespace tools { +namespace tools::cli { namespace detail { -template -T parse_as(std::string_view input) = delete; + template + T parse_as(std::string_view input) = delete; -template -std::string_view type_name() = delete; + template + std::string_view type_name() = delete; -// -// Specializations of parse_string -// + // + // Specializations of parse_string + // -template<> -CPPTOOLS_API inline std::string parse_as(std::string_view input) { - return std::string(input); -} - -template<> -CPPTOOLS_API inline int parse_as(std::string_view input) { - if (!is_integer(input)) { - throw std::invalid_argument("parse_string: String to parse is not exclusively made of digits and a minus sign, or it is at a wrong position."); + template<> + CPPTOOLS_API inline std::string parse_as(std::string_view input) { + return std::string(input); } - return std::stoi(std::string(input)); -} -template<> -CPPTOOLS_API inline bool parse_as(std::string_view input) { - if (input == "y" || input == "yes" || input == "true") { - return true; + template<> + CPPTOOLS_API inline int parse_as(std::string_view input) { + if (!is_integer(input)) { + throw std::invalid_argument("parse_string: String to parse is not exclusively made of digits and a minus sign, or it is at a wrong position."); + } + return std::stoi(std::string(input)); } - if (input == "n" || input == "no" || input == "false") { - return false; - } + template<> + CPPTOOLS_API inline bool parse_as(std::string_view input) { + if (input == "y" || input == "yes" || input == "true") { + return true; + } - throw std::invalid_argument("parse_string: Invalid string value for expected bool input."); -} + if (input == "n" || input == "no" || input == "false") { + return false; + } -// -// Specializations of type_name -// + throw std::invalid_argument("parse_string: Invalid string value for expected bool input."); + } -template <> -CPPTOOLS_API inline std::string_view type_name() { - return "string"; -} + // + // Specializations of type_name + // -template <> -CPPTOOLS_API inline std::string_view type_name() { - return "integer"; -} + template <> + CPPTOOLS_API inline std::string_view type_name() { + return "string"; + } -template <> -CPPTOOLS_API inline std::string_view type_name() { - return "boolean (\"y\", \"yes\", \"true\", \"n\", \"no\", \"false\")"; -} + template <> + CPPTOOLS_API inline std::string_view type_name() { + return "integer"; + } -} // namespace detail + template <> + CPPTOOLS_API inline std::string_view type_name() { + return "boolean (\"y\", \"yes\", \"true\", \"n\", \"no\", \"false\")"; + } -namespace cli { +} // namespace detail template T read_input(cli::streams& streams) { @@ -134,8 +132,6 @@ T prompt_bounded(std::string_view title, T min, T max, cli::streams& streams) { } } -} // namespace cli - } // namespace tools #endif//CPPTOOLS_CLI_INPUT \ No newline at end of file diff --git a/cpptools/cpptools.config.cpp b/cpptools/cpptools.config.cpp new file mode 100644 index 0000000..1d541bd --- /dev/null +++ b/cpptools/cpptools.config.cpp @@ -0,0 +1 @@ +@CPPTOOLS_INCLUDE_HEADERS@ \ No newline at end of file diff --git a/cpptools/exception/parameter_exception.hpp b/cpptools/exception/parameter_exception.hpp index 03c89e4..c45217d 100644 --- a/cpptools/exception/parameter_exception.hpp +++ b/cpptools/exception/parameter_exception.hpp @@ -25,7 +25,7 @@ class parameter_exception : public base_exception { CPPTOOLS_API parameter_exception(std::string_view parameter_name, std::string parameter_value = "") : base_exception(), _parameter_name(parameter_name), - _parameter_value(parameter_value) + _parameter_value(std::move(parameter_value)) { } diff --git a/cpptools/utility/string.cpp b/cpptools/utility/string.cpp index d0b9d2d..490075d 100644 --- a/cpptools/utility/string.cpp +++ b/cpptools/utility/string.cpp @@ -56,6 +56,7 @@ void strip_cr(std::string& str) { void strip_c_comments(std::string& str) { const auto npos = std::string::npos; + // character ranges that belong to comments, in formet {start, count} std::vector> comment_ranges; // find all comments @@ -66,20 +67,27 @@ void strip_c_comments(std::string& str) { if (str.at(pos + 1) == '/') { // found "//" // find eol auto end_pos = str.find('\n', pos + 2); - if (end_pos != npos) ++end_pos; - - comment_ranges.push_back(std::make_pair(pos, end_pos - pos)); - pos = end_pos + 1; - } else if (str.at(pos + 1) == '*') {// found "/*" + auto count = (end_pos != npos) + ? end_pos - pos + : npos; + + comment_ranges.push_back(std::make_pair(pos, count)); + pos = (end_pos != npos) + ? end_pos + 1 + : npos; + } else if (str.at(pos + 1) == '*') { // found "/*" // find "*/" - auto end_pos = str.find('*', pos + 2); - if (end_pos != npos) ++end_pos; - if (end_pos == npos || str.at(end_pos) == '/') - { - ++end_pos; - comment_ranges.push_back(std::make_pair(pos, end_pos - pos)); - } - pos = end_pos; + auto end_pos = str.find("*/", pos + 2); + auto count = (end_pos != npos) + ? end_pos - pos + 2 + : npos; + + comment_ranges.push_back(std::make_pair(pos, count)); + pos = (end_pos != npos) + ? end_pos + 3 + : npos; + } else { + ++pos; } pos = str.find('/', pos); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6ae73fb..c62e474 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,6 +17,7 @@ include( FetchContent ) FetchContent_Declare( Catch2 URL https://github.com/catchorg/Catch2/archive/refs/tags/v3.5.1.zip + FIND_PACKAGE_ARGS ) FetchContent_MakeAvailable( Catch2 ) @@ -51,15 +52,12 @@ add_executable( cpptools_tests utility/test_string.cpp utility/test_wrapping_value.cpp ) -target_include_directories( cpptools_tests PUBLIC - ${CMAKE_SOURCE_DIR} -) target_link_libraries( cpptools_tests cpptools_static Catch2::Catch2WithMain ) catch_discover_tests( cpptools_tests - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/tests" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) add_custom_command(