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