1 | //===----------------------------------------------------------------------===// |
2 | // DuckDB |
3 | // |
4 | // duckdb/common/serializer/format_serializer.hpp |
5 | // |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #pragma once |
10 | |
11 | #include "duckdb/common/field_writer.hpp" |
12 | #include "duckdb/common/serializer.hpp" |
13 | #include "duckdb/common/enum_util.hpp" |
14 | #include "duckdb/common/serializer/serialization_traits.hpp" |
15 | #include "duckdb/common/types/interval.hpp" |
16 | #include "duckdb/common/types/string_type.hpp" |
17 | #include "duckdb/common/unordered_map.hpp" |
18 | #include "duckdb/common/unordered_set.hpp" |
19 | |
20 | namespace duckdb { |
21 | |
22 | class FormatSerializer { |
23 | friend Vector; |
24 | |
25 | protected: |
26 | bool serialize_enum_as_string = false; |
27 | |
28 | public: |
29 | // Serialize a value |
30 | template <class T> |
31 | typename std::enable_if<!std::is_enum<T>::value, void>::type WriteProperty(const char *tag, T &value) { |
32 | SetTag(tag); |
33 | WriteValue(value); |
34 | } |
35 | |
36 | // Serialize an enum |
37 | template <class T> |
38 | typename std::enable_if<std::is_enum<T>::value, void>::type WriteProperty(const char *tag, T value) { |
39 | SetTag(tag); |
40 | if (serialize_enum_as_string) { |
41 | // Use the enum serializer to lookup tostring function |
42 | auto str = EnumUtil::ToChars(value); |
43 | WriteValue(str); |
44 | } else { |
45 | // Use the underlying type |
46 | WriteValue(static_cast<typename std::underlying_type<T>::type>(value)); |
47 | } |
48 | } |
49 | |
50 | // Optional pointer |
51 | template <class T> |
52 | void WriteOptionalProperty(const char *tag, T *ptr) { |
53 | SetTag(tag); |
54 | if (ptr == nullptr) { |
55 | OnOptionalBegin(present: false); |
56 | OnOptionalEnd(present: false); |
57 | } else { |
58 | OnOptionalBegin(present: true); |
59 | WriteValue(*ptr); |
60 | OnOptionalEnd(present: true); |
61 | } |
62 | } |
63 | |
64 | // Optional unique_ptr |
65 | template <class T> |
66 | void WriteOptionalProperty(const char *tag, const unique_ptr<T> &ptr) { |
67 | SetTag(tag); |
68 | if (ptr == nullptr) { |
69 | OnOptionalBegin(present: false); |
70 | OnOptionalEnd(present: false); |
71 | } else { |
72 | OnOptionalBegin(present: true); |
73 | WriteValue(*ptr); |
74 | OnOptionalEnd(present: true); |
75 | } |
76 | } |
77 | |
78 | // Special case: data_ptr_T |
79 | void WriteProperty(const char *tag, const_data_ptr_t ptr, idx_t count) { |
80 | SetTag(tag); |
81 | WriteDataPtr(ptr, count); |
82 | } |
83 | |
84 | protected: |
85 | // Unique Pointer Ref |
86 | template <typename T> |
87 | void WriteValue(const unique_ptr<T> &ptr) { |
88 | WriteValue(ptr.get()); |
89 | } |
90 | |
91 | // Pointer |
92 | template <typename T> |
93 | typename std::enable_if<std::is_pointer<T>::value, void>::type WriteValue(const T ptr) { |
94 | if (ptr == nullptr) { |
95 | WriteNull(); |
96 | } else { |
97 | WriteValue(*ptr); |
98 | } |
99 | } |
100 | |
101 | // Pair |
102 | template <class K, class V> |
103 | void WriteValue(const std::pair<K, V> &pair) { |
104 | OnPairBegin(); |
105 | OnPairKeyBegin(); |
106 | WriteValue(pair.first); |
107 | OnPairKeyEnd(); |
108 | OnPairValueBegin(); |
109 | WriteValue(pair.second); |
110 | OnPairValueEnd(); |
111 | OnPairEnd(); |
112 | } |
113 | |
114 | // Vector |
115 | template <class T> |
116 | void WriteValue(const vector<T> &vec) { |
117 | auto count = vec.size(); |
118 | OnListBegin(count); |
119 | for (auto &item : vec) { |
120 | WriteValue(item); |
121 | } |
122 | OnListEnd(count); |
123 | } |
124 | |
125 | // UnorderedSet |
126 | // Serialized the same way as a list/vector |
127 | template <class T, class HASH, class CMP> |
128 | void WriteValue(const unordered_set<T, HASH, CMP> &set) { |
129 | auto count = set.size(); |
130 | OnListBegin(count); |
131 | for (auto &item : set) { |
132 | WriteValue(item); |
133 | } |
134 | OnListEnd(count); |
135 | } |
136 | |
137 | // Set |
138 | // Serialized the same way as a list/vector |
139 | template <class T, class HASH, class CMP> |
140 | void WriteValue(const set<T, HASH, CMP> &set) { |
141 | auto count = set.size(); |
142 | OnListBegin(count); |
143 | for (auto &item : set) { |
144 | WriteValue(item); |
145 | } |
146 | OnListEnd(count); |
147 | } |
148 | |
149 | // Map |
150 | template <class K, class V, class HASH, class CMP> |
151 | void WriteValue(const std::unordered_map<K, V, HASH, CMP> &map) { |
152 | auto count = map.size(); |
153 | OnMapBegin(count); |
154 | for (auto &item : map) { |
155 | OnMapEntryBegin(); |
156 | OnMapKeyBegin(); |
157 | WriteValue(item.first); |
158 | OnMapKeyEnd(); |
159 | OnMapValueBegin(); |
160 | WriteValue(item.second); |
161 | OnMapValueEnd(); |
162 | OnMapEntryEnd(); |
163 | } |
164 | OnMapEnd(count); |
165 | } |
166 | |
167 | // class or struct implementing `FormatSerialize(FormatSerializer& FormatSerializer)`; |
168 | template <typename T> |
169 | typename std::enable_if<has_serialize<T>::value>::type WriteValue(T &value) { |
170 | // Else, we defer to the .FormatSerialize method |
171 | OnObjectBegin(); |
172 | value.FormatSerialize(*this); |
173 | OnObjectEnd(); |
174 | } |
175 | |
176 | // Handle setting a "tag" (optional) |
177 | virtual void SetTag(const char *tag) { |
178 | (void)tag; |
179 | } |
180 | |
181 | // Hooks for subclasses to override to implement custom behavior |
182 | virtual void OnListBegin(idx_t count) { |
183 | (void)count; |
184 | } |
185 | virtual void OnListEnd(idx_t count) { |
186 | (void)count; |
187 | } |
188 | virtual void OnMapBegin(idx_t count) { |
189 | (void)count; |
190 | } |
191 | virtual void OnMapEnd(idx_t count) { |
192 | (void)count; |
193 | } |
194 | virtual void OnMapEntryBegin() { |
195 | } |
196 | virtual void OnMapEntryEnd() { |
197 | } |
198 | virtual void OnMapKeyBegin() { |
199 | } |
200 | virtual void OnMapKeyEnd() { |
201 | } |
202 | virtual void OnMapValueBegin() { |
203 | } |
204 | virtual void OnMapValueEnd() { |
205 | } |
206 | virtual void OnOptionalBegin(bool present) { |
207 | } |
208 | virtual void OnOptionalEnd(bool present) { |
209 | } |
210 | virtual void OnObjectBegin() { |
211 | } |
212 | virtual void OnObjectEnd() { |
213 | } |
214 | virtual void OnPairBegin() { |
215 | } |
216 | virtual void OnPairKeyBegin() { |
217 | } |
218 | virtual void OnPairKeyEnd() { |
219 | } |
220 | virtual void OnPairValueBegin() { |
221 | } |
222 | virtual void OnPairValueEnd() { |
223 | } |
224 | virtual void OnPairEnd() { |
225 | } |
226 | |
227 | // Handle primitive types, a serializer needs to implement these. |
228 | virtual void WriteNull() = 0; |
229 | virtual void WriteValue(bool value) = 0; |
230 | virtual void WriteValue(uint8_t value) = 0; |
231 | virtual void WriteValue(int8_t value) = 0; |
232 | virtual void WriteValue(uint16_t value) = 0; |
233 | virtual void WriteValue(int16_t value) = 0; |
234 | virtual void WriteValue(uint32_t value) = 0; |
235 | virtual void WriteValue(int32_t value) = 0; |
236 | virtual void WriteValue(uint64_t value) = 0; |
237 | virtual void WriteValue(int64_t value) = 0; |
238 | virtual void WriteValue(hugeint_t value) = 0; |
239 | virtual void WriteValue(float value) = 0; |
240 | virtual void WriteValue(double value) = 0; |
241 | virtual void WriteValue(const string_t value) = 0; |
242 | virtual void WriteValue(const string &value) = 0; |
243 | virtual void WriteValue(const char *str) = 0; |
244 | virtual void WriteValue(interval_t value) = 0; |
245 | virtual void WriteDataPtr(const_data_ptr_t ptr, idx_t count) = 0; |
246 | }; |
247 | |
248 | } // namespace duckdb |
249 | |