11
11
#include < stdx/tuple_algorithms.hpp>
12
12
#include < stdx/type_traits.hpp>
13
13
14
+ #include < boost/mp11/set.hpp>
15
+
14
16
#include < algorithm>
15
17
#include < array>
16
18
#include < cstddef>
20
22
#include < utility>
21
23
22
24
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
+
23
30
[[nodiscard]] constexpr auto edge_size (auto const &nodes,
24
31
auto const &edges) -> std::size_t {
25
32
auto const edge_capacities = transform (
26
33
[&]<typename N>(N const &) {
27
34
return edges.fold_left (
28
35
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>>) {
31
40
return ++acc;
32
41
} else {
33
42
return acc;
@@ -43,8 +52,6 @@ namespace flow {
43
52
44
53
template <template <stdx::ct_string, std::size_t > typename Impl>
45
54
struct graph_builder {
46
- template <typename T> using name_for = typename T::name_t ;
47
-
48
55
template <typename Node, std::size_t N, std::size_t E>
49
56
[[nodiscard]] constexpr static auto make_graph (auto const &nodes,
50
57
auto const &edges) {
@@ -119,13 +126,58 @@ struct graph_builder {
119
126
std::span{std::cbegin (ordered_list), std::size (ordered_list)}};
120
127
}
121
128
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
+
122
168
template <typename Graph>
123
169
[[nodiscard]] constexpr static auto build (Graph const &input) {
124
170
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
+
125
177
auto edges = flow::dsl::get_edges (input);
126
178
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);
129
181
130
182
using output_t = Impl<Graph::name, node_capacity>;
131
183
using rt_node_t = typename output_t ::node_t ;
@@ -135,11 +187,11 @@ struct graph_builder {
135
187
[]<typename N>(N const &) {
136
188
return std::is_convertible_v<N, rt_node_t >;
137
189
},
138
- nodes ),
190
+ node_set ),
139
191
" Output node type is not compatible with given input nodes" );
140
192
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);
143
195
return topo_sort<output_t >(g);
144
196
}
145
197
@@ -177,10 +229,17 @@ template <stdx::ct_string Name = "", typename Renderer = graph_builder<impl>,
177
229
flow::dsl::node... Fragments>
178
230
class graph {
179
231
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 ) {
181
233
return stdx::tuple_cat (flow::dsl::get_nodes (frags)...);
182
234
});
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
+ });
184
243
}
185
244
186
245
friend constexpr auto tag_invoke (flow::dsl::get_edges_t , graph const &g) {
0 commit comments