Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 <catch2/catch_test_macros.hpp>` 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.
15 changes: 15 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
9 changes: 2 additions & 7 deletions examples/saxpy/saxpy_valarray.cpp
Original file line number Diff line number Diff line change
@@ -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 <giannis.papadopoulos@gmail.com>
// SPDX-License-Identifier: MIT

#include <algorithm>
#include <iostream>
Expand Down
9 changes: 2 additions & 7 deletions examples/saxpy/saxpy_vector.cpp
Original file line number Diff line number Diff line change
@@ -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 <giannis.papadopoulos@gmail.com>
// SPDX-License-Identifier: MIT

#include <algorithm>
#include <iostream>
Expand Down
9 changes: 2 additions & 7 deletions examples/trivial/main.cpp
Original file line number Diff line number Diff line change
@@ -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 <giannis.papadopoulos@gmail.com>
// SPDX-License-Identifier: MIT

#include <deferred/deferred.hpp>
#include <iostream>
Expand Down
16 changes: 3 additions & 13 deletions include/deferred/apply.hpp
Original file line number Diff line number Diff line change
@@ -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 <giannis.papadopoulos@gmail.com>
// SPDX-License-Identifier: MIT

#ifndef DEFERRED_APPLY_HPP
#define DEFERRED_APPLY_HPP
Expand All @@ -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<typename F, typename Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>)
Expand Down
28 changes: 14 additions & 14 deletions include/deferred/conditional.hpp
Original file line number Diff line number Diff line change
@@ -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 <giannis.papadopoulos@gmail.com>
// SPDX-License-Identifier: MIT

#ifndef DEFERRED_CONDITIONAL_HPP
#define DEFERRED_CONDITIONAL_HPP
Expand All @@ -31,9 +25,6 @@ namespace deferred {
template<typename ConditionExpression, typename ThenExpression, typename ElseExpression>
class if_then_else_expression
{
[[no_unique_address]] std::tuple<ConditionExpression, ThenExpression, ElseExpression>
m_expressions;

public:
using condition_expression_type = ConditionExpression;
using then_expression_type = ThenExpression;
Expand All @@ -42,6 +33,10 @@ class if_then_else_expression
decltype(std::declval<ElseExpression>()())>;
using subexpression_types = std::tuple<ConditionExpression, ThenExpression, ElseExpression>;

private:
[[no_unique_address]] subexpression_types m_expressions;

public:
/**
* @brief Constructs an if_then_else_expression.
* @tparam Condition Type of the condition expression.
Expand All @@ -60,7 +55,11 @@ class if_then_else_expression
std::forward<ElseEx>(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)))
{
Expand All @@ -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)))
{
Expand Down Expand Up @@ -116,7 +116,7 @@ class if_then_else_expression
* @return An \ref if_then_else_expression that will perform the deferred evaluation.
*/
template<typename ConditionExpression, typename ThenExpression, typename ElseExpression>
constexpr auto
[[nodiscard]] constexpr auto
if_then_else(ConditionExpression&& condition, ThenExpression&& then_, ElseExpression&& else_)
{
using condition_expression = make_deferred_t<ConditionExpression>;
Expand Down
18 changes: 6 additions & 12 deletions include/deferred/constant.hpp
Original file line number Diff line number Diff line change
@@ -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 <giannis.papadopoulos@gmail.com>
// SPDX-License-Identifier: MIT

#ifndef DEFERRED_CONSTANT_HPP
#define DEFERRED_CONSTANT_HPP
Expand All @@ -29,7 +23,7 @@ class constant_
using subexpression_types = std::tuple<>;

private:
T m_t;
[[no_unique_address]] T m_t;

public:
/**
Expand All @@ -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);
}
Expand Down Expand Up @@ -83,7 +77,7 @@ class constant_
* @return A constant_ object containing the evaluated value.
*/
template<typename T>
constexpr auto constant(T&& t)
[[nodiscard]] constexpr auto constant(T&& t)
{
using result_type = std::decay_t<decltype(recursive_evaluate(std::forward<T>(t)))>;
return constant_<result_type>(recursive_evaluate(std::forward<T>(t)));
Expand Down
10 changes: 2 additions & 8 deletions include/deferred/deferred.hpp
Original file line number Diff line number Diff line change
@@ -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 <giannis.papadopoulos@gmail.com>
// SPDX-License-Identifier: MIT
Comment thread
ipapadop marked this conversation as resolved.

#ifndef DEFERRED_DEFERRED_HPP
#define DEFERRED_DEFERRED_HPP
Expand Down
24 changes: 7 additions & 17 deletions include/deferred/evaluate.hpp
Original file line number Diff line number Diff line change
@@ -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 <giannis.papadopoulos@gmail.com>
// SPDX-License-Identifier: MIT

#ifndef DEFERRED_EVALUATE_HPP
#define DEFERRED_EVALUATE_HPP
Expand All @@ -24,7 +18,7 @@ namespace deferred {
* @return The result of evaluating the expression.
*/
template<typename T>
constexpr decltype(auto) evaluate(T&& t)
constexpr auto evaluate(T&& t)
Comment thread
ipapadop marked this conversation as resolved.
{
if constexpr (Deferred<T>)
{
Comment thread
ipapadop marked this conversation as resolved.
Expand All @@ -34,8 +28,7 @@ constexpr decltype(auto) evaluate(T&& t)
}
else
{
auto v = evaluate(std::forward<T>(t)());
return v;
return evaluate(std::forward<T>(t)());
}
}
else
Expand All @@ -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<typename T>
constexpr decltype(auto) recursive_evaluate(T&& t)
constexpr auto recursive_evaluate(T&& t)
Comment thread
ipapadop marked this conversation as resolved.
{
if constexpr (std::is_invocable_v<T>)
{
auto v = recursive_evaluate(std::forward<T>(t)());
return v;
return recursive_evaluate(std::forward<T>(t)());
}
else
{
Expand Down
27 changes: 12 additions & 15 deletions include/deferred/expression.hpp
Original file line number Diff line number Diff line change
@@ -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 <giannis.papadopoulos@gmail.com>
// SPDX-License-Identifier: MIT

#ifndef DEFERRED_EXPRESSION_HPP
#define DEFERRED_EXPRESSION_HPP
Expand All @@ -31,14 +25,16 @@ namespace deferred {
template<typename Operator, typename... Expressions>
class expression_
{
[[no_unique_address]] Operator m_op;
[[no_unique_address]] std::tuple<Expressions...> m_expressions;

public:
using operator_type = Operator;
using expression_types = std::tuple<Expressions...>;
using subexpression_types = std::tuple<Operator, Expressions...>;

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.
Expand All @@ -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;
}
Expand Down
Loading
Loading