Zen C++ Libraries
Zero-dependency re-usable components for C++
Loading...
Searching...
No Matches
transformer.hpp
1#ifndef ZEN_TRANSFORMER_HPP
2#define ZEN_TRANSFORMER_HPP
3
4#include <optional>
5
6#include "zen/config.hpp"
7#include "zen/concepts.hpp"
8
9ZEN_NAMESPACE_START
10
11class transformer;
14
15template<typename T>
16concept can_transform = requires (T& t) {
17 t.transform(std::declval<transformer&>());
18};
19
21public:
22
23 virtual void transform(bool& value) = 0;
24 virtual void transform(char& value) = 0;
25 virtual void transform(short& value) = 0;
26 virtual void transform(int& value) = 0;
27 virtual void transform(long& value) = 0;
28 virtual void transform(long long& value) = 0;
29 virtual void transform(unsigned char& value) = 0;
30 virtual void transform(unsigned short& value) = 0;
31 virtual void transform(unsigned int& value) = 0;
32 virtual void transform(unsigned long& value) = 0;
33 virtual void transform(unsigned long long& value) = 0;
34 virtual void transform(float& value) = 0;
35 virtual void transform(double& value) = 0;
36 virtual void transform(std::string& value) = 0;
37
38 virtual void start_transform_optional() = 0;
39 virtual void transform_nil() = 0;
40 virtual void end_transform_optional() = 0;
41
42 virtual void start_transform_object(const std::string& tag_name) = 0;
43 virtual void start_transform_field(const std::string& name) = 0;
44 virtual void end_transform_field() = 0;
45 virtual void end_transform_object() = 0;
46
47 virtual void start_transform_sequence() = 0;
48 virtual void transform_size(std::size_t size) = 0;
49 virtual void start_transform_element() = 0;
50 virtual void end_transform_element() = 0;
51 virtual void end_transform_sequence() = 0;
52
53 template<typename T>
54 void transform(std::optional<T>& value);
55
56 template<typename T1, typename T2>
57 void transform(std::pair<T1, T2>& value);
58
59 template<pointer T>
60 void transform(T& value);
61
62 template<container T>
63 void transform(T& value);
64
65 template<can_transform T>
66 void transform(T& value);
67
68 object_transformer transform_object(const std::string& tag_name);
69 sequence_transformer transform_sequence(std::size_t size);
70
71 virtual ~transformer() {}
72
73};
74
75class object_transformer {
76
77 transformer& parent;
78
79#ifndef NDEBUG
80 bool has_finalized = false;
81#endif
82
83public:
84
85 object_transformer(class transformer& transformer):
86 parent(transformer) {}
87
88 template<typename T>
89 void transform_field(std::string name, T value) {
90 parent.start_transform_field(name);
91 parent.transform(value);
92 parent.end_transform_field();
93 }
94
95 void finalize() {
96 parent.end_transform_object();
97#ifndef NDEBUG
98 has_finalized = true;
99#endif
100 }
101
102#ifndef NDEBUG
103 ~object_transformer() {
104 if (!has_finalized) {
105 ZEN_PANIC("detected a missing call to zen::object_transformer::finalize()");
106 }
107 }
108#endif
109
110};
111
112inline object_transformer transformer::transform_object(const std::string& tag_name) {
113 start_transform_object(tag_name);
114 return object_transformer(*this);
115}
116
117class sequence_transformer {
118
119 transformer& parent;
120
121#ifndef NDEBUG
122 bool has_finalized = false;
123#endif
124
125public:
126
127 inline sequence_transformer(class transformer& transformer):
128 parent(transformer) {}
129
130 template<typename T>
131 void transform(T value) {
132 parent.start_transform_element();
133 parent.transform(value);
134 parent.end_transform_element();
135 }
136
137 void finalize() {
138 parent.end_transform_sequence();
139#ifndef NDEBUG
140 has_finalized = true;
141#endif
142 }
143
144#ifndef NDEBUG
145 ~sequence_transformer() {
146 if (!has_finalized) {
147 ZEN_PANIC("detected a missing call to zen::sequence_transformer::finalize()");
148 }
149 }
150#endif
151
152};
153
154inline sequence_transformer transformer::transform_sequence(std::size_t size) {
155 start_transform_sequence();
156 transform_size(size);
157 return sequence_transformer(*this);
158}
159
160template<typename T>
161void transformer::transform(std::optional<T>& value) {
162 start_transform_optional();
163 if (value.has_value()) {
164 transform_nil();
165 } else {
166 transform(*value);
167 }
168 end_transform_optional();
169}
170
171template<typename T1, typename T2>
172void transformer::transform(std::pair<T1, T2>& value) {
173 start_transform_sequence();
174 start_transform_element();
175 transform(value.first);
176 end_transform_element();
177 start_transform_element();
178 transform(value.second);
179 end_transform_element();
180 end_transform_sequence();
181}
182
183template<container T>
184void transformer::transform(T& value) {
185 start_transform_sequence();
186 transform_size(value.size());
187 for (const auto& element: value) {
188 start_transform_element();
189 transform(element);
190 end_transform_element();
191 }
192 end_transform_sequence();
193}
194
195template<pointer T>
196void transformer::transform(T& value) {
197 start_transform_optional();
198 if (value == nullptr) {
199 transform_nil();
200 } else {
201 transform(*value);
202 }
203 end_transform_optional();
204}
205
206template<can_transform T>
207void transformer::transform(T& value) {
208 value.transform(*this);
209}
210
211template<typename T>
212void decode(transformer& decoder, T& value) {
213 // FIXME The object tag is set to the empty string
214 auto s = decoder.transform_object("");
215 value.transform_fields(s);
216 s.finalize();
217}
218
219ZEN_NAMESPACE_END
220
221#endif // of #ifndef ZEN_TRANSFORMER_HPP
Definition transformer.hpp:75
Definition transformer.hpp:117
Definition transformer.hpp:20
Definition value.hpp:34
Definition transformer.hpp:16