diff --git a/include/flow/builder.hpp b/include/flow/builder.hpp index fae71370..8fe751f1 100644 --- a/include/flow/builder.hpp +++ b/include/flow/builder.hpp @@ -9,18 +9,14 @@ #include #include +#include +#include + #include namespace flow { template class builder_for { - template - friend constexpr auto tag_invoke(Tag, builder_for const &b) { - return b.fragments.apply([](auto const &...frags) { - return stdx::tuple_cat(Tag{}(frags)...); - }); - } - public: using interface_t = typename Renderer::interface_t; constexpr static auto name = Renderer::name; @@ -39,9 +35,38 @@ class builder_for { return Renderer::template render(); } + using is_builder = void; stdx::tuple fragments; }; template > using builder = builder_for>; } // namespace flow + +namespace flow::dsl::detail { +// Builders aggregate parts. Just expand all of the parts. +template +struct initials_of> { + using type = boost::mp11::mp_append...>; +}; + +template +struct finals_of> { + using type = boost::mp11::mp_append...>; +}; + +template +struct all_mentioned_of> { + using type = boost::mp11::mp_append...>; +}; + +template +struct nodes_of> { + using type = boost::mp11::mp_append...>; +}; + +template +struct edges_of> { + using type = boost::mp11::mp_append...>; +}; +} // namespace flow::dsl::detail diff --git a/include/flow/dsl/par.hpp b/include/flow/dsl/par.hpp index eb13fef1..ebdb8448 100644 --- a/include/flow/dsl/par.hpp +++ b/include/flow/dsl/par.hpp @@ -3,7 +3,8 @@ #include #include -#include +#include +#include namespace flow::dsl { template {Lhs{}, Rhs{}}; } +}; - private: - friend constexpr auto tag_invoke(get_initials_t, par const &p) { - return stdx::tuple_cat(get_initials(p.lhs), get_initials(p.rhs)); - } +template par(Lhs, Rhs) -> par; - friend constexpr auto tag_invoke(get_finals_t, par const &p) { - return stdx::tuple_cat(get_finals(p.lhs), get_finals(p.rhs)); - } +namespace detail { +template +struct initials_of> { + using type = boost::mp11::mp_append, initials_of_t>; +}; - friend constexpr auto tag_invoke(get_nodes_t, par const &p) { - if constexpr (Identity == subgraph_identity::VALUE) { - auto all_nodes = stdx::to_unsorted_set( - stdx::tuple_cat(get_all_mentioned_nodes(p.lhs), - get_all_mentioned_nodes(p.rhs))); +template +struct finals_of> { + using type = boost::mp11::mp_append, finals_of_t>; +}; - return stdx::transform([](auto const &n) { return *n; }, all_nodes); +template +struct all_mentioned_of> { + using type = + boost::mp11::mp_append, all_mentioned_of_t>; +}; - } else { - return stdx::tuple_cat(get_nodes(p.lhs), get_nodes(p.rhs)); - } - } +template +struct nodes_of> { + using type = boost::mp11::mp_transform< + star_t, boost::mp11::mp_unique< + all_mentioned_of_t>>>; +}; - friend constexpr auto tag_invoke(get_all_mentioned_nodes_t, par const &p) { - return stdx::tuple_cat(get_all_mentioned_nodes(p.lhs), - get_all_mentioned_nodes(p.rhs)); - } +template +struct nodes_of> { + using type = boost::mp11::mp_append, nodes_of_t>; +}; - friend constexpr auto tag_invoke(get_edges_t, par const &p) { - return stdx::tuple_cat(get_edges(p.lhs), get_edges(p.rhs)); - } +template +struct edges_of> { + using type = boost::mp11::mp_append, edges_of_t>; }; +} // namespace detail -template par(Lhs, Rhs) -> par; } // namespace flow::dsl template diff --git a/include/flow/dsl/seq.hpp b/include/flow/dsl/seq.hpp index e064f74d..03d66094 100644 --- a/include/flow/dsl/seq.hpp +++ b/include/flow/dsl/seq.hpp @@ -4,7 +4,8 @@ #include #include -#include +#include +#include namespace flow::dsl { template {Lhs{}, Rhs{}}; } +}; - private: - friend constexpr auto tag_invoke(get_initials_t, seq const &s) { - return get_initials(s.lhs); - } - - friend constexpr auto tag_invoke(get_finals_t, seq const &s) { - return get_finals(s.rhs); - } +template seq(Lhs, Rhs) -> seq; - friend constexpr auto tag_invoke(get_nodes_t, seq const &s) { - if constexpr (Identity == subgraph_identity::VALUE) { - auto all_nodes = stdx::to_unsorted_set( - stdx::tuple_cat(get_all_mentioned_nodes(s.lhs), - get_all_mentioned_nodes(s.rhs))); +namespace detail { +template +struct initials_of> { + using type = typename initials_of::type; +}; - return stdx::transform([](auto const &n) { return *n; }, all_nodes); +template +struct finals_of> { + using type = typename finals_of::type; +}; - } else { - return stdx::tuple_cat(get_nodes(s.lhs), get_nodes(s.rhs)); - } - } +template +struct all_mentioned_of> { + using type = + boost::mp11::mp_append, all_mentioned_of_t>; +}; - friend constexpr auto tag_invoke(get_all_mentioned_nodes_t, seq const &s) { - return stdx::tuple_cat(get_all_mentioned_nodes(s.lhs), - get_all_mentioned_nodes(s.rhs)); - } +template +struct nodes_of> { + using type = + boost::mp11::mp_transform>>>; +}; - friend constexpr auto tag_invoke(get_edges_t, seq const &s) { - auto is = get_initials(s.rhs); - auto fs = get_finals(s.lhs); - - return stdx::tuple_cat( - get_edges(s.lhs), get_edges(s.rhs), - transform( - [](P const &) { - return edge, - stdx::tuple_element_t<1, P>, Cond>{}; - }, - cartesian_product_copy(fs, is))); - } +template +struct nodes_of> { + using type = boost::mp11::mp_append, nodes_of_t>; }; -template seq(Lhs, Rhs) -> seq; +template +struct edges_of> { + using cross = boost::mp11::mp_product_q, finals_of_t, + initials_of_t>; + using type = boost::mp11::mp_append, edges_of_t, cross>; +}; +} // namespace detail } // namespace flow::dsl diff --git a/include/flow/dsl/walk.hpp b/include/flow/dsl/walk.hpp index 1c8d144b..9b948384 100644 --- a/include/flow/dsl/walk.hpp +++ b/include/flow/dsl/walk.hpp @@ -5,8 +5,14 @@ #include #include #include +#include #include +#include +#include + +#include +#include #include namespace flow::dsl { @@ -19,99 +25,129 @@ template struct edge { using cond_t = Cond; }; -constexpr inline class get_initials_t { - template - friend constexpr auto tag_invoke(get_initials_t, N &&n) { - return stdx::make_tuple(std::forward(n)); - } +template struct node_reference { + using is_subgraph = void; + constexpr static auto identity = subgraph_identity::REFERENCE; + using name_t = stdx::cts_t; +}; - public: - template - constexpr auto operator()(Ts &&...ts) const - noexcept(noexcept(tag_invoke(std::declval(), - std::forward(ts)...))) - -> decltype(tag_invoke(*this, std::forward(ts)...)) { - return tag_invoke(*this, std::forward(ts)...); - } -} get_initials{}; +namespace literals { +template [[nodiscard]] constexpr auto operator""_ref() { + return node_reference{}; +} +} // namespace literals +} // namespace flow::dsl -constexpr inline class get_finals_t { - template - friend constexpr auto tag_invoke(get_finals_t, N &&n) { - return stdx::make_tuple(std::forward(n)); - } +namespace flow::dsl::detail { - public: - template - constexpr auto operator()(Ts &&...ts) const - noexcept(noexcept(tag_invoke(std::declval(), - std::forward(ts)...))) - -> decltype(tag_invoke(*this, std::forward(ts)...)) { - return tag_invoke(*this, std::forward(ts)...); - } -} get_finals{}; - -constexpr inline class get_nodes_t { - template friend constexpr auto tag_invoke(get_nodes_t, N &&n) { - if constexpr (std::remove_cvref_t::identity == - subgraph_identity::REFERENCE) { - return stdx::tuple{}; - } else { - return stdx::make_tuple(std::forward(n)); - } - } +template struct initials_of { + using type = boost::mp11::mp_list; +}; - public: - template - constexpr auto operator()(Ts &&...ts) const - noexcept(noexcept(tag_invoke(std::declval(), - std::forward(ts)...))) - -> decltype(tag_invoke(*this, std::forward(ts)...)) { - return tag_invoke(*this, std::forward(ts)...); - } -} get_nodes{}; +template using initials_of_t = typename initials_of::type; -constexpr inline class get_all_mentioned_nodes_t { - template - friend constexpr auto tag_invoke(get_all_mentioned_nodes_t, N &&n) { - return stdx::make_tuple(std::forward(n)); - } +template struct finals_of { + using type = boost::mp11::mp_list; +}; - public: - template - constexpr auto operator()(Ts &&...ts) const - noexcept(noexcept(tag_invoke(std::declval(), - std::forward(ts)...))) - -> decltype(tag_invoke(*this, std::forward(ts)...)) { - return tag_invoke(*this, std::forward(ts)...); - } -} get_all_mentioned_nodes{}; +template using finals_of_t = typename finals_of::type; + +template struct all_mentioned_of { + using type = boost::mp11::mp_list; +}; + +template +using all_mentioned_of_t = typename all_mentioned_of::type; + +template struct nodes_of { + using type = + std::conditional_t, boost::mp11::mp_list<>>; +}; + +template using nodes_of_t = typename nodes_of::type; + +template struct edges_of { + using type = boost::mp11::mp_list<>; +}; + +template using edges_of_t = typename edges_of::type; -constexpr inline class get_edges_t { - friend constexpr auto tag_invoke(get_edges_t, subgraph auto const &) { +template +using star_t = std::remove_cvref_t())>; + +template struct make_edge_q { + template using fn = edge; +}; + +template +constexpr auto to_tuple_v = boost::mp11::mp_apply{}; + +template +concept builder_like = requires { typename T::is_builder; }; + +template +concept composite_like = requires { typename T::is_composite; }; + +constexpr auto collect_node_values(builder_like auto const &); +constexpr auto collect_node_values(composite_like auto const &); +template constexpr auto collect_node_values(Leaf const &); + +[[nodiscard]] constexpr auto collect_node_values(builder_like auto const &b) { + return b.fragments.apply([](auto const &...fs) { + return stdx::tuple_cat(collect_node_values(fs)...); + }); +} + +[[nodiscard]] constexpr auto collect_node_values(composite_like auto const &c) { + return stdx::tuple_cat(collect_node_values(c.lhs), + collect_node_values(c.rhs)); +} + +template +[[nodiscard]] constexpr auto collect_node_values(Leaf const &l) { + if constexpr (requires { *l; }) { + return stdx::make_tuple(l); + } else { return stdx::tuple{}; } +} - public: - template - constexpr auto operator()(Ts &&...ts) const - noexcept(noexcept(tag_invoke(std::declval(), - std::forward(ts)...))) - -> decltype(tag_invoke(*this, std::forward(ts)...)) { - return tag_invoke(*this, std::forward(ts)...); +// Find the node in the existing leaf instantiations +template +[[nodiscard]] constexpr auto pick_node(Leaves const &leaves) { + using leaves_t = stdx::remove_cvref_t; + using leaf_instance_list = + boost::mp11::mp_apply>; + constexpr auto idx = boost::mp11::mp_find::value; + if constexpr (idx < stdx::tuple_size_v) { + return *stdx::get(leaves); + } else { + return N{}; } -} get_edges{}; +} -template struct node_reference { - using is_subgraph = void; - constexpr static auto identity = subgraph_identity::REFERENCE; - using name_t = stdx::cts_t; -}; +template +[[nodiscard]] constexpr auto pick_nodes(boost::mp11::mp_list, + Leaves const &leaves) { + return stdx::make_tuple(pick_node(leaves)...); +} +} // namespace flow::dsl::detail -namespace literals { -template [[nodiscard]] constexpr auto operator""_ref() { - return node_reference{}; +namespace flow::dsl { +template [[nodiscard]] constexpr auto get_nodes(T const &t) { + return detail::pick_nodes(detail::nodes_of_t>{}, + detail::collect_node_values(t)); } -} // namespace literals +template +[[nodiscard]] constexpr auto get_all_mentioned_nodes(T const &) { + return detail::to_tuple_v< + detail::all_mentioned_of_t>>; +} + +template [[nodiscard]] constexpr auto get_edges(T const &) { + return detail::to_tuple_v>>; +} } // namespace flow::dsl