23#if __has_include(<cxxabi.h>)
24#define LIBTCSPC_HAVE_CXA_DEMANGLE
27#warning introspected type names will be mangled (cxxabi.h not available)
35[[nodiscard]]
inline auto maybe_demangle(
char const *mangled) -> std::string {
36#ifdef LIBTCSPC_HAVE_CXA_DEMANGLE
38 auto demangled = std::unique_ptr<char, void (*)(void *)>(
39 abi::__cxa_demangle(mangled,
nullptr,
nullptr, &status), std::free);
40 return status == 0 ? demangled.get() : mangled;
75 template <
typename Processor>
77 : addr(std::uintptr_t(
processor)), typ(typeid(Processor)),
78 nm(std::move(
name)) {}
88 [[nodiscard]]
auto address() const -> std::uintptr_t {
return addr; }
103 return internal::maybe_demangle(typ.name());
111 [[nodiscard]]
auto name() const -> std::
string {
return nm; }
146 template <
typename Processor>
148 : addr(std::uintptr_t(
processor)), typ(typeid(Processor)) {}
157 return lhs.addr < rhs.addr ||
158 (lhs.addr == rhs.addr && lhs.typ < rhs.typ);
164 return lhs.addr > rhs.addr ||
165 (lhs.addr == rhs.addr && lhs.typ > rhs.typ);
171 return not(lhs > rhs);
177 return not(lhs < rhs);
205 std::vector<node_type> nds;
206 std::vector<std::pair<processor_node_id, processor_node_id>> edgs;
207 std::vector<processor_node_id> entrypts;
228 template <
typename Processor>
230 if (entrypts.size() > 1) {
231 throw std::logic_error(
232 "processor_graph can only push entry point when it has at most one entry point");
236 auto node = node_type{id,
processor->introspect_node()};
237 auto [node_lower, node_upper] = std::equal_range(
238 nds.begin(), nds.end(), node,
239 [](
auto const &l,
auto const &r) { return l.id < r.id; });
240 if (node_lower != node_upper) {
241 throw std::logic_error(
242 "processor_graph cannot push entry point that already exists");
244 nds.insert(node_upper, std::move(node));
246 if (entrypts.empty()) {
247 entrypts.push_back(
id);
249 auto const edge = std::pair{id, entrypts[0]};
250 auto edge_inspt = std::upper_bound(edgs.begin(), edgs.end(), edge);
251 edgs.insert(edge_inspt, edge);
264 std::vector<processor_node_id> ret;
265 ret.reserve(nds.size());
266 std::transform(nds.begin(), nds.end(), std::back_inserter(ret),
267 [](
auto const &n) { return n.id; });
300 return std::find(entrypts.begin(), entrypts.end(),
id) !=
315 auto it = std::find_if(nds.begin(), nds.end(),
316 [
id](
auto const &n) { return n.id == id; });
318 throw std::out_of_range(
"no such node id in processor_graph");
319 return std::size_t(std::distance(nds.begin(), it));
331 auto it = std::find_if(nds.begin(), nds.end(),
332 [
id](
auto const &n) { return n.id == id; });
334 throw std::out_of_range(
"no such node id in processor_graph");
362 c.nds.reserve(a.nds.size() + b.nds.size());
363 std::set_union(a.nds.begin(), a.nds.end(), b.nds.begin(), b.nds.end(),
364 std::back_inserter(c.nds),
365 [](
auto const &l,
auto const &r) { return l.id < r.id; });
367 c.edgs.reserve(a.edgs.size() + b.edgs.size());
368 std::set_union(a.edgs.begin(), a.edgs.end(), b.edgs.begin(), b.edgs.end(),
369 std::back_inserter(c.edgs));
371 c.entrypts.reserve(a.entrypts.size() + b.entrypts.size());
372 std::set_union(a.entrypts.begin(), a.entrypts.end(), b.entrypts.begin(),
373 b.entrypts.end(), std::back_inserter(c.entrypts));
380inline auto format_hex_addr(std::uintptr_t p) -> std::string {
381 std::array<char,
sizeof(
void *) * 2 + 3> buf{};
382 std::fill(buf.begin(), buf.end(),
'0');
385 std::to_chars(buf.data(), buf.data() + buf.size() - 1, p, 16);
387 std::rotate(buf.begin(),
388 std::next(buf.begin(), std::distance(buf.data(), r.ptr) + 1),
406[[nodiscard]]
inline auto
409 dot +=
"digraph G {\n";
410 for (
auto const &node : graph.nodes()) {
413 dot += std::to_string(graph.node_index(node));
414 dot +=
" [shape=box label=\"";
416 dot +=
"\" tooltip=\"";
419 dot += internal::format_hex_addr(info.
address());
422 for (
auto const &edge : graph.edges()) {
424 dot += std::to_string(graph.node_index(edge.first));
426 dot += std::to_string(graph.node_index(edge.second));
Value type representing a directed acyclic graph of processors.
Definition introspect.hpp:198
auto node_info(processor_node_id id) const -> processor_info
Return metadata for the processor represented by the given node.
Definition introspect.hpp:329
auto edges() const -> std::vector< std::pair< processor_node_id, processor_node_id > >
Return all of the edges of this graph.
Definition introspect.hpp:278
auto node_index(processor_node_id id) const -> std::size_t
Return the numerical index of the given node in this graph.
Definition introspect.hpp:314
auto nodes() const -> std::vector< processor_node_id >
Return all of the nodes of this graph.
Definition introspect.hpp:263
auto entry_points() const -> std::vector< processor_node_id >
Return all of the entry points of this graph.
Definition introspect.hpp:288
auto is_entry_point(processor_node_id id) const -> bool
Return whether the given node is an entry point of this graph.
Definition introspect.hpp:299
friend auto merge_processor_graphs(processor_graph const &a, processor_graph const &b) -> processor_graph
Create a new processor graph by merging two existing ones.
Definition introspect.hpp:357
auto push_entry_point(Processor const *processor) -> processor_graph &
Add a processor node to this graph, upstream of the current entry point (if any), making it the new e...
Definition introspect.hpp:229
Value type representing metadata of a processor.
Definition introspect.hpp:58
auto type_name() const -> std::string
Return the C++ type name of the processor.
Definition introspect.hpp:102
auto address() const -> std::uintptr_t
Return the address of the processor.
Definition introspect.hpp:88
processor_info(Processor const *processor, std::string name)
Construct with pointer to processor and name.
Definition introspect.hpp:76
friend auto operator==(processor_info const &lhs, processor_info const &rhs) -> bool=default
Equality comparison operator.
auto name() const -> std::string
Return the simple name of the processor.
Definition introspect.hpp:111
Value type representing processor identity within a graph.
Definition introspect.hpp:129
friend auto operator>(processor_node_id const &lhs, processor_node_id const &rhs) -> bool
Greater-than operator.
Definition introspect.hpp:162
friend auto operator==(processor_node_id const &lhs, processor_node_id const &rhs) -> bool=default
Equality comparison operator.
friend auto operator<(processor_node_id const &lhs, processor_node_id const &rhs) -> bool
Less-than operator.
Definition introspect.hpp:155
friend auto operator>=(processor_node_id const &lhs, processor_node_id const &rhs) -> bool
Greater-than-or-equal-to operator.
Definition introspect.hpp:175
friend auto operator<=(processor_node_id const &lhs, processor_node_id const &rhs) -> bool
Less-than-or-equal-to operator.
Definition introspect.hpp:169
processor_node_id(Processor const *processor)
Construct with a pointer to a processor.
Definition introspect.hpp:147
Concept that is satisfied when a processor handles the given event types and flush.
Definition processor.hpp:143
auto graphviz_from_processor_graph(processor_graph const &graph) -> std::string
Return a Graphviz dot representation of a processor graph.
Definition introspect.hpp:407
auto merge_processor_graphs(processor_graph const &a, processor_graph const &b) -> processor_graph
Create a new processor graph by merging two existing ones.
Definition introspect.hpp:357
libtcspc namespace.
Definition acquire.hpp:29