HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
BON8.hpp
1// Copyright Take Vos 2020-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "../container/container.hpp"
8#include "../utility/utility.hpp"
9#include "datum.hpp"
10#include "../macros.hpp"
11#include <cstddef>
12#include <string>
13
14hi_export_module(hikogui.codec.BON8);
15
16hi_warning_push();
17// C26429: Symbol '' is never tested for nullness, it can be marked as not_null (f.23)
18// False positive reported: https://developercommunity.visualstudio.com/t/C26429-false-positive-on-reference-to-po/10262151
19hi_warning_ignore_msvc(26429);
20
21hi_export namespace hi::inline v1 {
22namespace detail {
23constexpr auto BON8_code_array_count0 = uint8_t{0x80};
24constexpr auto BON8_code_array_count1 = uint8_t{0x81};
25constexpr auto BON8_code_array_count2 = uint8_t{0x82};
26constexpr auto BON8_code_array_count3 = uint8_t{0x83};
27constexpr auto BON8_code_array_count4 = uint8_t{0x84};
28constexpr auto BON8_code_array = uint8_t{0x85};
29constexpr auto BON8_code_object_count0 = uint8_t{0x86};
30constexpr auto BON8_code_object_count1 = uint8_t{0x87};
31constexpr auto BON8_code_object_count2 = uint8_t{0x88};
32constexpr auto BON8_code_object_count3 = uint8_t{0x89};
33constexpr auto BON8_code_object_count4 = uint8_t{0x8a};
34constexpr auto BON8_code_object = uint8_t{0x8b};
35constexpr auto BON8_code_int32 = uint8_t{0x8c};
36constexpr auto BON8_code_int64 = uint8_t{0x8d};
37constexpr auto BON8_code_binary32 = uint8_t{0x8e};
38constexpr auto BON8_code_binary64 = uint8_t{0x8f};
39constexpr auto BON8_code_positive_s = uint8_t{0x90};
40constexpr auto BON8_code_positive_e = uint8_t{0xb7};
41constexpr auto BON8_code_negative_s = uint8_t{0xb8};
42constexpr auto BON8_code_negative_e = uint8_t{0xc1};
43
44// The last 8 code-units after the extended characters.
45constexpr auto BON8_code_bool_false = uint8_t{0xf8};
46constexpr auto BON8_code_bool_true = uint8_t{0xf9};
47constexpr auto BON8_code_null = uint8_t{0xfa};
48constexpr auto BON8_code_float_min_one = uint8_t{0xfb};
49constexpr auto BON8_code_float_zero = uint8_t{0xfc};
50constexpr auto BON8_code_float_one = uint8_t{0xfd};
51constexpr auto BON8_code_eoc = uint8_t{0xfe};
52constexpr auto BON8_code_eot = uint8_t{0xff};
53
60[[nodiscard]] datum decode_BON8(cbyteptr& ptr, cbyteptr last);
61
62[[nodiscard]] bstring encode_BON8(datum const& value);
63
67 bool open_string;
68 bstring output;
69
70public:
71 BON8_encoder() noexcept : open_string(false), output() {}
72
75 bstring const& get() noexcept
76 {
77 if (open_string) {
78 output += static_cast<std::byte>(BON8_code_eot);
79 open_string = false;
80 }
81 return output;
82 }
83
87 void add(signed long long value) noexcept
88 {
89 open_string = false;
90
92 output += static_cast<std::byte>(BON8_code_int64);
93 for (int i = 0; i != 8; ++i) {
94 output += static_cast<std::byte>(value >> (56 - i * 8));
95 }
96
97 } else if (value <= -33818507) {
98 output += static_cast<std::byte>(BON8_code_int32);
99 for (int i = 0; i != 4; ++i) {
100 output += static_cast<std::byte>(value >> (24 - i * 8));
101 }
102
103 } else if (value <= -264075) {
104 value = -(value + 264075);
105 output += static_cast<std::byte>(0xf0 + (value >> 22 & 0x07));
106 output += static_cast<std::byte>(0xc0 + (value >> 16 & 0x3f));
107 output += static_cast<std::byte>(value >> 8);
108 output += static_cast<std::byte>(value);
109
110 } else if (value <= -1931) {
111 value = -(value + 1931);
112 output += static_cast<std::byte>(0xe0 + (value >> 14 & 0x0f));
113 output += static_cast<std::byte>(0xc0 + (value >> 8 & 0x3f));
114 output += static_cast<std::byte>(value);
115
116 } else if (value <= -11) {
117 value = -(value + 11);
118 output += static_cast<std::byte>(0xc2 + (value >> 6 & 0x1f));
119 output += static_cast<std::byte>(0xc0 + (value & 0x3f));
120
121 } else if (value <= -1) {
122 value = -(value + 1);
123 output += static_cast<std::byte>(BON8_code_negative_s + value);
124
125 } else if (value <= 39) {
126 output += static_cast<std::byte>(BON8_code_positive_s + value);
127
128 } else if (value <= 3879) {
129 value -= 40;
130 output += static_cast<std::byte>(0xc2 + (value >> 7 & 0x1f));
131 output += static_cast<std::byte>(value & 0x7f);
132
133 } else if (value <= 528167) {
134 value -= 3880;
135 output += static_cast<std::byte>(0xe0 + (value >> 15 & 0x0f));
136 output += static_cast<std::byte>(value >> 8 & 0x7f);
137 output += static_cast<std::byte>(value);
138
139 } else if (value <= 67637031) {
140 value -= 528168;
141 output += static_cast<std::byte>(0xf0 + (value >> 23 & 0x17));
142 output += static_cast<std::byte>(value >> 16 & 0x7f);
143 output += static_cast<std::byte>(value >> 8);
144 output += static_cast<std::byte>(value);
145
146 } else if (value <= std::numeric_limits<int32_t>::max()) {
147 output += static_cast<std::byte>(BON8_code_int32);
148 for (int i = 0; i != 4; ++i) {
149 output += static_cast<std::byte>(value >> (24 - i * 8));
150 }
151
152 } else {
153 output += static_cast<std::byte>(BON8_code_int64);
154 for (int i = 0; i != 8; ++i) {
155 output += static_cast<std::byte>(value >> (56 - i * 8));
156 }
157 }
158 }
159
163 void add(unsigned long long value) noexcept
164 {
165 return add(narrow_cast<signed long long>(value));
166 }
167
171 void add(signed long value) noexcept
172 {
173 return add(narrow_cast<signed long long>(value));
174 }
175
179 void add(unsigned long value) noexcept
180 {
181 return add(narrow_cast<signed long long>(value));
182 }
183
187 void add(signed int value) noexcept
188 {
189 return add(narrow_cast<signed long long>(value));
190 }
191
195 void add(unsigned int value) noexcept
196 {
197 return add(narrow_cast<signed long long>(value));
198 }
199
203 void add(signed short value) noexcept
204 {
205 return add(narrow_cast<signed long long>(value));
206 }
207
211 void add(unsigned short value) noexcept
212 {
213 return add(narrow_cast<signed long long>(value));
214 }
215
219 void add(signed char value) noexcept
220 {
221 return add(narrow_cast<signed long long>(value));
222 }
223
227 void add(unsigned char value) noexcept
228 {
229 return add(narrow_cast<signed long long>(value));
230 }
231
235 void add(double value) noexcept
236 {
237 open_string = false;
238
239 auto const f32 = static_cast<float>(value);
240 auto const f32_64 = static_cast<double>(f32);
241
242 if (value == -1.0) {
243 output += static_cast<std::byte>(BON8_code_float_min_one);
244
245 } else if (value == 0.0 and not std::signbit(value)) {
246 output += static_cast<std::byte>(BON8_code_float_zero);
247
248 } else if (value == 1.0) {
249 output += static_cast<std::byte>(BON8_code_float_one);
250
251 } else if (f32_64 == value) {
252 // After conversion to 32-bit float, precession was not reduced.
253 uint32_t u32;
254 std::memcpy(&u32, &f32, sizeof(u32));
255
256 output += static_cast<std::byte>(BON8_code_binary32);
257 for (int i = 0; i != 4; ++i) {
258 output += static_cast<std::byte>(u32 >> (24 - i * 8));
259 }
260
261 } else {
262 uint64_t u64;
263 std::memcpy(&u64, &value, sizeof(u64));
264
265 output += static_cast<std::byte>(BON8_code_binary64);
266 for (int i = 0; i != 8; ++i) {
267 output += static_cast<std::byte>(u64 >> (56 - i * 8));
268 }
269 }
270 }
271
275 void add(float value) noexcept
276 {
277 return add(static_cast<double>(value));
278 }
279
283 void add(bool value) noexcept
284 {
285 open_string = false;
286 output += static_cast<std::byte>(value ? BON8_code_bool_true : BON8_code_bool_false);
287 }
288
292 void add(nullptr_t value) noexcept
293 {
294 open_string = false;
295 output += static_cast<std::byte>(BON8_code_null);
296 }
297
303 void add(std::string_view value) noexcept
304 {
305 if (open_string) {
306 output += static_cast<std::byte>(BON8_code_eot);
307 }
308
309 if (value.empty()) {
310 output += static_cast<std::byte>(BON8_code_eot);
311 open_string = false;
312
313 } else {
314 int multi_byte = 0;
315
316 for (auto const _c : value) {
317 auto const c = truncate<uint8_t>(_c);
318
319#ifndef NDEBUG
320 if (multi_byte == 0) {
321 if (c >= 0xc2 and c <= 0xdf) {
322 multi_byte = 1;
323 } else if (c >= 0xe0 and c <= 0xef) {
324 multi_byte = 2;
325 } else if (c >= 0xf0 and c <= 0xf7) {
326 multi_byte = 3;
327 } else {
328 hi_assert(c <= 0x7f);
329 }
330
331 } else {
332 hi_assert(c >= 0x80 and c <= 0xbf);
333 --multi_byte;
334 }
335#endif
336
337 output += static_cast<std::byte>(c);
338 }
339 hi_assert(multi_byte == 0);
340
341 open_string = true;
342 }
343 }
344
350 void add(std::string const& value) noexcept
351 {
352 add(std::string_view{value});
353 }
354
360 void add(char const *value) noexcept
361 {
362 add(std::string_view{value});
363 }
364
368 void add(datum const& value);
369
374 template<typename T>
375 void add(std::vector<T> const& items)
376 {
377 open_string = false;
378 if (size(items) <= 4) {
379 output += static_cast<std::byte>(BON8_code_array_count0 + size(items));
380 } else {
381 output += static_cast<std::byte>(BON8_code_array);
382 }
383
384 for (auto const& item : items) {
385 add(item);
386 }
387
388 if (size(items) > 4) {
389 output += static_cast<std::byte>(BON8_code_eoc);
390 open_string = false;
391 }
392 }
393
399 template<typename Key, typename Value>
400 void add(std::map<Key, Value> const& items)
401 {
402 using key_type = typename std::remove_cvref_t<decltype(items)>::key_type;
403
404 open_string = false;
405 if (size(items) <= 4) {
406 output += static_cast<std::byte>(BON8_code_object_count0 + size(items));
407 } else {
408 output += static_cast<std::byte>(BON8_code_object);
409 }
410
411 for (auto const& item : items) {
412 if (auto *s = get_if<std::string>(item.first)) {
413 add(*s);
414 } else {
415 throw operation_error("BON8 object keys must be strings");
416 }
417 add(item.second);
418 }
419
420 if (size(items) > 4) {
421 output += static_cast<std::byte>(BON8_code_eoc);
422 open_string = false;
423 }
424 }
425};
426
427void inline BON8_encoder::add(datum const& value)
428{
429 if (auto s = get_if<std::string>(value)) {
430 add(*s);
431 } else if (auto b = get_if<bool>(value)) {
432 add(*b);
433 } else if (holds_alternative<nullptr_t>(value)) {
434 add(nullptr);
435 } else if (auto i = get_if<long long>(value)) {
436 add(*i);
437 } else if (auto f = get_if<double>(value)) {
438 add(*f);
439 } else if (auto v = get_if<datum::vector_type>(value)) {
440 add(*v);
441 } else if (auto m = get_if<datum::map_type>(value)) {
442 add(*m);
443 } else {
444 throw operation_error("Datum value can not be encoded to BON8");
445 }
446}
447
456[[nodiscard]] inline int BON8_multibyte_count(cbyteptr ptr, cbyteptr last)
457{
458 hi_assert_not_null(ptr);
459 hi_assert_not_null(last);
460
461 auto const c0 = static_cast<uint8_t>(*ptr);
462 auto const count = c0 <= 0xdf ? 2 : c0 <= 0xef ? 3 : 4;
463
464 hi_check(ptr + count <= last, "Incomplete Multi-byte character at end of buffer");
465
466 auto const c1 = static_cast<uint8_t>(*(ptr + 1));
467 return (c1 < 0x80 or c1 > 0xbf) ? -count : count;
468}
469
478[[nodiscard]] inline datum decode_BON8_int(cbyteptr& ptr, cbyteptr last, int count)
479{
480 hi_assert_not_null(ptr);
481 hi_assert_not_null(last);
482 hi_assert(count == 4 || count == 8);
483
484 auto u64 = uint64_t{0};
485 for (int i = 0; i != count; ++i) {
486 hi_check(ptr != last, "Incomplete signed integer at end of buffer");
487 u64 <<= 8;
488 u64 |= static_cast<uint64_t>(*(ptr++));
489 }
490
491 if (count == 4) {
492 auto const u32 = truncate<uint32_t>(u64);
493 auto const i32 = truncate<int32_t>(u32);
494 return datum{i32};
495 } else {
496 auto const i64 = truncate<int64_t>(u64);
497 return datum{i64};
498 }
499}
500
501[[nodiscard]] inline datum decode_BON8_float(cbyteptr& ptr, cbyteptr last, int count)
502{
503 hi_assert_not_null(ptr);
504 hi_assert_not_null(last);
505 hi_assert(count == 4 || count == 8);
506
507 auto u64 = uint64_t{0};
508 for (int i = 0; i != count; ++i) {
509 hi_check(ptr != last, "Incomplete signed integer at end of buffer");
510 u64 <<= 8;
511 u64 |= static_cast<uint64_t>(*(ptr++));
512 }
513
514 if (count == 4) {
515 auto const u32 = truncate<uint32_t>(u64);
516 float f32;
517 std::memcpy(&f32, &u32, sizeof(f32));
518 return datum{f32};
519
520 } else {
521 double f64;
522 std::memcpy(&f64, &u64, sizeof(f64));
523 return datum{f64};
524 }
525}
526
527[[nodiscard]] inline datum decode_BON8_array(cbyteptr& ptr, cbyteptr last)
528{
529 hi_assert_not_null(ptr);
530 hi_assert_not_null(last);
531
532 auto r = datum::make_vector();
533 auto& vector = get<datum::vector_type>(r);
534
535 while (ptr != last) {
536 if (*ptr == static_cast<std::byte>(BON8_code_eoc)) {
537 ++ptr;
538 return r;
539
540 } else {
541 vector.push_back(decode_BON8(ptr, last));
542 }
543 }
544 throw parse_error("Incomplete array at end of buffer");
545}
546
547[[nodiscard]] inline datum decode_BON8_array(cbyteptr& ptr, cbyteptr last, std::size_t count)
548{
549 auto r = datum::make_vector();
550 auto& vector = get<datum::vector_type>(r);
551
552 while (count--) {
553 vector.push_back(decode_BON8(ptr, last));
554 }
555 return r;
556}
557
558[[nodiscard]] inline datum decode_BON8_object(cbyteptr& ptr, cbyteptr last)
559{
560 hi_assert_not_null(ptr);
561 hi_assert_not_null(last);
562
563 auto r = datum::make_map();
564 auto& map = get<datum::map_type>(r);
565
566 while (ptr != last) {
567 if (*ptr == static_cast<std::byte>(BON8_code_eoc)) {
568 ++ptr;
569 return r;
570
571 } else {
572 auto key = decode_BON8(ptr, last);
573 hi_check(holds_alternative<std::string>(key), "Key in object is not a string");
574
575 auto value = decode_BON8(ptr, last);
576 map.emplace(std::move(key), std::move(value));
577 }
578 }
579 throw parse_error("Incomplete object at end of buffer");
580}
581
582[[nodiscard]] inline datum decode_BON8_object(cbyteptr& ptr, cbyteptr last, std::size_t count)
583{
584 auto r = datum::make_map();
585 auto& map = get<datum::map_type>(r);
586
587 while (count--) {
588 auto key = decode_BON8(ptr, last);
589 hi_check(holds_alternative<std::string>(key), "Key in object is not a string");
590
591 auto value = decode_BON8(ptr, last);
592 map.emplace(std::move(key), std::move(value));
593 }
594 return r;
595}
596
597[[nodiscard]] inline long long decode_BON8_UTF8_like_int(cbyteptr& ptr, cbyteptr last, int count) noexcept
598{
599 hi_assert_not_null(ptr);
600 hi_assert_not_null(last);
601 hi_assert(count >= 2 && count <= 4);
602 hi_assert(ptr != last);
603 auto const c0 = static_cast<uint8_t>(*(ptr++));
604
605 auto const mask = uint8_t{0b0111'1111} >> count;
606 auto value = static_cast<long long>(c0 & mask);
607 if (count == 2) {
608 // The two byte sequence starts with 0xc2, leaving only 30 entries in the first byte.
609 value -= 2;
610 }
611
612 // The second byte determines the sign, and adds 6 or 7 bits to the number.
613 hi_assert(ptr != last);
614 auto const c1 = static_cast<uint8_t>(*(ptr++));
615 auto const is_positive = c1 <= 0x7f;
616 if (is_positive) {
617 value <<= 7;
618 value |= static_cast<long long>(c1);
619 } else {
620 value <<= 6;
621 value |= static_cast<long long>(c1 & 0b0011'1111);
622 }
623
624 switch (count) {
625 case 4:
626 hi_assert(ptr != last);
627 value <<= 8;
628 value |= static_cast<int>(*(ptr++));
629 [[fallthrough]];
630 case 3:
631 hi_assert(ptr != last);
632 value <<= 8;
633 value |= static_cast<int>(*(ptr++));
634 [[fallthrough]];
635 default:;
636 }
637
638 if (is_positive) {
639 switch (count) {
640 case 2:
641 return value + 40;
642 case 3:
643 return value + 3880;
644 case 4:
645 return value + 528168;
646 default:
647 hi_no_default();
648 }
649
650 } else {
651 switch (count) {
652 case 2:
653 return -(value + 11);
654 case 3:
655 return -(value + 1931);
656 case 4:
657 return -(value + 264075);
658 default:
659 hi_no_default();
660 }
661 }
662}
663
664[[nodiscard]] inline datum decode_BON8(cbyteptr& ptr, cbyteptr last)
665{
666 hi_assert_not_null(ptr);
667 hi_assert_not_null(last);
668
669 std::string str;
670
671 while (ptr != last) {
672 auto const c = static_cast<uint8_t>(*ptr);
673
674 if (c == BON8_code_eot) {
675 // End of string found, return the current string.
676 ++ptr;
677 return datum{str};
678
679 } else if (c <= 0x7f) {
680 // ASCII character.
681 str += static_cast<char>(*(ptr++));
682 continue;
683
684 } else if (c >= 0xc2 && c <= 0xf7) {
685 auto const count = BON8_multibyte_count(ptr, last);
686 if (count > 0) {
687 // Multibyte UTF-8 code-point, The count includes the first code-unit.
688 for (int i = 0; i != count; ++i) {
689 str += static_cast<char>(*(ptr++));
690 }
691 continue;
692
693 } else if (not str.empty()) {
694 // Multibyte integer found, but first return the current string.
695 return datum{str};
696
697 } else {
698 // Multibyte integer, the first code-unit includes part of the integer.
699 return datum{decode_BON8_UTF8_like_int(ptr, last, -count)};
700 }
701
702 } else if (not str.empty()) {
703 // This must be a non-string type, but first return the current string.
704 return datum{str};
705
706 } else {
707 // This is one of the non-string types.
708 ++ptr;
709 switch (c) {
710 case BON8_code_null:
711 return datum{nullptr};
712 case BON8_code_bool_false:
713 return datum{false};
714 case BON8_code_bool_true:
715 return datum{true};
716 case BON8_code_float_min_one:
717 return datum{-1.0f};
718 case BON8_code_float_zero:
719 return datum{0.0f};
720 case BON8_code_float_one:
721 return datum{1.0f};
722 case BON8_code_int32:
723 return decode_BON8_int(ptr, last, 4);
724 case BON8_code_int64:
725 return decode_BON8_int(ptr, last, 8);
726 case BON8_code_binary32:
727 return decode_BON8_float(ptr, last, 4);
728 case BON8_code_binary64:
729 return decode_BON8_float(ptr, last, 8);
730 case BON8_code_array_count0:
731 return datum::make_vector();
732 case BON8_code_array_count1:
733 return decode_BON8_array(ptr, last, 1);
734 case BON8_code_array_count2:
735 return decode_BON8_array(ptr, last, 2);
736 case BON8_code_array_count3:
737 return decode_BON8_array(ptr, last, 3);
738 case BON8_code_array_count4:
739 return decode_BON8_array(ptr, last, 4);
740 case BON8_code_array:
741 return decode_BON8_array(ptr, last);
742 case BON8_code_object_count0:
743 return datum::make_map();
744 case BON8_code_object_count1:
745 return decode_BON8_object(ptr, last, 1);
746 case BON8_code_object_count2:
747 return decode_BON8_object(ptr, last, 2);
748 case BON8_code_object_count3:
749 return decode_BON8_object(ptr, last, 3);
750 case BON8_code_object_count4:
751 return decode_BON8_object(ptr, last, 4);
752 case BON8_code_object:
753 return decode_BON8_object(ptr, last);
754 case BON8_code_eoc:
755 throw parse_error("Unexpected end-of-container");
756 case BON8_code_eot:
757 throw parse_error("Unexpected end-of-text");
758 default:
759 // Everything below this, are non-string types.
760 if (c >= BON8_code_positive_s and c <= BON8_code_positive_e) {
761 return datum{c - BON8_code_positive_s};
762
763 } else if (c >= BON8_code_negative_s and c <= BON8_code_negative_e) {
764 return datum{~truncate<int>(c - BON8_code_negative_s)};
765
766 } else {
767 hi_no_default();
768 }
769 }
770 }
771 }
772 throw parse_error("Unexpected end-of-buffer");
773}
774
775} // namespace detail
776
781hi_export [[nodiscard]] inline datum decode_BON8(std::span<const std::byte> buffer)
782{
783 auto *ptr = buffer.data();
784 auto *last = ptr + buffer.size();
785 return detail::decode_BON8(ptr, last);
786}
787
792hi_export [[nodiscard]] inline datum decode_BON8(bstring const& buffer)
793{
794 auto *ptr = buffer.data();
795 auto *last = ptr + buffer.size();
796 return detail::decode_BON8(ptr, last);
797}
798
803hi_export [[nodiscard]] inline datum decode_BON8(bstring_view buffer)
804{
805 auto *ptr = buffer.data();
806 auto *last = ptr + buffer.size();
807 return detail::decode_BON8(ptr, last);
808}
809
814hi_export [[nodiscard]] inline bstring encode_BON8(datum const& value)
815{
816 auto encoder = detail::BON8_encoder{};
817 encoder.add(value);
818 return encoder.get();
819}
820
821} // namespace hi::inline v1
822
823hi_warning_pop();
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
BON8 encoder.
Definition BON8.hpp:66
void add(std::string const &value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:350
void add(double value) noexcept
Add a floating point number.
Definition BON8.hpp:235
void add(float value) noexcept
Add a floating point number.
Definition BON8.hpp:275
void add(unsigned long long value) noexcept
And a unsigned integer.
Definition BON8.hpp:163
void add(nullptr_t value) noexcept
Add a null.
Definition BON8.hpp:292
void add(bool value) noexcept
Add a boolean.
Definition BON8.hpp:283
void add(signed long value) noexcept
And a signed integer.
Definition BON8.hpp:171
void add(signed int value) noexcept
And a signed integer.
Definition BON8.hpp:187
void add(signed short value) noexcept
And a signed integer.
Definition BON8.hpp:203
void add(std::vector< T > const &items)
Add a vector of values of the same type.
Definition BON8.hpp:375
void add(unsigned int value) noexcept
And a unsigned integer.
Definition BON8.hpp:195
void add(unsigned long value) noexcept
And a unsigned integer.
Definition BON8.hpp:179
void add(char const *value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:360
void add(signed char value) noexcept
And a signed integer.
Definition BON8.hpp:219
void add(signed long long value) noexcept
And a signed integer.
Definition BON8.hpp:87
bstring const & get() noexcept
Return a byte_string of the encoded object.
Definition BON8.hpp:75
void add(unsigned short value) noexcept
And a unsigned integer.
Definition BON8.hpp:211
void add(unsigned char value) noexcept
And a unsigned integer.
Definition BON8.hpp:227
void add(std::string_view value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:303
void add(std::map< Key, Value > const &items)
Add a map of key/values pairs.
Definition BON8.hpp:400
T count(T... args)
T data(T... args)
T empty(T... args)
T memcpy(T... args)
T move(T... args)
T signbit(T... args)
T size(T... args)