cpp-reflect
C++ Reflection and Annotations Library
Loading...
Searching...
No Matches
format_base.cppm
Go to the documentation of this file.
1// Copyright (c) 2024-2025, Vรญctor Castillo Agรผero.
2// SPDX-License-Identifier: GPL-3.0-or-later
3
8
10
11import std;
12
13import packtl;
14import reflect;
15
16export namespace serialize::policy {
22 template <typename F>
23 struct handle {
25 };
26}
27export namespace serialize {
28 struct name {
29 std::string value;
30 };
31}
32
33
34export namespace formats {
35 template <typename Format, typename Args>
36 struct base {
37 using args_t = Args;
39
40 explicit base(args_t args_)
41 : args(args_) {}
42
43 virtual ~base() {}
44
45 template <typename O, refl::Reflected R, std::size_t I>
46 void print_obj_field_impl(O& out, const R& obj, std::size_t indent) {
47 using f = refl::field<R, I>;
48
49 for (std::size_t i = 0; i < std::max((indent * args.indent), 0UL); ++i) {
50 out << " ";
51 }
52
53 switch (f::access) {
55 out << " -";
56 break;
58 // out << "๐Ÿ”’";
59 out << "๐Ÿ”’";
60 break;
61 // ๐Ÿ”“
63 out << " \\";
64 break;
66 out << " ";
67 break;
68 }
69
70 out << f::name;
71 // using raw_field_type = std::remove_pointer_t<std::remove_reference_t<typename f::type>>;
72 // if constexpr (not refl::Reflected<typename f::type>) {
73 // out << " [" << type_name<typename f::type> << "]";
74 out << ": " << refl::type_name<typename f::type> << " = ";
75 // }
76
77 // if constexpr (f::access == field_access::PUBLIC) {
78 if constexpr (std::is_reference_v<typename f::type>) {
79 const auto& it = f::from_instance(obj);
80 out << " {";
81 out << std::format("0x{:X}", (std::size_t)&it);
82 out << "} ";
83
84 // if constexpr (refl::Reflected<std::remove_reference_t<typename f::type>>) {
85
86 print_any(out, it, indent);
87 // }
88 } else if constexpr (std::is_pointer_v<typename f::type>) {
89 const auto* it = f::from_instance(obj);
90 out << " {";
91 out << std::format("0x{:X}", (std::size_t)it);
92 out << "} ";
93
94 // if constexpr (refl::Reflected<std::remove_reference_t<typename f::type>>) {
95 if constexpr (not std::is_void_v<std::remove_pointer_t<typename f::type>>) {
96 if (it != nullptr) {
97 print_any(out, *it, indent);
98 }
99 }
100 } else {
101 if constexpr (not refl::Reflected<typename f::type>) {
102 out << " { ";
103 }
104 const auto& it = f::from_instance(obj);
105 // const typename f::type& it =
106 // *(const typename f::type*)(((unsigned char*)&obj) + f::offset);
107 print_any(out, it, indent);
108 if constexpr (not refl::Reflected<typename f::type>) {
109 out << " }";
110 }
111 }
112 // }
113
114 out << std::endl;
115 }
116
117 template <typename O, refl::Reflected R, std::size_t... I>
118 void print_obj_impl(O& out, const R& obj, std::size_t indent, std::index_sequence<I...>) {
119 out << refl::type_name<R> << " {" << "\n";
120 ((print_obj_field_impl<O, R, I>(out, obj, indent + 1)), ...);
121 for (std::size_t i = 0; i < indent; ++i) {
122 for (std::size_t j = 0; j < args.indent; ++j) {
123 out << " ";
124 }
125 }
126 out << "}";
127 }
128
129 template <typename O, refl::Reflected R, std::size_t I>
130 void print_obj_method(O& out, const R& obj) {
131 using m = refl::method<R, I>;
132
133 switch (m::access) {
135 out << " -";
136 break;
138 // out << "๐Ÿ”’";
139 out << "๐Ÿ”’";
140 break;
141 // ๐Ÿ”“
143 out << " \\";
144 break;
146 out << " ";
147 break;
148 }
149
150 out << m::name;
152 }
153
154 template <typename O, refl::Reflected R>
155 void print_obj(O& out, const R& obj, std::size_t indent = 0) {
156 print_obj_impl(out, obj, indent, std::make_index_sequence<refl::field_count<R>>());
157
158 [&]<std::size_t... I>(std::index_sequence<I...>) {
159 (print_obj_method<O, R, I>(out, obj), ...);
160 }(std::make_index_sequence<refl::method_count<R>>());
161 }
162
163 template <typename O, typename T>
164 void print_std_iterable(O& out, const T& it, std::size_t indent) {
165 using item_type = typename T::value_type;
166 out << "[" << std::endl;
167 for (auto item = it.begin(); item != it.end(); ++item) {
168 for (std::size_t i = 0; i < std::max((indent * args.indent), 0UL); ++i) {
169 out << " ";
170 }
171
172 if constexpr (std::is_reference_v<item_type>) {
173 const auto& value = *item;
174 out << " {";
175 out << std::format("0x{:X}", (std::size_t)&value);
176 out << "} ";
177
178 // if constexpr (refl::Reflected<std::remove_reference_t<typename f::type>>) {
179
180 print_any(out, value, indent + 1);
181 // }
182 } else if constexpr (std::is_pointer_v<item_type>) {
183 const auto* value = *item;
184 out << " {";
185 out << std::format("0x{:X}", (std::size_t)value);
186 out << "} ";
187
188 // if constexpr (refl::Reflected<std::remove_reference_t<typename f::type>>) {
189 if constexpr (not std::is_void_v<std::remove_pointer_t<item_type>>) {
190 if (value != nullptr) {
191 print_any(out, *value, indent + 1);
192 }
193 }
194 } else {
195 if constexpr (refl::Reflected<item_type>) {
196 out << " ";
197 } else {
198 out << " {";
199 }
200 const auto& value = *item;
201 // const typename f::type& it =
202 // *(const typename f::type*)(((unsigned char*)&obj) + f::offset);
203 print_any(out, value, indent + 1);
204 if constexpr (not refl::Reflected<item_type>) {
205 out << " }";
206 }
207 }
208 out << "," << std::endl;
209 }
210 for (std::size_t i = 0; i < std::max((indent * args.indent), 0UL); ++i) {
211 out << " ";
212 }
213 out << "]";
214 }
215
216 template <typename O, typename T>
217 void print_std_pair(O& out, const T& it, std::size_t indent) {
218 using item_type_1 = typename T::first_type;
219 using item_type_2 = typename T::second_type;
220 out << "[";
221
222 if constexpr (std::is_reference_v<item_type_1>) {
223 const auto& value = it.first;
224 out << " {";
225 out << std::format("0x{:X}", (std::size_t)&value);
226 out << "} ";
227
228 // if constexpr (refl::Reflected<std::remove_reference_t<typename f::type>>) {
229
230 print_any(out, value, indent + 1);
231 // }
232 } else if constexpr (std::is_pointer_v<item_type_1>) {
233 const auto* value = it.first;
234 out << " {";
235 out << std::format("0x{:X}", (std::size_t)value);
236 out << "} ";
237
238 // if constexpr (refl::Reflected<std::remove_reference_t<typename f::type>>) {
239 if constexpr (not std::is_void_v<std::remove_pointer_t<item_type_1>>) {
240 if (value != nullptr) {
241 out << ": ";
242
243 print_any(out, *value, indent + 1);
244 }
245 }
246 } else {
247 if constexpr (not refl::Reflected<item_type_1>) {
248 out << "{";
249 }
250 const auto& value = it.first;
251 // const typename f::type& it =
252 // *(const typename f::type*)(((unsigned char*)&obj) + f::offset);
253 print_any(out, value, indent + 1);
254 if constexpr (not refl::Reflected<item_type_1>) {
255 out << "}";
256 }
257 }
258 out << ", ";
259 if constexpr (std::is_reference_v<item_type_2>) {
260 const auto& value = it.second;
261 out << " {";
262 out << std::format("0x{:X}", (std::size_t)&value);
263 out << "} ";
264
265 // if constexpr (refl::Reflected<std::remove_reference_t<typename f::type>>) {
266
267 print_any(out, value, indent);
268 // }
269 } else if constexpr (std::is_pointer_v<item_type_2>) {
270 const auto* value = it.second;
271 out << " {";
272 out << std::format("0x{:X}", (std::size_t)value);
273 out << "} ";
274
275 // if constexpr (refl::Reflected<std::remove_reference_t<typename f::type>>) {
276 if constexpr (not std::is_void_v<std::remove_pointer_t<item_type_2>>) {
277 if (value != nullptr) {
278 print_any(out, *value, indent);
279 }
280 }
281 } else {
282 if constexpr (not refl::Reflected<item_type_2>) {
283 out << "{";
284 }
285 const auto& value = it.second;
286 // const typename f::type& it =
287 // *(const typename f::type*)(((unsigned char*)&obj) + f::offset);
288 print_any(out, value, indent);
289 if constexpr (not refl::Reflected<item_type_2>) {
290 out << "}";
291 }
292 }
293 out << "]";
294 }
295
296 template <typename O, typename T>
297 void print_any(O& out, const T& it, std::size_t indent) {
298 if constexpr (packtl::is_type<std::vector, T>::value) {
299 print_std_iterable(out, it, indent);
300 } else if constexpr (packtl::is_type<std::list, T>::value) {
301 print_std_iterable(out, it, indent);
302 } else if constexpr (packtl::is_type<std::deque, T>::value) {
303 print_std_iterable(out, it, indent);
304 } else if constexpr (packtl::is_type<std::queue, T>::value) {
305 print_std_iterable(out, it, indent);
306 } else if constexpr (packtl::is_type<std::stack, T>::value) {
307 print_std_iterable(out, it, indent);
308 } else if constexpr (packtl::is_type<std::map, T>::value) {
309 print_std_iterable(out, it, indent);
310 } else if constexpr (packtl::is_type<std::unordered_map, T>::value) {
311 print_std_iterable(out, it, indent);
312 } else if constexpr (packtl::is_type<std::set, T>::value) {
313 print_std_iterable(out, it, indent);
314 } else if constexpr (packtl::is_type<std::unordered_set, T>::value) {
315 print_std_iterable(out, it, indent);
316 } else if constexpr (packtl::is_type<std::pair, T>::value) {
317 print_std_pair(out, it, indent);
318 } else if constexpr (std::is_same_v<T, std::atomic_flag>) {
319 out << (it.test() ? "SET" : "CLEAR");
320 } else if constexpr (packtl::is_type<std::unique_ptr, T>::value) {
321 const auto* value = it.get();
322 out << " {";
323 out << std::format("0x{:X}", (std::size_t)value);
324 out << "} ";
325 print_any(out, *value, indent);
326 } else if constexpr (packtl::is_type<std::shared_ptr, T>::value) {
327 const auto* value = it.get();
328 out << "{";
329 out << std::format("0x{:X}", (std::size_t)value);
330 out << "} ";
331 print_any(out, *value, indent);
332 } else if constexpr (packtl::is_type<std::weak_ptr, T>::value) {
333 const auto* value = it.get();
334 out << " {";
335 out << std::format("0x{:X}", (std::size_t)value);
336 out << "}: ";
337 print_any(out, *value, indent);
338 } else if constexpr (refl::Reflected<T>) {
339 if (visited_.contains((std::size_t)&it)) {
340 out << "<circular reference>";
341 return;
342 }
343 visited_.emplace((std::size_t)&it);
344 print_obj(out, it, indent);
345 } else if constexpr (std::is_convertible_v<T, std::string>) {
346 out << std::format("{:?}", it);
347 } else if constexpr (std::same_as<T, char>) {
348 out << std::format("0x{:X} '{}'", (int)it, it);
349 } else if constexpr (std::formattable<T, char>) {
350 out << std::format("{}", it);
351 }
352 }
353
354 template <refl::Reflected R>
355 void visit(const R& obj) {
356 self().handle_obj(obj);
357 }
358
359 private:
360 template <typename T>
361 void handle_obj(const T& obj) {
362 visit_obj(obj);
363 }
364
365 template <typename T>
366 void handle_reference(const T& obj) {
367 self().handle_value(obj);
368 }
369
370 template <typename T>
371 void handle_pointer(const T* obj) {
372 if constexpr (not std::is_void_v<T>) {
373 if (obj != nullptr) {
374 self().handle_value(*obj);
375 }
376 }
377 }
378
379 template <typename T, typename Field>
380 void handle_field(const T& obj) {
382 }
383
384 template <typename T>
385 void handle_iterable(const T& iterable) {
386 visit_iterable(iterable);
387 }
388
389 template <typename T>
390 void handle_value(const T& value) {
391 visit_value(value);
392 }
393
394 protected:
395 template <typename T>
396 void visit_value(const T& obj) {
397 visit_any(obj);
398 }
399
400 template <refl::Reflected R>
401 void visit_obj(const R& obj) {
402 [&]<std::size_t... I>(std::index_sequence<I...>) {
403 (self().template handle_field<R, refl::field<R, I>>(obj), ...);
404 }(std::make_index_sequence<refl::field_count<R>>());
405
406 [&]<std::size_t... I>(std::index_sequence<I...>) {
407 (visit_obj_method<R, I>(obj), ...);
408 }(std::make_index_sequence<refl::method_count<R>>());
409 }
410
411 template <refl::Reflected R, typename Field>
412 void visit_obj_field(const R& obj) {
413 if constexpr (std::is_reference_v<typename Field::type>) {
414 const auto& it = Field::from_instance(obj);
415 self().handle_reference(it);
416 } else if constexpr (std::is_pointer_v<typename Field::type>) {
417 const auto* it = Field::from_instance(obj);
418 self().handle_pointer(it);
419 } else {
420 const auto& it = Field::from_instance(obj);
421 self().handle_value(it);
422 }
423 }
424
425 template <typename T>
426 void visit_iterable(const T& iterable) {
427 using item_type = typename T::value_type;
428 for (auto item = iterable.begin(); item != iterable.end(); ++item) {
429 if constexpr (std::is_reference_v<item_type>) {
430 const auto& it = *item;
431 self().handle_reference(it);
432 } else if constexpr (std::is_pointer_v<item_type>) {
433 const auto* it = *item;
434 self().handle_pointer(it);
435 } else {
436 const auto& it = *item;
437 self().handle_value(it);
438 }
439 }
440 }
441
442 private:
443 auto& self() {
444 return *static_cast<Format*>(this);
445 }
446
447 template <typename T>
448 void visit_std_pair(const T& it) {}
449
450 template <refl::Reflected R, std::size_t I>
451 void visit_obj_method(const R& obj) {
452// using m = refl::method<R, I>;
453 }
454
455 protected:
456 template <typename T>
457 void visit_any(const T& it) {
458 if constexpr (packtl::is_type<std::vector, T>::value) {
459 self().handle_iterable(it);
460 } else if constexpr (packtl::is_type<std::list, T>::value) {
461 self().handle_iterable(it);
462 } else if constexpr (packtl::is_type<std::deque, T>::value) {
463 self().handle_iterable(it);
464 } else if constexpr (packtl::is_type<std::queue, T>::value) {
465 self().handle_iterable(it);
466 } else if constexpr (packtl::is_type<std::stack, T>::value) {
467 self().handle_iterable(it);
468 } else if constexpr (packtl::is_type<std::map, T>::value) {
469 self().handle_iterable(it);
470 } else if constexpr (packtl::is_type<std::unordered_map, T>::value) {
471 self().handle_iterable(it);
472 } else if constexpr (packtl::is_type<std::set, T>::value) {
473 self().handle_iterable(it);
474 } else if constexpr (packtl::is_type<std::unordered_set, T>::value) {
475 self().handle_iterable(it);
476 } else if constexpr (packtl::is_type<std::pair, T>::value) {
477 self().visit_std_pair(it);
478 // } else if constexpr (std::is_same_v<T, std::atomic_flag>) {
479 // out << (it.test() ? "SET" : "CLEAR");
480 // } else if constexpr (packtl::is_type<std::unique_ptr, T>::value) {
481 // const auto* value = it.get();
482 // out << " {";
483 // out << std::format("0x{:X}", (std::size_t)value);
484 // out << "} ";
485 // print_any(out, *value, indent);
486 // } else if constexpr (packtl::is_type<std::shared_ptr, T>::value) {
487 // const auto* value = it.get();
488 // out << "{";
489 // out << std::format("0x{:X}", (std::size_t)value);
490 // out << "} ";
491 // print_any(out, *value, indent);
492 // } else if constexpr (packtl::is_type<std::weak_ptr, T>::value) {
493 // const auto* value = it.get();
494 // out << " {";
495 // out << std::format("0x{:X}", (std::size_t)value);
496 // out << "}: ";
497 // print_any(out, *value, indent);
498 } else if constexpr (refl::Reflected<T>) {
499 self().handle_obj(it);
500 // } else if constexpr (std::is_convertible_v<T, std::string>) {
501 // out << std::format("{:?}", it);
502 // } else if constexpr (std::same_as<T, char>) {
503 // out << std::format("0x{:X} '{}'", (int)it, it);
504 // } else if constexpr (std::formattable<T, char>) {
505 // out << std::format("{}", it);
506 }
507 }
508
509 private:
510 std::unordered_set<std::size_t> visited_{};
511 };
512} // namespace formats
constexpr std::size_t field_count
constexpr auto type_name
void print_obj(O &out, const R &obj, std::size_t indent=0)
void visit_obj(const R &obj)
void print_obj_method(O &out, const R &obj)
void print_std_pair(O &out, const T &it, std::size_t indent)
void print_std_iterable(O &out, const T &it, std::size_t indent)
void print_obj_field_impl(O &out, const R &obj, std::size_t indent)
virtual ~base()
void print_obj_impl(O &out, const R &obj, std::size_t indent, std::index_sequence< I... >)
base(args_t args_)
void visit_iterable(const T &iterable)
void visit(const R &obj)
void visit_value(const T &obj)
void visit_any(const T &it)
void visit_obj_field(const R &obj)
void print_any(O &out, const T &it, std::size_t indent)
std::string value