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 "../byte_string.hpp"
8#include "../utility.hpp"
9#include "../datum.hpp"
10#include "../exception.hpp"
11#include "../cast.hpp"
12#include <cstddef>
13#include <string>
14
15namespace hi::inline v1 {
16namespace detail {
17constexpr auto BON8_code_array_count0 = uint8_t{0x80};
18constexpr auto BON8_code_array_count1 = uint8_t{0x81};
19constexpr auto BON8_code_array_count2 = uint8_t{0x82};
20constexpr auto BON8_code_array_count3 = uint8_t{0x83};
21constexpr auto BON8_code_array_count4 = uint8_t{0x84};
22constexpr auto BON8_code_array = uint8_t{0x85};
23constexpr auto BON8_code_object_count0 = uint8_t{0x86};
24constexpr auto BON8_code_object_count1 = uint8_t{0x87};
25constexpr auto BON8_code_object_count2 = uint8_t{0x88};
26constexpr auto BON8_code_object_count3 = uint8_t{0x89};
27constexpr auto BON8_code_object_count4 = uint8_t{0x8a};
28constexpr auto BON8_code_object = uint8_t{0x8b};
29constexpr auto BON8_code_int32 = uint8_t{0x8c};
30constexpr auto BON8_code_int64 = uint8_t{0x8d};
31constexpr auto BON8_code_binary32 = uint8_t{0x8e};
32constexpr auto BON8_code_binary64 = uint8_t{0x8f};
33constexpr auto BON8_code_positive_s = uint8_t{0x90};
34constexpr auto BON8_code_positive_e = uint8_t{0xb7};
35constexpr auto BON8_code_negative_s = uint8_t{0xb8};
36constexpr auto BON8_code_negative_e = uint8_t{0xc1};
37
38// The last 8 code-units after the extended characters.
39constexpr auto BON8_code_bool_false = uint8_t{0xf8};
40constexpr auto BON8_code_bool_true = uint8_t{0xf9};
41constexpr auto BON8_code_null = uint8_t{0xfa};
42constexpr auto BON8_code_float_min_one = uint8_t{0xfb};
43constexpr auto BON8_code_float_zero = uint8_t{0xfc};
44constexpr auto BON8_code_float_one = uint8_t{0xfd};
45constexpr auto BON8_code_eoc = uint8_t{0xfe};
46constexpr auto BON8_code_eot = uint8_t{0xff};
47
54[[nodiscard]] datum decode_BON8(cbyteptr &ptr, cbyteptr last);
55
56[[nodiscard]] bstring encode_BON8(datum const &value);
57
61 bool open_string;
62 bstring output;
63
64public:
65 BON8_encoder() noexcept : open_string(false), output() {}
66
69 bstring const &get() noexcept
70 {
71 if (open_string) {
72 output += static_cast<std::byte>(BON8_code_eot);
73 open_string = false;
74 }
75 return output;
76 }
77
81 void add(signed long long value) noexcept
82 {
83 open_string = false;
84
86 output += static_cast<std::byte>(BON8_code_int64);
87 for (int i = 0; i != 8; ++i) {
88 output += static_cast<std::byte>(value >> (56 - i * 8));
89 }
90
91 } else if (value <= -33818507) {
92 output += static_cast<std::byte>(BON8_code_int32);
93 for (int i = 0; i != 4; ++i) {
94 output += static_cast<std::byte>(value >> (24 - i * 8));
95 }
96
97 } else if (value <= -264075) {
98 value = -(value + 264075);
99 output += static_cast<std::byte>(0xf0 + (value >> 22 & 0x07));
100 output += static_cast<std::byte>(0xc0 + (value >> 16 & 0x3f));
101 output += static_cast<std::byte>(value >> 8);
102 output += static_cast<std::byte>(value);
103
104 } else if (value <= -1931) {
105 value = -(value + 1931);
106 output += static_cast<std::byte>(0xe0 + (value >> 14 & 0x0f));
107 output += static_cast<std::byte>(0xc0 + (value >> 8 & 0x3f));
108 output += static_cast<std::byte>(value);
109
110 } else if (value <= -11) {
111 value = -(value + 11);
112 output += static_cast<std::byte>(0xc2 + (value >> 6 & 0x1f));
113 output += static_cast<std::byte>(0xc0 + (value & 0x3f));
114
115 } else if (value <= -1) {
116 value = -(value + 1);
117 output += static_cast<std::byte>(BON8_code_negative_s + value);
118
119 } else if (value <= 39) {
120 output += static_cast<std::byte>(BON8_code_positive_s + value);
121
122 } else if (value <= 3879) {
123 value -= 40;
124 output += static_cast<std::byte>(0xc2 + (value >> 7 & 0x1f));
125 output += static_cast<std::byte>(value & 0x7f);
126
127 } else if (value <= 528167) {
128 value -= 3880;
129 output += static_cast<std::byte>(0xe0 + (value >> 15 & 0x0f));
130 output += static_cast<std::byte>(value >> 8 & 0x7f);
131 output += static_cast<std::byte>(value);
132
133 } else if (value <= 67637031) {
134 value -= 528168;
135 output += static_cast<std::byte>(0xf0 + (value >> 23 & 0x17));
136 output += static_cast<std::byte>(value >> 16 & 0x7f);
137 output += static_cast<std::byte>(value >> 8);
138 output += static_cast<std::byte>(value);
139
140 } else if (value <= std::numeric_limits<int32_t>::max()) {
141 output += static_cast<std::byte>(BON8_code_int32);
142 for (int i = 0; i != 4; ++i) {
143 output += static_cast<std::byte>(value >> (24 - i * 8));
144 }
145
146 } else {
147 output += static_cast<std::byte>(BON8_code_int64);
148 for (int i = 0; i != 8; ++i) {
149 output += static_cast<std::byte>(value >> (56 - i * 8));
150 }
151 }
152 }
153
157 void add(unsigned long long value) noexcept
158 {
159 return add(narrow_cast<signed long long>(value));
160 }
161
165 void add(signed long value) noexcept
166 {
167 return add(narrow_cast<signed long long>(value));
168 }
169
173 void add(unsigned long value) noexcept
174 {
175 return add(narrow_cast<signed long long>(value));
176 }
177
181 void add(signed int value) noexcept
182 {
183 return add(narrow_cast<signed long long>(value));
184 }
185
189 void add(unsigned int value) noexcept
190 {
191 return add(narrow_cast<signed long long>(value));
192 }
193
197 void add(signed short value) noexcept
198 {
199 return add(narrow_cast<signed long long>(value));
200 }
201
205 void add(unsigned short value) noexcept
206 {
207 return add(narrow_cast<signed long long>(value));
208 }
209
213 void add(signed char value) noexcept
214 {
215 return add(narrow_cast<signed long long>(value));
216 }
217
221 void add(unsigned char value) noexcept
222 {
223 return add(narrow_cast<signed long long>(value));
224 }
225
229 void add(double value) noexcept
230 {
231 open_string = false;
232
233 hilet f32 = static_cast<float>(value);
234 hilet f32_64 = static_cast<double>(f32);
235
236 if (value == -1.0) {
237 output += static_cast<std::byte>(BON8_code_float_min_one);
238
239 } else if (value == 0.0 and not std::signbit(value)) {
240 output += static_cast<std::byte>(BON8_code_float_zero);
241
242 } else if (value == 1.0) {
243 output += static_cast<std::byte>(BON8_code_float_one);
244
245 } else if (f32_64 == value) {
246 // After conversion to 32-bit float, precession was not reduced.
247 uint32_t u32;
248 std::memcpy(&u32, &f32, sizeof(u32));
249
250 output += static_cast<std::byte>(BON8_code_binary32);
251 for (int i = 0; i != 4; ++i) {
252 output += static_cast<std::byte>(u32 >> (24 - i * 8));
253 }
254
255 } else {
256 uint64_t u64;
257 std::memcpy(&u64, &value, sizeof(u64));
258
259 output += static_cast<std::byte>(BON8_code_binary64);
260 for (int i = 0; i != 8; ++i) {
261 output += static_cast<std::byte>(u64 >> (56 - i * 8));
262 }
263 }
264 }
265
269 void add(float value) noexcept
270 {
271 return add(static_cast<double>(value));
272 }
273
277 void add(bool value) noexcept
278 {
279 open_string = false;
280 output += static_cast<std::byte>(value ? BON8_code_bool_true : BON8_code_bool_false);
281 }
282
286 void add(nullptr_t value) noexcept
287 {
288 open_string = false;
289 output += static_cast<std::byte>(BON8_code_null);
290 }
291
297 void add(std::string_view value) noexcept
298 {
299 if (open_string) {
300 output += static_cast<std::byte>(BON8_code_eot);
301 }
302
303 if (value.empty()) {
304 output += static_cast<std::byte>(BON8_code_eot);
305 open_string = false;
306
307 } else {
308 int multi_byte = 0;
309
310 for (hilet _c : value) {
311 hilet c = truncate<uint8_t>(_c);
312
313#ifndef NDEBUG
314 if (multi_byte == 0) {
315 if (c >= 0xc2 and c <= 0xdf) {
316 multi_byte = 1;
317 } else if (c >= 0xe0 and c <= 0xef) {
318 multi_byte = 2;
319 } else if (c >= 0xf0 and c <= 0xf7) {
320 multi_byte = 3;
321 } else {
322 hi_assert(c <= 0x7f);
323 }
324
325 } else {
326 hi_assert(c >= 0x80 and c <= 0xbf);
327 --multi_byte;
328 }
329#endif
330
331 output += static_cast<std::byte>(c);
332 }
333 hi_axiom(multi_byte == 0);
334
335 open_string = true;
336 }
337 }
338
344 void add(std::string const &value) noexcept
345 {
346 add(std::string_view{value});
347 }
348
354 void add(char const *value) noexcept
355 {
356 add(std::string_view{value});
357 }
358
362 void add(datum const &value);
363
368 template<typename T>
369 void add(std::vector<T> const &items)
370 {
371 open_string = false;
372 if (size(items) <= 4) {
373 output += static_cast<std::byte>(BON8_code_array_count0 + size(items));
374 } else {
375 output += static_cast<std::byte>(BON8_code_array);
376 }
377
378 for (hilet &item : items) {
379 add(item);
380 }
381
382 if (size(items) > 4) {
383 output += static_cast<std::byte>(BON8_code_eoc);
384 open_string = false;
385 }
386 }
387
393 template<typename Key, typename Value>
394 void add(std::map<Key, Value> const &items)
395 {
396 using key_type = typename std::remove_cvref_t<decltype(items)>::key_type;
397
398 open_string = false;
399 if (size(items) <= 4) {
400 output += static_cast<std::byte>(BON8_code_object_count0 + size(items));
401 } else {
402 output += static_cast<std::byte>(BON8_code_object);
403 }
404
405 for (hilet &item : items) {
406 if (auto *s = get_if<std::string>(item.first)) {
407 add(*s);
408 } else {
409 throw operation_error("BON8 object keys must be strings");
410 }
411 add(item.second);
412 }
413
414 if (size(items) > 4) {
415 output += static_cast<std::byte>(BON8_code_eoc);
416 open_string = false;
417 }
418 }
419};
420
421void BON8_encoder::add(datum const &value)
422{
423 if (auto s = get_if<std::string>(value)) {
424 add(*s);
425 } else if (auto u = get_if<URL>(value)) {
426 add(to_string(*u));
427 } else if (auto b = get_if<bool>(value)) {
428 add(*b);
429 } else if (holds_alternative<nullptr_t>(value)) {
430 add(nullptr);
431 } else if (auto i = get_if<long long>(value)) {
432 add(*i);
433 } else if (auto f = get_if<double>(value)) {
434 add(*f);
435 } else if (auto v = get_if<datum::vector_type>(value)) {
436 add(*v);
437 } else if (auto m = get_if<datum::map_type>(value)) {
438 add(*m);
439 } else {
440 throw operation_error("Datum value can not be encoded to BON8");
441 }
442}
443
452[[nodiscard]] int BON8_multibyte_count(cbyteptr ptr, cbyteptr last)
453{
454 hi_axiom(ptr != nullptr);
455 hi_axiom(last != nullptr);
456
457 hilet c0 = static_cast<uint8_t>(*ptr);
458 hilet count = c0 <= 0xdf ? 2 : c0 <= 0xef ? 3 : 4;
459
460 hi_parse_check(ptr + count <= last, "Incomplete Multi-byte character at end of buffer");
461
462 hilet c1 = static_cast<uint8_t>(*(ptr + 1));
463 return (c1 < 0x80 or c1 > 0xbf) ? -count : count;
464}
465
474[[nodiscard]] datum decode_BON8_int(cbyteptr &ptr, cbyteptr last, int count)
475{
476 hi_axiom(ptr != nullptr);
477 hi_axiom(last != nullptr);
478 hi_axiom(count == 4 || count == 8);
479
480 auto u64 = uint64_t{0};
481 for (int i = 0; i != count; ++i) {
482 hi_parse_check(ptr != last, "Incomplete signed integer at end of buffer");
483 u64 <<= 8;
484 u64 |= static_cast<uint64_t>(*(ptr++));
485 }
486
487 if (count == 4) {
488 hilet u32 = truncate<uint32_t>(u64);
489 hilet i32 = truncate<int32_t>(u32);
490 return datum{i32};
491 } else {
492 hilet i64 = truncate<int64_t>(u64);
493 return datum{i64};
494 }
495}
496
497[[nodiscard]] datum decode_BON8_float(cbyteptr &ptr, cbyteptr last, int count)
498{
499 hi_axiom(ptr != nullptr);
500 hi_axiom(last != nullptr);
501 hi_axiom(count == 4 || count == 8);
502
503 auto u64 = uint64_t{0};
504 for (int i = 0; i != count; ++i) {
505 hi_parse_check(ptr != last, "Incomplete signed integer at end of buffer");
506 u64 <<= 8;
507 u64 |= static_cast<uint64_t>(*(ptr++));
508 }
509
510 if (count == 4) {
511 hilet u32 = truncate<uint32_t>(u64);
512 float f32;
513 std::memcpy(&f32, &u32, sizeof(f32));
514 return datum{f32};
515
516 } else {
517 double f64;
518 std::memcpy(&f64, &u64, sizeof(f64));
519 return datum{f64};
520 }
521}
522
523[[nodiscard]] datum decode_BON8_array(cbyteptr &ptr, cbyteptr last)
524{
525 hi_axiom(ptr != nullptr);
526 hi_axiom(last != nullptr);
527
528 auto r = datum::make_vector();
529 auto &vector = get<datum::vector_type>(r);
530
531 while (ptr != last) {
532 if (*ptr == static_cast<std::byte>(BON8_code_eoc)) {
533 ++ptr;
534 return r;
535
536 } else {
537 vector.push_back(decode_BON8(ptr, last));
538 }
539 }
540 throw parse_error("Incomplete array at end of buffer");
541}
542
543[[nodiscard]] datum decode_BON8_array(cbyteptr &ptr, cbyteptr last, std::size_t count)
544{
545 auto r = datum::make_vector();
546 auto &vector = get<datum::vector_type>(r);
547
548 while (count--) {
549 vector.push_back(decode_BON8(ptr, last));
550 }
551 return r;
552}
553
554[[nodiscard]] datum decode_BON8_object(cbyteptr &ptr, cbyteptr last)
555{
556 hi_axiom(ptr != nullptr);
557 hi_axiom(last != nullptr);
558
559 auto r = datum::make_map();
560 auto &map = get<datum::map_type>(r);
561
562 while (ptr != last) {
563 if (*ptr == static_cast<std::byte>(BON8_code_eoc)) {
564 ++ptr;
565 return r;
566
567 } else {
568 auto key = decode_BON8(ptr, last);
569 hi_parse_check(holds_alternative<std::string>(key), "Key in object is not a string");
570
571 auto value = decode_BON8(ptr, last);
572 map.emplace(std::move(key), std::move(value));
573 }
574 }
575 throw parse_error("Incomplete object at end of buffer");
576}
577
578[[nodiscard]] datum decode_BON8_object(cbyteptr &ptr, cbyteptr last, std::size_t count)
579{
580 auto r = datum::make_map();
581 auto &map = get<datum::map_type>(r);
582
583 while (count--) {
584 auto key = decode_BON8(ptr, last);
585 hi_parse_check(holds_alternative<std::string>(key), "Key in object is not a string");
586
587 auto value = decode_BON8(ptr, last);
588 map.emplace(std::move(key), std::move(value));
589 }
590 return r;
591}
592
593[[nodiscard]] long long decode_BON8_UTF8_like_int(cbyteptr &ptr, cbyteptr last, int count) noexcept
594{
595 hi_axiom(ptr != nullptr);
596 hi_axiom(last != nullptr);
597 hi_axiom(count >= 2 && count <= 4);
598 hi_axiom(ptr != last);
599 hilet c0 = static_cast<uint8_t>(*(ptr++));
600
601 hilet mask = uint8_t{0b0111'1111} >> count;
602 auto value = static_cast<long long>(c0 & mask);
603 if (count == 2) {
604 // The two byte sequence starts with 0xc2, leaving only 30 entries in the first byte.
605 value -= 2;
606 }
607
608 // The second byte determines the sign, and adds 6 or 7 bits to the number.
609 hi_axiom(ptr != last);
610 hilet c1 = static_cast<uint8_t>(*(ptr++));
611 hilet is_positive = c1 <= 0x7f;
612 if (is_positive) {
613 value <<= 7;
614 value |= static_cast<long long>(c1);
615 } else {
616 value <<= 6;
617 value |= static_cast<long long>(c1 & 0b0011'1111);
618 }
619
620 switch (count) {
621 case 4:
622 hi_axiom(ptr != last);
623 value <<= 8;
624 value |= static_cast<int>(*(ptr++));
625 [[fallthrough]];
626 case 3:
627 hi_axiom(ptr != last);
628 value <<= 8;
629 value |= static_cast<int>(*(ptr++));
630 [[fallthrough]];
631 default:;
632 }
633
634 if (is_positive) {
635 switch (count) {
636 case 2: return value + 40;
637 case 3: return value + 3880;
638 case 4: return value + 528168;
639 default: hi_no_default();
640 }
641
642 } else {
643 switch (count) {
644 case 2: return -(value + 11);
645 case 3: return -(value + 1931);
646 case 4: return -(value + 264075);
647 default: hi_no_default();
648 }
649 }
650}
651
652[[nodiscard]] datum decode_BON8(cbyteptr &ptr, cbyteptr last)
653{
654 hi_axiom(ptr != nullptr);
655 hi_axiom(last != nullptr);
656
657 std::string str;
658
659 while (ptr != last) {
660 hilet c = static_cast<uint8_t>(*ptr);
661
662 if (c == BON8_code_eot) {
663 // End of string found, return the current string.
664 ++ptr;
665 return datum{str};
666
667 } else if (c <= 0x7f) {
668 // ASCII character.
669 str += static_cast<char>(*(ptr++));
670 continue;
671
672 } else if (c >= 0xc2 && c <= 0xf7) {
673 hilet count = BON8_multibyte_count(ptr, last);
674 if (count > 0) {
675 // Multibyte UTF-8 code-point, The count includes the first code-unit.
676 for (int i = 0; i != count; ++i) {
677 str += static_cast<char>(*(ptr++));
678 }
679 continue;
680
681 } else if (not str.empty()) {
682 // Multibyte integer found, but first return the current string.
683 return datum{str};
684
685 } else {
686 // Multibyte integer, the first code-unit includes part of the integer.
687 return datum{decode_BON8_UTF8_like_int(ptr, last, -count)};
688 }
689
690 } else if (not str.empty()) {
691 // This must be a non-string type, but first return the current string.
692 return datum{str};
693
694 } else {
695 // This is one of the non-string types.
696 ++ptr;
697 switch (c) {
698 case BON8_code_null: return datum{nullptr};
699 case BON8_code_bool_false: return datum{false};
700 case BON8_code_bool_true: return datum{true};
701 case BON8_code_float_min_one: return datum{-1.0f};
702 case BON8_code_float_zero: return datum{0.0f};
703 case BON8_code_float_one: return datum{1.0f};
704 case BON8_code_int32: return decode_BON8_int(ptr, last, 4);
705 case BON8_code_int64: return decode_BON8_int(ptr, last, 8);
706 case BON8_code_binary32: return decode_BON8_float(ptr, last, 4);
707 case BON8_code_binary64: return decode_BON8_float(ptr, last, 8);
708 case BON8_code_array_count0: return datum::make_vector();
709 case BON8_code_array_count1: return decode_BON8_array(ptr, last, 1);
710 case BON8_code_array_count2: return decode_BON8_array(ptr, last, 2);
711 case BON8_code_array_count3: return decode_BON8_array(ptr, last, 3);
712 case BON8_code_array_count4: return decode_BON8_array(ptr, last, 4);
713 case BON8_code_array: return decode_BON8_array(ptr, last);
714 case BON8_code_object_count0: return datum::make_map();
715 case BON8_code_object_count1: return decode_BON8_object(ptr, last, 1);
716 case BON8_code_object_count2: return decode_BON8_object(ptr, last, 2);
717 case BON8_code_object_count3: return decode_BON8_object(ptr, last, 3);
718 case BON8_code_object_count4: return decode_BON8_object(ptr, last, 4);
719 case BON8_code_object: return decode_BON8_object(ptr, last);
720 case BON8_code_eoc: throw parse_error("Unexpected end-of-container");
721 case BON8_code_eot: throw parse_error("Unexpected end-of-text");
722 default:
723 // Everything below this, are non-string types.
724 if (c >= BON8_code_positive_s and c <= BON8_code_positive_e) {
725 return datum{c - BON8_code_positive_s};
726
727 } else if (c >= BON8_code_negative_s and c <= BON8_code_negative_e) {
728 return datum{~truncate<int>(c - BON8_code_negative_s)};
729
730 } else {
731 hi_no_default();
732 }
733 }
734 }
735 }
736 throw parse_error("Unexpected end-of-buffer");
737}
738} // namespace detail
739
744[[nodiscard]] datum decode_BON8(std::span<const std::byte> buffer)
745{
746 auto *ptr = buffer.data();
747 auto *last = ptr + buffer.size();
748 return detail::decode_BON8(ptr, last);
749}
750
755[[nodiscard]] datum decode_BON8(bstring const &buffer)
756{
757 auto *ptr = buffer.data();
758 auto *last = ptr + buffer.size();
759 return detail::decode_BON8(ptr, last);
760}
761
766[[nodiscard]] datum decode_BON8(bstring_view buffer)
767{
768 auto *ptr = buffer.data();
769 auto *last = ptr + buffer.size();
770 return detail::decode_BON8(ptr, last);
771}
772
777[[nodiscard]] bstring encode_BON8(datum const &value)
778{
779 auto encoder = detail::BON8_encoder{};
780 encoder.add(value);
781 return encoder.get();
782}
783
784} // namespace hi::inline v1
Utilities used by the HikoGUI library itself.
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:15
@ m
Mirror but not bracket.
BON8 encoder.
Definition BON8.hpp:60
void add(std::string const &value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:344
void add(double value) noexcept
Add a floating point number.
Definition BON8.hpp:229
void add(float value) noexcept
Add a floating point number.
Definition BON8.hpp:269
void add(unsigned long long value) noexcept
And a unsigned integer.
Definition BON8.hpp:157
void add(nullptr_t value) noexcept
Add a null.
Definition BON8.hpp:286
void add(bool value) noexcept
Add a boolean.
Definition BON8.hpp:277
void add(signed long value) noexcept
And a signed integer.
Definition BON8.hpp:165
void add(signed int value) noexcept
And a signed integer.
Definition BON8.hpp:181
void add(signed short value) noexcept
And a signed integer.
Definition BON8.hpp:197
void add(std::vector< T > const &items)
Add a vector of values of the same type.
Definition BON8.hpp:369
void add(unsigned int value) noexcept
And a unsigned integer.
Definition BON8.hpp:189
void add(unsigned long value) noexcept
And a unsigned integer.
Definition BON8.hpp:173
void add(char const *value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:354
void add(signed char value) noexcept
And a signed integer.
Definition BON8.hpp:213
void add(signed long long value) noexcept
And a signed integer.
Definition BON8.hpp:81
bstring const & get() noexcept
Return a byte_string of the encoded object.
Definition BON8.hpp:69
void add(unsigned short value) noexcept
And a unsigned integer.
Definition BON8.hpp:205
void add(unsigned char value) noexcept
And a unsigned integer.
Definition BON8.hpp:221
void add(std::string_view value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:297
void add(std::map< Key, Value > const &items)
Add a map of key/values pairs.
Definition BON8.hpp:394
A dynamic data type.
Definition datum.hpp:225
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)