7#include "../byte_string.hpp"
10#include "../exception.hpp"
15namespace hi::inline
v1 {
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};
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};
54[[nodiscard]] datum decode_BON8(cbyteptr &ptr, cbyteptr last);
56[[nodiscard]] bstring encode_BON8(datum
const &value);
65 BON8_encoder() noexcept : open_string(
false), output() {}
72 output +=
static_cast<std::byte
>(BON8_code_eot);
81 void add(
signed long long value)
noexcept
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));
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));
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);
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);
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));
115 }
else if (value <= -1) {
116 value = -(value + 1);
117 output +=
static_cast<std::byte
>(BON8_code_negative_s + value);
119 }
else if (value <= 39) {
120 output +=
static_cast<std::byte
>(BON8_code_positive_s + value);
122 }
else if (value <= 3879) {
124 output +=
static_cast<std::byte
>(0xc2 + (value >> 7 & 0x1f));
125 output +=
static_cast<std::byte
>(value & 0x7f);
127 }
else if (value <= 528167) {
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);
133 }
else if (value <= 67637031) {
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);
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));
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));
157 void add(
unsigned long long value)
noexcept
159 return add(narrow_cast<signed long long>(value));
165 void add(
signed long value)
noexcept
167 return add(narrow_cast<signed long long>(value));
173 void add(
unsigned long value)
noexcept
175 return add(narrow_cast<signed long long>(value));
181 void add(
signed int value)
noexcept
183 return add(narrow_cast<signed long long>(value));
189 void add(
unsigned int value)
noexcept
191 return add(narrow_cast<signed long long>(value));
197 void add(
signed short value)
noexcept
199 return add(narrow_cast<signed long long>(value));
205 void add(
unsigned short value)
noexcept
207 return add(narrow_cast<signed long long>(value));
213 void add(
signed char value)
noexcept
215 return add(narrow_cast<signed long long>(value));
221 void add(
unsigned char value)
noexcept
223 return add(narrow_cast<signed long long>(value));
229 void add(
double value)
noexcept
233 hilet f32 =
static_cast<float>(value);
234 hilet f32_64 =
static_cast<double>(f32);
237 output +=
static_cast<std::byte
>(BON8_code_float_min_one);
240 output +=
static_cast<std::byte
>(BON8_code_float_zero);
242 }
else if (value == 1.0) {
243 output +=
static_cast<std::byte
>(BON8_code_float_one);
245 }
else if (f32_64 == value) {
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));
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));
269 void add(
float value)
noexcept
271 return add(
static_cast<double>(value));
277 void add(
bool value)
noexcept
280 output +=
static_cast<std::byte
>(value ? BON8_code_bool_true : BON8_code_bool_false);
286 void add(nullptr_t value)
noexcept
289 output +=
static_cast<std::byte
>(BON8_code_null);
297 void add(std::string_view value)
noexcept
300 output +=
static_cast<std::byte
>(BON8_code_eot);
304 output +=
static_cast<std::byte
>(BON8_code_eot);
310 for (
hilet _c : value) {
311 hilet c = truncate<uint8_t>(_c);
314 if (multi_byte == 0) {
315 if (
c >= 0xc2 and
c <= 0xdf) {
317 }
else if (
c >= 0xe0 and
c <= 0xef) {
319 }
else if (
c >= 0xf0 and
c <= 0xf7) {
322 hi_assert(
c <= 0x7f);
326 hi_assert(
c >= 0x80 and
c <= 0xbf);
331 output +=
static_cast<std::byte
>(
c);
333 hi_axiom(multi_byte == 0);
346 add(std::string_view{value});
354 void add(
char const *value)
noexcept
356 add(std::string_view{value});
362 void add(
datum const &value);
372 if (size(items) <= 4) {
373 output +=
static_cast<std::byte
>(BON8_code_array_count0 + size(items));
375 output +=
static_cast<std::byte
>(BON8_code_array);
378 for (
hilet &item : items) {
382 if (size(items) > 4) {
383 output +=
static_cast<std::byte
>(BON8_code_eoc);
393 template<
typename Key,
typename Value>
396 using key_type =
typename std::remove_cvref_t<
decltype(items)>::key_type;
399 if (size(items) <= 4) {
400 output +=
static_cast<std::byte
>(BON8_code_object_count0 + size(items));
402 output +=
static_cast<std::byte
>(BON8_code_object);
405 for (
hilet &item : items) {
406 if (
auto *s = get_if<std::string>(item.first)) {
409 throw operation_error(
"BON8 object keys must be strings");
414 if (size(items) > 4) {
415 output +=
static_cast<std::byte
>(BON8_code_eoc);
421void BON8_encoder::add(
datum const &value)
423 if (
auto s = get_if<std::string>(value)) {
425 }
else if (
auto u = get_if<URL>(value)) {
427 }
else if (
auto b = get_if<bool>(value)) {
429 }
else if (holds_alternative<nullptr_t>(value)) {
431 }
else if (
auto i = get_if<long long>(value)) {
433 }
else if (
auto f = get_if<double>(value)) {
435 }
else if (
auto v = get_if<datum::vector_type>(value)) {
437 }
else if (
auto m = get_if<datum::map_type>(value)) {
440 throw operation_error(
"Datum value can not be encoded to BON8");
452[[nodiscard]]
int BON8_multibyte_count(cbyteptr ptr, cbyteptr last)
454 hi_axiom(ptr !=
nullptr);
455 hi_axiom(last !=
nullptr);
457 hilet c0 =
static_cast<uint8_t
>(*ptr);
458 hilet count = c0 <= 0xdf ? 2 : c0 <= 0xef ? 3 : 4;
460 hi_parse_check(ptr + count <= last,
"Incomplete Multi-byte character at end of buffer");
462 hilet c1 =
static_cast<uint8_t
>(*(ptr + 1));
463 return (c1 < 0x80 or c1 > 0xbf) ? -count : count;
474[[nodiscard]]
datum decode_BON8_int(cbyteptr &ptr, cbyteptr last,
int count)
476 hi_axiom(ptr !=
nullptr);
477 hi_axiom(last !=
nullptr);
478 hi_axiom(count == 4 || count == 8);
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");
484 u64 |=
static_cast<uint64_t
>(*(ptr++));
488 hilet u32 = truncate<uint32_t>(u64);
489 hilet i32 = truncate<int32_t>(u32);
492 hilet i64 = truncate<int64_t>(u64);
497[[nodiscard]] datum decode_BON8_float(cbyteptr &ptr, cbyteptr last,
int count)
499 hi_axiom(ptr !=
nullptr);
500 hi_axiom(last !=
nullptr);
501 hi_axiom(count == 4 || count == 8);
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");
507 u64 |=
static_cast<uint64_t
>(*(ptr++));
511 hilet u32 = truncate<uint32_t>(u64);
523[[nodiscard]] datum decode_BON8_array(cbyteptr &ptr, cbyteptr last)
525 hi_axiom(ptr !=
nullptr);
526 hi_axiom(last !=
nullptr);
528 auto r = datum::make_vector();
529 auto &vector = get<datum::vector_type>(r);
531 while (ptr != last) {
532 if (*ptr ==
static_cast<std::byte
>(BON8_code_eoc)) {
537 vector.push_back(decode_BON8(ptr, last));
540 throw parse_error(
"Incomplete array at end of buffer");
543[[nodiscard]] datum decode_BON8_array(cbyteptr &ptr, cbyteptr last,
std::size_t count)
545 auto r = datum::make_vector();
546 auto &vector = get<datum::vector_type>(r);
549 vector.push_back(decode_BON8(ptr, last));
554[[nodiscard]] datum decode_BON8_object(cbyteptr &ptr, cbyteptr last)
556 hi_axiom(ptr !=
nullptr);
557 hi_axiom(last !=
nullptr);
559 auto r = datum::make_map();
560 auto &map = get<datum::map_type>(r);
562 while (ptr != last) {
563 if (*ptr ==
static_cast<std::byte
>(BON8_code_eoc)) {
568 auto key = decode_BON8(ptr, last);
569 hi_parse_check(holds_alternative<std::string>(key),
"Key in object is not a string");
571 auto value = decode_BON8(ptr, last);
575 throw parse_error(
"Incomplete object at end of buffer");
578[[nodiscard]] datum decode_BON8_object(cbyteptr &ptr, cbyteptr last,
std::size_t count)
580 auto r = datum::make_map();
581 auto &map = get<datum::map_type>(r);
584 auto key = decode_BON8(ptr, last);
585 hi_parse_check(holds_alternative<std::string>(key),
"Key in object is not a string");
587 auto value = decode_BON8(ptr, last);
593[[nodiscard]]
long long decode_BON8_UTF8_like_int(cbyteptr &ptr, cbyteptr last,
int count)
noexcept
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++));
602 auto value =
static_cast<long long>(c0 & mask);
609 hi_axiom(ptr != last);
610 hilet c1 =
static_cast<uint8_t
>(*(ptr++));
611 hilet is_positive = c1 <= 0x7f;
614 value |=
static_cast<long long>(c1);
617 value |=
static_cast<long long>(c1 & 0b0011'1111);
622 hi_axiom(ptr != last);
624 value |=
static_cast<int>(*(ptr++));
627 hi_axiom(ptr != last);
629 value |=
static_cast<int>(*(ptr++));
636 case 2:
return value + 40;
637 case 3:
return value + 3880;
638 case 4:
return value + 528168;
639 default: hi_no_default();
644 case 2:
return -(value + 11);
645 case 3:
return -(value + 1931);
646 case 4:
return -(value + 264075);
647 default: hi_no_default();
652[[nodiscard]] datum decode_BON8(cbyteptr &ptr, cbyteptr last)
654 hi_axiom(ptr !=
nullptr);
655 hi_axiom(last !=
nullptr);
659 while (ptr != last) {
660 hilet c =
static_cast<uint8_t
>(*ptr);
662 if (c == BON8_code_eot) {
667 }
else if (c <= 0x7f) {
669 str +=
static_cast<char>(*(ptr++));
672 }
else if (c >= 0xc2 && c <= 0xf7) {
673 hilet count = BON8_multibyte_count(ptr, last);
676 for (
int i = 0; i !=
count; ++i) {
677 str +=
static_cast<char>(*(ptr++));
681 }
else if (not str.
empty()) {
687 return datum{decode_BON8_UTF8_like_int(ptr, last, -count)};
690 }
else if (not str.
empty()) {
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");
724 if (c >= BON8_code_positive_s and c <= BON8_code_positive_e) {
725 return datum{
c - BON8_code_positive_s};
727 }
else if (c >= BON8_code_negative_s and c <= BON8_code_negative_e) {
728 return datum{~truncate<int>(c - BON8_code_negative_s)};
736 throw parse_error(
"Unexpected end-of-buffer");
744[[nodiscard]]
datum decode_BON8(std::span<const std::byte> buffer)
746 auto *ptr = buffer.data();
747 auto *last = ptr + buffer.size();
748 return detail::decode_BON8(ptr, last);
757 auto *ptr = buffer.
data();
758 auto *last = ptr + buffer.
size();
759 return detail::decode_BON8(ptr, last);
766[[nodiscard]]
datum decode_BON8(bstring_view buffer)
768 auto *ptr = buffer.data();
769 auto *last = ptr + buffer.size();
770 return detail::decode_BON8(ptr, last);
781 return encoder.get();
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