7#include "../byte_string.hpp"
8#include "../utility/module.hpp"
16hi_warning_ignore_msvc(26429);
18namespace hi::inline
v1 {
20constexpr auto BON8_code_array_count0 = uint8_t{0x80};
21constexpr auto BON8_code_array_count1 = uint8_t{0x81};
22constexpr auto BON8_code_array_count2 = uint8_t{0x82};
23constexpr auto BON8_code_array_count3 = uint8_t{0x83};
24constexpr auto BON8_code_array_count4 = uint8_t{0x84};
25constexpr auto BON8_code_array = uint8_t{0x85};
26constexpr auto BON8_code_object_count0 = uint8_t{0x86};
27constexpr auto BON8_code_object_count1 = uint8_t{0x87};
28constexpr auto BON8_code_object_count2 = uint8_t{0x88};
29constexpr auto BON8_code_object_count3 = uint8_t{0x89};
30constexpr auto BON8_code_object_count4 = uint8_t{0x8a};
31constexpr auto BON8_code_object = uint8_t{0x8b};
32constexpr auto BON8_code_int32 = uint8_t{0x8c};
33constexpr auto BON8_code_int64 = uint8_t{0x8d};
34constexpr auto BON8_code_binary32 = uint8_t{0x8e};
35constexpr auto BON8_code_binary64 = uint8_t{0x8f};
36constexpr auto BON8_code_positive_s = uint8_t{0x90};
37constexpr auto BON8_code_positive_e = uint8_t{0xb7};
38constexpr auto BON8_code_negative_s = uint8_t{0xb8};
39constexpr auto BON8_code_negative_e = uint8_t{0xc1};
42constexpr auto BON8_code_bool_false = uint8_t{0xf8};
43constexpr auto BON8_code_bool_true = uint8_t{0xf9};
44constexpr auto BON8_code_null = uint8_t{0xfa};
45constexpr auto BON8_code_float_min_one = uint8_t{0xfb};
46constexpr auto BON8_code_float_zero = uint8_t{0xfc};
47constexpr auto BON8_code_float_one = uint8_t{0xfd};
48constexpr auto BON8_code_eoc = uint8_t{0xfe};
49constexpr auto BON8_code_eot = uint8_t{0xff};
57[[nodiscard]] datum decode_BON8(cbyteptr& ptr, cbyteptr last);
59[[nodiscard]] bstring encode_BON8(datum
const& value);
68 BON8_encoder() noexcept : open_string(
false), output() {}
75 output +=
static_cast<std::byte
>(BON8_code_eot);
84 void add(
signed long long value)
noexcept
89 output +=
static_cast<std::byte
>(BON8_code_int64);
90 for (
int i = 0; i != 8; ++i) {
91 output +=
static_cast<std::byte
>(value >> (56 - i * 8));
94 }
else if (value <= -33818507) {
95 output +=
static_cast<std::byte
>(BON8_code_int32);
96 for (
int i = 0; i != 4; ++i) {
97 output +=
static_cast<std::byte
>(value >> (24 - i * 8));
100 }
else if (value <= -264075) {
101 value = -(value + 264075);
102 output +=
static_cast<std::byte
>(0xf0 + (value >> 22 & 0x07));
103 output +=
static_cast<std::byte
>(0xc0 + (value >> 16 & 0x3f));
104 output +=
static_cast<std::byte
>(value >> 8);
105 output +=
static_cast<std::byte
>(value);
107 }
else if (value <= -1931) {
108 value = -(value + 1931);
109 output +=
static_cast<std::byte
>(0xe0 + (value >> 14 & 0x0f));
110 output +=
static_cast<std::byte
>(0xc0 + (value >> 8 & 0x3f));
111 output +=
static_cast<std::byte
>(value);
113 }
else if (value <= -11) {
114 value = -(value + 11);
115 output +=
static_cast<std::byte
>(0xc2 + (value >> 6 & 0x1f));
116 output +=
static_cast<std::byte
>(0xc0 + (value & 0x3f));
118 }
else if (value <= -1) {
119 value = -(value + 1);
120 output +=
static_cast<std::byte
>(BON8_code_negative_s + value);
122 }
else if (value <= 39) {
123 output +=
static_cast<std::byte
>(BON8_code_positive_s + value);
125 }
else if (value <= 3879) {
127 output +=
static_cast<std::byte
>(0xc2 + (value >> 7 & 0x1f));
128 output +=
static_cast<std::byte
>(value & 0x7f);
130 }
else if (value <= 528167) {
132 output +=
static_cast<std::byte
>(0xe0 + (value >> 15 & 0x0f));
133 output +=
static_cast<std::byte
>(value >> 8 & 0x7f);
134 output +=
static_cast<std::byte
>(value);
136 }
else if (value <= 67637031) {
138 output +=
static_cast<std::byte
>(0xf0 + (value >> 23 & 0x17));
139 output +=
static_cast<std::byte
>(value >> 16 & 0x7f);
140 output +=
static_cast<std::byte
>(value >> 8);
141 output +=
static_cast<std::byte
>(value);
144 output +=
static_cast<std::byte
>(BON8_code_int32);
145 for (
int i = 0; i != 4; ++i) {
146 output +=
static_cast<std::byte
>(value >> (24 - i * 8));
150 output +=
static_cast<std::byte
>(BON8_code_int64);
151 for (
int i = 0; i != 8; ++i) {
152 output +=
static_cast<std::byte
>(value >> (56 - i * 8));
160 void add(
unsigned long long value)
noexcept
162 return add(narrow_cast<signed long long>(value));
168 void add(
signed long value)
noexcept
170 return add(narrow_cast<signed long long>(value));
176 void add(
unsigned long value)
noexcept
178 return add(narrow_cast<signed long long>(value));
184 void add(
signed int value)
noexcept
186 return add(narrow_cast<signed long long>(value));
192 void add(
unsigned int value)
noexcept
194 return add(narrow_cast<signed long long>(value));
200 void add(
signed short value)
noexcept
202 return add(narrow_cast<signed long long>(value));
208 void add(
unsigned short value)
noexcept
210 return add(narrow_cast<signed long long>(value));
216 void add(
signed char value)
noexcept
218 return add(narrow_cast<signed long long>(value));
224 void add(
unsigned char value)
noexcept
226 return add(narrow_cast<signed long long>(value));
232 void add(
double value)
noexcept
236 hilet f32 =
static_cast<float>(value);
237 hilet f32_64 =
static_cast<double>(f32);
240 output +=
static_cast<std::byte
>(BON8_code_float_min_one);
243 output +=
static_cast<std::byte
>(BON8_code_float_zero);
245 }
else if (value == 1.0) {
246 output +=
static_cast<std::byte
>(BON8_code_float_one);
248 }
else if (f32_64 == value) {
253 output +=
static_cast<std::byte
>(BON8_code_binary32);
254 for (
int i = 0; i != 4; ++i) {
255 output +=
static_cast<std::byte
>(u32 >> (24 - i * 8));
262 output +=
static_cast<std::byte
>(BON8_code_binary64);
263 for (
int i = 0; i != 8; ++i) {
264 output +=
static_cast<std::byte
>(u64 >> (56 - i * 8));
272 void add(
float value)
noexcept
274 return add(
static_cast<double>(value));
280 void add(
bool value)
noexcept
283 output +=
static_cast<std::byte
>(value ? BON8_code_bool_true : BON8_code_bool_false);
289 void add(nullptr_t value)
noexcept
292 output +=
static_cast<std::byte
>(BON8_code_null);
300 void add(std::string_view value)
noexcept
303 output +=
static_cast<std::byte
>(BON8_code_eot);
307 output +=
static_cast<std::byte
>(BON8_code_eot);
313 for (
hilet _c : value) {
314 hilet c = truncate<uint8_t>(_c);
317 if (multi_byte == 0) {
318 if (
c >= 0xc2 and
c <= 0xdf) {
320 }
else if (
c >= 0xe0 and
c <= 0xef) {
322 }
else if (
c >= 0xf0 and
c <= 0xf7) {
334 output +=
static_cast<std::byte
>(
c);
349 add(std::string_view{value});
357 void add(
char const *value)
noexcept
359 add(std::string_view{value});
365 void add(
datum const& value);
375 if (size(items) <= 4) {
376 output +=
static_cast<std::byte
>(BON8_code_array_count0 + size(items));
378 output +=
static_cast<std::byte
>(BON8_code_array);
381 for (
hilet& item : items) {
385 if (size(items) > 4) {
386 output +=
static_cast<std::byte
>(BON8_code_eoc);
396 template<
typename Key,
typename Value>
399 using key_type =
typename std::remove_cvref_t<
decltype(items)>::key_type;
402 if (size(items) <= 4) {
403 output +=
static_cast<std::byte
>(BON8_code_object_count0 + size(items));
405 output +=
static_cast<std::byte
>(BON8_code_object);
408 for (
hilet& item : items) {
409 if (
auto *s = get_if<std::string>(item.first)) {
412 throw operation_error(
"BON8 object keys must be strings");
417 if (size(items) > 4) {
418 output +=
static_cast<std::byte
>(BON8_code_eoc);
424void BON8_encoder::add(
datum const& value)
426 if (
auto s = get_if<std::string>(value)) {
428 }
else if (
auto b = get_if<bool>(value)) {
430 }
else if (holds_alternative<nullptr_t>(value)) {
432 }
else if (
auto i = get_if<long long>(value)) {
434 }
else if (
auto f = get_if<double>(value)) {
436 }
else if (
auto v = get_if<datum::vector_type>(value)) {
438 }
else if (
auto m = get_if<datum::map_type>(value)) {
441 throw operation_error(
"Datum value can not be encoded to BON8");
453[[nodiscard]]
int BON8_multibyte_count(cbyteptr ptr, cbyteptr last)
458 hilet c0 =
static_cast<uint8_t
>(*ptr);
459 hilet count = c0 <= 0xdf ? 2 : c0 <= 0xef ? 3 : 4;
461 hi_check(ptr + count <= last,
"Incomplete Multi-byte character at end of buffer");
463 hilet c1 =
static_cast<uint8_t
>(*(ptr + 1));
464 return (c1 < 0x80 or c1 > 0xbf) ? -count : count;
475[[nodiscard]]
datum decode_BON8_int(cbyteptr& ptr, cbyteptr last,
int count)
481 auto u64 = uint64_t{0};
482 for (
int i = 0; i != count; ++i) {
483 hi_check(ptr != last,
"Incomplete signed integer at end of buffer");
485 u64 |=
static_cast<uint64_t
>(*(ptr++));
489 hilet u32 = truncate<uint32_t>(u64);
490 hilet i32 = truncate<int32_t>(u32);
493 hilet i64 = truncate<int64_t>(u64);
498[[nodiscard]] datum decode_BON8_float(cbyteptr& ptr, cbyteptr last,
int count)
504 auto u64 = uint64_t{0};
505 for (
int i = 0; i !=
count; ++i) {
506 hi_check(ptr != last,
"Incomplete signed integer at end of buffer");
508 u64 |=
static_cast<uint64_t
>(*(ptr++));
512 hilet u32 = truncate<uint32_t>(u64);
524[[nodiscard]] datum decode_BON8_array(cbyteptr& ptr, cbyteptr last)
529 auto r = datum::make_vector();
530 auto& vector = get<datum::vector_type>(r);
532 while (ptr != last) {
533 if (*ptr ==
static_cast<std::byte
>(BON8_code_eoc)) {
538 vector.push_back(decode_BON8(ptr, last));
541 throw parse_error(
"Incomplete array at end of buffer");
544[[nodiscard]] datum decode_BON8_array(cbyteptr& ptr, cbyteptr last,
std::size_t count)
546 auto r = datum::make_vector();
547 auto& vector = get<datum::vector_type>(r);
550 vector.push_back(decode_BON8(ptr, last));
555[[nodiscard]] datum decode_BON8_object(cbyteptr& ptr, cbyteptr last)
560 auto r = datum::make_map();
561 auto& map = get<datum::map_type>(r);
563 while (ptr != last) {
564 if (*ptr ==
static_cast<std::byte
>(BON8_code_eoc)) {
569 auto key = decode_BON8(ptr, last);
570 hi_check(holds_alternative<std::string>(key),
"Key in object is not a string");
572 auto value = decode_BON8(ptr, last);
576 throw parse_error(
"Incomplete object at end of buffer");
579[[nodiscard]] datum decode_BON8_object(cbyteptr& ptr, cbyteptr last,
std::size_t count)
581 auto r = datum::make_map();
582 auto& map = get<datum::map_type>(r);
585 auto key = decode_BON8(ptr, last);
586 hi_check(holds_alternative<std::string>(key),
"Key in object is not a string");
588 auto value = decode_BON8(ptr, last);
594[[nodiscard]]
long long decode_BON8_UTF8_like_int(cbyteptr& ptr, cbyteptr last,
int count)
noexcept
600 hilet c0 =
static_cast<uint8_t
>(*(ptr++));
603 auto value =
static_cast<long long>(c0 & mask);
611 hilet c1 =
static_cast<uint8_t
>(*(ptr++));
612 hilet is_positive = c1 <= 0x7f;
615 value |=
static_cast<long long>(c1);
618 value |=
static_cast<long long>(c1 & 0b0011'1111);
625 value |=
static_cast<int>(*(ptr++));
630 value |=
static_cast<int>(*(ptr++));
642 return value + 528168;
650 return -(value + 11);
652 return -(value + 1931);
654 return -(value + 264075);
661[[nodiscard]] datum decode_BON8(cbyteptr& ptr, cbyteptr last)
668 while (ptr != last) {
669 hilet c =
static_cast<uint8_t
>(*ptr);
671 if (c == BON8_code_eot) {
676 }
else if (c <= 0x7f) {
678 str +=
static_cast<char>(*(ptr++));
681 }
else if (c >= 0xc2 && c <= 0xf7) {
682 hilet count = BON8_multibyte_count(ptr, last);
685 for (
int i = 0; i !=
count; ++i) {
686 str +=
static_cast<char>(*(ptr++));
690 }
else if (not str.
empty()) {
696 return datum{decode_BON8_UTF8_like_int(ptr, last, -count)};
699 }
else if (not str.
empty()) {
708 return datum{
nullptr};
709 case BON8_code_bool_false:
711 case BON8_code_bool_true:
713 case BON8_code_float_min_one:
715 case BON8_code_float_zero:
717 case BON8_code_float_one:
719 case BON8_code_int32:
720 return decode_BON8_int(ptr, last, 4);
721 case BON8_code_int64:
722 return decode_BON8_int(ptr, last, 8);
723 case BON8_code_binary32:
724 return decode_BON8_float(ptr, last, 4);
725 case BON8_code_binary64:
726 return decode_BON8_float(ptr, last, 8);
727 case BON8_code_array_count0:
728 return datum::make_vector();
729 case BON8_code_array_count1:
730 return decode_BON8_array(ptr, last, 1);
731 case BON8_code_array_count2:
732 return decode_BON8_array(ptr, last, 2);
733 case BON8_code_array_count3:
734 return decode_BON8_array(ptr, last, 3);
735 case BON8_code_array_count4:
736 return decode_BON8_array(ptr, last, 4);
737 case BON8_code_array:
738 return decode_BON8_array(ptr, last);
739 case BON8_code_object_count0:
740 return datum::make_map();
741 case BON8_code_object_count1:
742 return decode_BON8_object(ptr, last, 1);
743 case BON8_code_object_count2:
744 return decode_BON8_object(ptr, last, 2);
745 case BON8_code_object_count3:
746 return decode_BON8_object(ptr, last, 3);
747 case BON8_code_object_count4:
748 return decode_BON8_object(ptr, last, 4);
749 case BON8_code_object:
750 return decode_BON8_object(ptr, last);
752 throw parse_error(
"Unexpected end-of-container");
754 throw parse_error(
"Unexpected end-of-text");
757 if (c >= BON8_code_positive_s and c <= BON8_code_positive_e) {
758 return datum{
c - BON8_code_positive_s};
760 }
else if (c >= BON8_code_negative_s and c <= BON8_code_negative_e) {
761 return datum{~truncate<int>(c - BON8_code_negative_s)};
769 throw parse_error(
"Unexpected end-of-buffer");
777[[nodiscard]]
datum decode_BON8(std::span<const std::byte> buffer)
779 auto *ptr = buffer.data();
780 auto *last = ptr + buffer.size();
781 return detail::decode_BON8(ptr, last);
790 auto *ptr = buffer.
data();
791 auto *last = ptr + buffer.
size();
792 return detail::decode_BON8(ptr, last);
799[[nodiscard]]
datum decode_BON8(bstring_view buffer)
801 auto *ptr = buffer.data();
802 auto *last = ptr + buffer.size();
803 return detail::decode_BON8(ptr, last);
814 return encoder.get();
#define hi_check(expression, message,...)
Check if the expression is valid, or throw a parse_error.
Definition assert.hpp:95
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:184
#define hi_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:264
#define hi_assert_not_null(x,...)
Assert if an expression is not nullptr.
Definition assert.hpp:223
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
@ m
Mirror but not bracket.
BON8 encoder.
Definition BON8.hpp:63
void add(std::string const &value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:347
void add(double value) noexcept
Add a floating point number.
Definition BON8.hpp:232
void add(float value) noexcept
Add a floating point number.
Definition BON8.hpp:272
void add(unsigned long long value) noexcept
And a unsigned integer.
Definition BON8.hpp:160
void add(nullptr_t value) noexcept
Add a null.
Definition BON8.hpp:289
void add(bool value) noexcept
Add a boolean.
Definition BON8.hpp:280
void add(signed long value) noexcept
And a signed integer.
Definition BON8.hpp:168
void add(signed int value) noexcept
And a signed integer.
Definition BON8.hpp:184
void add(signed short value) noexcept
And a signed integer.
Definition BON8.hpp:200
void add(std::vector< T > const &items)
Add a vector of values of the same type.
Definition BON8.hpp:372
void add(unsigned int value) noexcept
And a unsigned integer.
Definition BON8.hpp:192
void add(unsigned long value) noexcept
And a unsigned integer.
Definition BON8.hpp:176
void add(char const *value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:357
void add(signed char value) noexcept
And a signed integer.
Definition BON8.hpp:216
void add(signed long long value) noexcept
And a signed integer.
Definition BON8.hpp:84
bstring const & get() noexcept
Return a byte_string of the encoded object.
Definition BON8.hpp:72
void add(unsigned short value) noexcept
And a unsigned integer.
Definition BON8.hpp:208
void add(unsigned char value) noexcept
And a unsigned integer.
Definition BON8.hpp:224
void add(std::string_view value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:300
void add(std::map< Key, Value > const &items)
Add a map of key/values pairs.
Definition BON8.hpp:397
A dynamic data type.
Definition datum.hpp:219