Bond
 
All Classes Namespaces Files Functions Variables Typedefs Friends Pages
Loading...
Searching...
No Matches
fast_binary.h
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#pragma once
5
6#include <bond/core/config.h>
7
8#include "encoding.h"
9
10#include <bond/core/bond_version.h>
11#include <bond/core/detail/checked.h>
12#include <bond/core/detail/recursionguard.h>
13
14#include <boost/call_traits.hpp>
15#include <boost/noncopyable.hpp>
16
17/*
18 .----------.--------------. .----------.---------.
19 struct hierarchy | struct | BT_STOP_BASE |...| struct | BT_STOP |
20 '----------'--------------' '----------'---------'
21
22 .----------.----------. .----------.
23 struct | field | field |...| field |
24 '----------'----------' '----------'
25
26 .------.----.----------.
27 field | type | id | value |
28 '------'----'----------'
29
30 .---.---.---.---.---.---.---.---. i - id bits
31 type | 0 | 0 | 0 | t | t | t | t | t | t - type bits
32 '---'---'---'---'---'---'---'---' v - value bits
33 4 0
34
35 id .---. .---.---. .---.
36 | i |...| i | i |...| i |
37 '---' '---'---' '---'
38 7 0 15 8
39
40 .---.---.---.---.---.---.---.---.
41 value bool | | | | | | | | v |
42 '---'---'---'---'---'---'---'---'
43 0
44
45 integer, little endian
46 float, double
47
48
49 .-------.------------.
50 string, wstring | count | characters |
51 '-------'------------'
52
53 count variable encoded uint32 count of 1-byte (for
54 string) or 2-byte (for wstring) Unicode code
55 units
56
57 characters 1-byte UTF-8 code units (for string) or 2-byte
58 UTF-16LE code units (for wstring)
59
60
61 .-------.-------.-------.
62 blob, list, set, | type | count | items |
63 vector, nullable '-------'-------'-------'
64
65 .---.---.---.---.---.---.---.---.
66 type | | | | t | t | t | t | t |
67 '---'---'---'---'---'---'---'---'
68 4 0
69
70 count variable uint32 count of items
71
72 items each item encoded according to its type
73
74
75 .----------.------------.-------.-----.-------.
76 map | key type | value type | count | key | value |
77 '----------'------------'-------'-----'-------'
78
79 .---.---.---.---.---.---.---.---.
80 key type, | | | | t | t | t | t | t |
81 value type '---'---'---'---'---'---'---'---'
82 4 0
83
84 count variable encoded uint32 count of {key,mapped} pairs
85
86 key, mapped each item encoded according to its type
87
88
89 variable uint32
90 .---.---. .---..---.---. .---..---.---. .---..---.---. .---..---.---.---.---. .---.
91 | 1 | v |...| v || 1 | v |...| v || 1 | v |...| v || 1 | v |...| v || 0 | 0 | 0 | v |...| v |
92 '---'---' '---''---'---' '---''---'---' '---''---'---' '---''---'---'---'---' '---'
93 6 0 13 7 20 14 27 21 31 28
94
95 1 to 5 bytes, high bit of every byte indicates if there is another byte
96
97*/
98
99namespace bond
100{
101
102template <typename BufferT>
103class FastBinaryWriter;
104
106template <typename BufferT>
108{
109public:
110 typedef BufferT Buffer;
111 typedef DynamicParser<FastBinaryReader&> Parser;
112 typedef FastBinaryWriter<Buffer> Writer;
113
114 BOND_STATIC_CONSTEXPR uint16_t magic = FAST_PROTOCOL;
115 BOND_STATIC_CONSTEXPR uint16_t version = v1;
116
118 FastBinaryReader(typename boost::call_traits<Buffer>::param_type buffer)
119 : _input(buffer)
120 {}
121
122
123 // This identical to compiler generated ctor except for noexcept declaration.
124 // Copy ctor that is explicitly declared throw() is needed for boost::variant
125 // to use optimized code path.
127 FastBinaryReader(const FastBinaryReader& that) BOND_NOEXCEPT
128 : _input(that._input)
129 {}
130
131
133 bool operator==(const FastBinaryReader& rhs) const
134 {
135 return _input == rhs._input;
136 }
137
138
140 typename boost::call_traits<Buffer>::const_reference
141 GetBuffer() const
142 {
143 return _input;
144 }
145
146
148 typename boost::call_traits<Buffer>::reference
150 {
151 return _input;
152 }
153
154
155 bool ReadVersion()
156 {
157 uint16_t magic_value, version_value;
158
159 _input.Read(magic_value);
160 _input.Read(version_value);
161
162 return magic_value == FastBinaryReader::magic
163 && version_value <= FastBinaryReader::version;
164 }
165
166
167 // Read for primitive types
168 template <typename T>
169 typename boost::disable_if<is_string_type<T> >::type
170 Read(T& value)
171 {
172 _input.Read(value);
173 }
174
175
176 // Read for strings
177 template <typename T>
178 typename boost::enable_if<is_string_type<T> >::type
179 Read(T& value)
180 {
181 uint32_t length = 0;
182
183 ReadVariableUnsigned(_input, length);
184
185 constexpr uint8_t charSize = static_cast<uint8_t>(sizeof(typename detail::string_char_int_type<T>::type));
186 uint32_t numStringBytes = detail::checked_multiply(length, charSize);
187 if (!_input.CanRead(numStringBytes))
188 OutOfBoundStringSizeException();
189
190 detail::ReadStringData(_input, value, length);
191 }
192
193
194 // Read for blob
195 void Read(blob& value, uint32_t size)
196 {
197 _input.Read(value, size);
198 }
199
200 // Does the reader have enough input buffer left to read an array of T?
201 template<typename T>
202 bool CanReadArray(uint32_t num_elems)
203 {
204#ifdef _MSC_VER
205#pragma warning(push)
206#pragma warning(disable:4127)
207#endif
208
209 BOND_IF_CONSTEXPR(is_string_type<T>::value)
210 {
211 return _input.CanRead(num_elems);
212 }
213 else
214 {
215 // We will need to read num_elems instances of T. This will not overflow because
216 // num_elems < 2^32 and we call this only for primitive types, so sizeof(T) <= 8.
217 uint64_t num_bytes = static_cast<uint64_t>(num_elems) * sizeof(T);
218 return (num_bytes >> 32 == 0) && _input.CanRead(num_bytes & 0xffffffff);
219 }
220
221#ifdef _MSC_VER
222#pragma warning(pop)
223#endif
224 }
225
226 void ReadStructBegin()
227 {}
228
229
230 void ReadStructEnd()
231 {}
232
233
234 void ReadFieldBegin(BondDataType& type, uint16_t& id)
235 {
236 ReadType(type);
237
238 if (type != BT_STOP && type != BT_STOP_BASE)
239 Read(id);
240 else
241 id = 0;
242 }
243
244
245 void ReadFieldEnd()
246 {}
247
248
249 void ReadContainerBegin(uint32_t& size, BondDataType& type)
250 {
251 ReadType(type);
252 ReadVariableUnsigned(_input, size);
253 }
254
255
256 // container of 2-tuple (e.g. map)
257 void ReadContainerBegin(uint32_t& size, std::pair<BondDataType, BondDataType>& type)
258 {
259 ReadType(type.first);
260 ReadType(type.second);
261 ReadVariableUnsigned(_input, size);
262 }
263
264
265 void ReadContainerEnd()
266 {}
267
268
269 template <typename T>
270 void Skip()
271 {
272 SkipType<get_type_id<T>::value>();
273 }
274
275
276 template <typename T>
277 void Skip(const bonded<T, FastBinaryReader&>&)
278 {
279 SkipType<BT_STRUCT>();
280 }
281
282 void Skip(BondDataType type)
283 {
284 SkipType(type);
285 }
286
287protected:
288 void ReadType(BondDataType& type)
289 {
290 uint8_t byte;
291
292 Read(byte);
293 type = static_cast<BondDataType>(byte);
294 }
295
296 using BT = BondDataType;
297
298 template <BT T>
299 typename boost::enable_if_c<(T == BT_BOOL || T == BT_UINT8 || T == BT_INT8)>::type
300 SkipType(uint32_t size = 1)
301 {
302 _input.Skip(detail::checked_multiply(size, sizeof(uint8_t)));
303 }
304
305 template <BT T>
306 typename boost::enable_if_c<(T == BT_UINT16 || T == BT_INT16)>::type
307 SkipType(uint32_t size = 1)
308 {
309 _input.Skip(detail::checked_multiply(size, sizeof(uint16_t)));
310 }
311
312 template <BT T>
313 typename boost::enable_if_c<(T == BT_UINT32 || T == BT_INT32)>::type
314 SkipType(uint32_t size = 1)
315 {
316 _input.Skip(detail::checked_multiply(size, sizeof(uint32_t)));
317 }
318
319 template <BT T>
320 typename boost::enable_if_c<(T == BT_UINT64 || T == BT_INT64)>::type
321 SkipType(uint32_t size = 1)
322 {
323 _input.Skip(detail::checked_multiply(size, sizeof(uint64_t)));
324 }
325
326 template <BT T>
327 typename boost::enable_if_c<(T == BT_FLOAT)>::type
328 SkipType(uint32_t size = 1)
329 {
330 _input.Skip(detail::checked_multiply(size, sizeof(float)));
331 }
332
333 template <BT T>
334 typename boost::enable_if_c<(T == BT_DOUBLE)>::type
335 SkipType(uint32_t size = 1)
336 {
337 _input.Skip(detail::checked_multiply(size, sizeof(double)));
338 }
339
340 template <BT T>
341 typename boost::enable_if_c<(T == BT_STRING)>::type
342 SkipType()
343 {
344 uint32_t size = 0;
345
346 ReadVariableUnsigned(_input, size);
347 _input.Skip(size);
348 }
349
350 template <BT T>
351 typename boost::enable_if_c<(T == BT_WSTRING)>::type
352 SkipType()
353 {
354 uint32_t size = 0;
355
356 ReadVariableUnsigned(_input, size);
357 _input.Skip(detail::checked_multiply(size, sizeof(uint16_t)));
358 }
359
360 template <BT T>
361 typename boost::enable_if_c<(T == BT_STRUCT)>::type
362 SkipType()
363 {
364 bond::detail::RecursionGuard guard;
365
366 for (;;)
367 {
368 ReadStructBegin();
369
370 uint16_t id;
371 BondDataType field_type;
372
373 for (ReadFieldBegin(field_type, id);
374 field_type != BT_STOP && field_type != BT_STOP_BASE;
375 ReadFieldEnd(), ReadFieldBegin(field_type, id))
376 {
377 SkipType(field_type);
378 }
379
380 ReadStructEnd();
381
382 if (field_type == BT_STOP)
383 break;
384 }
385 }
386
387 template <BT T>
388 typename boost::enable_if_c<(T == BT_SET || T == BT_LIST)>::type
389 SkipType()
390 {
391 BondDataType element_type;
392 uint32_t size;
393
394 bond::detail::RecursionGuard guard;
395
396 ReadContainerBegin(size, element_type);
397 SkipType(element_type, size);
398 ReadContainerEnd();
399 }
400
401 template <BT T>
402 typename boost::enable_if_c<(T == BT_MAP)>::type
403 SkipType()
404 {
405 std::pair<BondDataType, BondDataType> element_type;
406 uint32_t size;
407
408 bond::detail::RecursionGuard guard;
409
410 ReadContainerBegin(size, element_type);
411 for (int64_t i = 0; i < size; ++i)
412 {
413 SkipType(element_type.first);
414 SkipType(element_type.second);
415 }
416 ReadContainerEnd();
417 }
418
419 template <BT T>
420 typename boost::enable_if_c<(T == BT_STRING || T == BT_WSTRING || T == BT_STRUCT
421 || T == BT_SET || T == BT_LIST || T == BT_MAP)>::type
422 SkipType(uint32_t size)
423 {
424 for (int64_t i = 0; i < size; ++i)
425 {
426 SkipType<T>();
427 }
428 }
429
430 template <typename... Args>
431 void SkipType(BondDataType type, Args&&... args)
432 {
433 switch (type)
434 {
435 case BT_BOOL:
436 case BT_UINT8:
437 case BT_INT8:
438 SkipType<BT_BOOL>(std::forward<Args>(args)...);
439 break;
440
441 case BT_UINT16:
442 case BT_INT16:
443 SkipType<BT_UINT16>(std::forward<Args>(args)...);
444 break;
445
446 case BT_UINT32:
447 case BT_INT32:
448 SkipType<BT_UINT32>(std::forward<Args>(args)...);
449 break;
450
451 case BT_UINT64:
452 case BT_INT64:
453 SkipType<BT_UINT64>(std::forward<Args>(args)...);
454 break;
455
456 case BT_FLOAT:
457 SkipType<BT_FLOAT>(std::forward<Args>(args)...);
458 break;
459
460 case BT_DOUBLE:
461 SkipType<BT_DOUBLE>(std::forward<Args>(args)...);
462 break;
463
464 case BT_STRING:
465 SkipType<BT_STRING>(std::forward<Args>(args)...);
466 break;
467
468 case BT_WSTRING:
469 SkipType<BT_WSTRING>(std::forward<Args>(args)...);
470 break;
471
472 case BT_SET:
473 case BT_LIST:
474 SkipType<BT_SET>(std::forward<Args>(args)...);
475 break;
476
477 case BT_MAP:
478 SkipType<BT_MAP>(std::forward<Args>(args)...);
479 break;
480
481 case BT_STRUCT:
482 SkipType<BT_STRUCT>(std::forward<Args>(args)...);
483 break;
484
485 default:
486 bond::UnknownDataTypeException();
487 break;
488 }
489 }
490
491 Buffer _input;
492};
493
494template <typename Buffer>
495BOND_CONSTEXPR_OR_CONST uint16_t FastBinaryReader<Buffer>::magic;
496
497template <typename Buffer>
498BOND_CONSTEXPR_OR_CONST uint16_t FastBinaryReader<Buffer>::version;
499
500
502template <typename BufferT>
504 : boost::noncopyable
505{
506public:
507 typedef BufferT Buffer;
508 typedef FastBinaryReader<Buffer> Reader;
509
511 FastBinaryWriter(Buffer& buffer)
512 : _output(buffer)
513 {
514 }
515
517 typename boost::call_traits<Buffer>::reference
519 {
520 return _output;
521 }
522
523 void WriteVersion()
524 {
525 _output.Write(Reader::magic);
526 _output.Write(Reader::version);
527 }
528
529 //
530 // Write methods
531 //
532 void WriteStructBegin(const Metadata& /*metadata*/, bool /*base*/)
533 {}
534
535 void WriteStructEnd(bool base = false)
536 {
537 WriteType(base ? BT_STOP_BASE : BT_STOP);
538 }
539
540 template <typename T>
541 void WriteField(uint16_t id, const bond::Metadata& /*metadata*/, const T& value)
542 {
543 WriteFieldBegin(get_type_id<T>::value, id);
544 Write(value);
545 WriteFieldEnd();
546 }
547
548 void WriteFieldBegin(BondDataType type, uint16_t id, const bond::Metadata& /*metadata*/)
549 {
550 WriteFieldBegin(type, id);
551 }
552
553 void WriteFieldBegin(BondDataType type, uint16_t id)
554 {
555 WriteType(type);
556 Write(id);
557 }
558
559 void WriteFieldEnd()
560 {}
561
562 void WriteContainerBegin(uint32_t size, BondDataType type)
563 {
564 WriteType(type);
565 WriteVariableUnsigned(_output, size);
566 }
567
568 // container of 2-tuples (e.g. map)
569 void WriteContainerBegin(uint32_t size, std::pair<BondDataType, BondDataType> type)
570 {
571 WriteType(type.first);
572 WriteType(type.second);
573 WriteVariableUnsigned(_output, size);
574 }
575
576 void WriteContainerEnd()
577 {}
578
579 // Write for primitive types
580 template<typename T>
581 typename boost::disable_if<is_string_type<T> >::type
582 Write(const T& value)
583 {
584 _output.Write(value);
585 }
586
587 // Write for strings
588 template <typename T>
589 typename boost::enable_if<is_string_type<T> >::type
590 Write(const T& value)
591 {
592 uint32_t length = string_length(value);
593
594 WriteVariableUnsigned(_output, length);
595 detail::WriteStringData(_output, value, length);
596 }
597
598 // Write for blob
599 void Write(const blob& value)
600 {
601 _output.Write(value);
602 }
603
604protected:
605 void WriteType(BondDataType type)
606 {
607 _output.Write(static_cast<uint8_t>(type));
608 }
609
610 Buffer& _output;
611};
612
613
614}; // namespace bond
Reader for Fast Binary protocol.
Definition fast_binary.h:108
bool operator==(const FastBinaryReader &rhs) const
Comparison operator.
Definition fast_binary.h:133
boost::call_traits< Buffer >::const_reference GetBuffer() const
Access to underlying buffer.
Definition fast_binary.h:141
FastBinaryReader(const FastBinaryReader &that) BOND_NOEXCEPT
Copy constructor.
Definition fast_binary.h:127
FastBinaryReader(typename boost::call_traits< Buffer >::param_type buffer)
Construct from input buffer/stream containing serialized data.
Definition fast_binary.h:118
boost::call_traits< Buffer >::reference GetBuffer()
Access to underlying buffer.
Definition fast_binary.h:149
Writer for Fast Binary protocol.
Definition fast_binary.h:505
boost::call_traits< Buffer >::reference GetBuffer()
Access to underlying buffer.
Definition fast_binary.h:518
FastBinaryWriter(Buffer &buffer)
Construct from output buffer/stream.
Definition fast_binary.h:511
namespace bond
Definition apply.h:17