Skip to content

Commit 1dfecef

Browse files
authored
Merge pull request #798 from elbeno/debug-graph
✨ Allow parts of flow graphs to be shown during compilation
2 parents 77a0508 + 8c98eed commit 1dfecef

File tree

9 files changed

+322
-148
lines changed

9 files changed

+322
-148
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,15 @@ target_sources(
241241
include
242242
FILES
243243
include/flow/builder.hpp
244+
include/flow/debug_builder.hpp
244245
include/flow/dsl/par.hpp
245246
include/flow/dsl/seq.hpp
246247
include/flow/dsl/subgraph_identity.hpp
247248
include/flow/dsl/walk.hpp
248249
include/flow/flow.hpp
249250
include/flow/func_list.hpp
250251
include/flow/graph_builder.hpp
252+
include/flow/graph_common.hpp
251253
include/flow/log.hpp
252254
include/flow/run.hpp
253255
include/flow/service.hpp

include/flow/debug_builder.hpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#pragma once
2+
3+
#include <flow/dsl/walk.hpp>
4+
#include <flow/graph_common.hpp>
5+
#include <flow/viz_builder.hpp>
6+
7+
#include <stdx/ct_string.hpp>
8+
#include <stdx/static_assert.hpp>
9+
#include <stdx/tuple.hpp>
10+
#include <stdx/tuple_algorithms.hpp>
11+
12+
#include <boost/mp11/set.hpp>
13+
14+
#include <type_traits>
15+
16+
namespace flow {
17+
template <stdx::ct_string Start, stdx::ct_string End,
18+
typename Renderer = graphviz>
19+
struct debug_builder {
20+
template <typename Graph>
21+
[[nodiscard]] static auto build(Graph const &input) {
22+
auto const nodes = stdx::to_unsorted_set(flow::dsl::get_nodes(input));
23+
auto const edges = stdx::to_unsorted_set(flow::dsl::get_edges(input));
24+
auto const named_nodes = stdx::apply_indices<name_for>(nodes);
25+
26+
using nodes_t = std::remove_cvref_t<decltype(nodes)>;
27+
using edges_t = std::remove_cvref_t<decltype(edges)>;
28+
29+
auto const start = stdx::get<stdx::cts_t<Start>>(named_nodes);
30+
using start_t = std::remove_cvref_t<decltype(start)>;
31+
32+
auto const end = stdx::get<stdx::cts_t<End>>(named_nodes);
33+
using end_t = std::remove_cvref_t<decltype(end)>;
34+
35+
using downstream_t = boost::mp11::mp_copy_if_q<
36+
nodes_t, detail::descendant_of_q<start_t, edges_t>>;
37+
using upstream_t =
38+
boost::mp11::mp_copy_if_q<nodes_t,
39+
detail::ancestor_of_q<end_t, edges_t>>;
40+
41+
using subgraph_nodes_t =
42+
boost::mp11::mp_set_intersection<downstream_t, upstream_t>;
43+
using subgraph_edges_t = boost::mp11::mp_copy_if_q<
44+
edges_t, detail::contained_edge_q<subgraph_nodes_t>>;
45+
46+
using viz_t = viz_builder<name, Renderer>;
47+
STATIC_ASSERT(
48+
false, "subgraph debug\n\n{}",
49+
(viz_t::template visualize<subgraph_nodes_t, subgraph_edges_t>()));
50+
}
51+
52+
constexpr static auto name = Start + stdx::ct_string{" -> "} + End;
53+
using interface_t = auto (*)() -> void;
54+
55+
template <typename Initialized> class built_flow {
56+
static auto run() -> void {
57+
auto const v = Initialized::value;
58+
build(v);
59+
}
60+
61+
public:
62+
// NOLINTNEXTLINE(google-explicit-constructor)
63+
constexpr explicit(false) operator interface_t() const { return run; }
64+
auto operator()() const { run(); }
65+
constexpr static bool active = true;
66+
};
67+
68+
template <typename Initialized>
69+
[[nodiscard]] constexpr static auto render() -> built_flow<Initialized> {
70+
return {};
71+
}
72+
};
73+
} // namespace flow

include/flow/graph_builder.hpp

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <flow/dsl/walk.hpp>
44
#include <flow/func_list.hpp>
5+
#include <flow/graph_common.hpp>
56

67
#include <stdx/ct_string.hpp>
78
#include <stdx/cx_multimap.hpp>
@@ -39,31 +40,6 @@ constexpr static auto error_steps =
3940
});
4041
} // namespace detail
4142

42-
template <typename T> using name_for = typename T::name_t;
43-
44-
[[nodiscard]] constexpr auto edge_size(auto const &nodes, auto const &edges)
45-
-> std::size_t {
46-
auto const edge_capacities = transform(
47-
[&]<typename N>(N const &) {
48-
return edges.fold_left(
49-
std::size_t{}, []<typename E>(auto acc, E const &) {
50-
if constexpr (std::is_same_v<name_for<typename E::source_t>,
51-
name_for<N>> or
52-
std::is_same_v<name_for<typename E::dest_t>,
53-
name_for<N>>) {
54-
return ++acc;
55-
} else {
56-
return acc;
57-
}
58-
});
59-
},
60-
nodes);
61-
62-
return edge_capacities.fold_left(std::size_t{1}, [](auto acc, auto next) {
63-
return std::max(acc, next);
64-
});
65-
}
66-
6743
template <stdx::ct_string Name, typename LogPolicy = log_policy_t<Name>,
6844
template <stdx::ct_string, typename, std::size_t> typename Impl =
6945
func_list>

include/flow/graph_common.hpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#pragma once
2+
3+
#include <stdx/ct_string.hpp>
4+
5+
#include <boost/mp11/algorithm.hpp>
6+
7+
#include <algorithm>
8+
#include <cstddef>
9+
#include <type_traits>
10+
11+
namespace flow {
12+
template <typename T> using name_for = typename T::name_t;
13+
14+
[[nodiscard]] constexpr auto edge_size(auto const &nodes, auto const &edges)
15+
-> std::size_t {
16+
auto const edge_capacities = transform(
17+
[&]<typename N>(N const &) {
18+
return edges.fold_left(
19+
std::size_t{}, []<typename E>(auto acc, E const &) {
20+
if constexpr (std::is_same_v<name_for<typename E::source_t>,
21+
name_for<N>> or
22+
std::is_same_v<name_for<typename E::dest_t>,
23+
name_for<N>>) {
24+
return ++acc;
25+
} else {
26+
return acc;
27+
}
28+
});
29+
},
30+
nodes);
31+
32+
return edge_capacities.fold_left(std::size_t{1}, [](auto acc, auto next) {
33+
return std::max(acc, next);
34+
});
35+
}
36+
37+
namespace detail {
38+
template <typename N> struct matching_source {
39+
template <typename Edge>
40+
using fn = std::is_same<name_for<N>, name_for<typename Edge::source_t>>;
41+
};
42+
43+
template <typename N> struct matching_dest {
44+
template <typename Edge>
45+
using fn = std::is_same<name_for<N>, name_for<typename Edge::dest_t>>;
46+
};
47+
48+
template <typename T> struct matching_name {
49+
template <typename U> using fn = std::is_same<name_for<T>, name_for<U>>;
50+
};
51+
52+
template <typename Nodes> struct contained_edge_q {
53+
template <typename Edge>
54+
using fn = std::bool_constant<
55+
not boost::mp11::mp_empty<boost::mp11::mp_copy_if_q<
56+
Nodes, matching_name<typename Edge::source_t>>>::value and
57+
not boost::mp11::mp_empty<boost::mp11::mp_copy_if_q<
58+
Nodes, matching_name<typename Edge::dest_t>>>::value>;
59+
};
60+
61+
template <template <typename> typename Matcher, typename Edges>
62+
struct has_no_edge_q {
63+
template <typename Node>
64+
using fn =
65+
boost::mp11::mp_empty<boost::mp11::mp_copy_if_q<Edges, Matcher<Node>>>;
66+
};
67+
68+
template <typename E> using parent_of = typename E::source_t;
69+
template <typename E> using child_of = typename E::dest_t;
70+
71+
template <typename Node, typename Edges>
72+
using parents_of = boost::mp11::mp_transform<
73+
parent_of, boost::mp11::mp_copy_if_q<Edges, matching_dest<Node>>>;
74+
75+
template <typename Node, typename Edges>
76+
using children_of = boost::mp11::mp_transform<
77+
child_of, boost::mp11::mp_copy_if_q<Edges, matching_source<Node>>>;
78+
79+
template <typename...> struct descendant_of_q;
80+
81+
template <typename L, typename Start, typename Edges>
82+
using any_descendants =
83+
boost::mp11::mp_any_of_q<L, descendant_of_q<Start, Edges>>;
84+
85+
template <typename Start, typename Edges> struct descendant_of_q<Start, Edges> {
86+
template <typename Node>
87+
using fn = boost::mp11::mp_eval_if_c<
88+
std::is_same_v<name_for<Node>, name_for<Start>>, std::true_type,
89+
any_descendants, parents_of<Node, Edges>, Start, Edges>;
90+
};
91+
92+
template <typename...> struct ancestor_of_q;
93+
94+
template <typename L, typename Start, typename Edges>
95+
using any_ancestors = boost::mp11::mp_any_of_q<L, ancestor_of_q<Start, Edges>>;
96+
97+
template <typename Start, typename Edges> struct ancestor_of_q<Start, Edges> {
98+
template <typename Node>
99+
using fn = boost::mp11::mp_eval_if_c<
100+
std::is_same_v<name_for<Node>, name_for<Start>>, std::true_type,
101+
any_ancestors, children_of<Node, Edges>, Start, Edges>;
102+
};
103+
} // namespace detail
104+
} // namespace flow

0 commit comments

Comments
 (0)