Cppgres
Build Postgres extensions in C++
Loading...
Searching...
No Matches
node.hpp
1#pragma once
2#include <concepts>
3#include <type_traits>
4
5#include "imports.h"
6#include "utils/pfr.hpp"
7
8#if PG_MAJORVERSION_NUM < 16
9typedef bool (*tree_walker_callback)(Node *node, void *context);
10#endif
11
12namespace cppgres {
13
14using node_tag = ::NodeTag;
15
16template <typename T>
17concept node_tagged = std::is_standard_layout_v<T> && requires(T t) {
18 { t.type } -> std::convertible_to<node_tag>;
19} && (offsetof(T, type) == 0);
20
21template <typename T>
22concept node_xpr_tagged = std::is_standard_layout_v<T> && requires(T t) {
23 { t.xpr } -> std::convertible_to<::Expr>;
24} && (offsetof(T, xpr) == 0);
25
26template <typename T>
27concept node_inherited_base = std::is_standard_layout_v<std::remove_cvref_t<T>> && requires(T t) {
29 node_xpr_tagged<std::remove_cvref_t<decltype(boost::pfr::get<0>(t))>>;
30};
31
32template <typename T>
33concept node_inherited = std::is_standard_layout_v<std::remove_cvref_t<T>> && requires(T t) {
35 node_xpr_tagged<std::remove_cvref_t<decltype(boost::pfr::get<0>(t))>> ||
36 node_inherited_base<std::remove_cvref_t<decltype(boost::pfr::get<0>(t))>>;
37};
38
39template <typename T>
41
42template <typename T> struct node_traits {
43 static inline bool is(auto &node) { return false; }
44};
45template <node_tag T> struct node_tag_traits;
46template <typename T> struct node_coverage;
47
48#define node_mapping(name) \
49 namespace nodes { \
50 struct name { \
51 using underlying_type = ::name; \
52 static constexpr inline node_tag tag = T_##name; \
53 name(underlying_type v) : val(v) {} \
54 name() { reinterpret_cast<node_tag &>(val) = T_##name; } \
55 underlying_type &as_ref() { return val; } \
56 underlying_type *as_ptr() { return &val; } \
57 \
58 private: \
59 [[maybe_unused]] underlying_type val{}; \
60 }; \
61 } \
62 static_assert((sizeof(name) == sizeof(::name)) && (alignof(name) == alignof(::name))); \
63 static_assert(std::is_standard_layout_v<name>); \
64 static_assert(std::is_aggregate_v<name>); \
65 template <> struct node_coverage<::name> { \
66 using type = nodes::name; \
67 }; \
68 template <> struct node_tag_traits<node_tag::T_##name> { \
69 using type = nodes::name; \
70 }; \
71 template <> struct node_traits<nodes::name> { \
72 static inline constexpr node_tag tag = node_tag::T_##name; \
73 static inline bool is(::Node *node) { \
74 return *reinterpret_cast<node_tag *>(node) == node_tag::T_##name; \
75 } \
76 static inline bool is(::name *node) { \
77 return *reinterpret_cast<node_tag *>(node) == node_tag::T_##name; \
78 } \
79 static inline bool is(void *node) { \
80 return *reinterpret_cast<node_tag *>(node) == node_tag::T_##name; \
81 } \
82 static inline bool is(nodes::name *node) { return true; } \
83 static inline bool is(nodes::name &node) { return true; } \
84 static inline bool is(auto &node) { return false; } \
85 static inline nodes::name *allocate(abstract_memory_context &&ctx = memory_context()) { \
86 auto ptr = ctx.alloc<nodes::name>(); \
87 reinterpret_cast<node_tag &>(ptr) = tag; \
88 return ptr; \
89 } \
90 }
91
92#define node_mapping_no_node_traits(name) \
93 namespace nodes { \
94 using name = node_coverage<::name>::type; \
95 } \
96 template <> struct node_tag_traits<node_tag::T_##name> { \
97 using type = nodes::name; \
98 static_assert(::cppgres::node<name>); \
99 }
100
101#include "node_mapping_table.hpp"
102#undef node_mapping
103
104namespace nodes {
105template <typename T> struct unknown_node {
106 T node;
107};
108}; // namespace nodes
109
110#define node_dispatch(name) \
111 case T_##name: \
112 static_assert( \
113 covering_node<std::remove_pointer_t<decltype(reinterpret_cast<nodes::name *>(node))>>); \
114 visitor(*reinterpret_cast<nodes::name *>(node)); \
115 break
116
117template <typename T>
119 std::is_class_v<node_traits<T>> && requires { typename T::underlying_type; };
120
121template <typename Visitor> void visit_node(covering_node auto node, Visitor &&visitor) {
122 visitor(node);
123}
124
125template <typename T>
126concept covered_node = std::is_class_v<node_coverage<T>> &&
127 requires { typename node_coverage<T>::type::underlying_type; };
128
129template <typename Visitor> void visit_node(covered_node auto *node, Visitor &&visitor) {
130 visitor(*reinterpret_cast<node_coverage<std::remove_pointer_t<decltype(node)>>::type *>(node));
131}
132
133template <typename Visitor> void visit_node(void *node, Visitor &&visitor) {
134 switch (nodeTag(node)) {
135#include "node_dispatch_table.hpp"
136 default:
137 break;
138 }
139 if constexpr (requires {
140 std::declval<Visitor>()(std::declval<nodes::unknown_node<decltype(node)>>());
141 }) {
142 visitor(nodes::unknown_node<decltype(node)>{node});
143 } else {
144 throw std::runtime_error("unknown node tag");
145 }
146}
147
148template <typename T>
149concept walker_implementation = requires(T t, ::Node *node, ::tree_walker_callback cb, void *ctx) {
150 { t(node, cb, ctx) } -> std::same_as<bool>;
151};
152
153template <typename T> struct node_walker {
154 void operator()(T &node, auto &&visitor, const walker_implementation auto &walker)
155 requires covering_node<T>
156 {
157 auto *recasted_node = reinterpret_cast<::Node *>(node.as_ptr());
158 (*this)(recasted_node, visitor, walker);
159 }
160
161 void operator()(::Node *recasted_node, auto &&visitor, const walker_implementation auto &walker) {
166
167 struct _ctx {
168 decltype(visitor) _visitor;
169 };
170 _ctx c{std::forward<decltype(visitor)>(visitor)};
171 ffi_guard{walker}(
172 recasted_node,
173 [](::Node *node, void *ctx) {
174 if (node == nullptr) {
175 return false;
176 }
177 _ctx *c = reinterpret_cast<_ctx *>(ctx);
178 if constexpr (std::is_pointer_v<std::remove_cvref_t<decltype(visitor)>>) {
179 cppgres::visit_node(node, *c->_visitor);
180 } else {
181 cppgres::visit_node(node, c->_visitor);
182 }
183 return false;
184 },
185 &c);
186 }
187};
188
189template <> struct node_walker<nodes::RawStmt> {
190 void operator()(nodes::RawStmt &node, auto &&visitor, const walker_implementation auto &walker) {
191 if constexpr (std::is_pointer_v<std::remove_cvref_t<decltype(visitor)>>) {
192 cppgres::visit_node(node.as_ref().stmt, *visitor);
193 } else {
194 cppgres::visit_node(node.as_ref().stmt, visitor);
195 }
196 }
197};
198
199template <> struct node_walker<nodes::List> {
200 void operator()(nodes::List &node, auto &&visitor, const walker_implementation auto &walker) {
201 ::ListCell *lc;
202 ::List *node_p = node.as_ptr();
203 if (nodeTag(node_p) == T_List) {
204 foreach (lc, node_p) {
205 void *node = lfirst(lc);
206 if constexpr (std::is_pointer_v<std::remove_cvref_t<decltype(visitor)>>) {
207 cppgres::visit_node(node, *visitor);
208 } else {
209 cppgres::visit_node(node, visitor);
210 }
211 }
212 }
213 }
214};
215
216template <covering_node T> struct raw_expr_node_walker {
217 void operator()(T &node, auto &&visitor) {
218 _walker(node, std::forward<decltype(visitor)>(visitor),
219#if PG_MAJORVERSION_NUM < 16
220 reinterpret_cast<bool (*)(::Node *, ::tree_walker_callback, void *)>(
221 raw_expression_tree_walker)
222#else
223 ::raw_expression_tree_walker_impl
224#endif
225 );
226 }
227
228private:
229 node_walker<T> _walker;
230};
231
232template <typename T> struct expr_node_walker {
233
234 void operator()(T &node, auto &&visitor) {
235 _walker(node, std::forward<decltype(visitor)>(visitor),
236#if PG_MAJORVERSION_NUM < 16
237 reinterpret_cast<bool (*)(::Node *, ::tree_walker_callback, void *)>(
238 ::expression_tree_walker)
239#else
240 ::expression_tree_walker_impl
241#endif
242 );
243 }
244
245private:
246 node_walker<T> _walker;
247};
248
249template <> struct expr_node_walker<nodes::Query> {
251 explicit expr_node_walker(int flags) : _flags(flags) {}
252 void operator()(nodes::Query &node, auto &&visitor) {
253 _walker(node, std::forward<decltype(visitor)>(visitor),
254 [this](auto query, auto cb, auto ctx) -> bool {
255 return
256#if PG_MAJORVERSION_NUM < 16
257 reinterpret_cast<bool (*)(::Query *, ::tree_walker_callback, void *, int)>(
258 ::query_tree_walker)(reinterpret_cast<::Query *>(query), cb, ctx, _flags);
259#else
260 ::query_tree_walker_impl
261 (reinterpret_cast<::Query *>(query), cb, ctx, _flags);
262#endif
263 });
264 }
265
266private:
268 int _flags = QTW_EXAMINE_SORTGROUP | QTW_EXAMINE_RTES_BEFORE;
269};
270
271#undef node_dispatch
272
273} // namespace cppgres
Definition: node.hpp:126
Definition: node.hpp:118
Definition: node.hpp:27
Definition: node.hpp:33
Definition: node.hpp:17
Definition: node.hpp:22
Definition: node.hpp:40
Definition: node.hpp:149
Definition: node.hpp:232
Definition: guard.hpp:19
Definition: node.hpp:46
Definition: node.hpp:45
Definition: node.hpp:42
Definition: node.hpp:153
void operator()(::Node *recasted_node, auto &&visitor, const walker_implementation auto &walker)
Definition: node.hpp:161
Definition: node.hpp:105
Definition: node.hpp:216
Postgres type.
Definition: type.hpp:20