6#include "TTauri/Foundation/exceptions.hpp"
7#include "TTauri/Foundation/URL.hpp"
8#include "TTauri/Foundation/memory.hpp"
9#include "TTauri/Foundation/vec.hpp"
13#include <unordered_map>
17enum class pickle_type_t {
32constexpr uint8_t PICKLE_SMALL_NATURAL_MIN = 0x00;
33constexpr uint8_t PICKLE_SMALL_NATURAL_MAX = 0x3f;
35constexpr uint8_t PICKLE_SMALL_STRING_MIN = 0xc0;
36constexpr uint8_t PICKLE_SMALL_STRING_MAX = 0xdf;
38constexpr uint8_t PICKLE_END_MARK = 0xff;
39constexpr uint8_t PICKLE_NULL = 0xfe;
40constexpr uint8_t PICKLE_TRUE = 0xfd;
41constexpr uint8_t PICKLE_FALSE = 0xfc;
42constexpr uint8_t PICKLE_STRING = 0xfb;
43constexpr uint8_t PICKLE_OBJECT = 0xfa;
44constexpr uint8_t PICKLE_MAP = 0xf9;
45constexpr uint8_t PICKLE_VECTOR = 0xf8;
46constexpr uint8_t PICKLE_DOUBLE = 0xf7;
47constexpr uint8_t PICKLE_VEC = 0xf6;
48constexpr uint8_t PICKLE_URL = 0xf5;
50constexpr uint8_t PICKLE_RESERVED_MIN = 0x40;
51constexpr uint8_t PICKLE_RESERVED_MAX = 0xf4;
53template<
typename Iter>
54inline pickle_type_t pickle_type(Iter &i, Iter
const &end)
57 TTAURI_THROW(parse_error(
"End of stream"));
60 switch (ttlet c_ =
static_cast<uint8_t
>(*i)) {
61 case PICKLE_END_MARK:
return pickle_type_t::EndMark;
62 case PICKLE_NULL:
return pickle_type_t::Null;
63 case PICKLE_TRUE:
return pickle_type_t::Boolean;
64 case PICKLE_FALSE:
return pickle_type_t::Boolean;
65 case PICKLE_STRING:
return pickle_type_t::String;
66 case PICKLE_OBJECT:
return pickle_type_t::Object;
67 case PICKLE_MAP:
return pickle_type_t::Map;
68 case PICKLE_VECTOR:
return pickle_type_t::Vector;
69 case PICKLE_DOUBLE:
return pickle_type_t::Double;
70 case PICKLE_VEC:
return pickle_type_t::Vec;
71 case PICKLE_URL:
return pickle_type_t::URL;
73 if (c_ >= PICKLE_SMALL_STRING_MIN && c_ <= PICKLE_SMALL_STRING_MAX) {
74 return pickle_type_t::String;
75 }
else if (c_ >= PICKLE_RESERVED_MIN && c_ <= PICKLE_RESERVED_MAX) {
76 return pickle_type_t::Reserved;
78 return pickle_type_t::Integer;
83template<
typename R,
typename Iter>
84inline R unpickle(Iter &&i, Iter &&end)
89template<
typename Iter>
90inline long long unpickle(Iter &i, Iter
const &end)
93 switch (pickle_type(i, end)) {
94 case pickle_type_t::Null:
98 case pickle_type_t::Boolean:
99 return (
static_cast<uint8_t
>(*(i++)) == PICKLE_TRUE) ? 1 : 0;
101 case pickle_type_t::Double:
102 return numeric_cast<int64_t>(unpickle<double>(i, end));
104 case pickle_type_t::Integer:
108 TTAURI_THROW(parse_error(
"Unexpected type in stream."));
113 uint64_t u64value = 0;
120 u64value |= (c & 0x7f);
128 tt_assert(nr_bits < 64);
129 size_t sign_extent_shift = 64 - nr_bits;
130 u64value <<= sign_extent_shift;
132 auto i64value = bit_cast<int64_t>(u64value);
133 return i64value >> sign_extent_shift;
136template<
typename Iter>
137inline unsigned long long unpickle(Iter &i, Iter
const &end)
140 switch (pickle_type(i, end)) {
141 case pickle_type_t::Null:
145 case pickle_type_t::Boolean:
146 return (
static_cast<uint8_t
>(*(i++)) == PICKLE_TRUE) ? 1 : 0;
148 case pickle_type_t::Double:
149 return numeric_cast<uint64_t>(unpickle<double>(i, end));
151 case pickle_type_t::Integer:
155 TTAURI_THROW(parse_error(
"Unexpected type in stream."));
160 uint64_t u64value = 0;
167 u64value |= (c & 0x7f);
174template<
typename Iter>
175inline double unpickle(Iter &i, Iter
const &end)
178 switch (pickle_type(i, end)) {
179 case pickle_type_t::Null:
183 case pickle_type_t::Boolean:
184 return (
static_cast<uint8_t
>(*(i++)) == PICKLE_TRUE) ? 1.0 : 0.0;
186 case pickle_type_t::Double:
189 case pickle_type_t::Integer:
190 return numeric_cast<double>(unpickle<int64_t>(i, end));
193 TTAURI_THROW(parse_error(
"Unexpected type in stream."));
199 uint64_t u64value = 0;
200 if ((end - i) <
sizeof(u64value)) {
201 TTAURI_THROW(parse_error(
"End of stream"));
204 for (
size_t j = 0; j <
sizeof(u64value); j++) {
206 u64value |=
static_cast<uint8_t
>(*(i++));
209 return bit_cast<double>(u64value);
212template<
typename Iter>
inline unsigned long unpickle(Iter &i, Iter
const &end) {
return numeric_cast<unsigned long>(unpickle<unsigned long long>(i, end)); }
213template<
typename Iter>
inline unsigned int unpickle(Iter &i, Iter
const &end) {
return numeric_cast<unsigned int>(unpickle<unsigned long long>(i, end)); }
214template<
typename Iter>
inline unsigned short unpickle(Iter &i, Iter
const &end) {
return numeric_cast<unsigned short>(unpickle<unsigned long long>(i, end)); }
215template<
typename Iter>
inline unsigned char unpickle(Iter &i, Iter
const &end) {
return numeric_cast<unsigned char>(unpickle<unsigned long long>(i, end)); }
217template<
typename Iter>
inline signed long unpickle(Iter &i, Iter
const &end) {
return numeric_cast<signed long>(unpickle<signed long long>(i, end)); }
218template<
typename Iter>
inline signed int unpickle(Iter &i, Iter
const &end) {
return numeric_cast<signed int>(unpickle<signed long long>(i, end)); }
219template<
typename Iter>
inline signed short unpickle(Iter &i, Iter
const &end) {
return numeric_cast<signed short>(unpickle<signed long long>(i, end)); }
220template<
typename Iter>
inline signed char unpickle(Iter &i, Iter
const &end) {
return numeric_cast<signed char>(unpickle<signed long long>(i, end)); }
222template<
typename Iter>
inline float unpickle(Iter &i, Iter
const &end) {
return numeric_cast<float>(unpickle<double>(i, end)); }
224template<
typename Iter>
225inline std::string unpickle(Iter &i, Iter
const &end)
228 switch (pickle_type(i, end)) {
229 case pickle_type_t::String:
231 case pickle_type_t::URL:
234 TTAURI_THROW(parse_error(
"Unexpected type in stream."));
238 size_t stringLength = 0;
239 ttlet c =
static_cast<uint8_t
>(*i);
240 if (c == PICKLE_STRING || c == PICKLE_URL) {
242 stringLength = unpickle<size_t>(i, end);
244 stringLength = c - PICKLE_SMALL_STRING_MIN;
247 ttlet beginOfString = i;
248 ttlet endOfString = beginOfString + stringLength;
249 if (end - i < stringLength) {
250 TTAURI_THROW(parse_error(
"End of stream"));
254 return {beginOfString, endOfString};
257template<
typename Iter>
258inline URL unpickle(Iter &i, Iter
const &end)
260 return URL{unpickle<std::string>(i, end)};
263template<
typename Iter>
264inline bool unpickle(Iter &i, Iter
const &end)
266 switch (pickle_type(i, end)) {
267 case pickle_type_t::Null:
271 case pickle_type_t::Boolean:
272 return static_cast<uint8_t
>(*(i++)) == PICKLE_TRUE;
274 case pickle_type_t::Double:
275 return unpickle<double>(i, end) > 0.0;
277 case pickle_type_t::Integer:
278 return unpickle<int64_t>(i, end) > 0;
281 TTAURI_THROW(parse_error(
"Unexpected type in stream."));
285template<
typename T,
typename Iter>
288 switch (pickle_type(i, end)) {
289 case pickle_type_t::Vector: {
293 while (pickle_type(i, end) != pickle_type_t::EndMark) {
302 TTAURI_THROW(parse_error(
"Unexpected type in stream."));
306template<
typename K,
typename T,
typename Iter>
309 switch (pickle_type(i, end)) {
310 case pickle_type_t::Vector: {
314 while (pickle_type(i, end) != pickle_type_t::EndMark) {
315 r.
emplace(unpickle<K>(i, end), unpickle<T>(i, end));
323 TTAURI_THROW(parse_error(
"Unexpected type in stream."));
327template<
typename K,
typename T,
typename Iter>
330 switch (pickle_type(i, end)) {
331 case pickle_type_t::Vector: {
335 while (pickle_type(i, end) != pickle_type_t::EndMark) {
336 r.
emplace(unpickle<K>(i, end), unpickle<T>(i, end));
344 TTAURI_THROW(parse_error(
"Unexpected type in stream."));
351 return unpickle<R>(stream.
begin(), stream.
end());
354inline void pickleAppend(
std::string &lhs,
bool rhs)
noexcept
356 lhs.push_back(rhs ? PICKLE_TRUE : PICKLE_FALSE);
361 lhs.push_back(PICKLE_NULL);
364inline void pickleAppend(
std::string &lhs,
double rhs)
noexcept
366 lhs.push_back(PICKLE_DOUBLE);
368 auto u64rhs = bit_cast<uint64_t>(rhs);
369 for (
size_t i = 0; i <
sizeof(u64rhs); i++) {
370 lhs.push_back(
static_cast<char>(u64rhs & 0xff));
375inline void pickleAppend(
std::string &lhs,
unsigned long long rhs)
noexcept
378 uint8_t
const last_value = rhs & 0x7f;
381 if (rhs == 0 && last_value < 0x40) {
384 lhs.push_back(last_value | 0x80);
387 lhs.push_back(last_value);
398inline void pickleAppend(
std::string &lhs,
signed long long rhs)
noexcept
401 return pickleAppend(lhs,
static_cast<uint64_t
>(rhs));
404 lhs.push_back(rhs & 0x7f);
408 uint8_t
const last_value = rhs & 0x7f;
411 if (rhs == -1 && last_value >= 0x40) {
414 lhs.push_back(last_value | 0x80);
417 lhs.push_back(last_value);
422inline void pickleAppend(
std::string &lhs,
unsigned long rhs)
noexcept {
return pickleAppend(lhs,
static_cast<unsigned long long>(rhs)); }
423inline void pickleAppend(
std::string &lhs,
unsigned int rhs)
noexcept {
return pickleAppend(lhs,
static_cast<unsigned long long>(rhs)); }
424inline void pickleAppend(
std::string &lhs,
unsigned short rhs)
noexcept {
return pickleAppend(lhs,
static_cast<unsigned long long>(rhs)); }
425inline void pickleAppend(
std::string &lhs,
unsigned char rhs)
noexcept {
return pickleAppend(lhs,
static_cast<unsigned long long>(rhs)); }
427inline void pickleAppend(
std::string &lhs,
signed long rhs)
noexcept {
return pickleAppend(lhs,
static_cast<signed long long>(rhs)); }
428inline void pickleAppend(
std::string &lhs,
signed int rhs)
noexcept {
return pickleAppend(lhs,
static_cast<signed long long>(rhs)); }
429inline void pickleAppend(
std::string &lhs,
signed short rhs)
noexcept {
return pickleAppend(lhs,
static_cast<signed long long>(rhs)); }
430inline void pickleAppend(
std::string &lhs,
signed char rhs)
noexcept {
return pickleAppend(lhs,
static_cast<signed long long>(rhs)); }
432inline void pickleAppend(
std::string &lhs,
void *rhs)
noexcept {
return pickleAppend(lhs,
reinterpret_cast<size_t>(rhs)); }
434inline void pickleAppend(
std::string &lhs, URL
const &rhs)
noexcept
438 lhs.push_back(PICKLE_URL);
439 pickleAppend(lhs, s.size());
445inline void pickleAppend(
std::string &lhs, std::string_view
const &rhs)
noexcept
447 if (rhs.size() <= 0x1f) {
448 lhs.push_back(
static_cast<uint8_t
>(rhs.size()) | PICKLE_SMALL_STRING_MIN);
450 lhs.push_back(PICKLE_STRING);
451 pickleAppend(lhs, rhs.size());
457inline void pickleAppend(
std::string &lhs,
char const rhs[])
noexcept
459 return pickleAppend(lhs, std::string_view(rhs));
464 return pickleAppend(lhs, std::string_view(rhs));
467inline void pickleAppend(
std::string &lhs, vec
const &rhs)
noexcept
469 lhs.push_back(PICKLE_VEC);
471 pickleAppend(lhs, rhs.x());
472 pickleAppend(lhs, rhs.y());
473 if (rhs.z() != 0.0 || rhs.w() != 0.0) {
474 pickleAppend(lhs, rhs.z());
476 if (rhs.w() != 0.0) {
477 pickleAppend(lhs, rhs.w());
480 lhs.push_back(PICKLE_END_MARK);
486 lhs.push_back(PICKLE_VECTOR);
488 for (ttlet &
item: rhs) {
489 pickleAppend(lhs,
item);
492 lhs.push_back(PICKLE_END_MARK);
495template<
typename K,
typename V>
498 lhs.push_back(PICKLE_MAP);
500 for (ttlet &
item: rhs) {
501 pickleAppend(lhs,
item->first);
502 pickleAppend(lhs,
item->second);
505 lhs.push_back(PICKLE_END_MARK);
508template<
typename K,
typename V>
511 lhs.push_back(PICKLE_MAP);
513 for (ttlet &
item: rhs) {
514 pickleAppend(lhs,
item->first);
515 pickleAppend(lhs,
item->second);
518 lhs.push_back(PICKLE_END_MARK);
521template<
typename T,
typename U,
typename... Args>
522inline void pickleAppend(
std::string& dst, T&& firstArg, U&& secondArg, Args&&... args)
noexcept
524 pickleAppend(dst, firstArg);
525 pickleAppend(dst, secondArg);
527 if constexpr (
sizeof...(args) > 0) {
528 pickleAppend(dst, args...);
532template<
typename... Args>
533inline void clearAndPickleAppend(
std::string &dst, Args&&... args)
noexcept
536 pickleAppend(dst, args...);
539template<
typename... Args>
540[[nodiscard]]
inline std::string pickle(Args&&... args)
noexcept
543 pickleAppend(dst, args...);
Definition range_map.hpp:119