cpp-reflect
C++ Reflection and Annotations Library
Loading...
Searching...
No Matches
visitor.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
9export module reflect:visitor;
10
11import std;
12
13import packtl;
14
15import :types;
16import :accessors;
17import :type_name;
18
19export namespace refl {
20 template <typename T>
21 struct is_std_array: std::false_type {};
22
23 template <typename T, std::size_t N>
24 struct is_std_array<std::array<T, N>>: std::true_type {};
25
26 template <typename Derived>
27 struct visitor {
28 visitor() = default;
29 virtual ~visitor() {}
30
31 template <Reflected R>
32 void visit(const R& obj) {
33 self().handle_obj(obj);
34 }
35
36 private:
37 template <typename T>
38 void handle_obj(const T& obj) {
39 visit_obj(obj);
40 }
41
42 template <typename T>
43 void handle_reference(const T& obj) {
44 visit_reference(obj);
45 }
46
47 template <typename T>
48 void handle_pointer(const T* obj) {
49 visit_pointer(obj);
50 }
51
52 template <typename T, typename Field>
53 void handle_field(const T& obj) {
55 }
56
57 template <typename T>
58 void handle_iterable_element(const T& iterable) {
59 visit_iterable_element(iterable);
60 }
61
62 template <typename T>
63 void handle_iterable(const T& iterable) {
64 visit_iterable(iterable);
65 }
66
67 template <typename T>
68 void handle_tuple_element(const T& iterable) {
69 visit_tuple_element(iterable);
70 }
71
72 template <typename T>
73 void handle_tuple(const T& iterable) {
74 visit_tuple(iterable);
75 }
76
77 template <typename T>
78 void handle_value(const T& value) {
79 visit_value(value);
80 }
81
82 protected:
83 template <typename T>
84 void visit_value(const T& obj) {
85 visit_any(obj);
86 }
87
88 template <typename T>
89 void visit_reference(const T& obj) {
90 self().handle_value(obj);
91 }
92
93 template <typename T>
94 void visit_pointer(const T* obj) {
95 if constexpr (not std::is_void_v<T>) {
96 if (obj != nullptr) {
97 self().handle_value(*obj);
98 }
99 }
100 }
101
102 template <refl::Reflected R>
103 void visit_obj(const R& obj) {
104 [&]<std::size_t... I>(std::index_sequence<I...>) {
105 (self().template handle_field<R, refl::field<R, I>>(obj), ...);
106 }(std::make_index_sequence<refl::field_count<R>>());
107
108 [&]<std::size_t... I>(std::index_sequence<I...>) {
109 (visit_obj_method<R, I>(obj), ...);
110 }(std::make_index_sequence<refl::method_count<R>>());
111 }
112
113 template <refl::Reflected R, typename Field>
114 void visit_obj_field(const R& obj) {
115 if constexpr (std::is_reference_v<typename Field::type>) {
116 const auto& it = Field::from_instance(obj);
117 self().handle_reference(it);
118 } else if constexpr (std::is_pointer_v<typename Field::type>) {
119 const auto* it = Field::from_instance(obj);
120 self().handle_pointer(it);
121 } else {
122 const auto& it = Field::from_instance(obj);
123 self().handle_value(it);
124 }
125 }
126
127 template <typename T>
128 void visit_iterable(const T& iterable) {
129// using item_type = typename T::value_type;
130 for (auto item = iterable.begin(); item != iterable.end(); ++item) {
131 self().handle_iterable_element(*item);
132 }
133 }
134
135 template <typename T>
136 void visit_iterable_element(const T& item) {
137 using item_type = T;
138 if constexpr (std::is_reference_v<item_type>) {
139 const auto& it = item;
140 self().handle_reference(it);
141 } else if constexpr (std::is_pointer_v<item_type>) {
142 const auto* it = item;
143 self().handle_pointer(it);
144 } else {
145 const auto& it = item;
146 self().handle_value(it);
147 }
148 }
149
150 template <typename T>
151 void visit_tuple(const T& it) {
152 [&]<std::size_t... I>(std::index_sequence<I...>) {
153 (self().handle_tuple_element(std::get<I>(it)), ...);
154 }(std::make_index_sequence<std::tuple_size_v<T>>{});
155 }
156
157 template <typename T>
158 void visit_tuple_element(const T& item) {
159 using item_type = T;
160 if constexpr (std::is_reference_v<item_type>) {
161 const auto& it = item;
162 self().handle_reference(it);
163 } else if constexpr (std::is_pointer_v<item_type>) {
164 const auto* it = item;
165 self().handle_pointer(it);
166 } else {
167 const auto& it = item;
168 self().handle_value(it);
169 }
170 }
171
172 private:
173 auto& self() {
174 return *static_cast<Derived*>(this);
175 }
176
177 template <refl::Reflected R, std::size_t I>
178 void visit_obj_method(const R& obj) {
179// using m = refl::method<R, I>;
180 }
181
182 protected:
183 template <typename T>
184 void visit_any(const T& it) {
185 if constexpr (std::same_as<T, char*>) {
186 return;
187 } else if constexpr (std::same_as<T, const char*>) {
188 return;
189 } else if constexpr (std::is_reference_v<T>) {
190 self().handle_reference(it);
191 } else if constexpr (std::is_pointer_v<T>) {
192 self().handle_pointer(it);
193 } else if constexpr (packtl::is_type<std::vector, T>::value) {
194 self().handle_iterable(it);
195 } else if constexpr (is_std_array<T>::value) {
196 self().handle_iterable(it);
197 } else if constexpr (packtl::is_type<std::list, T>::value) {
198 self().handle_iterable(it);
199 } else if constexpr (packtl::is_type<std::deque, T>::value) {
200 self().handle_iterable(it);
201 } else if constexpr (packtl::is_type<std::map, T>::value) {
202 self().handle_iterable(it);
203 } else if constexpr (packtl::is_type<std::unordered_map, T>::value) {
204 self().handle_iterable(it);
205 } else if constexpr (packtl::is_type<std::set, T>::value) {
206 self().handle_iterable(it);
207 } else if constexpr (packtl::is_type<std::unordered_set, T>::value) {
208 self().handle_iterable(it);
209 } else if constexpr (packtl::is_type<std::pair, T>::value) {
210 self().handle_tuple(it);
211 // } else if constexpr (packtl::is_type<std::unique_ptr, T>::value) {
212 // const auto* value = it.get();
213 // self().handle_value(*value);
214 // } else if constexpr (packtl::is_type<std::shared_ptr, T>::value) {
215 // const auto* value = it.get();
216 // self().handle_value(*value);
217 } else if constexpr (packtl::is_type<std::weak_ptr, T>::value) {
218 if (not it.expired()) {
219 const auto* value = it.lock().get();
220 self().handle_value(*value);
221 }
222 } else if constexpr (refl::Reflected<T>) {
223 self().handle_obj(it);
224 }
225 }
226 };
227} // namespace refl
void visit_obj_field(const R &obj)
Definition visitor.cppm:114
void visit_obj(const R &obj)
Definition visitor.cppm:103
void visit_value(const T &obj)
Definition visitor.cppm:84
void visit_iterable_element(const T &item)
Definition visitor.cppm:136
virtual ~visitor()
Definition visitor.cppm:29
visitor()=default
void visit_any(const T &it)
Definition visitor.cppm:184
void visit_reference(const T &obj)
Definition visitor.cppm:89
void visit_tuple_element(const T &item)
Definition visitor.cppm:158
void visit_tuple(const T &it)
Definition visitor.cppm:151
void visit_iterable(const T &iterable)
Definition visitor.cppm:128
void visit(const R &obj)
Definition visitor.cppm:32
void visit_pointer(const T *obj)
Definition visitor.cppm:94