diff --git a/phlex/core/edge_creation_policy.hpp b/phlex/core/edge_creation_policy.hpp index b149e3b6..e117dcb3 100644 --- a/phlex/core/edge_creation_policy.hpp +++ b/phlex/core/edge_creation_policy.hpp @@ -45,8 +45,6 @@ namespace phlex::experimental { std::multimap result; for (auto const& [node_name, node] : nodes) { for (auto const& product_name : node->output()) { - if (empty(product_name.name())) - continue; result.emplace( product_name.name(), named_output_port{node_name, &node->sender(), &node->to_output(), product_name.type()}); diff --git a/phlex/core/product_query.cpp b/phlex/core/product_query.cpp index 14fad88e..8beb2677 100644 --- a/phlex/core/product_query.cpp +++ b/phlex/core/product_query.cpp @@ -1,6 +1,8 @@ #include "phlex/core/product_query.hpp" #include "fmt/format.h" +#include "phlex/model/algorithm_name.hpp" +#include "phlex/model/product_specification.hpp" #include #include @@ -23,6 +25,11 @@ namespace phlex::experimental { return fmt::format("{} ϵ {}", spec.full(), layer); } + product_tag from(char const* creator) + { + return {.spec = product_specification(algorithm_name(creator), "", type_id())}; + } + product_tag operator""_in(char const* product_name, std::size_t length) { if (length == 0ull) { diff --git a/phlex/core/product_query.hpp b/phlex/core/product_query.hpp index 81a79e4a..9c8c2665 100644 --- a/phlex/core/product_query.hpp +++ b/phlex/core/product_query.hpp @@ -19,6 +19,11 @@ namespace phlex::experimental { struct product_tag { product_specification spec; product_query operator()(std::string layer) &&; + product_query in(std::string layer) && + { + // std::move(*this) required to forward to rvalue ref qualified operator() + return std::move(*this).operator()(std::move(layer)); + } }; using product_queries = std::vector; @@ -26,6 +31,7 @@ namespace phlex::experimental { inline auto& to_name(product_query const& query) { return query.spec.name(); } inline auto& to_layer(product_query& query) { return query.layer; } + product_tag from(char const* creator); product_tag operator""_in(char const* str, std::size_t); bool operator==(product_query const& a, product_query const& b); bool operator!=(product_query const& a, product_query const& b); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3d93011a..6acbb1b6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -110,6 +110,15 @@ cet_test( Boost::json phlex::core ) +cet_test( + anonymous_products + USE_CATCH2_MAIN + SOURCE + anonymous_products.cpp + LIBRARIES + Boost::json + phlex::core + ) cet_test( data_cell_counting USE_CATCH2_MAIN diff --git a/test/anonymous_products.cpp b/test/anonymous_products.cpp new file mode 100644 index 00000000..7d19f764 --- /dev/null +++ b/test/anonymous_products.cpp @@ -0,0 +1,58 @@ +#include "phlex/core/framework_graph.hpp" +#include "phlex/model/data_layer_hierarchy.hpp" +#include "phlex/model/product_store.hpp" + +#include "catch2/catch_test_macros.hpp" + +#include +#include +#include + +using namespace phlex::experimental; + +namespace { + auto square_numbers(std::vector const& numbers) + { + std::vector result(size(numbers)); + std::ranges::transform(numbers, begin(result), [](unsigned i) { return i * i; }); + return result; + } + + auto sum_numbers(std::vector const& squared_numbers) + { + std::vector const expected_squared_numbers{0, 1, 4, 9, 16}; + CHECK(squared_numbers == expected_squared_numbers); + return std::accumulate(begin(squared_numbers), end(squared_numbers), 0u); + } + + double sqrt_sum_numbers(unsigned summed_numbers, unsigned offset) + { + CHECK(summed_numbers == 30u); + return std::sqrt(static_cast(summed_numbers + offset)); + } +} + +TEST_CASE("Test resolution without product suffixes", "[programming model]") +{ + framework_graph g{data_cell_index::base_ptr()}; + g.provide("provide_numbers", + [](data_cell_index const&) -> std::vector { return {0, 1, 2, 3, 4}; }) + .output_product("numbers"_in("job")); + g.provide("provide_offset", [](data_cell_index const&) -> unsigned { return 6u; }) + .output_product("offset"_in("job")); + + g.transform("square_numbers", square_numbers, concurrency::unlimited) + .input_family("numbers"_in("job")) + .output_products(""); + g.transform("sum_numbers", sum_numbers, concurrency::unlimited) + .input_family(from("square_numbers").in("job")) + .output_products(""); + g.transform("sqrt_sum_numbers", sqrt_sum_numbers, concurrency::unlimited) + .input_family(from("sum_numbers").in("job"), "offset"_in("job")) + .output_products("result"); + + // The following is invoked for *each* section above + g.observe("verify_result", [](double actual) { assert(actual == 6.); }) + .input_family("result"_in("job")); + g.execute(); +}