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