diff --git a/AGENTS.md b/AGENTS.md index a89089c..b97f7fa 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,6 +42,20 @@ ctest --output-on-failure ./test/integration/integration_tests ``` +### Formatting +The project uses `clang-format` for code formatting. + +To format all files: +```bash +# From the build directory +cmake --build . --target format +``` + +To format only changed files (requires `git`): +```bash +./scripts/format_changed.sh +``` + ### Building Documentation If Doxygen is found, you can generate the HTML documentation: ```bash @@ -63,11 +77,14 @@ Or simply copy the `include/deferred` directory to your project's include path. - **Indentation**: 2 spaces. - **Pointer Alignment**: Left (`Type* ptr`). - **Brace Wrapping**: Custom (check `.clang-format` for details). + - **Formatting**: All code must be formatted using `clang-format` before being committed. Use the `format` CMake target or the `scripts/format_changed.sh` script. - **Naming**: - Namespaces: `deferred` - Files: `.hpp` for headers, `.cpp` for tests/examples. - **Testing**: New features must include unit tests in `test/unit/` and integration tests in `test/integration/`. Tests use the Catch2 v3 framework. - **Catch2 v3**: Uses `#include ` and requires a custom `main` in `main.cpp` using `Catch::Session().run()`. + - **Verification**: All changes must be verified by ensuring that all tests pass (`ctest`). +- **Project Documentation**: After any code changes, `README.md` and `AGENTS.md` must be reviewed and updated if necessary to reflect the current state of the project. - **License**: MIT License. All source files should include the standard MIT license header. - **Header Guards**: Use `#ifndef DEFERRED_FILENAME_HPP` format. - **CI**: GitHub Actions workflow (`.github/workflows/c-cpp.yml`) builds the project on Ubuntu, Windows (MSVC), and macOS. diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d59244..8f7c0f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,3 +95,18 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) enable_testing() add_subdirectory(test) endif() + +# formatting + +find_program(CLANG_FORMAT clang-format) +if(CLANG_FORMAT) + file(GLOB_RECURSE ALL_SOURCE_FILES + "include/*.h*" + "test/*.c*" + "examples/*.c*") + add_custom_target(format + COMMAND ${CLANG_FORMAT} -i ${ALL_SOURCE_FILES} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Formatting code with clang-format" + VERBATIM) +endif() diff --git a/README.md b/README.md index 45618d1..4d91186 100644 --- a/README.md +++ b/README.md @@ -92,8 +92,18 @@ To run tests after building: ctest --output-on-failure ``` -Known Issues ------------- +Formatting +---------- + +The project uses `clang-format` for code formatting. + +To format all files: +```bash +# From the build directory +cmake --build . --target format +``` -* Using callable objects and functions with side-effects in ``invoke()`` and ``if_then_else()`` will result in a constant expression, assignable to ``constant_``. -* Using ``deferred`` with other expression template based classes (e.g., `std::valarray`) may not be possible. +To format only changed files (requires `git`): +```bash +./scripts/format_changed.sh +``` diff --git a/examples/saxpy/saxpy_valarray.cpp b/examples/saxpy/saxpy_valarray.cpp index 211594e..d0b42b8 100644 --- a/examples/saxpy/saxpy_valarray.cpp +++ b/examples/saxpy/saxpy_valarray.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include #include diff --git a/examples/saxpy/saxpy_vector.cpp b/examples/saxpy/saxpy_vector.cpp index 5a5c3eb..95fe8e6 100644 --- a/examples/saxpy/saxpy_vector.cpp +++ b/examples/saxpy/saxpy_vector.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include #include diff --git a/examples/trivial/main.cpp b/examples/trivial/main.cpp index f3b5e48..3720e27 100644 --- a/examples/trivial/main.cpp +++ b/examples/trivial/main.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include #include diff --git a/include/deferred/apply.hpp b/include/deferred/apply.hpp index 44412eb..22d5eeb 100644 --- a/include/deferred/apply.hpp +++ b/include/deferred/apply.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_APPLY_HPP #define DEFERRED_APPLY_HPP @@ -20,13 +14,9 @@ namespace detail { /** * @brief Helper function to apply a callable to the elements of a tuple. - * @tparam F Type of the callable. - * @tparam Tuple Type of the tuple. + * @copydoc apply(F&&, Tuple&&) * @tparam I Index sequence for tuple elements. - * @param f The callable to apply. - * @param t The tuple containing deferred objects. * @param I Index sequence for tuple elements. - * @return The result of applying @p f to the evaluated elements of @p t. */ template constexpr decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence) diff --git a/include/deferred/conditional.hpp b/include/deferred/conditional.hpp index b3c3eed..9b8deee 100644 --- a/include/deferred/conditional.hpp +++ b/include/deferred/conditional.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_CONDITIONAL_HPP #define DEFERRED_CONDITIONAL_HPP @@ -31,9 +25,6 @@ namespace deferred { template class if_then_else_expression { - [[no_unique_address]] std::tuple - m_expressions; - public: using condition_expression_type = ConditionExpression; using then_expression_type = ThenExpression; @@ -42,6 +33,10 @@ class if_then_else_expression decltype(std::declval()())>; using subexpression_types = std::tuple; +private: + [[no_unique_address]] subexpression_types m_expressions; + +public: /** * @brief Constructs an if_then_else_expression. * @tparam Condition Type of the condition expression. @@ -60,7 +55,11 @@ class if_then_else_expression std::forward(else_)) { } - constexpr result_type operator()() const + /** + * @brief Evaluates the conditional expression. + * @return The result of the conditional expression. + */ + [[nodiscard]] constexpr result_type operator()() const { if (evaluate(std::get<0>(m_expressions))) { @@ -72,7 +71,8 @@ class if_then_else_expression } } - constexpr result_type operator()() + /// @copydoc if_then_else_expression::operator()() const + [[nodiscard]] constexpr result_type operator()() { if (evaluate(std::get<0>(m_expressions))) { @@ -116,7 +116,7 @@ class if_then_else_expression * @return An \ref if_then_else_expression that will perform the deferred evaluation. */ template -constexpr auto +[[nodiscard]] constexpr auto if_then_else(ConditionExpression&& condition, ThenExpression&& then_, ElseExpression&& else_) { using condition_expression = make_deferred_t; diff --git a/include/deferred/constant.hpp b/include/deferred/constant.hpp index 9452ca5..7ca0c0d 100644 --- a/include/deferred/constant.hpp +++ b/include/deferred/constant.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_CONSTANT_HPP #define DEFERRED_CONSTANT_HPP @@ -29,7 +23,7 @@ class constant_ using subexpression_types = std::tuple<>; private: - T m_t; + [[no_unique_address]] T m_t; public: /** @@ -48,13 +42,13 @@ class constant_ constant_& operator=(constant_&&) = delete; /// Returns the stored value. - constexpr T const& operator()() const& noexcept + [[nodiscard]] constexpr T const& operator()() const& noexcept { return m_t; } /// @copydoc operator()() - constexpr T operator()() && noexcept + [[nodiscard]] constexpr T operator()() && noexcept { return std::move(m_t); } @@ -83,7 +77,7 @@ class constant_ * @return A constant_ object containing the evaluated value. */ template -constexpr auto constant(T&& t) +[[nodiscard]] constexpr auto constant(T&& t) { using result_type = std::decay_t(t)))>; return constant_(recursive_evaluate(std::forward(t))); diff --git a/include/deferred/deferred.hpp b/include/deferred/deferred.hpp index 34c7b99..9b377f9 100644 --- a/include/deferred/deferred.hpp +++ b/include/deferred/deferred.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_DEFERRED_HPP #define DEFERRED_DEFERRED_HPP diff --git a/include/deferred/evaluate.hpp b/include/deferred/evaluate.hpp index a21ae5b..9a4dd75 100644 --- a/include/deferred/evaluate.hpp +++ b/include/deferred/evaluate.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_EVALUATE_HPP #define DEFERRED_EVALUATE_HPP @@ -24,7 +18,7 @@ namespace deferred { * @return The result of evaluating the expression. */ template -constexpr decltype(auto) evaluate(T&& t) +constexpr auto evaluate(T&& t) { if constexpr (Deferred) { @@ -34,8 +28,7 @@ constexpr decltype(auto) evaluate(T&& t) } else { - auto v = evaluate(std::forward(t)()); - return v; + return evaluate(std::forward(t)()); } } else @@ -46,17 +39,14 @@ constexpr decltype(auto) evaluate(T&& t) /** * @brief Recursively evaluates @p t until a non-callable is returned. - * @tparam T The type of the expression to recursively evaluate. - * @param t The expression to recursively evaluate. - * @return The result of the recursive evaluation. + * @copydoc evaluate(T&&) */ template -constexpr decltype(auto) recursive_evaluate(T&& t) +constexpr auto recursive_evaluate(T&& t) { if constexpr (std::is_invocable_v) { - auto v = recursive_evaluate(std::forward(t)()); - return v; + return recursive_evaluate(std::forward(t)()); } else { diff --git a/include/deferred/expression.hpp b/include/deferred/expression.hpp index 6fe7df6..8aa5628 100644 --- a/include/deferred/expression.hpp +++ b/include/deferred/expression.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_EXPRESSION_HPP #define DEFERRED_EXPRESSION_HPP @@ -31,14 +25,16 @@ namespace deferred { template class expression_ { - [[no_unique_address]] Operator m_op; - [[no_unique_address]] std::tuple m_expressions; - public: using operator_type = Operator; using expression_types = std::tuple; using subexpression_types = std::tuple; +private: + [[no_unique_address]] operator_type m_op; + [[no_unique_address]] expression_types m_expressions; + +public: /** * @brief Constructs an expression. * @tparam Op The type of the operator. @@ -60,22 +56,23 @@ class expression_ expression_& operator=(expression_ const&) = delete; expression_& operator=(expression_&&) = delete; - constexpr decltype(auto) operator()() const + [[nodiscard]] constexpr decltype(auto) operator()() const { return deferred::apply(m_op, m_expressions); } - constexpr decltype(auto) operator()() + /// @copydoc operator()() const + [[nodiscard]] constexpr decltype(auto) operator()() { return deferred::apply(m_op, m_expressions); } - constexpr operator_type const& operator_() const noexcept + [[nodiscard]] constexpr operator_type const& operator_() const noexcept { return m_op; } - constexpr expression_types const& subexpressions() const noexcept + [[nodiscard]] constexpr expression_types const& subexpressions() const noexcept { return m_expressions; } diff --git a/include/deferred/invoke.hpp b/include/deferred/invoke.hpp index 0df8969..6af6317 100644 --- a/include/deferred/invoke.hpp +++ b/include/deferred/invoke.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_INVOKE_HPP #define DEFERRED_INVOKE_HPP @@ -31,7 +25,7 @@ namespace deferred { * @return An expression representing the invocation. */ template -constexpr auto invoke(F&& f, Args&&... args) +[[nodiscard]] constexpr auto invoke(F&& f, Args&&... args) { if constexpr (is_deferred_v>) { diff --git a/include/deferred/make_function_object.hpp b/include/deferred/make_function_object.hpp index 3b8e9c6..dcc1ef2 100644 --- a/include/deferred/make_function_object.hpp +++ b/include/deferred/make_function_object.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_MAKE_FUNCTION_OBJECT_HPP #define DEFERRED_MAKE_FUNCTION_OBJECT_HPP @@ -34,7 +28,8 @@ struct fun_ptr_wrapper { } template - constexpr decltype(auto) operator()(T&&... t) const noexcept(noexcept(m_f(std::forward(t)...))) + [[nodiscard]] constexpr decltype(auto) + operator()(T&&... t) const noexcept(noexcept(m_f(std::forward(t)...))) { return m_f(std::forward(t)...); } @@ -49,7 +44,8 @@ struct fun_ptr_wrapper * @return A callable object representing @p f. */ template -constexpr decltype(auto) make_function_object(F&& f) noexcept(noexcept(std::forward(f))) +[[nodiscard]] constexpr decltype(auto) +make_function_object(F&& f) noexcept(noexcept(std::forward(f))) { if constexpr (std::is_function_v>) { diff --git a/include/deferred/operators.hpp b/include/deferred/operators.hpp index c44bb7b..2828748 100644 --- a/include/deferred/operators.hpp +++ b/include/deferred/operators.hpp @@ -1,12 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ - +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_OPERATORS_HPP #define DEFERRED_OPERATORS_HPP @@ -29,7 +22,7 @@ namespace deferred { */ template requires AnyDeferred -constexpr auto operator+(T&& t, U&& u) +[[nodiscard]] constexpr auto operator+(T&& t, U&& u) { return invoke(std::plus<>{}, std::forward(t), std::forward(u)); } @@ -44,7 +37,7 @@ constexpr auto operator+(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator-(T&& t, U&& u) +[[nodiscard]] constexpr auto operator-(T&& t, U&& u) { return invoke(std::minus<>{}, std::forward(t), std::forward(u)); } @@ -56,7 +49,7 @@ constexpr auto operator-(T&& t, U&& u) * @return A deferred expression representing the operation. */ template -constexpr auto operator+(T&& t) +[[nodiscard]] constexpr auto operator+(T&& t) { return invoke([](auto&& x) { return +std::forward(x); }, std::forward(t)); } @@ -68,7 +61,7 @@ constexpr auto operator+(T&& t) * @return A deferred expression representing the operation. */ template -constexpr auto operator-(T&& t) +[[nodiscard]] constexpr auto operator-(T&& t) { return invoke(std::negate<>{}, std::forward(t)); } @@ -83,7 +76,7 @@ constexpr auto operator-(T&& t) */ template requires AnyDeferred -constexpr auto operator*(T&& t, U&& u) +[[nodiscard]] constexpr auto operator*(T&& t, U&& u) { return invoke(std::multiplies<>{}, std::forward(t), std::forward(u)); } @@ -98,7 +91,7 @@ constexpr auto operator*(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator/(T&& t, U&& u) +[[nodiscard]] constexpr auto operator/(T&& t, U&& u) { return invoke(std::divides<>{}, std::forward(t), std::forward(u)); } @@ -113,7 +106,7 @@ constexpr auto operator/(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator%(T&& t, U&& u) +[[nodiscard]] constexpr auto operator%(T&& t, U&& u) { return invoke(std::modulus<>{}, std::forward(t), std::forward(u)); } @@ -125,7 +118,7 @@ constexpr auto operator%(T&& t, U&& u) * @return A deferred expression representing the operation. */ template -constexpr auto operator++(T&& t) +[[nodiscard]] constexpr auto operator++(T&& t) { return invoke([](auto&& x) { return ++std::forward(x); }, std::forward(t)); } @@ -138,7 +131,7 @@ constexpr auto operator++(T&& t) * @return A deferred expression representing the operation. */ template -constexpr auto operator++(T&& t, int) +[[nodiscard]] constexpr auto operator++(T&& t, int) { return invoke([](auto&& x) { return std::forward(x)++; }, std::forward(t)); } @@ -150,7 +143,7 @@ constexpr auto operator++(T&& t, int) * @return A deferred expression representing the operation. */ template -constexpr auto operator--(T&& t) +[[nodiscard]] constexpr auto operator--(T&& t) { return invoke([](auto&& x) { return --std::forward(x); }, std::forward(t)); } @@ -163,7 +156,7 @@ constexpr auto operator--(T&& t) * @return A deferred expression representing the operation. */ template -constexpr auto operator--(T&& t, int) +[[nodiscard]] constexpr auto operator--(T&& t, int) { return invoke([](auto&& x) { return std::forward(x)--; }, std::forward(t)); } @@ -178,7 +171,7 @@ constexpr auto operator--(T&& t, int) */ template requires AnyDeferred -constexpr auto operator==(T&& t, U&& u) +[[nodiscard]] constexpr auto operator==(T&& t, U&& u) { return invoke(std::equal_to<>{}, std::forward(t), std::forward(u)); } @@ -193,7 +186,7 @@ constexpr auto operator==(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator!=(T&& t, U&& u) +[[nodiscard]] constexpr auto operator!=(T&& t, U&& u) { return invoke(std::not_equal_to<>{}, std::forward(t), std::forward(u)); } @@ -208,7 +201,7 @@ constexpr auto operator!=(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator>(T&& t, U&& u) +[[nodiscard]] constexpr auto operator>(T&& t, U&& u) { return invoke(std::greater<>{}, std::forward(t), std::forward(u)); } @@ -223,7 +216,7 @@ constexpr auto operator>(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator<(T&& t, U&& u) +[[nodiscard]] constexpr auto operator<(T&& t, U&& u) { return invoke(std::less<>{}, std::forward(t), std::forward(u)); } @@ -238,7 +231,7 @@ constexpr auto operator<(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator>=(T&& t, U&& u) +[[nodiscard]] constexpr auto operator>=(T&& t, U&& u) { return invoke(std::greater_equal<>{}, std::forward(t), std::forward(u)); } @@ -253,7 +246,7 @@ constexpr auto operator>=(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator<=(T&& t, U&& u) +[[nodiscard]] constexpr auto operator<=(T&& t, U&& u) { return invoke(std::less_equal<>{}, std::forward(t), std::forward(u)); } @@ -268,7 +261,7 @@ constexpr auto operator<=(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator&&(T&& t, U&& u) +[[nodiscard]] constexpr auto operator&&(T&& t, U&& u) { return invoke(std::logical_and<>{}, std::forward(t), std::forward(u)); } @@ -283,7 +276,7 @@ constexpr auto operator&&(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator||(T&& t, U&& u) +[[nodiscard]] constexpr auto operator||(T&& t, U&& u) { return invoke(std::logical_or<>{}, std::forward(t), std::forward(u)); } @@ -295,7 +288,7 @@ constexpr auto operator||(T&& t, U&& u) * @return A deferred expression representing the operation. */ template -constexpr auto operator!(T&& t) +[[nodiscard]] constexpr auto operator!(T&& t) { return invoke(std::logical_not<>{}, std::forward(t)); } @@ -310,7 +303,7 @@ constexpr auto operator!(T&& t) */ template requires AnyDeferred -constexpr auto operator&(T&& t, U&& u) +[[nodiscard]] constexpr auto operator&(T&& t, U&& u) { return invoke(std::bit_and<>{}, std::forward(t), std::forward(u)); } @@ -325,7 +318,7 @@ constexpr auto operator&(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator|(T&& t, U&& u) +[[nodiscard]] constexpr auto operator|(T&& t, U&& u) { return invoke(std::bit_or<>{}, std::forward(t), std::forward(u)); } @@ -340,7 +333,7 @@ constexpr auto operator|(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator^(T&& t, U&& u) +[[nodiscard]] constexpr auto operator^(T&& t, U&& u) { return invoke(std::bit_xor<>{}, std::forward(t), std::forward(u)); } @@ -352,7 +345,7 @@ constexpr auto operator^(T&& t, U&& u) * @return A deferred expression representing the operation. */ template -constexpr auto operator~(T&& t) +[[nodiscard]] constexpr auto operator~(T&& t) { return invoke(std::bit_not<>{}, std::forward(t)); } @@ -367,7 +360,7 @@ constexpr auto operator~(T&& t) */ template requires AnyDeferred -constexpr auto operator<<(T&& t, U&& u) +[[nodiscard]] constexpr auto operator<<(T&& t, U&& u) { return invoke( [](auto&& x, auto&& y) { return std::forward(x) << std::forward(y); }, @@ -385,7 +378,7 @@ constexpr auto operator<<(T&& t, U&& u) */ template requires AnyDeferred -constexpr auto operator>>(T&& t, U&& u) +[[nodiscard]] constexpr auto operator>>(T&& t, U&& u) { return invoke( [](auto&& x, auto&& y) { return std::forward(x) >> std::forward(y); }, diff --git a/include/deferred/switch.hpp b/include/deferred/switch.hpp index 125368b..b4b58ff 100644 --- a/include/deferred/switch.hpp +++ b/include/deferred/switch.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_SWITCH_HPP #define DEFERRED_SWITCH_HPP @@ -40,7 +34,7 @@ class default_expression constexpr explicit default_expression(T&&... t) : m_expression(std::forward(t)...) { } - constexpr decltype(auto) operator()() const + [[nodiscard]] constexpr decltype(auto) operator()() const { return m_expression(); } @@ -67,13 +61,15 @@ class default_expression template class case_expression { - [[no_unique_address]] std::tuple m_expressions; - public: using label_expression_type = LabelExpression; using body_expression_type = BodyExpression; using subexpression_types = std::tuple; +private: + [[no_unique_address]] subexpression_types m_expressions; + +public: /** * @brief Constructs a case_expression. * @tparam LabelEx The type of the label expression. @@ -88,17 +84,23 @@ class case_expression /// Compares @p T with the label expression. template - constexpr decltype(auto) compare(T&& t) const + [[nodiscard]] constexpr decltype(auto) compare(T&& t) const { return std::forward(t) == evaluate(std::get<0>(m_expressions)); } /// Returns the result of the body expression. - constexpr decltype(auto) operator()() const + [[nodiscard]] constexpr decltype(auto) operator()() const { return evaluate(std::get<1>(m_expressions)); } + /** + * @brief Visits the case expression with a visitor. + * @tparam Visitor The type of the visitor. + * @param v The visitor. + * @param nesting The nesting level. + */ template constexpr void visit(Visitor&& v, std::size_t nesting = 0) const { @@ -174,7 +176,7 @@ class switch_expression * If none does, the default (@c std::tuple_element<1>) is returned. */ template - constexpr result_type choose_case(T&& t) const + [[nodiscard]] constexpr result_type choose_case(T&& t) const { if constexpr (I < std::tuple_size::value) { @@ -191,9 +193,9 @@ class switch_expression } } - /// @copydoc choose_case(T&&) const + /// @copydoc switch_expression::choose_case(T&&) const template - constexpr result_type choose_case(T&& t) + [[nodiscard]] constexpr result_type choose_case(T&& t) { if constexpr (I < std::tuple_size::value) { @@ -211,22 +213,36 @@ class switch_expression } public: - constexpr result_type operator()() const + /** + * @brief Evaluates the switch expression. + * @return The result of the switch expression. + */ + [[nodiscard]] constexpr result_type operator()() const { // start from second case, as first is the default return choose_case<2>(evaluate(std::get(m_expressions))); } - constexpr result_type operator()() + /// @copydoc switch_expression::operator()() const + [[nodiscard]] constexpr result_type operator()() { // start from second case, as first is the default return choose_case<2>(evaluate(std::get(m_expressions))); } + /** + * @brief Visits the switch expression with a visitor. + * @tparam Visitor The type of the visitor. + * @param v The visitor. + * @param nesting The nesting level. + */ template - constexpr decltype(auto) visit(Visitor&& v) const + constexpr void visit(Visitor&& v, std::size_t nesting = 0) const { - return std::forward(v)(*this); + std::forward(v)(*this, nesting); + std::apply([&v, nesting]( + auto const&... args) { (args.visit(std::forward(v), nesting + 1), ...); }, + m_expressions); } }; @@ -237,7 +253,7 @@ class switch_expression * @return A \ref default_expression wrapping the given expression. */ template -auto default_(Expression&& ex) +[[nodiscard]] constexpr auto default_(Expression&& ex) { using expression = make_deferred_t; return default_expression(std::forward(ex)); @@ -252,7 +268,7 @@ auto default_(Expression&& ex) * @return A \ref case_expression wrapping the label and body. */ template -auto case_(LabelExpression&& label, BodyExpression&& body) +[[nodiscard]] constexpr auto case_(LabelExpression&& label, BodyExpression&& body) { using label_expression = make_deferred_t; using body_expression = make_deferred_t; @@ -286,7 +302,7 @@ auto case_(LabelExpression&& label, BodyExpression&& body) * @return A tuple-like expression representing the switch construct. */ template -constexpr auto +[[nodiscard]] constexpr auto switch_(ConditionExpression&& condition, DefaultExpression&& default_, CaseExpressions&&... case_) { static_assert(std::conjunction_v>>, diff --git a/include/deferred/type_name.hpp b/include/deferred/type_name.hpp index c10031b..411572e 100644 --- a/include/deferred/type_name.hpp +++ b/include/deferred/type_name.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_TYPE_NAME_HPP #define DEFERRED_TYPE_NAME_HPP @@ -30,7 +24,7 @@ namespace deferred { * https://stackoverflow.com/questions/18369128/how-can-i-see-the-type-deduced-for-a-template-type-parameter/18369732#18369732 */ template -std::string type_name() +[[nodiscard]] std::string type_name() { using TR = std::remove_reference_t; @@ -64,7 +58,7 @@ std::string type_name() /// @copydoc type_name() template -auto type_name(T&& t) +[[nodiscard]] auto type_name(T&& t) { return type_name(); } diff --git a/include/deferred/type_traits/is_constant_expression.hpp b/include/deferred/type_traits/is_constant_expression.hpp index ae6af32..a3bffa0 100644 --- a/include/deferred/type_traits/is_constant_expression.hpp +++ b/include/deferred/type_traits/is_constant_expression.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_TYPE_TRAITS_IS_CONSTANT_EXPRESSION_HPP #define DEFERRED_TYPE_TRAITS_IS_CONSTANT_EXPRESSION_HPP diff --git a/include/deferred/type_traits/is_deferred.hpp b/include/deferred/type_traits/is_deferred.hpp index 78fe231..d37b3df 100644 --- a/include/deferred/type_traits/is_deferred.hpp +++ b/include/deferred/type_traits/is_deferred.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_TYPE_TRAITS_IS_DEFERRED_HPP #define DEFERRED_TYPE_TRAITS_IS_DEFERRED_HPP @@ -14,22 +8,20 @@ namespace deferred { -namespace detail { - -template> -struct has_subexpression_types : std::false_type -{ }; - +/// Checks if @p T has a nested type @c subexpression_types. +/// @tparam T The type to check against the concept. template -struct has_subexpression_types> : std::true_type -{ }; +concept HasSubexpressionTypes = requires { typename T::subexpression_types; }; -} // namespace detail +/// Concept for types that are deferred expressions. +/// @tparam T The type to check against the concept. +template +concept Deferred = HasSubexpressionTypes>; /// Checks if @p T is a type in @c deferred namespace. /// @tparam T The type to check. template -struct is_deferred : public detail::has_subexpression_types> +struct is_deferred : public std::bool_constant> { }; /// Alias for @c is_deferred_datatype::type. @@ -42,21 +34,6 @@ using is_deferred_t = typename is_deferred::type; template inline constexpr bool is_deferred_v = is_deferred::value; -/// Concept for types that are deferred expressions. -/// @tparam T The type to check against the concept. -template -concept Deferred = is_deferred_v>; - -/// Checks if any of @p T... satisfies @ref is_deferred. -/// @tparam T A parameter pack of types to check. -template -using any_deferred_t = std::disjunction...>; - -/// Alias for @c any_deferred_t::value. -/// @tparam T A parameter pack of types to check. -template -inline constexpr bool any_deferred_v = any_deferred_t::value; - /// Concept for when at least one type in a set is a deferred expression. /// @tparam T A parameter pack of types to check. template diff --git a/include/deferred/variable.hpp b/include/deferred/variable.hpp index 1fd0ea5..780a5a9 100644 --- a/include/deferred/variable.hpp +++ b/include/deferred/variable.hpp @@ -1,14 +1,11 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT + #ifndef DEFERRED_VARIABLE_HPP #define DEFERRED_VARIABLE_HPP +#include +#include #include #include @@ -28,7 +25,7 @@ class [[nodiscard]] variable_ using subexpression_types = void; private: - T m_t{}; + [[no_unique_address]] T m_t{}; public: variable_() = default; @@ -53,28 +50,42 @@ class [[nodiscard]] variable_ variable_& operator=(variable_ const&) = delete; variable_& operator=(variable_&&) = delete; + /** + * @brief Assigns a value to the variable. + */ constexpr variable_& operator=(T const& t) { m_t = t; return *this; } + /// @copydoc variable_::operator=(T const&) constexpr variable_& operator=(T&& t) noexcept { m_t = std::move(t); return *this; } - constexpr T const& operator()() const& noexcept + /** + * @brief Returns the stored value. + */ + [[nodiscard]] constexpr T const& operator()() const& noexcept { return m_t; } - constexpr T& operator()() & noexcept + /// @copydoc variable_::operator()() const& noexcept + [[nodiscard]] constexpr T& operator()() & noexcept { return m_t; } + /// @copydoc variable_::operator()() const& noexcept + [[nodiscard]] constexpr T operator()() && noexcept + { + return std::move(m_t); + } + /** * @brief Visits the variable with a visitor. * @tparam Visitor The type of the visitor. @@ -94,9 +105,9 @@ class [[nodiscard]] variable_ * @return A newly constructed variable. */ template -constexpr variable_ variable() noexcept +[[nodiscard]] constexpr auto variable() noexcept { - return {}; + return variable_{}; } /** @@ -110,7 +121,7 @@ constexpr variable_ variable() noexcept * @return A variable representing the evaluated type of @p t. */ template -constexpr auto variable(T&& t) +[[nodiscard]] constexpr auto variable(T&& t) { using result_type = std::decay_t(t)))>; return variable_(recursive_evaluate(std::forward(t))); diff --git a/include/deferred/while.hpp b/include/deferred/while.hpp index 3e7f1aa..6f9459b 100644 --- a/include/deferred/while.hpp +++ b/include/deferred/while.hpp @@ -1,15 +1,10 @@ -/** @file */ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #ifndef DEFERRED_WHILE_HPP #define DEFERRED_WHILE_HPP +#include #include #include "evaluate.hpp" @@ -46,7 +41,19 @@ class while_expression m_expressions(std::forward(condition), std::forward(body)) { } - constexpr void operator()() const + /** + * @brief Evaluates the while loop. + */ + constexpr void operator()() const& + { + while (evaluate(std::get<0>(m_expressions))) + { + evaluate(std::get<1>(m_expressions)); + } + } + + /// @copydoc while_expression::operator()() const& + constexpr void operator()() & { while (evaluate(std::get<0>(m_expressions))) { @@ -54,7 +61,8 @@ class while_expression } } - constexpr void operator()() + /// @copydoc while_expression::operator()() const& + constexpr void operator()() && { while (evaluate(std::get<0>(m_expressions))) { @@ -85,10 +93,10 @@ class while_expression * @tparam BodyExpression The type of the body expression. * @param condition The condition expression. * @param body The body expression. - * @return A \ref while_expression capturing the condition and body. + * @return A @ref while_expression capturing the condition and body. */ template -constexpr auto while_(ConditionExpression&& condition, BodyExpression&& body) +[[nodiscard]] constexpr auto while_(ConditionExpression&& condition, BodyExpression&& body) { using condition_expression = make_deferred_t; using body_expression = make_deferred_t; diff --git a/scripts/format_changed.sh b/scripts/format_changed.sh new file mode 100755 index 0000000..bad7a2e --- /dev/null +++ b/scripts/format_changed.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Find changed files (Added, Copied, Modified, Renamed) in the working tree and staged area +FILES=$(git diff --name-only --diff-filter=ACMR HEAD | grep -E "\.(cpp|hpp)$") + +if [ -z "$FILES" ]; then + echo "No changed source files to format." + exit 0 +fi + +echo "Formatting changed files:" +for file in $FILES; do + if [ -f "$file" ]; then + echo " $file" + clang-format -i "$file" + fi +done diff --git a/test/integration/apply.cpp b/test/integration/apply.cpp index bc228c6..bd7261e 100644 --- a/test/integration/apply.cpp +++ b/test/integration/apply.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/integration/conditional.cpp b/test/integration/conditional.cpp index 8e87676..4d36903 100644 --- a/test/integration/conditional.cpp +++ b/test/integration/conditional.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/integration/constant.cpp b/test/integration/constant.cpp index f2515df..ee82195 100644 --- a/test/integration/constant.cpp +++ b/test/integration/constant.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/integration/main.cpp b/test/integration/main.cpp index 6a71e87..cb2e4cf 100644 --- a/test/integration/main.cpp +++ b/test/integration/main.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/integration/operators.cpp b/test/integration/operators.cpp index 975291b..8f430a8 100644 --- a/test/integration/operators.cpp +++ b/test/integration/operators.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/integration/switch.cpp b/test/integration/switch.cpp index ec9b6da..ae3e705 100644 --- a/test/integration/switch.cpp +++ b/test/integration/switch.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/integration/variable.cpp b/test/integration/variable.cpp index a7e263b..2691c05 100644 --- a/test/integration/variable.cpp +++ b/test/integration/variable.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/integration/while.cpp b/test/integration/while.cpp index 2a4c4d5..1067b24 100644 --- a/test/integration/while.cpp +++ b/test/integration/while.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/unit/conditional.cpp b/test/unit/conditional.cpp index 71db696..377a544 100644 --- a/test/unit/conditional.cpp +++ b/test/unit/conditional.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/unit/constant.cpp b/test/unit/constant.cpp index 2b3256e..1053bb5 100644 --- a/test/unit/constant.cpp +++ b/test/unit/constant.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/unit/invoke.cpp b/test/unit/invoke.cpp index eb2513e..9128bdb 100644 --- a/test/unit/invoke.cpp +++ b/test/unit/invoke.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/unit/main.cpp b/test/unit/main.cpp index 6a71e87..cb2e4cf 100644 --- a/test/unit/main.cpp +++ b/test/unit/main.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/unit/make_function_object.cpp b/test/unit/make_function_object.cpp index e79dc3a..03b60d0 100644 --- a/test/unit/make_function_object.cpp +++ b/test/unit/make_function_object.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/unit/switch.cpp b/test/unit/switch.cpp index cfd297a..45521ef 100644 --- a/test/unit/switch.cpp +++ b/test/unit/switch.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/unit/variable.cpp b/test/unit/variable.cpp index 46f4180..4094339 100644 --- a/test/unit/variable.cpp +++ b/test/unit/variable.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include diff --git a/test/unit/while.cpp b/test/unit/while.cpp index 62770b4..914583e 100644 --- a/test/unit/while.cpp +++ b/test/unit/while.cpp @@ -1,10 +1,5 @@ -/* - * Copyright (c) 2019-2020 Yiannis Papadopoulos - * - * Distributed under the terms of the MIT License. - * - * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT) - */ +// SPDX-FileCopyrightText: 2019-2026 Yiannis Papadopoulos +// SPDX-License-Identifier: MIT #include