Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
INode.hpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
10#pragma once
11
18
19#include "shambase/memory.hpp"
21#include "shambase/string.hpp"
25#include <memory>
26#include <vector>
27
28namespace shamrock::solvergraph {
29
31 class INode : public std::enable_shared_from_this<INode> {
32
34 std::vector<std::shared_ptr<IEdge>> ro_edges;
36 std::vector<std::shared_ptr<IEdge>> rw_edges;
37
41
42 public:
43 INode() = default;
44
45 INode(const INode &) = delete;
46 INode &operator=(const INode &) = delete;
47
49 INode(INode &&) noexcept = default;
50
52 INode &operator=(INode &&) noexcept = default;
53
55 inline u64 get_uuid() const { return tracker.get_uuid(); }
56
58 inline std::shared_ptr<INode> getptr_shared() { return shared_from_this(); }
60 inline std::weak_ptr<INode> getptr_weak() { return weak_from_this(); }
61
63 inline std::vector<std::shared_ptr<IEdge>> &get_ro_edges() { return ro_edges; }
65 inline std::vector<std::shared_ptr<IEdge>> &get_rw_edges() { return rw_edges; }
66
68 inline void __internal_set_ro_edges(std::vector<std::shared_ptr<IEdge>> new_ro_edges);
70 inline void __internal_set_rw_edges(std::vector<std::shared_ptr<IEdge>> new_rw_edges);
71
73 template<class Func>
74 void on_edge_ro_edges(Func &&f);
75
77 template<class Func>
78 void on_edge_rw_edges(Func &&f);
79
83 virtual ~INode() {
84 tracker.trace_destroy();
87 }
88
90 template<class T>
91 inline const T &get_ro_edge(int slot) {
92 return shambase::get_check_ref(std::dynamic_pointer_cast<T>(ro_edges.at(slot)));
93 }
94
96 template<class T>
97 inline T &get_rw_edge(int slot) {
98 return shambase::get_check_ref(std::dynamic_pointer_cast<T>(rw_edges.at(slot)));
99 }
100
102 template<class T>
103 inline std::optional<std::reference_wrapper<const T>> get_ro_edge_optional(int slot) {
104 auto &edge = ro_edges.at(slot);
105
106 auto ptr = std::dynamic_pointer_cast<T>(edge);
107 if (ptr) {
108 return std::cref(*ptr);
109 }
110
111 if (is_null_opt_edge(edge)) {
112 return std::nullopt;
113 }
114
116 sham::format("Edge is not from the requested type: {}", slot));
117 }
118
120 template<class T>
121 inline std::optional<std::reference_wrapper<T>> get_rw_edge_optional(int slot) {
122 auto &edge = rw_edges.at(slot);
123
124 auto ptr = std::dynamic_pointer_cast<T>(edge);
125 if (ptr) {
126 return std::cref(*ptr);
127 }
128
129 if (is_null_opt_edge(edge)) {
130 return std::nullopt;
131 }
132
134 sham::format("Edge is not from the requested type: {}", slot));
135 }
136
138 inline const IEdge &get_ro_edge_base(int slot) {
139 return shambase::get_check_ref(ro_edges.at(slot));
140 }
141
142 inline const IEdge &get_ro_edge_base(int slot) const {
143 return shambase::get_check_ref(ro_edges.at(slot));
144 }
145
147 inline IEdge &get_rw_edge_base(int slot) {
148 return shambase::get_check_ref(rw_edges.at(slot));
149 }
150
151 inline const IEdge &get_rw_edge_base(int slot) const {
152 return shambase::get_check_ref(rw_edges.at(slot));
153 }
154
156 inline void evaluate() {
157 // if solvergraph tracing is not enabled the .trace_event has the perf of a if statement
158 tracker.trace_event([]() {
159 return "evaluate_begin";
160 });
162 tracker.trace_event([]() {
163 return "evaluate_end";
164 });
165 }
166
168 inline std::string get_dot_graph() { return get_dot_graph_partial(); };
169
171 inline std::string get_dot_graph_partial() { return _impl_get_dot_graph_partial(); };
172
176 inline std::string get_dot_graph_node_end() { return _impl_get_dot_graph_node_end(); };
177
179 inline std::string get_tex() { return _impl_get_tex(); };
181 inline std::string get_tex_partial() { return _impl_get_tex(); };
183 inline std::string get_label() const { return _impl_get_label(); };
184
186 inline virtual std::string print_node_info() const {
187 std::string node_info = sham::format("Node info :\n");
188 node_info += sham::format(" - Node type : {}\n", typeid(*this).name());
189 node_info += sham::format(" - Node UUID : {}\n", get_uuid());
190 node_info += sham::format(" - Node label : {}\n", _impl_get_label());
191
192 auto append_edges_info = [&](const char *title, const auto &edges) {
193 node_info += sham::format(" - {}: {}\n", title, edges.size());
194 for (const auto &edge : edges) {
195 const auto &e = *edge; // necessary to avoid -Wpotentially-evaluated-expression
196 node_info += sham::format(
197 " - Edge ptr = {}, uuid = {}, label = {},\n type = {} \n",
198 static_cast<void *>(edge.get()),
199 edge->get_uuid(),
200 edge->get_label(),
201 typeid(e).name());
202 }
203 };
204
205 append_edges_info("Node Read Only edges", ro_edges);
206 append_edges_info("Node Read Write edges", rw_edges);
207
208 return node_info;
209 };
210
211 protected:
219 inline void notify_self_state_update() { tracker.trace_state_update(*this); }
220
222 virtual void _impl_evaluate_internal() = 0;
223
225 virtual std::string _impl_get_label() const = 0;
226
228 virtual std::string _impl_get_dot_graph_partial() const;
230 virtual std::string _impl_get_dot_graph_node_start() const;
232 virtual std::string _impl_get_dot_graph_node_end() const;
233
235 virtual std::string _impl_get_tex() const = 0;
236 };
237
238 inline void INode::__internal_set_ro_edges(std::vector<std::shared_ptr<IEdge>> new_ro_edges) {
239 for (auto e : ro_edges) {
240 // shambase::get_check_ref(e).parent = {};
241 }
242 this->ro_edges = new_ro_edges;
243 for (auto e : ro_edges) {
244 // shambase::get_check_ref(e).parent = getptr_weak();
245 }
246 tracker.trace_state_update(*this);
247 }
248
249 inline void INode::__internal_set_rw_edges(std::vector<std::shared_ptr<IEdge>> new_rw_edges) {
250 for (auto e : rw_edges) {
251 // shambase::get_check_ref(e).child = {};
252 }
253 this->rw_edges = new_rw_edges;
254 for (auto e : rw_edges) {
255 // shambase::get_check_ref(e).child = getptr_weak();
256 }
257 tracker.trace_state_update(*this);
258 }
259
260 template<class Func>
261 inline void INode::on_edge_ro_edges(Func &&f) {
262 for (auto &in : ro_edges) {
264 }
265 }
266
267 template<class Func>
268 inline void INode::on_edge_rw_edges(Func &&f) {
269 for (auto &out : rw_edges) {
271 }
272 }
273
274 inline std::string INode::_impl_get_dot_graph_partial() const {
275 std::string node_str
276 = sham::format("n_{} [label=\"{}\"];\n", this->get_uuid(), _impl_get_label());
277
278 std::string edge_str = "";
279 for (auto &in : ro_edges) {
280 edge_str += sham::format(
281 "e_{} -> n_{} [style=\"dashed\", color=green];\n",
282 in->get_uuid(),
283 this->get_uuid());
284 edge_str += sham::format(
285 "e_{} [label=\"{}\",shape=rect, style=filled];\n", in->get_uuid(), in->get_label());
286 }
287 for (auto &out : rw_edges) {
288 edge_str += sham::format(
289 "n_{} -> e_{} [style=\"dashed\", color=red];\n", this->get_uuid(), out->get_uuid());
290 edge_str += sham::format(
291 "e_{} [label=\"{}\",shape=rect, style=filled];\n",
292 out->get_uuid(),
293 out->get_label());
294 }
295
296 return sham::format("{}{}", node_str, edge_str);
297 };
298
299 inline std::string INode::_impl_get_dot_graph_node_start() const {
300 return sham::format("n_{}", this->get_uuid());
301 }
302 inline std::string INode::_impl_get_dot_graph_node_end() const {
303 return sham::format("n_{}", this->get_uuid());
304 }
305
306} // namespace shamrock::solvergraph
307
308#define INODE_DECL_RO(type, name) const type &name;
309#define INODE_DECL_RW(type, name) type & name;
310#define INODE_PARAM_RO(type, name) const std::shared_ptr<type> &name,
311#define INODE_PARAM_RW(type, name) const std::shared_ptr<type> &name,
312#define INODE_PUSH_RO1(type, name) name,
313#define INODE_PUSH_RW1(type, name)
314#define INODE_PUSH_RO2(type, name)
315#define INODE_PUSH_RW2(type, name) name,
316#define INODE_GET_RO(type, name) get_ro_edge<type>(ro++),
317#define INODE_GET_RW(type, name) get_rw_edge<type>(rw++),
318
319#define INODE_DECL_RO_OPTIONAL(type, name) \
320 const std::optional<std::reference_wrapper<const type>> name;
321#define INODE_DECL_RW_OPTIONAL(type, name) const std::optional<std::reference_wrapper<type>> name;
322#define INODE_PARAM_RO_OPTIONAL(type, name) const std::optional<std::shared_ptr<type>> &name,
323#define INODE_PARAM_RW_OPTIONAL(type, name) const std::optional<std::shared_ptr<type>> &name,
324#define INODE_PUSH_RO1_OPTIONAL(type, name) shamrock::solvergraph::obsfucate_null_opt_edge(name),
325#define INODE_PUSH_RW1_OPTIONAL(type, name)
326#define INODE_PUSH_RO2_OPTIONAL(type, name)
327#define INODE_PUSH_RW2_OPTIONAL(type, name) shamrock::solvergraph::obsfucate_null_opt_edge(name),
328#define INODE_GET_RO_OPTIONAL(type, name) get_ro_edge_optional<type>(ro++),
329#define INODE_GET_RW_OPTIONAL(type, name) get_rw_edge_optional<type>(rw++),
330
331// TeX symbol accessors, shared by the plain and optional variants (a null optional edge still
332// occupies its slot and reports a placeholder symbol)
333#define INODE_TEX_DECL(type, name) std::string name;
334#define INODE_TEX_GET_RO(type, name) get_ro_edge_base(ro++).get_tex_symbol(),
335#define INODE_TEX_GET_RW(type, name) get_rw_edge_base(rw++).get_tex_symbol(),
336#define INODE_TEX_REPLACE(type, name) shambase::replace_all(tex, "{" #name "}", symbols.name);
337
347#define INODE_EXPAND_TEX_SYMBOLS(TEX_DECLS, TEX_GETS, TEX_REPLACES) \
348 \
349 struct EdgesTexSymbols { \
350 TEX_DECLS \
351 }; \
352 \
353 inline EdgesTexSymbols get_edges_tex_symbols() const { \
354 int ro = 0; \
355 int rw = 0; \
356 return EdgesTexSymbols{TEX_GETS}; \
357 } \
358 \
359 inline void replace_edges_tex_symbols(std::string &tex) const { \
360 auto symbols = get_edges_tex_symbols(); \
361 TEX_REPLACES \
362 }
363
364#define EXPAND_NODE_EDGES(EDGES) \
365 \
366 struct Edges { \
367 EDGES(INODE_DECL_RO, INODE_DECL_RW) \
368 }; \
369 \
370 inline void set_edges( \
371 EDGES(INODE_PARAM_RO, INODE_PARAM_RW) SourceLocation loc = SourceLocation{}) { \
372 __shamrock_log_callsite(loc); \
373 \
374 __internal_set_ro_edges({EDGES(INODE_PUSH_RO1, INODE_PUSH_RW1)}); \
375 __internal_set_rw_edges({EDGES(INODE_PUSH_RO2, INODE_PUSH_RW2)}); \
376 } \
377 \
378 inline Edges get_edges() { \
379 int ro = 0; \
380 int rw = 0; \
381 return Edges{EDGES(INODE_GET_RO, INODE_GET_RW)}; \
382 } \
383 \
384 INODE_EXPAND_TEX_SYMBOLS( \
385 EDGES(INODE_TEX_DECL, INODE_TEX_DECL), \
386 EDGES(INODE_TEX_GET_RO, INODE_TEX_GET_RW), \
387 EDGES(INODE_TEX_REPLACE, INODE_TEX_REPLACE))
388
389#define EXPAND_NODE_EDGES_OPTIONAL(EDGES) \
390 \
391 struct Edges { \
392 EDGES(INODE_DECL_RO, INODE_DECL_RW, INODE_DECL_RO_OPTIONAL, INODE_DECL_RW_OPTIONAL) \
393 }; \
394 \
395 inline void set_edges( \
396 EDGES(INODE_PARAM_RO, INODE_PARAM_RW, INODE_PARAM_RO_OPTIONAL, INODE_PARAM_RW_OPTIONAL) \
397 SourceLocation loc = SourceLocation{}) { \
398 __shamrock_log_callsite(loc); \
399 \
400 __internal_set_ro_edges({EDGES( \
401 INODE_PUSH_RO1, INODE_PUSH_RW1, INODE_PUSH_RO1_OPTIONAL, INODE_PUSH_RW1_OPTIONAL)}); \
402 __internal_set_rw_edges({EDGES( \
403 INODE_PUSH_RO2, INODE_PUSH_RW2, INODE_PUSH_RO2_OPTIONAL, INODE_PUSH_RW2_OPTIONAL)}); \
404 } \
405 \
406 inline Edges get_edges() { \
407 int ro = 0; \
408 int rw = 0; \
409 return Edges{ \
410 EDGES(INODE_GET_RO, INODE_GET_RW, INODE_GET_RO_OPTIONAL, INODE_GET_RW_OPTIONAL)}; \
411 } \
412 \
413 INODE_EXPAND_TEX_SYMBOLS( \
414 EDGES(INODE_TEX_DECL, INODE_TEX_DECL, INODE_TEX_DECL, INODE_TEX_DECL), \
415 EDGES(INODE_TEX_GET_RO, INODE_TEX_GET_RW, INODE_TEX_GET_RO, INODE_TEX_GET_RW), \
416 EDGES(INODE_TEX_REPLACE, INODE_TEX_REPLACE, INODE_TEX_REPLACE, INODE_TEX_REPLACE))
Callback API to track the lifetime, state updates and operations of solvergraph objects.
std::uint64_t u64
64 bit unsigned integer
void evaluate()
Evaluate the node.
Definition INode.hpp:156
INode & operator=(const INode &)=delete
would violate shared_from_this() & unique UUID
std::vector< std::shared_ptr< IEdge > > & get_ro_edges()
Get the read only edges.
Definition INode.hpp:63
virtual std::string _impl_get_dot_graph_node_start() const
get the dot graph of the node start
Definition INode.hpp:299
void on_edge_ro_edges(Func &&f)
Apply a function to the read only edges.
Definition INode.hpp:261
T & get_rw_edge(int slot)
Get a read write edge and cast it to the type T.
Definition INode.hpp:97
INode(INode &&) noexcept=default
would violate shared_from_this() & unique UUID
void __internal_set_rw_edges(std::vector< std::shared_ptr< IEdge > > new_rw_edges)
Set the read write edges.
Definition INode.hpp:249
std::string get_dot_graph_node_start()
Get the id of the node start in the dot graph.
Definition INode.hpp:174
std::string get_tex_partial()
Get the TeX of the node partial.
Definition INode.hpp:181
std::weak_ptr< INode > getptr_weak()
Get a weak pointer to this node.
Definition INode.hpp:60
std::optional< std::reference_wrapper< const T > > get_ro_edge_optional(int slot)
Get a read only edge and cast it to the type T, return an optional.
Definition INode.hpp:103
u64 get_uuid() const
Get the UUID of the node.
Definition INode.hpp:55
std::string get_tex()
Get the TeX of the node.
Definition INode.hpp:179
virtual void _impl_evaluate_internal()=0
evaluate the node
IEdge & get_rw_edge_base(int slot)
Get a reference to a read write edge and cast it to the type IEdge.
Definition INode.hpp:147
void on_edge_rw_edges(Func &&f)
Apply a function to the read write edges.
Definition INode.hpp:268
std::string get_dot_graph()
Get the dot graph of the node (Currently only an alias to get_dot_graph_partial).
Definition INode.hpp:168
std::shared_ptr< INode > getptr_shared()
Get a shared pointer to this node.
Definition INode.hpp:58
std::string get_label() const
Get the label of the node.
Definition INode.hpp:183
virtual std::string print_node_info() const
print the node info
Definition INode.hpp:186
void __internal_set_ro_edges(std::vector< std::shared_ptr< IEdge > > new_ro_edges)
Set the read only edges.
Definition INode.hpp:238
std::string get_dot_graph_partial()
Get the dot graph of the subgraph corresponding to the node.
Definition INode.hpp:171
std::string get_dot_graph_node_end()
Get the id of the node end in the dot graph.
Definition INode.hpp:176
std::optional< std::reference_wrapper< T > > get_rw_edge_optional(int slot)
Get a read write edge and cast it to the type T, return an optional.
Definition INode.hpp:121
virtual std::string _impl_get_label() const =0
get the label of the node
const T & get_ro_edge(int slot)
Get a read only edge and cast it to the type T.
Definition INode.hpp:91
virtual std::string _impl_get_dot_graph_partial() const
get the dot graph of the node partial
Definition INode.hpp:274
std::vector< std::shared_ptr< IEdge > > & get_rw_edges()
Get the read write edges.
Definition INode.hpp:65
virtual std::string _impl_get_tex() const =0
get the tex of the node
virtual std::string _impl_get_dot_graph_node_end() const
get the dot graph of the node end
Definition INode.hpp:302
const IEdge & get_ro_edge_base(int slot)
Get a reference to a read only edge.
Definition INode.hpp:138
Tracks the lifetime of an object of type T and notifies observers through static callbacks.
T & get_check_ref(const std::unique_ptr< T > &ptr, SourceLocation loc=SourceLocation())
Takes a std::unique_ptr and returns a reference to the object it holds. It throws a std::runtime_erro...
Definition memory.hpp:112
ExcptTypes make_except_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Create an exception with a message and a location.
This file contains the definition for the stacktrace related functionality.