PyDecisionGraph 0.3.2.post1__cp315-cp315t-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. decision_graph/__infra__.pxd +1 -0
  2. decision_graph/__init__.pxd +1 -0
  3. decision_graph/__init__.py +39 -0
  4. decision_graph/decision_tree/__init__.pxd +2 -0
  5. decision_graph/decision_tree/__init__.py +85 -0
  6. decision_graph/decision_tree/bake/__infra__.pxd +502 -0
  7. decision_graph/decision_tree/bake/__init__.pxd +502 -0
  8. decision_graph/decision_tree/bake/__init__.py +29 -0
  9. decision_graph/decision_tree/bake/c_action.cp315t-win_amd64.pyd +0 -0
  10. decision_graph/decision_tree/bake/c_action.h +324 -0
  11. decision_graph/decision_tree/bake/c_action.pxd +54 -0
  12. decision_graph/decision_tree/bake/c_action.pyi +126 -0
  13. decision_graph/decision_tree/bake/c_action.pyx +65 -0
  14. decision_graph/decision_tree/bake/c_allocator_protocol.cp315t-win_amd64.pyd +0 -0
  15. decision_graph/decision_tree/bake/c_allocator_protocol.pxd +24 -0
  16. decision_graph/decision_tree/bake/c_allocator_protocol.pyi +61 -0
  17. decision_graph/decision_tree/bake/c_allocator_protocol.pyx +109 -0
  18. decision_graph/decision_tree/bake/c_bake.cp315t-win_amd64.pyd +0 -0
  19. decision_graph/decision_tree/bake/c_bake.h +629 -0
  20. decision_graph/decision_tree/bake/c_bake.pxd +52 -0
  21. decision_graph/decision_tree/bake/c_bake.pyi +151 -0
  22. decision_graph/decision_tree/bake/c_bake.pyx +142 -0
  23. decision_graph/decision_tree/bake/c_collections.cp315t-win_amd64.pyd +0 -0
  24. decision_graph/decision_tree/bake/c_collections.h +692 -0
  25. decision_graph/decision_tree/bake/c_collections.pxd +52 -0
  26. decision_graph/decision_tree/bake/c_collections.pyi +193 -0
  27. decision_graph/decision_tree/bake/c_collections.pyx +161 -0
  28. decision_graph/decision_tree/bake/c_const.cp315t-win_amd64.pyd +0 -0
  29. decision_graph/decision_tree/bake/c_const.h +395 -0
  30. decision_graph/decision_tree/bake/c_const.pxd +56 -0
  31. decision_graph/decision_tree/bake/c_const.pyi +305 -0
  32. decision_graph/decision_tree/bake/c_const.pyx +278 -0
  33. decision_graph/decision_tree/bake/c_edge.cp315t-win_amd64.pyd +0 -0
  34. decision_graph/decision_tree/bake/c_edge.h +511 -0
  35. decision_graph/decision_tree/bake/c_edge.pxd +117 -0
  36. decision_graph/decision_tree/bake/c_edge.pyi +192 -0
  37. decision_graph/decision_tree/bake/c_edge.pyx +270 -0
  38. decision_graph/decision_tree/bake/c_eval.h +848 -0
  39. decision_graph/decision_tree/bake/c_eval.pxd +40 -0
  40. decision_graph/decision_tree/bake/c_expr.cp315t-win_amd64.pyd +0 -0
  41. decision_graph/decision_tree/bake/c_expr.h +1900 -0
  42. decision_graph/decision_tree/bake/c_expr.pxd +129 -0
  43. decision_graph/decision_tree/bake/c_expr.pyi +280 -0
  44. decision_graph/decision_tree/bake/c_expr.pyx +272 -0
  45. decision_graph/decision_tree/bake/c_hierarchy.cp315t-win_amd64.pyd +0 -0
  46. decision_graph/decision_tree/bake/c_hierarchy.h +731 -0
  47. decision_graph/decision_tree/bake/c_hierarchy.pxd +71 -0
  48. decision_graph/decision_tree/bake/c_hierarchy.pyi +409 -0
  49. decision_graph/decision_tree/bake/c_hierarchy.pyx +277 -0
  50. decision_graph/decision_tree/bake/c_logic_group.cp315t-win_amd64.pyd +0 -0
  51. decision_graph/decision_tree/bake/c_logic_group.h +1226 -0
  52. decision_graph/decision_tree/bake/c_logic_group.pxd +162 -0
  53. decision_graph/decision_tree/bake/c_logic_group.pyi +264 -0
  54. decision_graph/decision_tree/bake/c_logic_group.pyx +308 -0
  55. decision_graph/decision_tree/bake/c_node.cp315t-win_amd64.pyd +0 -0
  56. decision_graph/decision_tree/bake/c_node.h +2660 -0
  57. decision_graph/decision_tree/bake/c_node.pxd +381 -0
  58. decision_graph/decision_tree/bake/c_node.pyi +438 -0
  59. decision_graph/decision_tree/bake/c_node.pyx +639 -0
  60. decision_graph/decision_tree/bake/c_reconstruct.cp315t-win_amd64.pyd +0 -0
  61. decision_graph/decision_tree/bake/c_reconstruct.pxd +63 -0
  62. decision_graph/decision_tree/bake/c_reconstruct.pyi +60 -0
  63. decision_graph/decision_tree/bake/c_reconstruct.pyx +252 -0
  64. decision_graph/decision_tree/bake/c_var.cp315t-win_amd64.pyd +0 -0
  65. decision_graph/decision_tree/bake/c_var.h +2054 -0
  66. decision_graph/decision_tree/bake/c_var.pxd +205 -0
  67. decision_graph/decision_tree/bake/c_var.pyi +271 -0
  68. decision_graph/decision_tree/bake/c_var.pyx +228 -0
  69. decision_graph/decision_tree/capi/__infra__.pxd +33 -0
  70. decision_graph/decision_tree/capi/__init__.pxd +33 -0
  71. decision_graph/decision_tree/capi/__init__.py +57 -0
  72. decision_graph/decision_tree/capi/c_abc.cp315t-win_amd64.pyd +0 -0
  73. decision_graph/decision_tree/capi/c_abc.pxd +246 -0
  74. decision_graph/decision_tree/capi/c_abc.pyi +770 -0
  75. decision_graph/decision_tree/capi/c_abc.pyx +1532 -0
  76. decision_graph/decision_tree/capi/c_collection.cp315t-win_amd64.pyd +0 -0
  77. decision_graph/decision_tree/capi/c_collection.pxd +22 -0
  78. decision_graph/decision_tree/capi/c_collection.pyi +245 -0
  79. decision_graph/decision_tree/capi/c_collection.pyx +138 -0
  80. decision_graph/decision_tree/capi/c_node.cp315t-win_amd64.pyd +0 -0
  81. decision_graph/decision_tree/capi/c_node.pxd +95 -0
  82. decision_graph/decision_tree/capi/c_node.pyi +492 -0
  83. decision_graph/decision_tree/capi/c_node.pyx +551 -0
  84. decision_graph/decision_tree/exc.py +189 -0
  85. decision_graph/decision_tree/native/__init__.py +57 -0
  86. decision_graph/decision_tree/native/abc.py +1167 -0
  87. decision_graph/decision_tree/native/collection.py +134 -0
  88. decision_graph/decision_tree/native/node.py +521 -0
  89. decision_graph/includes/decision_graph/decision_tree/bake/c_action.c +16320 -0
  90. decision_graph/includes/decision_graph/decision_tree/bake/c_action.h +324 -0
  91. decision_graph/includes/decision_graph/decision_tree/bake/c_allocator_protocol.c +12473 -0
  92. decision_graph/includes/decision_graph/decision_tree/bake/c_bake.c +16485 -0
  93. decision_graph/includes/decision_graph/decision_tree/bake/c_bake.h +629 -0
  94. decision_graph/includes/decision_graph/decision_tree/bake/c_collections.c +17381 -0
  95. decision_graph/includes/decision_graph/decision_tree/bake/c_collections.h +692 -0
  96. decision_graph/includes/decision_graph/decision_tree/bake/c_const.c +20815 -0
  97. decision_graph/includes/decision_graph/decision_tree/bake/c_const.h +395 -0
  98. decision_graph/includes/decision_graph/decision_tree/bake/c_edge.c +20696 -0
  99. decision_graph/includes/decision_graph/decision_tree/bake/c_edge.h +511 -0
  100. decision_graph/includes/decision_graph/decision_tree/bake/c_eval.h +848 -0
  101. decision_graph/includes/decision_graph/decision_tree/bake/c_expr.c +22065 -0
  102. decision_graph/includes/decision_graph/decision_tree/bake/c_expr.h +1900 -0
  103. decision_graph/includes/decision_graph/decision_tree/bake/c_hierarchy.c +23267 -0
  104. decision_graph/includes/decision_graph/decision_tree/bake/c_hierarchy.h +731 -0
  105. decision_graph/includes/decision_graph/decision_tree/bake/c_logic_group.c +22434 -0
  106. decision_graph/includes/decision_graph/decision_tree/bake/c_logic_group.h +1226 -0
  107. decision_graph/includes/decision_graph/decision_tree/bake/c_node.c +28385 -0
  108. decision_graph/includes/decision_graph/decision_tree/bake/c_node.h +2660 -0
  109. decision_graph/includes/decision_graph/decision_tree/bake/c_reconstruct.c +15955 -0
  110. decision_graph/includes/decision_graph/decision_tree/bake/c_var.c +16881 -0
  111. decision_graph/includes/decision_graph/decision_tree/bake/c_var.h +2054 -0
  112. decision_graph/includes/decision_graph/decision_tree/capi/c_abc.c +59196 -0
  113. decision_graph/includes/decision_graph/decision_tree/capi/c_collection.c +19967 -0
  114. decision_graph/includes/decision_graph/decision_tree/capi/c_node.c +39229 -0
  115. decision_graph/logic_group/__init__.py +25 -0
  116. decision_graph/logic_group/base.py +100 -0
  117. decision_graph/logic_group/pending_request.py +384 -0
  118. decision_graph/webui/__init__.py +24 -0
  119. decision_graph/webui/bake/__init__.py +65 -0
  120. decision_graph/webui/bake/app.py +488 -0
  121. decision_graph/webui/bake/static/d3.v7.min.js +2 -0
  122. decision_graph/webui/bake/static/script.js +1440 -0
  123. decision_graph/webui/bake/static/style.css +920 -0
  124. decision_graph/webui/bake/templates/index.html +183 -0
  125. decision_graph/webui/bake/templates/offline.html +184 -0
  126. decision_graph/webui/capi/__init__.py +54 -0
  127. decision_graph/webui/capi/app.py +366 -0
  128. decision_graph/webui/capi/main.py +53 -0
  129. decision_graph/webui/capi/static/d3.v7.min.js +2 -0
  130. decision_graph/webui/capi/static/script.js +1026 -0
  131. decision_graph/webui/capi/static/style.css +656 -0
  132. decision_graph/webui/capi/templates/index.html +93 -0
  133. decision_graph/webui/capi/templates/offline.html +94 -0
  134. decision_graph/webui/native/__init__.py +54 -0
  135. decision_graph/webui/native/app.py +366 -0
  136. decision_graph/webui/native/main.py +53 -0
  137. decision_graph/webui/native/static/d3.v7.min.js +2 -0
  138. decision_graph/webui/native/static/script.js +1026 -0
  139. decision_graph/webui/native/static/style.css +656 -0
  140. decision_graph/webui/native/templates/index.html +93 -0
  141. decision_graph/webui/native/templates/offline.html +94 -0
  142. pydecisiongraph-0.3.2.post1.dist-info/METADATA +136 -0
  143. pydecisiongraph-0.3.2.post1.dist-info/RECORD +148 -0
  144. pydecisiongraph-0.3.2.post1.dist-info/WHEEL +5 -0
  145. pydecisiongraph-0.3.2.post1.dist-info/licenses/LICENSE +373 -0
  146. pydecisiongraph-0.3.2.post1.dist-info/top_level.txt +2 -0
  147. tests/bake_c_evaluator.cp315t-win_amd64.pyd +0 -0
  148. tests/bake_eval_probe.cp315t-win_amd64.pyd +0 -0
@@ -0,0 +1,395 @@
1
+ #ifndef C_DCG_BAKE_CONST_H
2
+ #define C_DCG_BAKE_CONST_H
3
+
4
+ #include <stdbool.h>
5
+ #include <stdint.h>
6
+ #include <stdio.h>
7
+ #include <string.h>
8
+ #include <sys/types.h>
9
+
10
+ #include <cbase/allocator_protocol/c_allocator_protocol.h>
11
+
12
+ #include <decision_graph/decision_tree/bake/c_node.h>
13
+
14
+ /*
15
+ * The input family: what a graph is fed rather than what it computes. Two
16
+ * shapes of it:
17
+ *
18
+ * - a literal, which stands for a value: the family adds no field of its own,
19
+ * so base.out IS the value, every constructor here is a base init plus the
20
+ * value it was given, and the string flavours copy their text into a block
21
+ * nested under the node;
22
+ * - a variable, which stands for a value someone else holds: it names the
23
+ * logic group it reads and the key it reads there, and base.out refers to
24
+ * that entry's slot rather than holding a value of its own.
25
+ *
26
+ * Both are inputs because both are known to the graph from the outside - one
27
+ * because it was written into it, the other because it is read out of a store
28
+ * that outlives it.
29
+ */
30
+
31
+ // ========== Constants ==========
32
+
33
+ #ifndef DCG_DEF_REPR_TRUE
34
+ #define DCG_DEF_REPR_TRUE "True"
35
+ #endif
36
+
37
+ #ifndef DCG_DEF_REPR_FALSE
38
+ #define DCG_DEF_REPR_FALSE "False"
39
+ #endif
40
+
41
+ // ========== Structs ==========
42
+
43
+ // clang-format off
44
+
45
+ /**
46
+ * @brief A literal input: the base node, holding its value in base.out.
47
+ *
48
+ * A literal carries nothing beyond the base node - the value it stands for is
49
+ * base.out, which is why this struct has no field of its own. It exists so the
50
+ * literals have a name to construct, cast and dispatch on, and so a future
51
+ * per-type payload (a parsed literal, an interned string) has a home that does
52
+ * not touch every other family.
53
+ *
54
+ * The base node must stay the FIRST member: a dcg_constant_node* is therefore
55
+ * a valid dcg_node*, which is what lets the base graph API walk it.
56
+ */
57
+ typedef struct dcg_constant_node {
58
+ dcg_node base; // The common node header. Must stay first.
59
+ } dcg_constant_node;
60
+
61
+ /**
62
+ * @brief A variable input: a node that reads a value out of a logic group.
63
+ *
64
+ * It holds no value of its own - base.out is a REFERENCE to the entry's slot,
65
+ * so reading the variable reads that slot, live. That is what makes it usable
66
+ * as an input to an expression (c_expr.h binds the out slot of its inputs)
67
+ * while the value itself stays where it belongs, in the group's store.
68
+ *
69
+ * `key` names the entry it reads, and the node owns its copy: the key is the
70
+ * node's, so a caller can hand one in and walk away. `logic_group` is the
71
+ * group the entry belongs to, and is NOT owned - a group serves any number of
72
+ * variables, so it outlives them all and is the caller's to release.
73
+ *
74
+ * How the entry is found is the node's OUT slot, and it changes once: a read a
75
+ * store built is born with the entry's OFFSET in it - `VAR_TYPE_INFERRED`, so
76
+ * nothing reads it as a value - and its first evaluation replaces that offset
77
+ * with a reference to the entry itself. An offset rather than a pointer because
78
+ * a store's `slots` block grows, and growing it moves every entry in it: the
79
+ * index survives the move, and the evaluation that spends it runs before the
80
+ * reference it leaves behind can be dangled (see
81
+ * c_dcg_node_mapping_var_node_eval_hook).
82
+ *
83
+ * A variable that reads no store - one bound by hand to another node's slot -
84
+ * carries no offset at all: its slot is the reference, from the bind on.
85
+ *
86
+ * The pair is what the capi's AttrExpression carries: the group gives the
87
+ * store, the key gives the entry in it.
88
+ *
89
+ * The base node must stay the FIRST member: a dcg_variable_node* is therefore
90
+ * a valid dcg_node*.
91
+ */
92
+ typedef struct dcg_variable_node {
93
+ dcg_node base; // The common node header. Must stay first.
94
+ const char* key; // Entry name in the group's store.
95
+ dcg_logic_group* logic_group; // The parent group whose store this reads.
96
+ } dcg_variable_node;
97
+
98
+ // clang-format on
99
+
100
+ // ========== Forward Declarations ==========
101
+
102
+ // Lifecycle
103
+ static inline dcg_constant_node* c_dcg_node_new_const(dcg_node_type ntype, const char* repr, allocator_protocol* allocator);
104
+ static inline void c_dcg_node_free_const(dcg_constant_node* node);
105
+
106
+ static inline dcg_constant_node* c_dcg_node_new_const_value(const char* repr, dcg_var_t value, allocator_protocol* allocator);
107
+ static inline dcg_constant_node* c_dcg_node_new_const_bool(bool value, allocator_protocol* allocator);
108
+ static inline dcg_constant_node* c_dcg_node_new_const_double(double value, allocator_protocol* allocator);
109
+ static inline dcg_constant_node* c_dcg_node_new_const_int(ssize_t value, allocator_protocol* allocator);
110
+ static inline dcg_constant_node* c_dcg_node_new_const_string(const char* value, allocator_protocol* allocator);
111
+
112
+ // Reading
113
+ static inline const dcg_var_t* c_dcg_node_const_get(const dcg_constant_node* node);
114
+ static inline int c_dcg_node_const_set(dcg_constant_node* node, dcg_var_t value);
115
+
116
+ // Lifecycle - the variable
117
+ static inline dcg_variable_node* c_dcg_node_new_var(const char* repr, const char* key, size_t key_len, dcg_var_t* value, dcg_logic_group* group, allocator_protocol* allocator);
118
+ static inline int c_dcg_node_var_bind(dcg_variable_node* node, dcg_var_t* value);
119
+ static inline void c_dcg_node_free_var(dcg_variable_node* node);
120
+
121
+ // ========== Lifecycle Methods ==========
122
+
123
+ /**
124
+ * @brief Allocate a literal input of an explicit type.
125
+ *
126
+ * A variable is an input too, but not one this block holds: it carries a key
127
+ * and the group it reads, so it is built by c_dcg_node_new_var() instead.
128
+ *
129
+ * @param ntype A literal type (INPUT / TRUE / FALSE / DOUBLE / STRING / INT).
130
+ * @param repr Display text to copy (may be NULL).
131
+ * @param allocator Allocator for the block; NULL falls back to the plain heap.
132
+ * @return The node, or NULL on OOM / invalid type.
133
+ */
134
+ static inline dcg_constant_node* c_dcg_node_new_const(dcg_node_type ntype, const char* repr, allocator_protocol* allocator) {
135
+ if (!c_dcg_node_type_is_input(ntype) || ntype == DCG_NODE_VARIABLE) return NULL;
136
+
137
+ dcg_constant_node* node = (dcg_constant_node*) c_ap_alloc(sizeof(dcg_constant_node), allocator);
138
+ if (!node) return NULL;
139
+
140
+ if (c_dcg_node_init(&node->base, ntype, repr) != DCG_OK) {
141
+ c_ap_free_owned(node);
142
+ return NULL;
143
+ }
144
+ #if DCG_EVAL_DIRECT_HOOKS
145
+ #endif
146
+ return node;
147
+ }
148
+
149
+ /**
150
+ * @brief Tear down a literal and free its buf.
151
+ *
152
+ * The value lives in the base node, so there is nothing else to release: the
153
+ * base teardown frees the repr, the string payload and the node itself.
154
+ *
155
+ * A variable is an input too, but not one this free takes: its block has a
156
+ * different layout, so the dispatcher routes it to c_dcg_node_free_var()
157
+ * instead of casting it to this one.
158
+ *
159
+ * @param node Node to free (NULL-safe).
160
+ */
161
+ static inline void c_dcg_node_free_const(dcg_constant_node* node) {
162
+ if (!node) return;
163
+ c_dcg_node_free(&node->base);
164
+ }
165
+
166
+ // ========== Public APIs - Typed Constructors ==========
167
+
168
+ /**
169
+ * @brief Allocate a constant node holding an explicit value.
170
+ *
171
+ * @param repr Display text to copy (may be NULL).
172
+ * @param value Constant payload (a string payload is copied).
173
+ * @param allocator Allocator for the block; NULL falls back to the plain heap.
174
+ * @return The node, or NULL on OOM.
175
+ */
176
+ static inline dcg_constant_node* c_dcg_node_new_const_value(const char* repr, dcg_var_t value, allocator_protocol* allocator) {
177
+ dcg_constant_node* node = c_dcg_node_new_const(DCG_NODE_INPUT, repr, allocator);
178
+ if (!node) return NULL;
179
+
180
+ if (c_dcg_node_const_set(node, value) != DCG_OK) {
181
+ c_ap_free_owned(node);
182
+ return NULL;
183
+ }
184
+ return node;
185
+ }
186
+
187
+ /**
188
+ * @brief Allocate a boolean constant.
189
+ *
190
+ * The type follows the value (TRUE / FALSE) and so does the repr
191
+ * (DCG_DEF_REPR_TRUE / DCG_DEF_REPR_FALSE), so there is nothing for the caller
192
+ * to tell it that the payload does not already say.
193
+ *
194
+ * @param value Boolean payload.
195
+ * @param allocator Allocator for the block; NULL falls back to the plain heap.
196
+ * @return The node, or NULL on OOM.
197
+ */
198
+ static inline dcg_constant_node* c_dcg_node_new_const_bool(bool value, allocator_protocol* allocator) {
199
+ dcg_node_type ntype = value ? DCG_NODE_TRUE : DCG_NODE_FALSE;
200
+ dcg_constant_node* node = c_dcg_node_new_const(ntype, value ? DCG_DEF_REPR_TRUE : DCG_DEF_REPR_FALSE, allocator);
201
+ if (!node) return NULL;
202
+
203
+ (void) c_dcg_var_init_bool(&node->base.out, value);
204
+ return node;
205
+ }
206
+
207
+ /**
208
+ * @brief Allocate a double constant, its repr rendered from the value.
209
+ *
210
+ * @param value Double payload.
211
+ * @param allocator Allocator for the block; NULL falls back to the plain heap.
212
+ * @return The node, or NULL on OOM.
213
+ */
214
+ static inline dcg_constant_node* c_dcg_node_new_const_double(double value, allocator_protocol* allocator) {
215
+ char repr[DCG_NODE_STRING_MAXLEN];
216
+ (void) snprintf(repr, sizeof(repr), "%g", value);
217
+
218
+ dcg_constant_node* node = c_dcg_node_new_const(DCG_NODE_DOUBLE, repr, allocator);
219
+ if (!node) return NULL;
220
+
221
+ (void) c_dcg_var_init_double(&node->base.out, value);
222
+ return node;
223
+ }
224
+
225
+ /**
226
+ * @brief Allocate an integer constant, its repr rendered from the value.
227
+ *
228
+ * @param value Integer payload.
229
+ * @param allocator Allocator for the block; NULL falls back to the plain heap.
230
+ * @return The node, or NULL on OOM.
231
+ */
232
+ static inline dcg_constant_node* c_dcg_node_new_const_int(ssize_t value, allocator_protocol* allocator) {
233
+ char repr[DCG_NODE_STRING_MAXLEN];
234
+ (void) snprintf(repr, sizeof(repr), "%zd", value);
235
+
236
+ dcg_constant_node* node = c_dcg_node_new_const(DCG_NODE_INT, repr, allocator);
237
+ if (!node) return NULL;
238
+
239
+ (void) c_dcg_var_init_int(&node->base.out, value);
240
+ return node;
241
+ }
242
+
243
+ /**
244
+ * @brief Allocate a string constant owning a copy of the text.
245
+ *
246
+ * The repr is the text itself, as it is for a string-valued expression.
247
+ *
248
+ * @param value Text to copy (may be NULL).
249
+ * @param allocator Allocator for the block; NULL falls back to the plain heap.
250
+ * @return The node, or NULL on OOM.
251
+ */
252
+ static inline dcg_constant_node* c_dcg_node_new_const_string(const char* value, allocator_protocol* allocator) {
253
+ dcg_constant_node* node = c_dcg_node_new_const(DCG_NODE_STRING, value, allocator);
254
+ if (!node) return NULL;
255
+
256
+ if (c_dcg_node_set_string(&node->base, value) != DCG_OK) {
257
+ c_ap_free_owned(node);
258
+ return NULL;
259
+ }
260
+ return node;
261
+ }
262
+
263
+ // ========== Public APIs - Reading ==========
264
+
265
+ /**
266
+ * @brief The value a constant node stands for.
267
+ *
268
+ * @param node Node to read (NULL-safe).
269
+ * @return The value, or NULL.
270
+ */
271
+ static inline const dcg_var_t* c_dcg_node_const_get(const dcg_constant_node* node) {
272
+ if (!node) return NULL;
273
+ return &node->base.out;
274
+ }
275
+
276
+ /**
277
+ * @brief Replace the value a constant node stands for.
278
+ *
279
+ * A string value is copied into a block nested under the node, so the caller's
280
+ * text can go away at once; the previous string value is released first.
281
+ *
282
+ * @param node Node to modify.
283
+ * @param value New value.
284
+ * @return DCG_OK, or a DCG_ERR_* code.
285
+ */
286
+ static inline int c_dcg_node_const_set(dcg_constant_node* node, dcg_var_t value) {
287
+ if (!node) return DCG_ERR_INVALID_ARG;
288
+ if (value.dtype == VAR_TYPE_STRING) return c_dcg_node_set_string(&node->base, value.value.as_string);
289
+ node->base.out = value;
290
+ return DCG_OK;
291
+ }
292
+
293
+ // ========== Public APIs - The Variable Node ==========
294
+
295
+ /**
296
+ * @brief Allocate a node that reads an entry out of a logic group.
297
+ *
298
+ * The node's out is a REFERENCE to `value`, so the node reads that value live
299
+ * and hands it to whoever reads the node - an expression bound to it, or a
300
+ * caller inspecting the graph. `value` must outlive the node, which is what the
301
+ * group holding it guarantees.
302
+ *
303
+ * A node built with no slot reflects nothing until c_dcg_node_var_bind() gives
304
+ * it one. That is the late half of the pair: a read often has to exist before
305
+ * the store it reads does, and refusing to build one without a slot would only
306
+ * push the same ordering problem onto the caller.
307
+ *
308
+ * When `group` is given the node is allocated as a BLOCK OF THAT GROUP, so the
309
+ * group owns the read: freeing the group releases every variable built over its
310
+ * store, keys included, without the caller tracking them. The key is a nested
311
+ * block of the NODE either way - a variable owns its own key, not the group -
312
+ * so releasing the node releases the key with it.
313
+ *
314
+ * The two lifetimes are therefore nested - value outlives group, group outlives
315
+ * node - and a node that must outlive its group is built with a NULL group and
316
+ * lives on the caller's slot alone. What must NOT happen is the group going
317
+ * while a graph still holds one of its reads: the graph names a block that is
318
+ * gone, and nothing in the node header can tell.
319
+ *
320
+ * @param repr Display text to copy (may be NULL).
321
+ * @param key Entry name to copy; NULL leaves the node naming no entry.
322
+ * @param key_len Length of key. The copy takes exactly this many bytes, so a
323
+ * key that came out of a store - where a name is a pointer
324
+ * and a length, not a C string - needs no termination.
325
+ * @param value Value slot to reflect (must outlive the node; NULL leaves
326
+ * the node reflecting nothing, for c_dcg_node_var_bind()).
327
+ * @param group Group the entry belongs to (not owned; may be NULL, and
328
+ * owning the node when it is given).
329
+ * @param allocator Allocator for the block; NULL derives it from the group,
330
+ * or falls back to the plain heap when there is none.
331
+ * @return The node, or NULL on OOM.
332
+ */
333
+ static inline dcg_variable_node* c_dcg_node_new_var(const char* repr, const char* key, size_t key_len, dcg_var_t* value, dcg_logic_group* group, allocator_protocol* allocator) {
334
+ dcg_variable_node* node = group ? (dcg_variable_node*) c_ap_alloc_child(sizeof(dcg_variable_node), allocator, group)
335
+ : (dcg_variable_node*) c_ap_alloc(sizeof(dcg_variable_node), allocator);
336
+ if (!node) return NULL;
337
+
338
+ if (c_dcg_node_init(&node->base, DCG_NODE_VARIABLE, repr) != DCG_OK) {
339
+ c_ap_free_owned(node);
340
+ return NULL;
341
+ }
342
+
343
+ node->logic_group = group;
344
+ node->key = NULL;
345
+
346
+ if (key) {
347
+ /* The key is the node's own copy, nested under it, so the caller's text
348
+ * can go away at once - and it is copied before the value is bound, so
349
+ * a failure here leaves nothing to unwind. */
350
+ char* copy = (char*) c_ap_alloc_child(key_len + 1, NULL, node);
351
+ if (!copy) {
352
+ c_ap_free_owned(node);
353
+ return NULL;
354
+ }
355
+ memcpy(copy, key, key_len);
356
+ copy[key_len] = '\0';
357
+ node->key = copy;
358
+ }
359
+
360
+ if (value) (void) c_dcg_var_init_ref(&node->base.out, value);
361
+ else (void) c_dcg_var_init(&node->base.out); /* reflects nothing yet */
362
+ return node;
363
+ }
364
+
365
+ /**
366
+ * @brief Give a variable the slot it reads, after it was built.
367
+ *
368
+ * The node's out becomes a reference to `value`, so from here on the read is
369
+ * live: whatever the slot holds when the node is read is what the node reports.
370
+ * Binding again simply points the read somewhere else.
371
+ *
372
+ * @param node Variable node to modify.
373
+ * @param value Value slot to reflect (must outlive the node).
374
+ * @return DCG_OK, or DCG_ERR_INVALID_ARG.
375
+ */
376
+ static inline int c_dcg_node_var_bind(dcg_variable_node* node, dcg_var_t* value) {
377
+ if (!node || !value) return DCG_ERR_INVALID_ARG;
378
+ return c_dcg_var_init_ref(&node->base.out, value);
379
+ }
380
+
381
+ /**
382
+ * @brief Tear down a variable node and free its buf.
383
+ *
384
+ * The reflected value is the store's, and the group is the caller's, so the
385
+ * base teardown is the whole of it: it releases the repr, the key and the
386
+ * block.
387
+ *
388
+ * @param node Node to free (NULL-safe).
389
+ */
390
+ static inline void c_dcg_node_free_var(dcg_variable_node* node) {
391
+ if (!node) return;
392
+ c_dcg_node_free(&node->base);
393
+ }
394
+
395
+ #endif // C_DCG_BAKE_CONST_H
@@ -0,0 +1,56 @@
1
+ from libcpp cimport bool as c_bool
2
+
3
+ from cbase.allocator_protocol cimport allocator_protocol
4
+
5
+ from .c_node cimport LogicNode, dcg_node, dcg_node_type
6
+ from .c_var cimport dcg_var_t
7
+
8
+
9
+ cdef extern from "decision_graph/decision_tree/bake/c_const.h":
10
+ ctypedef struct dcg_constant_node:
11
+ dcg_node base
12
+
13
+ ctypedef struct dcg_variable_node:
14
+ dcg_node base
15
+ const char* key
16
+ dcg_logic_group* logic_group
17
+
18
+ dcg_constant_node* c_dcg_node_new_const(dcg_node_type ntype, const char* repr, allocator_protocol* allocator) noexcept nogil
19
+ void c_dcg_node_free_const(dcg_constant_node* node) noexcept nogil
20
+
21
+ dcg_constant_node* c_dcg_node_new_const_value(const char* repr, dcg_var_t value, allocator_protocol* allocator) noexcept nogil
22
+ dcg_constant_node* c_dcg_node_new_const_bool(c_bool value, allocator_protocol* allocator) noexcept nogil
23
+ dcg_constant_node* c_dcg_node_new_const_double(double value, allocator_protocol* allocator) noexcept nogil
24
+ dcg_constant_node* c_dcg_node_new_const_int(ssize_t value, allocator_protocol* allocator) noexcept nogil
25
+ dcg_constant_node* c_dcg_node_new_const_string(const char* value, allocator_protocol* allocator) noexcept nogil
26
+ const dcg_var_t* c_dcg_node_const_get(const dcg_constant_node* node) noexcept nogil
27
+ int c_dcg_node_const_set(dcg_constant_node* node, dcg_var_t value) noexcept nogil
28
+
29
+ dcg_variable_node* c_dcg_node_new_var(const char* repr, const char* key, size_t key_len, dcg_var_t* value, dcg_logic_group* group, allocator_protocol* allocator) noexcept nogil
30
+ int c_dcg_node_var_bind(dcg_variable_node* node, dcg_var_t* value) noexcept nogil
31
+ void c_dcg_node_free_var(dcg_variable_node* node) noexcept nogil
32
+
33
+
34
+ cdef extern from "decision_graph/decision_tree/bake/c_logic_group.h":
35
+ ctypedef struct dcg_logic_group:
36
+ pass
37
+
38
+ ctypedef struct dcg_logic_group_manager:
39
+ pass
40
+
41
+ dcg_logic_group* c_dcg_lgm_active_group(const dcg_logic_group_manager* mgr) noexcept nogil
42
+
43
+
44
+ cdef class ConstantNode(LogicNode):
45
+ pass
46
+
47
+
48
+ cdef class VariableNode(LogicNode):
49
+ cdef readonly object logic_group
50
+
51
+ cdef void c_bind_slot(self, dcg_var_t* slot)
52
+
53
+ cpdef void c_bind_const(self, ConstantNode node)
54
+
55
+
56
+ cdef LogicNode c_dcg_node_pypack(object value)