5#include "../byte_string.hpp"
6#include "../required.hpp"
8#include "../exception.hpp"
16constexpr auto BON8_code_float_min_one = uint8_t{0xba};
17constexpr auto BON8_code_float_zero = uint8_t{0xbb};
18constexpr auto BON8_code_float_one = uint8_t{0xbc};
19constexpr auto BON8_code_array_empty = uint8_t{0xbd};
20constexpr auto BON8_code_object_empty = uint8_t{0xbe};
21constexpr auto BON8_code_null = uint8_t{0xbf};
22constexpr auto BON8_code_bool_false = uint8_t{0xc0};
23constexpr auto BON8_code_bool_true = uint8_t{0xc1};
24constexpr auto BON8_code_int32 = uint8_t{0xf8};
25constexpr auto BON8_code_int64 = uint8_t{0xf9};
26constexpr auto BON8_code_binary32 = uint8_t{0xfa};
27constexpr auto BON8_code_binary64 = uint8_t{0xfb};
28constexpr auto BON8_code_array = uint8_t{0xfc};
29constexpr auto BON8_code_object = uint8_t{0xfd};
30constexpr auto BON8_code_eoc = uint8_t{0xfe};
31constexpr auto BON8_code_eot = uint8_t{0xff};
39[[nodiscard]] datum decode_BON8(cbyteptr &ptr, cbyteptr last);
41[[nodiscard]] bstring encode_BON8(datum
const &value);
52 open_string(
false), output() {}
63 void add(
signed long long value)
noexcept {
67 output +=
static_cast<std::byte
>(BON8_code_int64);
68 for (
int i = 0; i != 8; ++i) {
69 output +=
static_cast<std::byte
>(value >> (56 - i*8));
72 }
else if (value < -33554432) {
73 output +=
static_cast<std::byte
>(BON8_code_int32);
74 for (
int i = 0; i != 4; ++i) {
75 output +=
static_cast<std::byte
>(value >> (24 - i*8));
78 }
else if (value < -262144) {
80 output +=
static_cast<std::byte
>(0xf0 + (value >> 22 & 0x07));
81 output +=
static_cast<std::byte
>(0xc0 + (value >> 16 & 0x3f));
82 output +=
static_cast<std::byte
>(value >> 8);
83 output +=
static_cast<std::byte
>(value);
85 }
else if (value < -1920) {
87 output +=
static_cast<std::byte
>(0xe0 + (value >> 14 & 0x0f));
88 output +=
static_cast<std::byte
>(0xc0 + (value >> 8 & 0x3f));
89 output +=
static_cast<std::byte
>(value);
91 }
else if (value < -10) {
93 output +=
static_cast<std::byte
>(0xc2 + (value >> 6 & 0x1f));
94 output +=
static_cast<std::byte
>(0xc0 + (value & 0x3f));
96 }
else if (value < 0) {
98 output +=
static_cast<std::byte
>(0xb0 + value);
100 }
else if (value <= 47) {
101 output +=
static_cast<std::byte
>(0x80 + value);
103 }
else if (value <= 3839) {
104 output +=
static_cast<std::byte
>(0xc2 + (value >> 7 & 0x1f));
105 output +=
static_cast<std::byte
>(value & 0x7f);
107 }
else if (value <= 524287) {
108 output +=
static_cast<std::byte
>(0xe0 + (value >> 15 & 0x0f));
109 output +=
static_cast<std::byte
>(value >> 8 & 0x7f);
110 output +=
static_cast<std::byte
>(value);
112 }
else if (value <= 67108863) {
113 output +=
static_cast<std::byte
>(0xf0 + (value >> 23 & 0x17));
114 output +=
static_cast<std::byte
>(value >> 16 & 0x7f);
115 output +=
static_cast<std::byte
>(value >> 8);
116 output +=
static_cast<std::byte
>(value);
119 output +=
static_cast<std::byte
>(BON8_code_int32);
120 for (
int i = 0; i != 4; ++i) {
121 output +=
static_cast<std::byte
>(value >> (24 - i*8));
125 output +=
static_cast<std::byte
>(BON8_code_int64);
126 for (
int i = 0; i != 8; ++i) {
127 output +=
static_cast<std::byte
>(value >> (56 - i*8));
135 void add(
unsigned long long value)
noexcept {
136 return add(narrow_cast<signed long long>(value));
142 void add(
signed long value)
noexcept {
143 return add(narrow_cast<signed long long>(value));
149 void add(
unsigned long value)
noexcept {
150 return add(narrow_cast<signed long long>(value));
156 void add(
signed int value)
noexcept {
157 return add(narrow_cast<signed long long>(value));
163 void add(
unsigned int value)
noexcept {
164 return add(narrow_cast<signed long long>(value));
170 void add(
signed short value)
noexcept {
171 return add(narrow_cast<signed long long>(value));
177 void add(
unsigned short value)
noexcept {
178 return add(narrow_cast<signed long long>(value));
184 void add(
signed char value)
noexcept {
185 return add(narrow_cast<signed long long>(value));
191 void add(
unsigned char value)
noexcept {
192 return add(narrow_cast<signed long long>(value));
198 void add(
double value)
noexcept {
201 ttlet f32 =
static_cast<float>(value);
202 ttlet f32_64 =
static_cast<double>(f32);
205 output +=
static_cast<std::byte
>(BON8_code_float_min_one);
207 }
else if (value == 0.0 || value == -0.0) {
208 output +=
static_cast<std::byte
>(BON8_code_float_zero);
210 }
else if (value == 1.0) {
211 output +=
static_cast<std::byte
>(BON8_code_float_one);
213 }
else if (f32_64 == value) {
217 output +=
static_cast<std::byte
>(BON8_code_binary32);
218 for (
int i = 0; i != 4; ++i) {
219 output +=
static_cast<std::byte
>(u32 >> (24 - i*8));
226 output +=
static_cast<std::byte
>(BON8_code_binary64);
227 for (
int i = 0; i != 8; ++i) {
228 output +=
static_cast<std::byte
>(u64 >> (56 - i*8));
236 void add(
float value)
noexcept {
237 return add(narrow_cast<double>(value));
243 void add(
bool value)
noexcept {
245 output +=
static_cast<std::byte
>(value ? BON8_code_bool_true : BON8_code_bool_false);
251 void add(nullptr_t value)
noexcept {
253 output +=
static_cast<std::byte
>(BON8_code_null);
261 void add(std::u8string_view value)
noexcept {
263 output +=
static_cast<std::byte
>(BON8_code_eot);
266 if (std::ssize(value) == 0) {
267 output +=
static_cast<std::byte
>(BON8_code_eot);
273 for (ttlet _c : value) {
274 ttlet c =
static_cast<uint8_t
>(_c);
276 if constexpr (BuildType::current == BuildType::Debug) {
277 if (multi_byte == 0) {
278 if (c >= 0xc2 && c <= 0xdf) {
280 }
else if (c >= 0xe0 && c <= 0xef) {
282 }
else if (c >= 0xf0 && c <= 0xf7) {
285 tt_assert(c <= 0x7f);
289 tt_assert(c >= 0x80 && c <= 0xbf);
294 output +=
static_cast<std::byte
>(c);
297 tt_assert(multi_byte == 0);
308 void add(std::u8string
const &value)
noexcept {
309 return add(std::u8string_view{value});
317 void add(
char8_t const *value)
noexcept {
318 return add(std::u8string_view{value});
333 if (std::ssize(items) == 0) {
334 output +=
static_cast<std::byte
>(BON8_code_array_empty);
336 output +=
static_cast<std::byte
>(BON8_code_array);
338 for (ttlet &item: items) {
342 output +=
static_cast<std::byte
>(BON8_code_eoc);
352 template<
typename Key,
typename Value>
357 if (std::ssize(items) == 0) {
358 output +=
static_cast<std::byte
>(BON8_code_object_empty);
362 std::sort(sorted_items.begin(), sorted_items.end(), [](item_type
const &a, item_type
const &b) {
364 static_cast<std::u8string_view>(a.first) <
365 static_cast<std::u8string_view>(b.first);
368 output +=
static_cast<std::byte
>(BON8_code_object);
369 for (item_type
const &item: sorted_items) {
370 add(
static_cast<std::u8string_view
>(item.first));
373 output +=
static_cast<std::byte
>(BON8_code_eoc);
380 if (value.is_string() || value.is_url()) {
382 }
else if (value.is_bool()) {
383 add(
static_cast<bool>(value));
384 }
else if (value.is_null()) {
386 }
else if (value.is_integer()) {
387 add(
static_cast<signed long long>(value));
388 }
else if (value.is_float()) {
389 add(
static_cast<double>(value));
390 }
else if (value.is_vector()) {
392 }
else if (value.is_map()) {
407[[nodiscard]]
int BON8_multibyte_count(cbyteptr ptr, cbyteptr last) {
408 ttlet c0 =
static_cast<uint8_t
>(*ptr);
414 tt_parse_check(ptr + count <= last,
"Incomplete Multi-byte character at end of buffer");
416 ttlet c1 =
static_cast<uint8_t
>(*(ptr + 1));
417 return (c1 < 0x80 || c1 > 0xbf) ? -count : count;
428[[nodiscard]]
datum decode_BON8_int(cbyteptr &ptr, cbyteptr last,
int count)
430 tt_axiom(count == 4 || count == 8);
432 auto u64 = uint64_t{0};
433 for (
int i = 0; i != count; ++i) {
434 tt_parse_check(ptr != last,
"Incomplete signed integer at end of buffer");
436 u64 |=
static_cast<uint64_t
>(*(ptr++));
440 ttlet u32 =
static_cast<uint32_t
>(u64);
441 ttlet i32 =
static_cast<int32_t
>(u32);
444 ttlet i64 =
static_cast<int64_t
>(u64);
449[[nodiscard]] datum decode_BON8_float(cbyteptr &ptr, cbyteptr last,
int count)
451 tt_axiom(count == 4 || count == 8);
453 auto u64 = uint64_t{0};
454 for (
int i = 0; i !=
count; ++i) {
455 tt_parse_check(ptr != last,
"Incomplete signed integer at end of buffer");
457 u64 |=
static_cast<uint64_t
>(*(ptr++));
461 ttlet u32 =
static_cast<uint32_t
>(u64);
473[[nodiscard]] datum decode_BON8_array(cbyteptr &ptr, cbyteptr last)
475 auto r = datum::vector{};
477 while (ptr != last) {
478 if (*ptr ==
static_cast<std::byte
>(BON8_code_eoc)) {
483 r.push_back(decode_BON8(ptr, last));
486 throw parse_error(
"Incomplete array at end of buffer");
489[[nodiscard]] datum decode_BON8_object(cbyteptr &ptr, cbyteptr last)
491 auto r = datum::map{};
493 while (ptr != last) {
494 if (*ptr ==
static_cast<std::byte
>(BON8_code_eoc)) {
499 auto key = decode_BON8(ptr, last);
500 tt_parse_check(key.is_string(),
"Key in object is not a string");
502 auto value = decode_BON8(ptr, last);
506 throw parse_error(
"Incomplete array at end of buffer");
509[[nodiscard]] datum decode_BON8_UTF8_like_int(cbyteptr &ptr, cbyteptr last,
int count)
noexcept
511 tt_axiom(count >= 2 && count <= 4);
512 tt_axiom(ptr != last);
513 ttlet c0 =
static_cast<uint8_t
>(*(ptr++));
515 ttlet mask =
int{0b0111'1111} >>
count;
516 auto value =
static_cast<int>(c0) & mask;
521 tt_axiom(ptr != last);
522 ttlet c1 =
static_cast<uint8_t
>(*(ptr++));
523 ttlet is_positive = c1 <= 0x7f;
526 value |=
static_cast<int>(c1);
529 value |=
static_cast<int>(c1 & 0b0011'11111);
534 tt_axiom(ptr != last);
536 value |=
static_cast<int>(*(ptr++));
539 tt_axiom(ptr != last);
541 value |=
static_cast<int>(*(ptr++));
546 return datum{is_positive ? value : -value};
549[[nodiscard]] datum decode_BON8(cbyteptr &ptr, cbyteptr last) {
552 while (ptr != last) {
553 ttlet c =
static_cast<uint8_t
>(*ptr);
555 if (c == BON8_code_eot) {
560 }
else if (c <= 0x7f) {
562 str +=
static_cast<char>(*(ptr++));
565 }
else if (c >= 0xc2 && c <= 0xf7) {
566 ttlet
count = BON8_multibyte_count(ptr, last);
569 for (
int i = 0; i !=
count; ++i) {
570 str +=
static_cast<char>(*(ptr++));
574 }
else if (std::ssize(str) != 0) {
580 return decode_BON8_UTF8_like_int(ptr, last, -count);
583 }
else if (std::ssize(str) != 0) {
588 }
else if (c <= 0xaf) {
590 return datum{c - 0x80};
592 }
else if (c <= 0xb9) {
594 return datum{-
static_cast<int>(c - 0xb0)};
601 return datum{datum::null{}};
603 case BON8_code_bool_false:
607 case BON8_code_bool_true:
611 case BON8_code_float_min_one:
615 case BON8_code_float_zero:
619 case BON8_code_float_one:
623 case BON8_code_int32:
625 return decode_BON8_int(ptr, last, 4);
627 case BON8_code_int64:
629 return decode_BON8_int(ptr, last, 8);
631 case BON8_code_binary32:
633 return decode_BON8_float(ptr, last, 4);
635 case BON8_code_binary64:
637 return decode_BON8_float(ptr, last, 8);
640 throw parse_error(
"Unexpected end-of-container");
642 case BON8_code_array:
644 return decode_BON8_array(ptr, last);
646 case BON8_code_object:
648 return decode_BON8_object(ptr, last);
655 throw parse_error(
"Unexpected end-of-buffer");
663[[nodiscard]] datum decode_BON8(std::span<const std::byte> buffer)
665 auto *ptr = buffer.data();
666 auto *last = ptr + buffer.size();
667 return detail::decode_BON8(ptr, last);
674[[nodiscard]] datum decode_BON8(bstring
const &buffer)
676 auto *ptr = buffer.data();
677 auto *last = ptr + buffer.size();
678 return detail::decode_BON8(ptr, last);
685[[nodiscard]] datum decode_BON8(bstring_view buffer)
687 auto *ptr = buffer.data();
688 auto *last = ptr + buffer.size();
689 return detail::decode_BON8(ptr, last);
696[[nodiscard]] bstring encode_BON8(datum
const &value)
698 auto encoder = detail::BON8_encoder{};
700 return encoder.get();
BON8 encoder.
Definition BON8.hpp:46
void add(unsigned short value) noexcept
And a unsigned integer.
Definition BON8.hpp:177
void add(unsigned long long value) noexcept
And a unsigned integer.
Definition BON8.hpp:135
void add(unsigned char value) noexcept
And a unsigned integer.
Definition BON8.hpp:191
void add(double value) noexcept
Add a floating point number.
Definition BON8.hpp:198
void add(std::vector< T > const &items)
Add a vector of values of the same type.
Definition BON8.hpp:331
void add(signed int value) noexcept
And a signed integer.
Definition BON8.hpp:156
void add(unsigned long value) noexcept
And a unsigned integer.
Definition BON8.hpp:149
void add(unsigned int value) noexcept
And a unsigned integer.
Definition BON8.hpp:163
void add(signed short value) noexcept
And a signed integer.
Definition BON8.hpp:170
bstring const & get() const noexcept
Return a byte_string of the encoded object.
Definition BON8.hpp:56
void add(char8_t const *value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:317
void add(signed long value) noexcept
And a signed integer.
Definition BON8.hpp:142
void add(std::u8string_view value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:261
void add(float value) noexcept
Add a floating point number.
Definition BON8.hpp:236
void add(std::u8string const &value) noexcept
Add a UTF-8 string.
Definition BON8.hpp:308
void add(signed char value) noexcept
And a signed integer.
Definition BON8.hpp:184
void add(bool value) noexcept
Add a boolean.
Definition BON8.hpp:243
void add(nullptr_t value) noexcept
Add a null.
Definition BON8.hpp:251
void add(signed long long value) noexcept
And a signed integer.
Definition BON8.hpp:63
void add(std::map< Key, Value > const &items)
Add a map of key/values pairs.
Definition BON8.hpp:353
Exception thrown during execution of a dynamic operation.
Definition exception.hpp:37