From 18af01fd2ff929269426fefb8bb07767f305efb7 Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Thu, 26 Mar 2026 12:17:14 -0400 Subject: [PATCH 01/11] feat: Add `[[nodiscard]]`, rvalue-reference `operator()` --- include/deferred/variable.hpp | 28 ++++++++++++++++++++++------ include/deferred/while.hpp | 22 ++++++++++++++++++---- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/include/deferred/variable.hpp b/include/deferred/variable.hpp index 1fd0ea5..4d68b32 100644 --- a/include/deferred/variable.hpp +++ b/include/deferred/variable.hpp @@ -1,6 +1,6 @@ /** @file */ /* - * Copyright (c) 2019-2020 Yiannis Papadopoulos + * Copyright (c) 2019-2026 Yiannis Papadopoulos * * Distributed under the terms of the MIT License. * @@ -9,6 +9,8 @@ #ifndef DEFERRED_VARIABLE_HPP #define DEFERRED_VARIABLE_HPP +#include +#include #include #include @@ -53,28 +55,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 +110,9 @@ class [[nodiscard]] variable_ * @return A newly constructed variable. */ template -constexpr variable_ variable() noexcept +[[nodiscard]] constexpr auto variable() noexcept { - return {}; + return variable_{}; } /** @@ -110,7 +126,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..7c2224b 100644 --- a/include/deferred/while.hpp +++ b/include/deferred/while.hpp @@ -1,6 +1,6 @@ /** @file */ /* - * Copyright (c) 2019-2020 Yiannis Papadopoulos + * Copyright (c) 2019-2026 Yiannis Papadopoulos * * Distributed under the terms of the MIT License. * @@ -10,6 +10,7 @@ #ifndef DEFERRED_WHILE_HPP #define DEFERRED_WHILE_HPP +#include #include #include "evaluate.hpp" @@ -46,7 +47,10 @@ 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))) { @@ -54,7 +58,8 @@ class while_expression } } - constexpr void operator()() + /// @copydoc operator()() const& + constexpr void operator()() & { while (evaluate(std::get<0>(m_expressions))) { @@ -62,6 +67,15 @@ class while_expression } } + /// @copydoc operator()() const& + constexpr void operator()() && + { + while (evaluate(std::get<0>(std::move(m_expressions)))) + { + evaluate(std::get<1>(std::move(m_expressions))); + } + } + /** * @brief Visits the while expression with a visitor. * @tparam Visitor The type of the visitor. @@ -88,7 +102,7 @@ class while_expression * @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; From 2a6e4b9a1073a608a9776a504188e17d1e36dd92 Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Thu, 26 Mar 2026 12:17:53 -0400 Subject: [PATCH 02/11] refactor: Add `[[nodiscard]]` to deferred operators --- include/deferred/operators.hpp | 52 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/include/deferred/operators.hpp b/include/deferred/operators.hpp index c44bb7b..39fcc74 100644 --- a/include/deferred/operators.hpp +++ b/include/deferred/operators.hpp @@ -29,7 +29,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 +44,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 +56,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 +68,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 +83,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 +98,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 +113,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 +125,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 +138,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 +150,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 +163,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 +178,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 +193,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 +208,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 +223,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 +238,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 +253,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 +268,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 +283,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 +295,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 +310,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 +325,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 +340,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 +352,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 +367,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 +385,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); }, From 5e7918f1b797b87205529458de51c297031436b3 Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Wed, 15 Apr 2026 20:35:57 -0400 Subject: [PATCH 03/11] feat: simplify evaluation logic --- AGENTS.md | 2 ++ README.md | 6 ------ include/deferred/apply.hpp | 6 +----- include/deferred/evaluate.hpp | 14 +++++--------- include/deferred/expression.hpp | 1 + 5 files changed, 9 insertions(+), 20 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a89089c..d777341 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -68,6 +68,8 @@ Or simply copy the `include/deferred` directory to your project's include path. - 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/README.md b/README.md index 45618d1..6d13604 100644 --- a/README.md +++ b/README.md @@ -91,9 +91,3 @@ To run tests after building: ```bash ctest --output-on-failure ``` - -Known Issues ------------- - -* 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. diff --git a/include/deferred/apply.hpp b/include/deferred/apply.hpp index 44412eb..edf5b3d 100644 --- a/include/deferred/apply.hpp +++ b/include/deferred/apply.hpp @@ -20,13 +20,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/evaluate.hpp b/include/deferred/evaluate.hpp index a21ae5b..2cf4c76 100644 --- a/include/deferred/evaluate.hpp +++ b/include/deferred/evaluate.hpp @@ -24,7 +24,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 +34,7 @@ constexpr decltype(auto) evaluate(T&& t) } else { - auto v = evaluate(std::forward(t)()); - return v; + return evaluate(std::forward(t)()); } } else @@ -46,17 +45,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..411c9bb 100644 --- a/include/deferred/expression.hpp +++ b/include/deferred/expression.hpp @@ -65,6 +65,7 @@ class expression_ return deferred::apply(m_op, m_expressions); } + /// @copydoc operator()() const constexpr decltype(auto) operator()() { return deferred::apply(m_op, m_expressions); From a52c5773170e668d983b251e2a6313df6eec97ae Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Wed, 15 Apr 2026 20:46:31 -0400 Subject: [PATCH 04/11] feat: include script for formatting --- AGENTS.md | 15 +++++++++++++++ CMakeLists.txt | 15 +++++++++++++++ README.md | 16 ++++++++++++++++ scripts/format_changed.sh | 17 +++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100755 scripts/format_changed.sh diff --git a/AGENTS.md b/AGENTS.md index d777341..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,6 +77,7 @@ 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. 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 6d13604..4d91186 100644 --- a/README.md +++ b/README.md @@ -91,3 +91,19 @@ To run tests after building: ```bash ctest --output-on-failure ``` + +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 +``` 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 From ebee15b089e6dd846a7b4f098811d89a7ecfb0e9 Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Wed, 15 Apr 2026 20:46:42 -0400 Subject: [PATCH 05/11] feat: apply [[nodiscard]] to expression operators --- include/deferred/conditional.hpp | 6 +++--- include/deferred/constant.hpp | 6 +++--- include/deferred/expression.hpp | 8 ++++---- include/deferred/invoke.hpp | 2 +- include/deferred/make_function_object.hpp | 6 ++++-- include/deferred/switch.hpp | 24 +++++++++++------------ 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/include/deferred/conditional.hpp b/include/deferred/conditional.hpp index b3c3eed..4855036 100644 --- a/include/deferred/conditional.hpp +++ b/include/deferred/conditional.hpp @@ -60,7 +60,7 @@ class if_then_else_expression std::forward(else_)) { } - constexpr result_type operator()() const + [[nodiscard]] constexpr result_type operator()() const { if (evaluate(std::get<0>(m_expressions))) { @@ -72,7 +72,7 @@ class if_then_else_expression } } - constexpr result_type operator()() + [[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..75ab8f4 100644 --- a/include/deferred/constant.hpp +++ b/include/deferred/constant.hpp @@ -48,13 +48,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 +83,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/expression.hpp b/include/deferred/expression.hpp index 411c9bb..8ca1d7d 100644 --- a/include/deferred/expression.hpp +++ b/include/deferred/expression.hpp @@ -60,23 +60,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); } /// @copydoc operator()() const - constexpr decltype(auto) operator()() + [[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..3f6d342 100644 --- a/include/deferred/invoke.hpp +++ b/include/deferred/invoke.hpp @@ -31,7 +31,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..a3bed56 100644 --- a/include/deferred/make_function_object.hpp +++ b/include/deferred/make_function_object.hpp @@ -34,7 +34,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 +50,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/switch.hpp b/include/deferred/switch.hpp index 125368b..34ad3a7 100644 --- a/include/deferred/switch.hpp +++ b/include/deferred/switch.hpp @@ -40,7 +40,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(); } @@ -88,13 +88,13 @@ 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)); } @@ -174,7 +174,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) { @@ -193,7 +193,7 @@ class switch_expression /// @copydoc 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 +211,22 @@ class switch_expression } public: - constexpr result_type operator()() const + [[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()() + [[nodiscard]] constexpr result_type operator()() { // start from second case, as first is the default return choose_case<2>(evaluate(std::get(m_expressions))); } template - constexpr decltype(auto) visit(Visitor&& v) const + constexpr void visit(Visitor&& v) const { - return std::forward(v)(*this); + std::forward(v)(*this); } }; @@ -237,7 +237,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 +252,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 +286,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>>, From 65e117da4c1564c78f5d6d582a5b97d4032610d0 Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Wed, 15 Apr 2026 20:47:13 -0400 Subject: [PATCH 06/11] feat: mark type_name as nodiscard --- include/deferred/type_name.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/deferred/type_name.hpp b/include/deferred/type_name.hpp index c10031b..11c2949 100644 --- a/include/deferred/type_name.hpp +++ b/include/deferred/type_name.hpp @@ -30,7 +30,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 +64,7 @@ std::string type_name() /// @copydoc type_name() template -auto type_name(T&& t) +[[nodiscard]] auto type_name(T&& t) { return type_name(); } From 3f7c7b1f672e74ea04798a73ed02403b18a27966 Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Wed, 15 Apr 2026 21:08:03 -0400 Subject: [PATCH 07/11] chore: update file headers to use SPDX license identifiers --- examples/saxpy/saxpy_valarray.cpp | 9 ++------- examples/saxpy/saxpy_vector.cpp | 9 ++------- examples/trivial/main.cpp | 9 ++------- 3 files changed, 6 insertions(+), 21 deletions(-) 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 From d12869e35898e11a9833a79d2e9fec227016347a Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Wed, 15 Apr 2026 21:08:19 -0400 Subject: [PATCH 08/11] chore: update license headers to SPDX format across all source and test files --- include/deferred/apply.hpp | 10 ++-------- include/deferred/conditional.hpp | 10 ++-------- include/deferred/constant.hpp | 10 ++-------- include/deferred/deferred.hpp | 10 ++-------- include/deferred/evaluate.hpp | 10 ++-------- include/deferred/expression.hpp | 10 ++-------- include/deferred/invoke.hpp | 10 ++-------- include/deferred/make_function_object.hpp | 10 ++-------- include/deferred/operators.hpp | 11 ++--------- include/deferred/switch.hpp | 10 ++-------- include/deferred/type_name.hpp | 10 ++-------- .../deferred/type_traits/is_constant_expression.hpp | 10 ++-------- include/deferred/type_traits/is_deferred.hpp | 10 ++-------- include/deferred/variable.hpp | 11 +++-------- include/deferred/while.hpp | 10 ++-------- 15 files changed, 31 insertions(+), 121 deletions(-) diff --git a/include/deferred/apply.hpp b/include/deferred/apply.hpp index edf5b3d..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 diff --git a/include/deferred/conditional.hpp b/include/deferred/conditional.hpp index 4855036..1b68832 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 diff --git a/include/deferred/constant.hpp b/include/deferred/constant.hpp index 75ab8f4..948434d 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 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 2cf4c76..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 diff --git a/include/deferred/expression.hpp b/include/deferred/expression.hpp index 8ca1d7d..4b30a15 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 diff --git a/include/deferred/invoke.hpp b/include/deferred/invoke.hpp index 3f6d342..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 diff --git a/include/deferred/make_function_object.hpp b/include/deferred/make_function_object.hpp index a3bed56..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 diff --git a/include/deferred/operators.hpp b/include/deferred/operators.hpp index 39fcc74..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 diff --git a/include/deferred/switch.hpp b/include/deferred/switch.hpp index 34ad3a7..98126b8 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 diff --git a/include/deferred/type_name.hpp b/include/deferred/type_name.hpp index 11c2949..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 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..40aa7b6 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 diff --git a/include/deferred/variable.hpp b/include/deferred/variable.hpp index 4d68b32..96804fe 100644 --- a/include/deferred/variable.hpp +++ b/include/deferred/variable.hpp @@ -1,11 +1,6 @@ -/** @file */ -/* - * Copyright (c) 2019-2026 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 diff --git a/include/deferred/while.hpp b/include/deferred/while.hpp index 7c2224b..50a740f 100644 --- a/include/deferred/while.hpp +++ b/include/deferred/while.hpp @@ -1,11 +1,5 @@ -/** @file */ -/* - * Copyright (c) 2019-2026 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 From 59c34c96aae47c3b788bd1e3ea18bf1eae7b4c7f Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Wed, 15 Apr 2026 21:08:24 -0400 Subject: [PATCH 09/11] chore: update license headers to SPDX format in test files --- test/integration/apply.cpp | 9 ++------- test/integration/conditional.cpp | 9 ++------- test/integration/constant.cpp | 9 ++------- test/integration/main.cpp | 9 ++------- test/integration/operators.cpp | 9 ++------- test/integration/switch.cpp | 9 ++------- test/integration/variable.cpp | 9 ++------- test/integration/while.cpp | 9 ++------- test/unit/conditional.cpp | 9 ++------- test/unit/constant.cpp | 9 ++------- test/unit/invoke.cpp | 9 ++------- test/unit/main.cpp | 9 ++------- test/unit/make_function_object.cpp | 9 ++------- test/unit/switch.cpp | 9 ++------- test/unit/variable.cpp | 9 ++------- test/unit/while.cpp | 9 ++------- 16 files changed, 32 insertions(+), 112 deletions(-) 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 From 17c734a89daa4db5825e6fc8500f85d25fdd3958 Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Wed, 15 Apr 2026 21:32:06 -0400 Subject: [PATCH 10/11] refactor: modernize Deferred concept, add no_unique_address to storage, and improve documentation --- include/deferred/constant.hpp | 2 +- include/deferred/switch.hpp | 6 ++++ include/deferred/type_traits/is_deferred.hpp | 33 +++++--------------- include/deferred/variable.hpp | 2 +- include/deferred/while.hpp | 6 ++-- 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/include/deferred/constant.hpp b/include/deferred/constant.hpp index 948434d..7ca0c0d 100644 --- a/include/deferred/constant.hpp +++ b/include/deferred/constant.hpp @@ -23,7 +23,7 @@ class constant_ using subexpression_types = std::tuple<>; private: - T m_t; + [[no_unique_address]] T m_t; public: /** diff --git a/include/deferred/switch.hpp b/include/deferred/switch.hpp index 98126b8..31cec95 100644 --- a/include/deferred/switch.hpp +++ b/include/deferred/switch.hpp @@ -217,6 +217,12 @@ class switch_expression 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 void visit(Visitor&& v) const { diff --git a/include/deferred/type_traits/is_deferred.hpp b/include/deferred/type_traits/is_deferred.hpp index 40aa7b6..d37b3df 100644 --- a/include/deferred/type_traits/is_deferred.hpp +++ b/include/deferred/type_traits/is_deferred.hpp @@ -8,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. @@ -36,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 96804fe..780a5a9 100644 --- a/include/deferred/variable.hpp +++ b/include/deferred/variable.hpp @@ -25,7 +25,7 @@ class [[nodiscard]] variable_ using subexpression_types = void; private: - T m_t{}; + [[no_unique_address]] T m_t{}; public: variable_() = default; diff --git a/include/deferred/while.hpp b/include/deferred/while.hpp index 50a740f..15e5970 100644 --- a/include/deferred/while.hpp +++ b/include/deferred/while.hpp @@ -52,7 +52,7 @@ class while_expression } } - /// @copydoc operator()() const& + /// @copydoc while_expression::operator()() const& constexpr void operator()() & { while (evaluate(std::get<0>(m_expressions))) @@ -61,7 +61,7 @@ class while_expression } } - /// @copydoc operator()() const& + /// @copydoc while_expression::operator()() const& constexpr void operator()() && { while (evaluate(std::get<0>(std::move(m_expressions)))) @@ -93,7 +93,7 @@ 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 [[nodiscard]] constexpr auto while_(ConditionExpression&& condition, BodyExpression&& body) From 209c7d1fe9823ce6ee70a2291965e5752eddd8b7 Mon Sep 17 00:00:00 2001 From: Yiannis Papadopoulos Date: Wed, 15 Apr 2026 21:51:20 -0400 Subject: [PATCH 11/11] refactor: standardize expression member visibility, fix move semantics in while loop, and update switch expression visitor interface --- include/deferred/conditional.hpp | 12 +++++++++--- include/deferred/expression.hpp | 8 +++++--- include/deferred/switch.hpp | 26 +++++++++++++++++++++----- include/deferred/while.hpp | 4 ++-- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/include/deferred/conditional.hpp b/include/deferred/conditional.hpp index 1b68832..9b8deee 100644 --- a/include/deferred/conditional.hpp +++ b/include/deferred/conditional.hpp @@ -25,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; @@ -36,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. @@ -54,6 +55,10 @@ class if_then_else_expression std::forward(else_)) { } + /** + * @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))) @@ -66,6 +71,7 @@ class if_then_else_expression } } + /// @copydoc if_then_else_expression::operator()() const [[nodiscard]] constexpr result_type operator()() { if (evaluate(std::get<0>(m_expressions))) diff --git a/include/deferred/expression.hpp b/include/deferred/expression.hpp index 4b30a15..8aa5628 100644 --- a/include/deferred/expression.hpp +++ b/include/deferred/expression.hpp @@ -25,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. diff --git a/include/deferred/switch.hpp b/include/deferred/switch.hpp index 31cec95..b4b58ff 100644 --- a/include/deferred/switch.hpp +++ b/include/deferred/switch.hpp @@ -61,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. @@ -93,6 +95,12 @@ class case_expression 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 { @@ -185,7 +193,7 @@ class switch_expression } } - /// @copydoc choose_case(T&&) const + /// @copydoc switch_expression::choose_case(T&&) const template [[nodiscard]] constexpr result_type choose_case(T&& t) { @@ -205,12 +213,17 @@ class switch_expression } public: + /** + * @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))); } + /// @copydoc switch_expression::operator()() const [[nodiscard]] constexpr result_type operator()() { // start from second case, as first is the default @@ -224,9 +237,12 @@ class switch_expression * @param nesting The nesting level. */ template - constexpr void visit(Visitor&& v) const + constexpr void visit(Visitor&& v, std::size_t nesting = 0) const { - 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); } }; diff --git a/include/deferred/while.hpp b/include/deferred/while.hpp index 15e5970..6f9459b 100644 --- a/include/deferred/while.hpp +++ b/include/deferred/while.hpp @@ -64,9 +64,9 @@ class while_expression /// @copydoc while_expression::operator()() const& constexpr void operator()() && { - while (evaluate(std::get<0>(std::move(m_expressions)))) + while (evaluate(std::get<0>(m_expressions))) { - evaluate(std::get<1>(std::move(m_expressions))); + evaluate(std::get<1>(m_expressions)); } }