OpenCBDC Transaction Processor
Loading...
Searching...
No Matches
util/serialization/format.hpp
Go to the documentation of this file.
1// Copyright (c) 2021 MIT Digital Currency Initiative,
2// Federal Reserve Bank of Boston
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#ifndef OPENCBDC_TX_SRC_SERIALIZATION_FORMAT_H_
7#define OPENCBDC_TX_SRC_SERIALIZATION_FORMAT_H_
8
9#include "serializer.hpp"
13
14#include <algorithm>
15#include <array>
16#include <cassert>
17#include <cstdint>
18#include <limits>
19#include <optional>
20#include <set>
21#include <unordered_map>
22#include <unordered_set>
23#include <variant>
24#include <vector>
25
26namespace cbdc {
27
29 auto operator<<(serializer& packet, std::byte b) -> serializer&;
30
36 auto operator>>(serializer& packet, std::byte& b) -> serializer&;
37
44 auto operator<<(serializer& ser, const buffer& b) -> serializer&;
45
47 auto operator>>(serializer& deser, buffer& b) -> serializer&;
48
52 template<typename T>
53 auto operator<<(serializer& s, T /* t */) ->
54 typename std::enable_if_t<std::is_empty_v<T>, serializer&> {
55 return s;
56 }
57
60 template<typename T>
61 auto operator>>(serializer& s, T& /* t */) ->
62 typename std::enable_if_t<std::is_empty_v<T>, serializer&> {
63 return s;
64 }
65
72 template<typename T>
73 auto operator<<(serializer& s, T t) ->
74 typename std::enable_if_t<std::is_integral_v<T> && !std::is_enum_v<T>,
75 serializer&> {
76 s.write(&t, sizeof(t));
77 return s;
78 }
79
85 template<typename T>
86 auto operator>>(serializer& s, T& t) ->
87 typename std::enable_if_t<std::is_integral_v<T> && !std::is_enum_v<T>,
88 serializer&> {
89 s.read(&t, sizeof(t));
90 return s;
91 }
92
101 template<typename T, size_t len>
102 auto operator<<(serializer& packet, const std::array<T, len>& arr) ->
103 typename std::enable_if_t<std::is_integral_v<T>, serializer&> {
104 packet.write(arr.data(), sizeof(T) * len);
105 return packet;
106 }
107
110 template<typename T, size_t len>
111 auto operator>>(serializer& packet, std::array<T, len>& arr) ->
112 typename std::enable_if_t<std::is_integral_v<T>, serializer&> {
113 packet.read(arr.data(), sizeof(T) * len);
114 return packet;
115 }
116
119 template<typename T>
120 auto operator>>(serializer& deser, std::optional<T>& val) -> serializer& {
121 bool has_value{};
122 if(!(deser >> has_value)) {
123 return deser;
124 }
125
126 if(has_value) {
127 auto opt_val = T();
128 if(!(deser >> opt_val)) {
129 return deser;
130 }
131 val = std::move(opt_val);
132 } else {
133 val = std::nullopt;
134 }
135
136 return deser;
137 }
138
143 template<typename T>
144 auto operator<<(serializer& ser, const std::optional<T>& val)
145 -> serializer& {
146 auto has_value = val.has_value();
147 ser << has_value;
148 if(has_value) {
149 ser << *val;
150 }
151 return ser;
152 }
153
157 template<typename A, typename B>
158 auto operator<<(serializer& ser, const std::pair<A, B>& p) -> serializer& {
159 ser << p.first << p.second;
160 return ser;
161 }
162
165 template<typename A, typename B>
166 auto operator>>(serializer& deser, std::pair<A, B>& p) -> serializer& {
167 auto a = A();
168 if(!(deser >> a)) {
169 return deser;
170 }
171
172 auto b = B();
173 if(!(deser >> b)) {
174 return deser;
175 }
176
177 p = {std::move(a), std::move(b)};
178 return deser;
179 }
180
185 template<typename T>
186 auto operator<<(serializer& packet, const std::vector<T>& vec)
187 -> serializer& {
188 const auto len = static_cast<uint64_t>(vec.size());
189 packet << len;
190 for(uint64_t i = 0; i < len; i++) {
191 packet << static_cast<T>(vec[i]);
192 }
193 return packet;
194 }
195
198 template<typename T>
199 auto operator>>(serializer& packet, std::vector<T>& vec) -> serializer& {
200 static_assert(sizeof(T) <= config::maximum_reservation,
201 "Vector element size too large");
202
203 uint64_t len{};
204 if(!(packet >> len)) {
205 return packet;
206 }
207
208 uint64_t allocated = 0;
209 while(allocated < len) {
210 allocated = std::min(
211 len,
212 allocated + config::maximum_reservation / sizeof(T));
213 vec.reserve(allocated);
214 while(vec.size() < allocated) {
215 if constexpr(std::is_default_constructible_v<T>) {
216 T val{};
217 if(!(packet >> val)) {
218 return packet;
219 }
220 vec.push_back(std::move(val));
221 } else {
222 auto val = T(packet);
223 if(!packet) {
224 return packet;
225 }
226 vec.push_back(std::move(val));
227 }
228 }
229 }
230
231 vec.shrink_to_fit();
232 return packet;
233 }
234
238 template<typename K, typename V, typename... Ts>
240 const std::unordered_map<K, V, Ts...>& map)
241 -> serializer& {
242 auto len = static_cast<uint64_t>(map.size());
243 ser << len;
244 for(const auto& it : map) {
245 ser << static_cast<K>(it.first);
246 ser << static_cast<V>(it.second);
247 }
248 return ser;
249 }
250
253 template<typename K, typename V, typename... Ts>
254 auto operator>>(serializer& deser, std::unordered_map<K, V, Ts...>& map)
255 -> serializer& {
256 static_assert(sizeof(K) + sizeof(V) <= config::maximum_reservation,
257 "Unordered Map element size too large");
258 auto len = uint64_t();
259 if(!(deser >> len)) {
260 return deser;
261 }
262
263 uint64_t allocated = 0;
264 while(allocated < len) {
265 allocated = std::min(len,
266 allocated
267 + config::maximum_reservation
268 / (sizeof(K) + sizeof(V)));
269 map.reserve(allocated);
270 while(map.size() < allocated) {
271 auto key = K();
272 if(!(deser >> key)) {
273 return deser;
274 }
275
276 auto val = V();
277 if(!(deser >> val)) {
278 return deser;
279 }
280
281 map.emplace(std::move(key), std::move(val));
282 }
283 }
284 return deser;
285 }
286
289 template<typename K, typename... Ts>
290 auto operator<<(serializer& ser, const std::set<K, Ts...>& set)
291 -> serializer& {
292 auto len = static_cast<uint64_t>(set.size());
293 ser << len;
294 for(const auto& key : set) {
295 ser << static_cast<K>(key);
296 }
297 return ser;
298 }
299
302 template<typename K, typename... Ts>
303 auto operator>>(serializer& deser, std::set<K, Ts...>& set)
304 -> serializer& {
305 auto len = uint64_t();
306 if(!(deser >> len)) {
307 return deser;
308 }
309
310 for(uint64_t i = 0; i < len; i++) {
311 auto key = K();
312 if(!(deser >> key)) {
313 return deser;
314 }
315 set.emplace(std::move(key));
316 }
317 return deser;
318 }
319
322 template<typename K, typename... Ts>
323 auto operator<<(serializer& ser, const std::unordered_set<K, Ts...>& set)
324 -> serializer& {
325 auto len = static_cast<uint64_t>(set.size());
326 ser << len;
327 for(const auto& key : set) {
328 ser << static_cast<K>(key);
329 }
330 return ser;
331 }
332
335 template<typename K, typename... Ts>
336 auto operator>>(serializer& deser, std::unordered_set<K, Ts...>& set)
337 -> serializer& {
338 static_assert(sizeof(K) <= config::maximum_reservation,
339 "Unordered Set element size too large");
340 auto len = uint64_t();
341 if(!(deser >> len)) {
342 return deser;
343 }
344
345 uint64_t allocated = 0;
346 while(allocated < len) {
347 allocated = std::min(
348 len,
349 allocated + config::maximum_reservation / sizeof(K));
350 while(set.size() < allocated) {
351 auto key = K();
352 if(!(deser >> key)) {
353 return deser;
354 }
355 set.emplace(std::move(key));
356 }
357 }
358 return deser;
359 }
360
363 template<typename... Ts>
364 auto operator<<(serializer& ser, const std::variant<Ts...>& var)
365 -> serializer& {
366 using S = uint8_t;
367 static_assert(
368 std::variant_size_v<std::remove_reference_t<decltype(var)>> < std::
369 numeric_limits<S>::max());
370 auto idx = static_cast<S>(var.index());
371 ser << idx;
372 std::visit(
373 [&](auto&& arg) {
374 ser << arg;
375 },
376 var);
377 return ser;
378 }
379
382 template<typename... Ts>
383 auto operator>>(serializer& deser, std::variant<Ts...>& var)
384 -> std::enable_if_t<(std::is_default_constructible_v<Ts> && ...),
385 serializer&> {
386 using S = uint8_t;
387 static_assert(
388 std::variant_size_v<std::remove_reference_t<decltype(var)>> < std::
389 numeric_limits<S>::max());
390 S idx{};
391 deser >> idx;
392 auto var_idx = static_cast<size_t>(idx);
393 var = expand_type<Ts...>(var_idx);
394 std::visit(
395 [&](auto&& arg) {
396 deser >> arg;
397 },
398 var);
399 return deser;
400 }
401
408 template<typename... Ts>
409 [[nodiscard]] auto get_variant(serializer& deser) -> std::variant<Ts...> {
410 using T = typename std::variant<Ts...>;
411 using S = uint8_t;
412 static_assert(std::variant_size_v<T> < std::numeric_limits<S>::max());
413 // Since if the variant holds only default constructiable types
414 // we will be only able to unpack it using >>
415 // thus we can't extract the index value from the deser
416 if constexpr((std::is_default_constructible_v<Ts> && ...)) {
417 T variants;
418 deser >> variants;
419 return variants;
420 } else {
421 S idx{};
422 deser >> idx;
423 auto i = static_cast<size_t>(idx);
424 assert(i < std::variant_size_v<T>);
425 static constexpr auto t = std::array{+[](serializer& d) {
426 return T{std::in_place_type<Ts>, d};
427 }...};
428 // TODO: deserialization error handling for variant indexes.
429 return t.at(i)(deser);
430 }
431 }
432
433 // TODO: use std::is_scoped_enum_v and std::to_underlying once C++23 is
434 // available.
436 template<typename T>
437 auto operator<<(serializer& ser, T e) ->
438 typename std::enable_if_t<std::is_enum_v<T>, serializer&> {
439 return ser << static_cast<std::underlying_type_t<T>>(e);
440 }
441
443 template<typename T>
444 auto operator>>(serializer& deser, T& e) ->
445 typename std::enable_if_t<std::is_enum_v<T>, serializer&> {
446 std::underlying_type_t<T> val{};
447 if(deser >> val) {
448 e = static_cast<T>(val);
449 }
450 return deser;
451 }
452}
453
454#endif // OPENCBDC_TX_SRC_SERIALIZATION_FORMAT_H_
Interface for serializing objects into and out of raw bytes representations.
Tools for reading options from a configuration file and building application-specific parameter sets ...
auto get_variant(serializer &deser) -> std::variant< Ts... >
Deserializes a variant where the alternatives are all default constructible or all are not default co...
auto operator>>(serializer &deser, parsec::agent::rpc::request &req) -> serializer &
@ buffer
A singular RLP value (byte array)
auto expand_type(size_t i) -> std::variant< Ts... >
Default-constructs a std::variant from a template parameter pack.
auto operator<<(serializer &ser, const parsec::agent::rpc::request &req) -> serializer &