Skip to content

Commit bf5548f

Browse files
committed
add runtime_conditional and flow unary operator+
1 parent 6367d04 commit bf5548f

18 files changed

+494
-237
lines changed

examples/flow_daily_routine/main.cpp

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,10 @@ struct self_care_component_t {
9595
// Extend flow services
9696
constexpr static auto config = cib::config(
9797

98-
cib::extend<morning_routine_t>(self_care_component_t::WAKE_UP >>
99-
self_care_component_t::EXERCISE >>
100-
self_care_component_t::TAKE_BATH),
98+
cib::extend<morning_routine_t>(+WAKE_UP >> +EXERCISE >> +TAKE_BATH),
10199

102-
cib::extend<evening_routine_t>(self_care_component_t::EXERCISE >>
103-
self_care_component_t::TAKE_BATH >>
104-
self_care_component_t::RELAX >>
105-
self_care_component_t::GO_TO_BED));
100+
cib::extend<evening_routine_t>(+EXERCISE >> +TAKE_BATH >> +RELAX >>
101+
+GO_TO_BED));
106102
};
107103

108104
struct food_component_t {
@@ -119,10 +115,10 @@ struct food_component_t {
119115
constexpr static auto config = cib::config(
120116

121117
cib::extend<morning_routine_t>(self_care_component_t::TAKE_BATH >>
122-
food_component_t::BREAKFAST),
118+
+BREAKFAST),
123119

124120
cib::extend<evening_routine_t>(self_care_component_t::RELAX >>
125-
food_component_t::DINNER >>
121+
+DINNER >>
126122
self_care_component_t::GO_TO_BED));
127123
};
128124

@@ -141,16 +137,13 @@ struct dress_up_component_t {
141137
constexpr static auto config = cib::config(
142138

143139
cib::extend<morning_routine_t>(
144-
self_care_component_t::WAKE_UP >>
145-
dress_up_component_t::GET_READY_FOR_EXERCISE >>
140+
self_care_component_t::WAKE_UP >> +GET_READY_FOR_EXERCISE >>
146141
self_care_component_t::EXERCISE >>
147-
self_care_component_t::TAKE_BATH >>
148-
dress_up_component_t::GET_READY_TO_WORK >>
142+
self_care_component_t::TAKE_BATH >> +GET_READY_TO_WORK >>
149143
food_component_t::BREAKFAST),
150144

151-
cib::extend<evening_routine_t>(
152-
dress_up_component_t::GET_READY_FOR_EXERCISE >>
153-
self_care_component_t::EXERCISE));
145+
cib::extend<evening_routine_t>(+GET_READY_FOR_EXERCISE >>
146+
self_care_component_t::EXERCISE));
154147
};
155148

156149
struct commute_component_t {
@@ -167,11 +160,10 @@ struct commute_component_t {
167160
constexpr static auto config = cib::config(
168161

169162
cib::extend<morning_routine_t>(food_component_t::BREAKFAST >>
170-
commute_component_t::GO_TO_OFFICE),
163+
+GO_TO_OFFICE),
171164

172165
cib::extend<evening_routine_t>(
173-
commute_component_t::RETURN_HOME >>
174-
dress_up_component_t::GET_READY_FOR_EXERCISE));
166+
+RETURN_HOME >> dress_up_component_t::GET_READY_FOR_EXERCISE));
175167
};
176168

177169
struct daily_routine_component_t {
@@ -206,7 +198,7 @@ struct daily_routine_component_t {
206198

207199
// we need to extend the MainLoop as cib::top implements
208200
// MainLoop service
209-
cib::extend<cib::MainLoop>(DAILY_ROUTINES));
201+
cib::extend<cib::MainLoop>(+DAILY_ROUTINES));
210202
};
211203

212204
struct person_routine_proj {

include/cib/config.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <cib/detail/config_item.hpp>
88
#include <cib/detail/exports.hpp>
99
#include <cib/detail/extend.hpp>
10+
#include <cib/detail/runtime_conditional.hpp>
1011

1112
#include <stdx/compiler.hpp>
1213

@@ -22,6 +23,7 @@ namespace cib {
2223
* @see cib::extend
2324
* @see cib::exports
2425
* @see cib::conditional
26+
* @see cib::runtime_conditional
2527
*/
2628
template <typename... Configs>
2729
[[nodiscard]] CONSTEVAL auto config(Configs const &...configs) {
@@ -72,4 +74,11 @@ template <typename Predicate, typename... Configs>
7274
Configs const &...configs) {
7375
return detail::conditional<Predicate, Configs...>{configs...};
7476
}
77+
78+
template <typename Predicate, typename... Configs>
79+
requires std::is_default_constructible_v<Predicate>
80+
[[nodiscard]] CONSTEVAL auto runtime_conditional(Predicate const &,
81+
Configs const &...configs) {
82+
return detail::runtime_conditional<Predicate, Configs...>{configs...};
83+
}
7584
} // namespace cib
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
3+
#include <cib/detail/config_details.hpp>
4+
#include <cib/detail/config_item.hpp>
5+
#include <cib/detail/extend.hpp>
6+
7+
#include <stdx/compiler.hpp>
8+
#include <stdx/tuple.hpp>
9+
#include <stdx/tuple_algorithms.hpp>
10+
11+
namespace cib::detail {
12+
template <typename Pred, typename... Configs>
13+
requires std::is_default_constructible_v<Pred>
14+
struct runtime_conditional : config_item {
15+
detail::config<Configs...> body;
16+
17+
CONSTEVAL explicit runtime_conditional(Configs const &...configs)
18+
: body{configs...} {}
19+
20+
[[nodiscard]] constexpr auto extends_tuple() const {
21+
return stdx::transform(
22+
[]<typename E>(E e) {
23+
auto args_tuple = stdx::transform(
24+
[]<typename Arg>(Arg) {
25+
return make_runtime_conditional(Pred{}, Arg{});
26+
},
27+
e.args_tuple);
28+
29+
return stdx::apply(
30+
[]<typename... Args>(Args...) {
31+
return extend<typename E::service_type, Args...>{
32+
Args{}...};
33+
},
34+
args_tuple);
35+
},
36+
body.extends_tuple());
37+
}
38+
39+
[[nodiscard]] constexpr auto exports_tuple() const {
40+
return body.exports_tuple();
41+
}
42+
};
43+
} // namespace cib::detail

include/flow/detail/par.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ template <node Lhs, node Rhs> struct par {
2424
return stdx::tuple_cat(get_nodes(p.lhs), get_nodes(p.rhs));
2525
}
2626

27+
friend constexpr auto tag_invoke(get_all_mentioned_nodes_t, par const &p) {
28+
return stdx::tuple_cat(get_all_mentioned_nodes(p.lhs),
29+
get_all_mentioned_nodes(p.rhs));
30+
}
31+
2732
friend constexpr auto tag_invoke(get_edges_t, par const &p) {
2833
return stdx::tuple_cat(get_edges(p.lhs), get_edges(p.rhs));
2934
}
@@ -36,3 +41,9 @@ template <flow::dsl::node Lhs, flow::dsl::node Rhs>
3641
[[nodiscard]] constexpr auto operator&&(Lhs const &lhs, Rhs const &rhs) {
3742
return flow::dsl::par{lhs, rhs};
3843
}
44+
45+
template <typename P, flow::dsl::node Lhs, flow::dsl::node Rhs>
46+
constexpr auto make_runtime_conditional(P, flow::dsl::par<Lhs, Rhs>) {
47+
return flow::dsl::par{make_runtime_conditional(P{}, Lhs{}),
48+
make_runtime_conditional(P{}, Rhs{})};
49+
}

include/flow/detail/seq.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ template <node Lhs, node Rhs> struct seq {
2424
return stdx::tuple_cat(get_nodes(s.lhs), get_nodes(s.rhs));
2525
}
2626

27+
friend constexpr auto tag_invoke(get_all_mentioned_nodes_t, seq const &s) {
28+
return stdx::tuple_cat(get_all_mentioned_nodes(s.lhs),
29+
get_all_mentioned_nodes(s.rhs));
30+
}
31+
2732
friend constexpr auto tag_invoke(get_edges_t, seq const &s) {
2833
auto is = get_initials(s.rhs);
2934
auto fs = get_finals(s.lhs);
@@ -40,9 +45,16 @@ template <node Lhs, node Rhs> struct seq {
4045
};
4146

4247
template <node Lhs, node Rhs> seq(Lhs, Rhs) -> seq<Lhs, Rhs>;
48+
4349
} // namespace flow::dsl
4450

4551
template <flow::dsl::node Lhs, flow::dsl::node Rhs>
4652
[[nodiscard]] constexpr auto operator>>(Lhs const &lhs, Rhs const &rhs) {
4753
return flow::dsl::seq{lhs, rhs};
4854
}
55+
56+
template <typename P, flow::dsl::node Lhs, flow::dsl::node Rhs>
57+
constexpr auto make_runtime_conditional(P, flow::dsl::seq<Lhs, Rhs>) {
58+
return flow::dsl::seq{make_runtime_conditional(P{}, Lhs{}),
59+
make_runtime_conditional(P{}, Rhs{})};
60+
}

include/flow/detail/walk.hpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ constexpr inline class get_finals_t {
4747

4848
constexpr inline class get_nodes_t {
4949
template <node N> friend constexpr auto tag_invoke(get_nodes_t, N &&n) {
50-
return stdx::make_tuple(std::forward<N>(n));
50+
if constexpr (std::remove_cvref_t<N>::is_reference) {
51+
return stdx::tuple{};
52+
} else {
53+
return stdx::make_tuple(std::forward<N>(n));
54+
}
5155
}
5256

5357
public:
@@ -60,6 +64,22 @@ constexpr inline class get_nodes_t {
6064
}
6165
} get_nodes{};
6266

67+
constexpr inline class get_all_mentioned_nodes_t {
68+
template <node N>
69+
friend constexpr auto tag_invoke(get_all_mentioned_nodes_t, N &&n) {
70+
return stdx::make_tuple(std::forward<N>(n));
71+
}
72+
73+
public:
74+
template <typename... Ts>
75+
constexpr auto operator()(Ts &&...ts) const
76+
noexcept(noexcept(tag_invoke(std::declval<get_all_mentioned_nodes_t>(),
77+
std::forward<Ts>(ts)...)))
78+
-> decltype(tag_invoke(*this, std::forward<Ts>(ts)...)) {
79+
return tag_invoke(*this, std::forward<Ts>(ts)...);
80+
}
81+
} get_all_mentioned_nodes{};
82+
6383
constexpr inline class get_edges_t {
6484
friend constexpr auto tag_invoke(get_edges_t, node auto const &) {
6585
return stdx::tuple{};

include/flow/graph_builder.hpp

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <stdx/tuple_algorithms.hpp>
1212
#include <stdx/type_traits.hpp>
1313

14+
#include <boost/mp11/set.hpp>
15+
1416
#include <algorithm>
1517
#include <array>
1618
#include <cstddef>
@@ -20,14 +22,21 @@
2022
#include <utility>
2123

2224
namespace flow {
25+
namespace detail {
26+
template <typename T> using is_duplicated = std::bool_constant<(T::size() > 1)>;
27+
}
28+
template <typename T> using name_for = typename T::name_t;
29+
2330
[[nodiscard]] constexpr auto edge_size(auto const &nodes,
2431
auto const &edges) -> std::size_t {
2532
auto const edge_capacities = transform(
2633
[&]<typename N>(N const &) {
2734
return edges.fold_left(
2835
std::size_t{}, []<typename E>(auto acc, E const &) {
29-
if constexpr (std::is_same_v<typename E::source_t, N> or
30-
std::is_same_v<typename E::dest_t, N>) {
36+
if constexpr (std::is_same_v<name_for<typename E::source_t>,
37+
name_for<N>> or
38+
std::is_same_v<name_for<typename E::dest_t>,
39+
name_for<N>>) {
3140
return ++acc;
3241
} else {
3342
return acc;
@@ -43,8 +52,6 @@ namespace flow {
4352

4453
template <template <stdx::ct_string, std::size_t> typename Impl>
4554
struct graph_builder {
46-
template <typename T> using name_for = typename T::name_t;
47-
4855
template <typename Node, std::size_t N, std::size_t E>
4956
[[nodiscard]] constexpr static auto make_graph(auto const &nodes,
5057
auto const &edges) {
@@ -119,13 +126,58 @@ struct graph_builder {
119126
std::span{std::cbegin(ordered_list), std::size(ordered_list)}};
120127
}
121128

129+
constexpr static void check_for_missing_nodes(auto nodes,
130+
auto mentioned_nodes) {
131+
constexpr auto get_name = []<typename N>(N) ->
132+
typename N::name_t { return {}; };
133+
auto node_names = stdx::transform(get_name, nodes);
134+
auto mentioned_node_names = stdx::transform(get_name, mentioned_nodes);
135+
136+
using node_names_t = decltype(stdx::to_sorted_set(node_names));
137+
using mentioned_node_names_t =
138+
decltype(stdx::to_sorted_set(mentioned_node_names));
139+
140+
if constexpr (not std::is_same_v<node_names_t,
141+
mentioned_node_names_t>) {
142+
using missing_nodes_t =
143+
boost::mp11::mp_set_difference<mentioned_node_names_t,
144+
node_names_t>;
145+
146+
static_assert(
147+
stdx::always_false_v<missing_nodes_t>,
148+
"A node is referenced in the graph but not explicitly added "
149+
"with the unary plus operator. The beginning of this error "
150+
"shows you which nodes are missing.");
151+
}
152+
153+
if constexpr (stdx::tuple_size_v<node_names_t> !=
154+
stdx::tuple_size_v<decltype(node_names)>) {
155+
auto duplicates = stdx::transform(
156+
[](auto e) { return stdx::get<0>(e); },
157+
stdx::filter<detail::is_duplicated>(stdx::gather(node_names)));
158+
159+
static_assert(stdx::always_false_v<decltype(duplicates)>,
160+
"A node is explicitly added more than once using the "
161+
"unary plus "
162+
"operator. The beginning of this error shows you "
163+
"which nodes are "
164+
"duplicated.");
165+
}
166+
}
167+
122168
template <typename Graph>
123169
[[nodiscard]] constexpr static auto build(Graph const &input) {
124170
auto nodes = flow::dsl::get_nodes(input);
171+
auto mentioned_nodes = flow::dsl::get_all_mentioned_nodes(input);
172+
173+
check_for_missing_nodes(nodes, mentioned_nodes);
174+
175+
auto node_set = stdx::to_unsorted_set(nodes);
176+
125177
auto edges = flow::dsl::get_edges(input);
126178

127-
constexpr auto node_capacity = stdx::tuple_size_v<decltype(nodes)>;
128-
constexpr auto edge_capacity = edge_size(nodes, edges);
179+
constexpr auto node_capacity = stdx::tuple_size_v<decltype(node_set)>;
180+
constexpr auto edge_capacity = edge_size(node_set, edges);
129181

130182
using output_t = Impl<Graph::name, node_capacity>;
131183
using rt_node_t = typename output_t::node_t;
@@ -135,11 +187,11 @@ struct graph_builder {
135187
[]<typename N>(N const &) {
136188
return std::is_convertible_v<N, rt_node_t>;
137189
},
138-
nodes),
190+
node_set),
139191
"Output node type is not compatible with given input nodes");
140192

141-
auto g =
142-
make_graph<rt_node_t, node_capacity, edge_capacity>(nodes, edges);
193+
auto g = make_graph<rt_node_t, node_capacity, edge_capacity>(node_set,
194+
edges);
143195
return topo_sort<output_t>(g);
144196
}
145197

@@ -177,10 +229,17 @@ template <stdx::ct_string Name = "", typename Renderer = graph_builder<impl>,
177229
flow::dsl::node... Fragments>
178230
class graph {
179231
friend constexpr auto tag_invoke(flow::dsl::get_nodes_t, graph const &g) {
180-
auto t = g.fragments.apply([](auto const &...frags) {
232+
return g.fragments.apply([](auto const &...frags) {
181233
return stdx::tuple_cat(flow::dsl::get_nodes(frags)...);
182234
});
183-
return stdx::to_unsorted_set(t);
235+
}
236+
237+
friend constexpr auto tag_invoke(flow::dsl::get_all_mentioned_nodes_t,
238+
graph const &g) {
239+
return g.fragments.apply([](auto const &...frags) {
240+
return stdx::tuple_cat(
241+
flow::dsl::get_all_mentioned_nodes(frags)...);
242+
});
184243
}
185244

186245
friend constexpr auto tag_invoke(flow::dsl::get_edges_t, graph const &g) {

0 commit comments

Comments
 (0)