From 4d37acdda7900c121bed1915898800abc346a4a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Murta?= Date: Wed, 6 Aug 2025 21:07:05 +0100 Subject: [PATCH] feat: simple pipeline --- CMakeLists.txt | 10 ++++- include/freepipe/freepipe.hpp | 72 +++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 5 +++ tests/pipe.test.cpp | 25 ++++++++++++ 4 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 include/freepipe/freepipe.hpp create mode 100644 tests/pipe.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a147ad7..fae5e92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.20...4.0) project( - pipeline_asio + pipe VERSION 0.1.0 LANGUAGES CXX) @@ -9,5 +9,11 @@ find_package(fmt REQUIRED) add_subdirectory(external/pipeline) add_subdirectory(external/pipes) +# Specify the include directories include_directories(include) + +add_library(pipe INTERFACE) +target_compile_features(pipe INTERFACE cxx_std_23) +target_include_directories(pipe INTERFACE include) + enable_testing() add_subdirectory(tests) diff --git a/include/freepipe/freepipe.hpp b/include/freepipe/freepipe.hpp new file mode 100644 index 0000000..2e99cc5 --- /dev/null +++ b/include/freepipe/freepipe.hpp @@ -0,0 +1,72 @@ +// Copyright 2025, Luís Murta +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace freepipe { + +template struct Task { + explicit constexpr Task(Args &&...args) + requires(sizeof...(Args) > 0) + : args_(std::forward(args)...) {} + + explicit constexpr Task() + requires(sizeof...(Args) == 0) + {} + + constexpr auto const &operator*() const & { return args_; } + constexpr auto &operator*() & { return args_; } + constexpr auto &&operator*() && { return std::move(args_); } + constexpr auto const &&operator*() const && { return std::move(args_); } + +private: + std::tuple args_; +}; + +template F> +constexpr auto operator|(Task const &task, F &&func) { + using R = std::invoke_result_t; + + if constexpr (std::is_void_v) { + std::apply(std::forward(func), *task); + return Task<>{}; + } else { + return Task{std::apply(std::forward(func), *task)}; + } +} + +template F> +constexpr auto operator|(Task &&task, F &&func) { + using R = std::invoke_result_t; + + if constexpr (std::is_void_v) { + std::apply(std::forward(func), *std::move(task)); + return Task<>{}; + } else { + return Task{std::apply(std::forward(func), *std::move(task))}; + } +} + +template > +constexpr auto operator|(Task const &task, std::basic_ostream &os) { + std::apply([&os](auto &&...args) { ((os << args << '\n'), ...); }, *task); + return Task<>{}; +} + +template > +constexpr auto operator|(Task &&task, std::basic_ostream &os) { + std::apply([&os](auto &&...args) { ((os << args << '\n'), ...); }, *std::move(task)); + return Task<>{}; +} + +class Pipe : public Task<> {}; + +} // namespace freepipe diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 62377b6..63e340c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,3 +5,8 @@ target_compile_features(pipeline.test PUBLIC cxx_std_23) target_link_libraries(pipeline.test benchmark::benchmark_main pipeline::pipeline joboccara::pipes) add_test(NAME pipeline.test COMMAND pipeline.test) + +find_package(GTest REQUIRED) +add_executable(pipe.test pipe.test.cpp) +target_compile_features(pipe.test PUBLIC cxx_std_23) +target_link_libraries(pipe.test GTest::gtest_main pipe) diff --git a/tests/pipe.test.cpp b/tests/pipe.test.cpp new file mode 100644 index 0000000..2a9ddac --- /dev/null +++ b/tests/pipe.test.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +namespace freepipe { + +TEST(PipeTest, Single) { + Pipe p; + + auto r = p | [] { return 42; } | + [](auto result) { + EXPECT_EQ(result, 42); + return result; + } | + std::cout | + [] { + SUCCEED(); + return 0; + } | + [](auto result) { EXPECT_EQ(result, 0); } | [] { return 0; }; + + EXPECT_EQ(*r, std::tuple{0}); +} + +} // namespace freepipe