7#include "../container/container.hpp"
8#include "../utility/utility.hpp"
10#include "../macros.hpp"
14hi_export_module(hikogui.codec.BON8);
19hi_warning_ignore_msvc(26429);
21hi_export
namespace hi::inline
v1 {
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};
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};
60[[nodiscard]] datum decode_BON8(cbyteptr& ptr, cbyteptr last);
62[[nodiscard]] bstring encode_BON8(datum
const& value);
71 BON8_encoder() noexcept : open_string(
false), output() {}
78 output +=
static_cast<std::byte
>(BON8_code_eot);
87 void add(
signed long long value)
noexcept
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));
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));
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);
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);
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));
121 }
else if (value <= -1) {
122 value = -(value + 1);
123 output +=
static_cast<std::byte
>(BON8_code_negative_s + value);
125 }
else if (value <= 39) {
126 output +=
static_cast<std::byte
>(BON8_code_positive_s + value);
128 }
else if (value <= 3879) {
130 output +=
static_cast<std::byte
>(0xc2 + (value >> 7 & 0x1f));
131 output +=
static_cast<std::byte
>(value & 0x7f);
133 }
else if (value <= 528167) {
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);
139 }
else if (value <= 67637031) {
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);
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));
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));
163 void add(
unsigned long long value)
noexcept
165 return add(narrow_cast<signed long long>(value));
171 void add(
signed long value)
noexcept
173 return add(narrow_cast<signed long long>(value));
179 void add(
unsigned long value)
noexcept
181 return add(narrow_cast<signed long long>(value));
187 void add(
signed int value)
noexcept
189 return add(narrow_cast<signed long long>(value));
195 void add(
unsigned int value)
noexcept
197 return add(narrow_cast<signed long long>(value));
203 void add(
signed short value)
noexcept
205 return add(narrow_cast<signed long long>(value));
211 void add(
unsigned short value)
noexcept
213 return add(narrow_cast<signed long long>(value));
219 void add(
signed char value)
noexcept
221 return add(narrow_cast<signed long long>(value));
227 void add(
unsigned char value)
noexcept
229 return add(narrow_cast<signed long long>(value));
235 void add(
double value)
noexcept
239 auto const f32 =
static_cast<float>(value);
240 auto const f32_64 =
static_cast<double>(f32);
243 output +=
static_cast<std::byte
>(BON8_code_float_min_one);
246 output +=
static_cast<std::byte
>(BON8_code_float_zero);
248 }
else if (value == 1.0) {
249 output +=
static_cast<std::byte
>(BON8_code_float_one);
251 }
else if (f32_64 == value) {
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));
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));
275 void add(
float value)
noexcept
277 return add(
static_cast<double>(value));
283 void add(
bool value)
noexcept
286 output +=
static_cast<std::byte
>(value ? BON8_code_bool_true : BON8_code_bool_false);
292 void add(nullptr_t value)
noexcept
295 output +=
static_cast<std::byte
>(BON8_code_null);
303 void add(std::string_view value)
noexcept
306 output +=
static_cast<std::byte
>(BON8_code_eot);
310 output +=
static_cast<std::byte
>(BON8_code_eot);
316 for (
auto const _c : value) {
317 auto const c = truncate<uint8_t>(_c);
320 if (multi_byte == 0) {
321 if (c >= 0xc2 and c <= 0xdf) {
323 }
else if (c >= 0xe0 and c <= 0xef) {
325 }
else if (c >= 0xf0 and c <= 0xf7) {
328 hi_assert(c <= 0x7f);
332 hi_assert(c >= 0x80 and c <= 0xbf);
337 output +=
static_cast<std::byte
>(c);
339 hi_assert(multi_byte == 0);
352 add(std::string_view{value});
360 void add(
char const *value)
noexcept
362 add(std::string_view{value});
368 void add(datum
const& value);
378 if (size(items) <= 4) {
379 output +=
static_cast<std::byte
>(BON8_code_array_count0 + size(items));
381 output +=
static_cast<std::byte
>(BON8_code_array);
384 for (
auto const& item : items) {
388 if (size(items) > 4) {
389 output +=
static_cast<std::byte
>(BON8_code_eoc);
399 template<
typename Key,
typename Value>
402 using key_type =
typename std::remove_cvref_t<
decltype(items)>::key_type;
405 if (size(items) <= 4) {
406 output +=
static_cast<std::byte
>(BON8_code_object_count0 + size(items));
408 output +=
static_cast<std::byte
>(BON8_code_object);
411 for (
auto const& item : items) {
412 if (
auto *s = get_if<std::string>(item.first)) {
415 throw operation_error(
"BON8 object keys must be strings");
420 if (size(items) > 4) {
421 output +=
static_cast<std::byte
>(BON8_code_eoc);
427void inline BON8_encoder::add(datum
const& value)
429 if (
auto s = get_if<std::string>(value)) {
431 }
else if (
auto b = get_if<bool>(value)) {
433 }
else if (holds_alternative<nullptr_t>(value)) {
435 }
else if (
auto i = get_if<long long>(value)) {
437 }
else if (
auto f = get_if<double>(value)) {
439 }
else if (
auto v = get_if<datum::vector_type>(value)) {
441 }
else if (
auto m = get_if<datum::map_type>(value)) {
444 throw operation_error(
"Datum value can not be encoded to BON8");
456[[nodiscard]]
inline int BON8_multibyte_count(cbyteptr ptr, cbyteptr last)
458 hi_assert_not_null(ptr);
459 hi_assert_not_null(last);
461 auto const c0 =
static_cast<uint8_t
>(*ptr);
462 auto const count = c0 <= 0xdf ? 2 : c0 <= 0xef ? 3 : 4;
464 hi_check(ptr + count <= last,
"Incomplete Multi-byte character at end of buffer");
466 auto const c1 =
static_cast<uint8_t
>(*(ptr + 1));
467 return (c1 < 0x80 or c1 > 0xbf) ? -count : count;
478[[nodiscard]]
inline datum decode_BON8_int(cbyteptr& ptr, cbyteptr last,
int count)
480 hi_assert_not_null(ptr);
481 hi_assert_not_null(last);
482 hi_assert(count == 4 || count == 8);
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");
488 u64 |=
static_cast<uint64_t
>(*(ptr++));
492 auto const u32 = truncate<uint32_t>(u64);
493 auto const i32 = truncate<int32_t>(u32);
496 auto const i64 = truncate<int64_t>(u64);
501[[nodiscard]]
inline datum decode_BON8_float(cbyteptr& ptr, cbyteptr last,
int count)
503 hi_assert_not_null(ptr);
504 hi_assert_not_null(last);
505 hi_assert(count == 4 || count == 8);
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");
511 u64 |=
static_cast<uint64_t
>(*(ptr++));
515 auto const u32 = truncate<uint32_t>(u64);
527[[nodiscard]]
inline datum decode_BON8_array(cbyteptr& ptr, cbyteptr last)
529 hi_assert_not_null(ptr);
530 hi_assert_not_null(last);
532 auto r = datum::make_vector();
533 auto& vector = get<datum::vector_type>(r);
535 while (ptr != last) {
536 if (*ptr ==
static_cast<std::byte
>(BON8_code_eoc)) {
541 vector.push_back(decode_BON8(ptr, last));
544 throw parse_error(
"Incomplete array at end of buffer");
547[[nodiscard]]
inline datum decode_BON8_array(cbyteptr& ptr, cbyteptr last,
std::size_t count)
549 auto r = datum::make_vector();
550 auto& vector = get<datum::vector_type>(r);
553 vector.push_back(decode_BON8(ptr, last));
558[[nodiscard]]
inline datum decode_BON8_object(cbyteptr& ptr, cbyteptr last)
560 hi_assert_not_null(ptr);
561 hi_assert_not_null(last);
563 auto r = datum::make_map();
564 auto& map = get<datum::map_type>(r);
566 while (ptr != last) {
567 if (*ptr ==
static_cast<std::byte
>(BON8_code_eoc)) {
572 auto key = decode_BON8(ptr, last);
573 hi_check(holds_alternative<std::string>(key),
"Key in object is not a string");
575 auto value = decode_BON8(ptr, last);
579 throw parse_error(
"Incomplete object at end of buffer");
582[[nodiscard]]
inline datum decode_BON8_object(cbyteptr& ptr, cbyteptr last,
std::size_t count)
584 auto r = datum::make_map();
585 auto& map = get<datum::map_type>(r);
588 auto key = decode_BON8(ptr, last);
589 hi_check(holds_alternative<std::string>(key),
"Key in object is not a string");
591 auto value = decode_BON8(ptr, last);
597[[nodiscard]]
inline long long decode_BON8_UTF8_like_int(cbyteptr& ptr, cbyteptr last,
int count)
noexcept
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++));
605 auto const mask = uint8_t{0b0111'1111} >>
count;
606 auto value =
static_cast<long long>(c0 & mask);
613 hi_assert(ptr != last);
614 auto const c1 =
static_cast<uint8_t
>(*(ptr++));
615 auto const is_positive = c1 <= 0x7f;
618 value |=
static_cast<long long>(c1);
621 value |=
static_cast<long long>(c1 & 0b0011'1111);
626 hi_assert(ptr != last);
628 value |=
static_cast<int>(*(ptr++));
631 hi_assert(ptr != last);
633 value |=
static_cast<int>(*(ptr++));
645 return value + 528168;
653 return -(value + 11);
655 return -(value + 1931);
657 return -(value + 264075);
664[[nodiscard]]
inline datum decode_BON8(cbyteptr& ptr, cbyteptr last)
666 hi_assert_not_null(ptr);
667 hi_assert_not_null(last);
671 while (ptr != last) {
672 auto const c =
static_cast<uint8_t
>(*ptr);
674 if (c == BON8_code_eot) {
679 }
else if (c <= 0x7f) {
681 str +=
static_cast<char>(*(ptr++));
684 }
else if (c >= 0xc2 && c <= 0xf7) {
685 auto const count = BON8_multibyte_count(ptr, last);
688 for (
int i = 0; i !=
count; ++i) {
689 str +=
static_cast<char>(*(ptr++));
693 }
else if (not str.
empty()) {
699 return datum{decode_BON8_UTF8_like_int(ptr, last, -count)};
702 }
else if (not str.
empty()) {
711 return datum{
nullptr};
712 case BON8_code_bool_false:
714 case BON8_code_bool_true:
716 case BON8_code_float_min_one:
718 case BON8_code_float_zero:
720 case BON8_code_float_one:
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);
755 throw parse_error(
"Unexpected end-of-container");
757 throw parse_error(
"Unexpected end-of-text");
760 if (c >= BON8_code_positive_s and c <= BON8_code_positive_e) {
761 return datum{c - BON8_code_positive_s};
763 }
else if (c >= BON8_code_negative_s and c <= BON8_code_negative_e) {
764 return datum{~truncate<int>(c - BON8_code_negative_s)};
772 throw parse_error(
"Unexpected end-of-buffer");
781hi_export [[nodiscard]]
inline datum decode_BON8(std::span<const std::byte> buffer)
783 auto *ptr = buffer.data();
784 auto *last = ptr + buffer.size();
785 return detail::decode_BON8(ptr, last);
792hi_export [[nodiscard]]
inline datum decode_BON8(
bstring const& buffer)
794 auto *ptr = buffer.
data();
795 auto *last = ptr + buffer.
size();
796 return detail::decode_BON8(ptr, last);
803hi_export [[nodiscard]]
inline datum decode_BON8(bstring_view buffer)
805 auto *ptr = buffer.data();
806 auto *last = ptr + buffer.size();
807 return detail::decode_BON8(ptr, last);
814hi_export [[nodiscard]]
inline bstring encode_BON8(datum
const& value)
818 return encoder.get();
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