12#include <boost/pfr.hpp> 
   13#include <boost/mp11.hpp> 
   14#include "sygac-tuple.hpp" 
   15#include "sygac-metadata.hpp" 
   16#include "sygac-functions.hpp" 
   17#include "sygac-endpoints.hpp" 
   21using boost::mp11::mp_transform;
 
   41    =  not std::is_union_v<T>
 
   42    && (  std::is_aggregate_v<T>
 
   43       || std::is_scalar_v<T>
 
   53          && !std::same_as<void, typename function_reflection<&T::main>::return_type>)
 
   58    requires std::same_as<void, typename function_reflection<&T::main>::return_type>
 
   65    requires std::same_as<void, typename function_reflection<&T::init>::return_type>
 
   73    requires std::same_as<void, typename function_reflection<&T::external_sources>::return_type>
 
   81    requires std::same_as<void, typename function_reflection<&T::external_destinations>::return_type>
 
   85    =  std::same_as<void, 
typename function_reflection<&T::operator()>::return_type>
 
   86    || std::same_as<void, typename function_reflection<&T::main>::return_type>
 
   90    = std::same_as<void, typename function_reflection<&T::init>::return_type>;
 
   93    = std::same_as<void, typename function_reflection<&T::external_sources>::return_type>;
 
   96    = std::same_as<void, typename function_reflection<&T::external_destinations>::return_type>;
 
   98#define has_type_or_value(NAME)\ 
   99template<typename T> concept has_##NAME = requires (T t)\ 
  102    requires SimpleAggregate<decltype(t.NAME)>;\ 
  105template<has_##NAME T> struct type_of_##NAME\ 
  107    using type = decltype(std::declval<T>().NAME);\ 
  110template<typename T> using NAME##_t = typename type_of_##NAME<T>::type;\ 
  112template<typename T> requires has_##NAME<T> constexpr auto& NAME##_of(T& t) { return t.NAME; }\ 
  113template<typename T> requires has_##NAME<T> constexpr const auto& NAME##_of(const T& t) { return t.NAME; }\ 
  115has_type_or_value(inputs);
 
  116has_type_or_value(outputs);
 
  118#undef has_type_or_value 
  151struct assembly_predicate<T>
 
  153    using tup = 
decltype(boost::pfr::structure_to_tuple(std::declval<T&>()));
 
  154    using valid_components = boost::mp11::mp_transform<assembly_predicate, tup>;
 
  155    using all_valid = boost::mp11::mp_apply<boost::mp11::mp_all, valid_components>;
 
  156    static constexpr bool value = all_valid::value;
 
  195template<
typename Tag, 
typename Val>
 
  202template<
typename Tag, 
typename T>
 
  203constexpr auto endpoint_subtree(T& component)
 
  205    using ContainerTag = boost::mp11::mp_if_c< std::same_as<Tag, node::input_endpoint>
 
  210    constexpr auto f = []<
typename Container>(Container& container)
 
  212        auto endpoints = sygaldry::pfr::structure_tie(container);
 
  214        auto tail = endpoints.map([]<
typename Ep>(Ep& endpoint)
 
  216            return tpl::make_tuple(tagged<Tag, Ep>{endpoint});
 
  218        return tpl::make_tuple(tpl::tuple_cat(head, tail));
 
  221    constexpr bool inputs = std::same_as<Tag, node::input_endpoint> && has_inputs<T>;
 
  222    constexpr bool outputs = std::same_as<Tag, node::output_endpoint> && has_outputs<T>;
 
  223         if constexpr (inputs) 
return f(inputs_of(component));
 
  224    else if constexpr (outputs) 
return f(outputs_of(component));
 
  225    else return tpl::tuple<>{};
 
  229constexpr auto component_to_tree(T& component)
 
  231    if constexpr (Component<T>)
 
  233        return tpl::tuple_cat( tpl::make_tuple(tagged<node::component, T>{component})
 
  234                             , endpoint_subtree<node::input_endpoint>(component)
 
  235                             , endpoint_subtree<node::output_endpoint>(component)
 
  240        auto subcomponents = sygaldry::pfr::structure_tie(component);
 
  241        auto head = tpl::make_tuple(tagged<node::assembly, T>{component});
 
  242        auto tail = subcomponents.map([](
auto& subcomponent)
 
  244            return component_to_tree(subcomponent);
 
  246        return tpl::tuple_cat( head, tail);
 
  250constexpr auto component_tree_to_node_list(T tree)
 
  252    if constexpr (std::tuple_size_v<T> == 0) 
return tree;
 
  253    auto head = tuple_head(tree);
 
  254    auto tail = tuple_tail(tree);
 
  255    if constexpr (Tuple<
decltype(head)>) 
return tpl::tuple_cat(component_tree_to_node_list(head), component_tree_to_node_list(tail));
 
  256    else return tpl::tuple_cat(tpl::make_tuple(head), component_tree_to_node_list(tail));
 
  259constexpr auto component_to_node_list(T& component)
 
  261    return component_tree_to_node_list(component_to_tree(component));
 
  263template<
template<
typename>
typename F>
 
  264constexpr auto node_list_filter(Tuple 
auto tup)
 
  266    return tpl::apply([](
auto...args)
 
  268        auto ret = tpl::tuple_cat(args...);
 
  269        if constexpr (std::tuple_size_v<
decltype(ret)> == 0)
 
  271        else if constexpr (std::tuple_size_v<
decltype(ret)> == 1)
 
  272            return tpl::get<0>(ret);
 
  275    , tup.map([]<
typename E>(E element)
 
  277        if constexpr (F<E>::value) 
return tpl::make_tuple(element);
 
  278        else return tpl::tuple<>{};
 
  281template<
template<
typename>
typename F, 
typename T>
 
  282constexpr auto component_filter(T& component)
 
  284    return node_list_filter<F>(component_to_node_list(component));
 
  290    struct fn : std::is_same<T, typename Y::type> {};
 
 
  294constexpr auto& find(
Tuple auto tup)
 
  296    return node_list_filter<tagged_is_same<T>::template fn>(tup).ref;
 
  300constexpr auto& find(
auto& component)
 
  302    return node_list_filter<tagged_is_same<T>::template fn>(component_to_node_list(component)).ref;
 
  304template<
typename ... RequestedNodes>
 
  307    template<
typename Tag> 
using fn = boost::mp11::mp_contains<tpl::tuple<RequestedNodes...>, 
typename Tag::tag>;
 
 
  310template<
typename ... RequestedNodes>
 
  311constexpr auto node_list_filter_by_tag(
Tuple auto tup)
 
  313    return node_list_filter<
_search_by_tags<RequestedNodes...>::template fn>(tup);
 
  316template<
typename ... RequestedNodes>
 
  317constexpr auto component_filter_by_tag(
auto& component)
 
  319    return node_list_filter<_search_by_tags<RequestedNodes...>::template fn>(component_to_node_list(component));
 
  322template<
typename ... RequestedNodes>
 
  323constexpr auto for_each_node_in_list(
const Tuple 
auto node_list, 
auto callback)
 
  325    auto f = [&](
auto tagged_node)
 
  327        callback(tagged_node.ref, 
typename decltype(tagged_node)
::tag{});
 
  329    if constexpr (
sizeof...(RequestedNodes) > 0)
 
  331        constexpr auto filtered = node_list_filter_by_tag<RequestedNodes...>(node_list);
 
  332        tuple_for_each(filtered, f);
 
  334    else tuple_for_each(node_list, f);
 
  336template<
typename T, Tuple Tup>
 
  337constexpr auto path_of(
const Tup tree)
 
  339    if constexpr (std::tuple_size_v<Tup> == 0) 
 
  340        return tpl::tuple<>{};
 
  343    auto head = tuple_head(tree);
 
  344    auto tail_path = path_of<T>(tuple_tail(tree));
 
  346    if constexpr (Tuple<
decltype(head)>) 
 
  347        return tpl::tuple_cat(path_of<T>(head), tail_path);
 
  348    else if constexpr (std::same_as<
typename decltype(head)::type, T>) 
 
  349        return tpl::make_tuple(head);
 
  350    else if constexpr (std::tuple_size_v<
decltype(tail_path)> > 0) 
 
  352        if constexpr (has_name<
typename decltype(head)::type>) 
 
  353            return tpl::tuple_cat(tpl::make_tuple(head), tail_path);
 
  354        else return tail_path; 
 
  356    else return tpl::tuple<>{}; 
 
  359template<
typename T, 
typename C>
 
  360    requires Component<C> || Assembly<C>
 
  361constexpr auto path_of(C& component)
 
  363    return path_of<T>(component_to_tree(component));
 
  365template<
typename Tag> 
using untagged = 
typename Tag::type;
 
  369constexpr auto remove_node_tags(T tup)
 
  371    return tup.map([](
auto&& tagged) -> 
auto& {
return tagged.ref;});
 
  373template<
typename T> 
using output_endpoints_t =
 
  374    decltype(remove_node_tags(component_filter_by_tag<node::output_endpoint>(std::declval<T&>())));
 
  375template<
typename T> 
using input_endpoints_t =
 
  376    decltype(remove_node_tags(component_filter_by_tag<node::input_endpoint>(std::declval<T&>())));
 
  377template<
typename T> 
using endpoints_t =
 
  378    decltype(remove_node_tags(component_filter_by_tag<node::input_endpoint, node::output_endpoint>(std::declval<T&>())));
 
  379template<
typename T, 
typename C> 
using path_t =
 
  380    decltype(remove_node_tags(path_of<T>(std::declval<C&>())));
 
  382template<
typename T, 
typename ... RequestedNodes>
 
  383constexpr auto for_each_node(T& component, 
auto callback)
 
  385    using boost::mp11::mp_list;
 
  386    using boost::mp11::mp_contains;
 
  387    using boost::mp11::mp_empty;
 
  389    using nodes = mp_list<RequestedNodes...>;
 
  391    if constexpr (Assembly<T>)
 
  393        if constexpr (  mp_empty<nodes>::value
 
  394                     || mp_contains<nodes, node::assembly>::value
 
  395                     )  callback(component, node::assembly{});
 
  396        boost::pfr::for_each_field(component, [&]<
typename S>(S& subcomponent)
 
  398            for_each_node<S, RequestedNodes...>(subcomponent, callback);
 
  401    else if constexpr (Component<T>)
 
  403        if constexpr (  mp_empty<nodes>::value
 
  404                     || mp_contains<nodes, node::component>::value
 
  405                     )  callback(component, node::component{});
 
  406        if constexpr (has_inputs<T>)
 
  408            auto& inputs = inputs_of(component);
 
  410            if constexpr (  mp_empty<nodes>::value
 
  411                         || mp_contains<nodes, node::inputs_container>::value
 
  412                         || mp_contains<nodes, node::endpoints_container>::value
 
  413                         )  callback(inputs, node::inputs_container{});
 
  416            if constexpr (  mp_empty<nodes>::value
 
  417                         || mp_contains<nodes, node::input_endpoint>::value
 
  418                         || mp_contains<nodes, node::endpoint>::value
 
  419                         )  boost::pfr::for_each_field(inputs, [&](
auto& in)
 
  421                callback(in, node::input_endpoint{});
 
  424        if constexpr (has_outputs<T>)
 
  426            auto& outputs = outputs_of(component);
 
  428            if constexpr (  mp_empty<nodes>::value
 
  429                         || mp_contains<nodes, node::outputs_container>::value
 
  430                         || mp_contains<nodes, node::endpoints_container>::value
 
  431                         )  callback(outputs, node::outputs_container{});
 
  434            if constexpr (  mp_empty<nodes>::value
 
  435                         || mp_contains<nodes, node::output_endpoint>::value
 
  436                         || mp_contains<nodes, node::endpoint>::value
 
  437                         )  boost::pfr::for_each_field(outputs, [&](
auto& out)
 
  439                callback(out, node::output_endpoint{});
 
  444template <
typename T> 
constexpr void for_each_component(T& component, 
auto callback)
 
  446    for_each_node<T, node::component>(component, [&](
auto& c, 
auto) { callback(c); });
 
  449template<
typename T> 
constexpr void for_each_endpoint(T& component, 
auto callback)
 
  451    for_each_node<T, node::endpoint>(component, [&](
auto& c, 
auto) { callback(c); });
 
  454template<
typename T> 
constexpr void for_each_input(T& component, 
auto callback)
 
  456    for_each_node<T, node::input_endpoint>(component, [&](
auto& c, 
auto) { callback(c); });
 
  459template<
typename T> 
constexpr void for_each_output(T& component, 
auto callback)
 
  461    for_each_node<T, node::output_endpoint>(component, [&](
auto& c, 
auto) { callback(c); });
 
  465void clear_flag(Y& endpoint)
 
  467    if constexpr (ClearableFlag<Y>) clear_flag(endpoint);
 
  470void clear_flags(
auto& component)
 
  472    for_each_endpoint(component, [](
auto& endpoint) { clear_flag(endpoint); });
 
  475void clear_output_flags(
auto& component)
 
  477    for_each_output(component, [](
auto& endpoint) { clear_flag(endpoint); });
 
  480void clear_input_flags(
auto& component)
 
  482    for_each_input(component, [](
auto& endpoint) { clear_flag(endpoint); });
 
  486void init(T& component)
 
  488    if constexpr (
requires {component.init();}) component.init();
 
  492void init(T& container)
 
  494    for_each_component(container, [](
auto& component) {init(component);});
 
  498void activate_inner(T& component)
 
  500    if constexpr (
requires {component.main(component.inputs, component.outputs);})
 
  501        component.main(component.inputs, component.outputs);
 
  502    else if constexpr (
requires {component(component.inputs, component.outputs);})
 
  503        component(component.inputs, component.outputs);
 
  504    else if constexpr (
requires {component();})
 
  510void activate(T& component)
 
  512    clear_output_flags(component);
 
  513    activate_inner(component);
 
  514    clear_input_flags(component);
 
  518void activate(T& container)
 
  520    clear_output_flags(container);
 
  521    for_each_component(container, activate_inner);
 
  522    clear_input_flags(container);
 
Definition sygac-components.hpp:161
 
Check if T is a Sygaldry component.
Definition sygac-components.hpp:124
 
Ensure T is not a union and is either scalar or aggregate. Doesn't catch inheritance!
Definition sygac-components.hpp:41
 
Definition sygac-tuple.hpp:29
 
Definition sygac-components.hpp:96
 
Definition sygac-components.hpp:93
 
Definition sygac-components.hpp:90
 
Definition sygac-components.hpp:85
 
#define tag(TAG)
Helper struct for defining recognized tags. This is immediately undefed, so don't try to use it!
Definition sygah-endpoints.hpp:238
 
Base metafunction case for most types; most types are not assemblies.
Definition sygac-components.hpp:138
 
Default case for external destinations subroutine reflection where the subroutine does not exist.
Definition sygac-components.hpp:77
 
Default case for external sources subroutine reflection where the subroutine does not exist.
Definition sygac-components.hpp:69
 
Definition sygac-functions.hpp:107
 
Default case for init subroutine reflection where the init subroutine does not exist.
Definition sygac-components.hpp:61
 
Default case for main subroutine reflection where the main subroutine does not exist.
Definition sygac-components.hpp:48
 
Definition sygac-components.hpp:165
 
Definition sygac-components.hpp:166
 
Definition sygac-components.hpp:172
 
Definition sygac-components.hpp:169
 
Definition sygac-components.hpp:173
 
Definition sygac-components.hpp:175
 
Definition sygac-components.hpp:189
 
Definition sygac-components.hpp:185
 
Definition sygac-components.hpp:183
 
Definition sygac-components.hpp:179
 
Definition sygac-components.hpp:171
 
Definition sygac-components.hpp:168
 
Definition sygac-components.hpp:290
 
Definition sygac-components.hpp:288
 
Definition sygac-components.hpp:197