HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
datum.hpp
1// Copyright 2019 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/required.hpp"
7#include "TTauri/Foundation/URL.hpp"
8#include "TTauri/Foundation/decimal.hpp"
9#include "TTauri/Foundation/memory.hpp"
10#include "TTauri/Foundation/type_traits.hpp"
11#include "TTauri/Foundation/throw_exception.hpp"
12#include "TTauri/Foundation/math.hpp"
13#include "TTauri/Foundation/algorithm.hpp"
14#include <date/date.h>
15#include <vector>
16#include <unordered_map>
17#include <memory>
18#include <cstring>
19#include <cstdint>
20#include <variant>
21#include <limits>
22#include <type_traits>
23#include <typeinfo>
24#include <ostream>
25#include <numeric>
26#include <string_view>
27#include <cmath>
28
29
30namespace tt {
31template<bool HasLargeObjects>
32class datum_impl;
33
34}
35
36namespace std {
37
38template<bool HasLargeObjects>
39class hash<tt::datum_impl<HasLargeObjects>> {
40public:
41 size_t operator()(tt::datum_impl<HasLargeObjects> const &value) const;
42};
43
44}
45
46namespace tt {
47
48enum class datum_type_t {
49 Null,
50 Undefined,
51 Break,
52 Continue,
53 Boolean,
54 Integer,
55 Decimal,
56 Float,
57 String,
58 URL,
59 Map,
60 Vector,
61 YearMonthDay,
62};
63
64inline std::ostream &operator<<(std::ostream &lhs, datum_type_t rhs)
65{
66 switch (rhs) {
67 case datum_type_t::Null: lhs << "Null"; break;
68 case datum_type_t::Break: lhs << "Break"; break;
69 case datum_type_t::Continue: lhs << "Continue"; break;
70 case datum_type_t::Undefined: lhs << "Undefined"; break;
71 case datum_type_t::Boolean: lhs << "Boolean"; break;
72 case datum_type_t::Integer: lhs << "Integer"; break;
73 case datum_type_t::Decimal: lhs << "Decimal"; break;
74 case datum_type_t::Float: lhs << "Float"; break;
75 case datum_type_t::String: lhs << "String"; break;
76 case datum_type_t::URL: lhs << "URL"; break;
77 case datum_type_t::Map: lhs << "Map"; break;
78 case datum_type_t::Vector: lhs << "Vector"; break;
79 case datum_type_t::YearMonthDay: lhs << "YearMonthDay"; break;
80 default: tt_no_default;
81 }
82 return lhs;
83}
84
105template<bool HasLargeObjects>
107private:
113 static constexpr uint64_t make_string(std::string_view str) {
114 ttlet len = str.size();
115
116 if (len > 6) {
117 return 0;
118 }
119
120 uint64_t x = 0;
121 for (uint64_t i = 0; i < len; i++) {
122 x <<= 8;
123 x |= str[i];
124 }
125 return (string_mask + (len << 48)) | x;
126 }
127
134 static uint64_t make_pointer(uint64_t mask, void *ptr) {
135 return mask | (reinterpret_cast<uint64_t>(ptr) & pointer_mask);
136 }
137
143 static constexpr uint64_t id_to_mask(uint64_t id) {
144 return id << 48;
145 }
146
155 static constexpr uint16_t make_id(uint16_t id) {
156 return ((id & 0x10) << 11) | (id & 0xf) | 0x7ff0;
157 }
158
160 static constexpr int64_t minimum_int = 0xfffc'0000'0000'0000LL;
162 static constexpr int64_t maximum_int = 0x0003'ffff'ffff'ffffLL;
163
164 static constexpr int64_t minimum_mantissa = 0xffff'ff80'0000'0000LL;
165 static constexpr int64_t maximum_mantissa = 0x0000'007f'ffff'ffffLL;
166
167 static constexpr uint16_t exponent_mask = 0b0111'1111'1111'0000;
168 static constexpr uint64_t pointer_mask = 0x0000'ffff'ffff'ffff;
169
170 static constexpr uint64_t small_undefined = 0;
171 static constexpr uint64_t small_null = 1;
172 static constexpr uint64_t small_true = 2;
173 static constexpr uint64_t small_false = 3;
174 static constexpr uint64_t small_break = 4;
175 static constexpr uint64_t small_continue = 5;
176
177 static constexpr uint16_t phy_small_id = make_id(0b00001);
178 static constexpr uint16_t phy_decimal_id = make_id(0b00010);
179 static constexpr uint16_t phy_ymd_id = make_id(0b00011);
180 static constexpr uint16_t phy_reserved_id0 = make_id(0b00100);
181 static constexpr uint16_t phy_reserved_id1 = make_id(0b00101);
182 static constexpr uint16_t phy_reserved_id2 = make_id(0b00110);
183 static constexpr uint16_t phy_reserved_id3 = make_id(0b00111);
184 static constexpr uint16_t phy_integer_id0 = make_id(0b01000);
185 static constexpr uint16_t phy_integer_id1 = make_id(0b01001);
186 static constexpr uint16_t phy_integer_id2 = make_id(0b01010);
187 static constexpr uint16_t phy_integer_id3 = make_id(0b01011);
188 static constexpr uint16_t phy_integer_id4 = make_id(0b01100);
189 static constexpr uint16_t phy_integer_id5 = make_id(0b01101);
190 static constexpr uint16_t phy_integer_id6 = make_id(0b01110);
191 static constexpr uint16_t phy_integer_id7 = make_id(0b01111);
192
193 static constexpr uint16_t phy_string_id0 = make_id(0b10001);
194 static constexpr uint16_t phy_string_id1 = make_id(0b10010);
195 static constexpr uint16_t phy_string_id2 = make_id(0b10011);
196 static constexpr uint16_t phy_string_id3 = make_id(0b10100);
197 static constexpr uint16_t phy_string_id4 = make_id(0b10101);
198 static constexpr uint16_t phy_string_id5 = make_id(0b10110);
199 static constexpr uint16_t phy_string_id6 = make_id(0b10111);
200 static constexpr uint16_t phy_string_ptr_id = make_id(0b11000);
201 static constexpr uint16_t phy_url_ptr_id = make_id(0b11001);
202 static constexpr uint16_t phy_integer_ptr_id = make_id(0b11010);
203 static constexpr uint16_t phy_vector_ptr_id = make_id(0b11011);
204 static constexpr uint16_t phy_map_ptr_id = make_id(0b11100);
205 static constexpr uint16_t phy_decimal_ptr_id = make_id(0b11101);
206 static constexpr uint16_t phy_reserved_ptr_id0 = make_id(0b11110);
207 static constexpr uint16_t phy_reserved_ptr_id1 = make_id(0b11111);
208
209 static constexpr uint64_t small_mask = id_to_mask(phy_small_id);
210 static constexpr uint64_t undefined_mask = small_mask | small_undefined;
211 static constexpr uint64_t null_mask = small_mask | small_null;
212 static constexpr uint64_t true_mask = small_mask | small_true;
213 static constexpr uint64_t false_mask = small_mask | small_false;
214 static constexpr uint64_t break_mask = small_mask | small_break;
215 static constexpr uint64_t continue_mask = small_mask | small_continue;
216 static constexpr uint64_t string_mask = id_to_mask(phy_string_id0);
217 static constexpr uint64_t character_mask = id_to_mask(phy_string_id1);
218 static constexpr uint64_t integer_mask = id_to_mask(phy_integer_id0);
219 static constexpr uint64_t decimal_mask = id_to_mask(phy_decimal_id);
220 static constexpr uint64_t ymd_mask = id_to_mask(phy_ymd_id);
221 static constexpr uint64_t string_ptr_mask = id_to_mask(phy_string_ptr_id);
222 static constexpr uint64_t url_ptr_mask = id_to_mask(phy_url_ptr_id);
223 static constexpr uint64_t integer_ptr_mask = id_to_mask(phy_integer_ptr_id);
224 static constexpr uint64_t vector_ptr_mask = id_to_mask(phy_vector_ptr_id);
225 static constexpr uint64_t map_ptr_mask = id_to_mask(phy_map_ptr_id);
226 static constexpr uint64_t decimal_ptr_mask = id_to_mask(phy_decimal_ptr_id);
227
228 union {
229 double f64;
230 uint64_t u64;
231 };
232
241 tt_force_inline uint16_t type_id() const noexcept {
242 uint64_t data;
243 std::memcpy(&data, this, sizeof(data));
244 return static_cast<uint16_t>(data >> 48);
245 }
246
247 tt_force_inline bool is_phy_float() const noexcept {
248 ttlet id = type_id();
249 return (id & 0x7ff0) != 0x7ff0 || (id & 0x000f) == 0;
250 }
251
252 tt_force_inline bool is_phy_integer() const noexcept {
253 return (type_id() & 0xfff8) == 0x7ff8;
254 }
255
256 tt_force_inline bool is_phy_string() const noexcept {
257 ttlet id = type_id();
258 return (id & 0xfff8) == 0xfff0 && (id & 0x0007) > 0;
259 }
260
261 tt_force_inline bool is_phy_decimal() const noexcept {
262 return type_id() == phy_decimal_id;
263 }
264
265 tt_force_inline bool is_phy_ymd() const noexcept {
266 return type_id() == phy_ymd_id;
267 }
268
269 tt_force_inline bool is_phy_small() const noexcept {
270 return type_id() == phy_small_id;
271 }
272
273 tt_force_inline bool is_phy_pointer() const noexcept {
274 return HasLargeObjects && (type_id() & 0xfff8) == 0xfff8;
275 }
276
277 tt_force_inline bool is_phy_string_ptr() const noexcept {
278 return HasLargeObjects && type_id() == phy_string_ptr_id;
279 }
280
281 tt_force_inline bool is_phy_url_ptr() const noexcept {
282 return HasLargeObjects && type_id() == phy_url_ptr_id;
283 }
284
285 tt_force_inline bool is_phy_integer_ptr() const noexcept {
286 return HasLargeObjects && type_id() == phy_integer_ptr_id;
287 }
288
289 tt_force_inline bool is_phy_vector_ptr() const noexcept {
290 return HasLargeObjects && type_id() == phy_vector_ptr_id;
291 }
292
293 tt_force_inline bool is_phy_map_ptr() const noexcept {
294 return HasLargeObjects && type_id() == phy_map_ptr_id;
295 }
296
297 tt_force_inline bool is_phy_decimal_ptr() const noexcept {
298 return HasLargeObjects && type_id() == phy_decimal_ptr_id;
299 }
300
303 tt_force_inline uint64_t get_unsigned_integer() const noexcept {
304 return (u64 << 16) >> 16;
305 }
306
309 tt_force_inline int64_t get_signed_integer() const noexcept {
310 return static_cast<int64_t>(u64 << 16) >> 16;
311 }
312
317 template<typename O>
318 tt_force_inline O *get_pointer() const {
319 return std::launder(reinterpret_cast<O *>(get_signed_integer()));
320 }
321
325 void delete_pointer() noexcept {
326 if constexpr (HasLargeObjects) {
327 switch (type_id()) {
328 case phy_integer_ptr_id: delete get_pointer<int64_t>(); break;
329 case phy_string_ptr_id: delete get_pointer<std::string>(); break;
330 case phy_url_ptr_id: delete get_pointer<URL>(); break;
331 case phy_vector_ptr_id: delete get_pointer<datum_impl::vector>(); break;
332 case phy_map_ptr_id: delete get_pointer<datum_impl::map>(); break;
333 case phy_decimal_ptr_id: delete get_pointer<decimal>(); break;
334 default: tt_no_default;
335 }
336 }
337 }
338
344 void copy_pointer(datum_impl const &other) noexcept {
345 if constexpr (HasLargeObjects) {
346 switch (other.type_id()) {
347 case phy_integer_ptr_id: {
348 auto * const p = new int64_t(*other.get_pointer<int64_t>());
349 u64 = make_pointer(integer_ptr_mask, p);
350 } break;
351
352 case phy_string_ptr_id: {
353 auto * const p = new std::string(*other.get_pointer<std::string>());
354 u64 = make_pointer(string_ptr_mask, p);
355 } break;
356
357 case phy_url_ptr_id: {
358 auto * const p = new URL(*other.get_pointer<URL>());
359 u64 = make_pointer(url_ptr_mask, p);
360 } break;
361
362 case phy_vector_ptr_id: {
363 auto * const p = new datum_impl::vector(*other.get_pointer<datum_impl::vector>());
364 u64 = make_pointer(vector_ptr_mask, p);
365 } break;
366
367 case phy_map_ptr_id: {
368 auto * const p = new datum_impl::map(*other.get_pointer<datum_impl::map>());
369 u64 = make_pointer(map_ptr_mask, p);
370 } break;
371
372 case phy_decimal_ptr_id: {
373 auto* const p = new decimal(*other.get_pointer<decimal>());
374 u64 = make_pointer(decimal_ptr_mask, p);
375 } break;
376
377 default:
378 tt_no_default;
379 }
380 }
381 }
382
383
384public:
387 struct undefined {};
388 struct null {};
389 struct _continue {};
390 struct _break {};
391
392 datum_impl() noexcept : u64(undefined_mask) {}
393
394 ~datum_impl() noexcept {
395 if (tt_unlikely(is_phy_pointer())) {
396 delete_pointer();
397 }
398 }
399
400 datum_impl(datum_impl const &other) noexcept {
401 if (tt_unlikely(other.is_phy_pointer())) {
402 copy_pointer(other);
403 } else {
404 // We do a memcpy, because we don't know the type in the union.
405 std::memcpy(this, &other, sizeof(*this));
406 }
407 }
408
409 datum_impl &operator=(datum_impl const &other) noexcept {
410 if (this != &other) {
411 if (tt_unlikely(is_phy_pointer())) {
412 delete_pointer();
413 }
414 if (tt_unlikely(other.is_phy_pointer())) {
415 copy_pointer(other);
416 } else {
417 // We do a memcpy, because we don't know the type in the union.
418 std::memcpy(this, &other, sizeof(*this));
419 }
420 }
421 return *this;
422 }
423
424 datum_impl(datum_impl &&other) noexcept : u64(undefined_mask) {
425 // We do a memcpy, because we don't know the type in the union.
426 std::memcpy(this, &other, sizeof(*this));
427 other.u64 = undefined_mask;
428 }
429
430 datum_impl &operator=(datum_impl &&other) noexcept {
431 if (this != &other) {
432 // We do a memcpy, because we don't know the type in the union.
433 std::memcpy(this, &other, sizeof(*this));
434 }
435 other.u64 = undefined_mask;
436 return *this;
437 }
438
439 datum_impl(datum_impl::undefined) noexcept : u64(undefined_mask) {}
440 datum_impl(datum_impl::null) noexcept : u64(null_mask) {}
441 datum_impl(datum_impl::_break) noexcept : u64(break_mask) {}
442 datum_impl(datum_impl::_continue) noexcept : u64(continue_mask) {}
443
444 datum_impl(double value) noexcept : f64(value) {
445 if (value != value) {
446 u64 = undefined_mask;
447 }
448 }
449 datum_impl(float value) noexcept : datum_impl(static_cast<double>(value)) {}
450
451 datum_impl(decimal value) noexcept {
452 long long m = value.mantissa();
453
454 if (tt_unlikely(m < minimum_mantissa || m > maximum_mantissa)) {
455 if constexpr (HasLargeObjects) {
456 auto* const p = new decimal(value);
457 u64 = make_pointer(decimal_ptr_mask, p);
458 } else {
459 TTAURI_THROW_MATH_ERROR("Constructing decimal {} to datum", value);
460 }
461 } else {
462 int e = value.exponent();
463
464 u64 =
465 decimal_mask |
466 static_cast<uint8_t>(e) |
467 ((static_cast<uint64_t>(m) << 24) >> 16);
468 }
469 }
470
471 datum_impl(date::year_month_day const &ymd) noexcept :
472 u64(
473 ymd_mask | ((
474 (static_cast<uint64_t>(static_cast<int>(ymd.year())) << 9) |
475 (static_cast<uint64_t>(static_cast<unsigned>(ymd.month())) << 5) |
476 static_cast<uint64_t>(static_cast<unsigned>(ymd.day()))
477 ) & 0x0000ffff'ffffffff)
478 ) {}
479
480 datum_impl(unsigned long long value) noexcept : u64(integer_mask | value) {
481 if (tt_unlikely(value > maximum_int)) {
482 if constexpr (HasLargeObjects) {
483 auto * const p = new uint64_t(value);
484 u64 = make_pointer(integer_ptr_mask, p);
485 } else {
486 TTAURI_THROW_MATH_ERROR("Constructing datum from integer {}, larger than {}", value, maximum_int);
487 }
488 }
489 }
490 datum_impl(unsigned long value) noexcept : datum_impl(static_cast<unsigned long long>(value)) {}
491 datum_impl(unsigned int value) noexcept : datum_impl(static_cast<unsigned long long>(value)) {}
492 datum_impl(unsigned short value) noexcept : datum_impl(static_cast<unsigned long long>(value)) {}
493 datum_impl(unsigned char value) noexcept : datum_impl(static_cast<unsigned long long>(value)) {}
494
495 datum_impl(signed long long value) noexcept :
496 u64(integer_mask | (static_cast<uint64_t>(value) & 0x0007ffff'ffffffff))
497 {
498 if (tt_unlikely(value < minimum_int || value > maximum_int)) {
499 if constexpr (HasLargeObjects) {
500 auto * const p = new int64_t(value);
501 u64 = make_pointer(integer_ptr_mask, p);
502 } else {
503 TTAURI_THROW_MATH_ERROR("Constructing integer {} to datum, outside {} and {}", value, minimum_int, maximum_int);
504 }
505 }
506 }
507 datum_impl(signed long value) noexcept : datum_impl(static_cast<signed long long>(value)) {}
508 datum_impl(signed int value) noexcept : datum_impl(static_cast<signed long long>(value)) {}
509 datum_impl(signed short value) noexcept : datum_impl(static_cast<signed long long>(value)) {}
510 datum_impl(signed char value) noexcept : datum_impl(static_cast<signed long long>(value)) {}
511
512 datum_impl(bool value) noexcept : u64(value ? true_mask : false_mask) {}
513 datum_impl(char value) noexcept : u64(character_mask | value) {}
514
515 datum_impl(std::string_view value) noexcept : u64(make_string(value)) {
516 if (value.size() > 6) {
517 if constexpr (HasLargeObjects) {
518 auto * const p = new std::string(value);
519 u64 = make_pointer(string_ptr_mask, p);
520 } else {
521 TTAURI_THROW_MATH_ERROR("Constructing string {} to datum, larger than 6 characters", value);
522 }
523 }
524 }
525
526 datum_impl(std::string const &value) noexcept : datum_impl(std::string_view(value)) {}
527 datum_impl(char const *value) noexcept : datum_impl(std::string_view(value)) {}
528
529 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
530 datum_impl(URL const &value) noexcept {
531 auto * const p = new URL(value);
532 u64 = make_pointer(url_ptr_mask, p);
533 }
534
535 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
536 datum_impl(URL &&value) noexcept {
537 auto * const p = new URL(std::move(value));
538 u64 = make_pointer(url_ptr_mask, p);
539 }
540
541 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
542 datum_impl(datum_impl::vector const &value) noexcept {
543 auto * const p = new datum_impl::vector(value);
544 u64 = make_pointer(vector_ptr_mask, p);
545 }
546
547 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
548 datum_impl(datum_impl::vector &&value) noexcept {
549 auto * const p = new datum_impl::vector(std::move(value));
550 u64 = make_pointer(vector_ptr_mask, p);
551 }
552
553 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
554 datum_impl(datum_impl::map const &value) noexcept {
555 auto * const p = new datum_impl::map(value);
556 u64 = make_pointer(map_ptr_mask, p);
557 }
558
559 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
560 datum_impl(datum_impl::map &&value) noexcept {
561 auto * const p = new datum_impl::map(std::move(value));
562 u64 = make_pointer(map_ptr_mask, p);
563 }
564
565 datum_impl &operator=(datum_impl::undefined rhs) noexcept {
566 if (tt_unlikely(is_phy_pointer())) {
567 delete_pointer();
568 }
569 u64 = undefined_mask;
570 return *this;
571 }
572
573 datum_impl &operator=(datum_impl::null rhs) noexcept {
574 if (tt_unlikely(is_phy_pointer())) {
575 delete_pointer();
576 }
577 u64 = null_mask;
578 return *this;
579 }
580
581 datum_impl &operator=(datum_impl::_break rhs) noexcept {
582 if (tt_unlikely(is_phy_pointer())) {
583 delete_pointer();
584 }
585 u64 = break_mask;
586 return *this;
587 }
588
589 datum_impl &operator=(datum_impl::_continue rhs) noexcept {
590 if (tt_unlikely(is_phy_pointer())) {
591 delete_pointer();
592 }
593 u64 = continue_mask;
594 return *this;
595 }
596
597 datum_impl &operator=(double rhs) noexcept {
598 if (tt_unlikely(is_phy_pointer())) {
599 delete_pointer();
600 }
601
602 if (rhs == rhs) {
603 f64 = rhs;
604 } else {
605 u64 = undefined_mask;
606 }
607 return *this;
608 }
609 datum_impl& operator=(float rhs) noexcept { return *this = static_cast<double>(rhs); }
610
611
612 datum_impl& operator=(decimal rhs) noexcept {
613 if (tt_unlikely(is_phy_pointer())) {
614 delete_pointer();
615 }
616
617 long long m = rhs.mantissa();
618 if (tt_unlikely(m < minimum_mantissa || m > maximum_mantissa)) {
619 if constexpr (HasLargeObjects) {
620 auto* const p = new decimal(rhs);
621 u64 = make_pointer(decimal_ptr_mask, p);
622 } else {
623 TTAURI_THROW_MATH_ERROR("Constructing decimal {} to datum", rhs);
624 }
625 } else {
626 int e = rhs.exponent();
627
628 u64 =
629 decimal_mask |
630 static_cast<uint8_t>(e) |
631 ((static_cast<uint64_t>(m) << 24) >> 16);
632 }
633 return *this;
634 }
635
636 datum_impl &operator=(date::year_month_day const & ymd) noexcept {
637 if (tt_unlikely(is_phy_pointer())) {
638 delete_pointer();
639 }
640
641 u64 = ymd_mask | ((
642 (static_cast<uint64_t>(static_cast<int>(ymd.year())) << 9) |
643 (static_cast<uint64_t>(static_cast<unsigned>(ymd.month())) << 5) |
644 static_cast<uint64_t>(static_cast<unsigned>(ymd.day()))
645 ) & 0x0000ffff'ffffffff);
646 return *this;
647 }
648
649 datum_impl &operator=(unsigned long long rhs) noexcept {
650 if (tt_unlikely(is_phy_pointer())) {
651 delete_pointer();
652 }
653
654 u64 = integer_mask | static_cast<uint64_t>(rhs);
655 if (tt_unlikely(rhs > maximum_int)) {
656 if constexpr (HasLargeObjects) {
657 auto * const p = new uint64_t(rhs);
658 u64 = make_pointer(integer_ptr_mask, p);
659 } else {
660 TTAURI_THROW_MATH_ERROR("Assigning integer {} to datum, larger than {}", rhs, maximum_int);
661 }
662 }
663 return *this;
664 }
665 datum_impl& operator=(unsigned long rhs) noexcept { return *this = static_cast<unsigned long long>(rhs); }
666 datum_impl& operator=(unsigned int rhs) noexcept { return *this = static_cast<unsigned long long>(rhs); }
667 datum_impl& operator=(unsigned short rhs) noexcept { return *this = static_cast<unsigned long long>(rhs); }
668 datum_impl& operator=(unsigned char rhs) noexcept { return *this = static_cast<unsigned long long>(rhs); }
669
670 datum_impl &operator=(signed long long rhs) noexcept {
671 if (tt_unlikely(is_phy_pointer())) {
672 delete_pointer();
673 }
674
675 u64 = integer_mask | (static_cast<uint64_t>(rhs) & 0x0007ffff'ffffffff);
676 if (tt_unlikely(rhs < minimum_int || rhs > maximum_int)) {
677 if constexpr (HasLargeObjects) {
678 auto * const p = new int64_t(rhs);
679 u64 = make_pointer(integer_ptr_mask, p);
680 } else {
681 TTAURI_THROW_MATH_ERROR("Assigning integer {} to datum, outside {} and {}", rhs, minimum_int, maximum_int);
682 }
683 }
684
685 return *this;
686 }
687 datum_impl& operator=(signed long rhs) noexcept { return *this = static_cast<signed long long>(rhs); }
688 datum_impl& operator=(signed int rhs) noexcept { return *this = static_cast<signed long long>(rhs); }
689 datum_impl& operator=(signed short rhs) noexcept { return *this = static_cast<signed long long>(rhs); }
690 datum_impl& operator=(signed char rhs) noexcept { return *this = static_cast<signed long long>(rhs); }
691
692 datum_impl &operator=(bool rhs) noexcept {
693 if (tt_unlikely(is_phy_pointer())) {
694 delete_pointer();
695 }
696 u64 = rhs ? true_mask : false_mask;
697 return *this;
698 }
699
700 datum_impl &operator=(char rhs) noexcept {
701 if (tt_unlikely(is_phy_pointer())) {
702 delete_pointer();
703 }
704 u64 = character_mask | static_cast<uint64_t>(rhs);
705 return *this;
706 }
707
708 datum_impl &operator=(std::string_view rhs) {
709 if (tt_unlikely(is_phy_pointer())) {
710 delete_pointer();
711 }
712
713 u64 = make_string(rhs);
714 if (rhs.size() > 6) {
715 if constexpr (HasLargeObjects) {
716 auto * const p = new std::string(rhs);
717 u64 = make_pointer(string_ptr_mask, p);
718 } else {
719 TTAURI_THROW_MATH_ERROR("Assigning string {} to datum, larger than 6 characters", rhs);
720 }
721 }
722 return *this;
723 }
724
725 datum_impl &operator=(std::string const &rhs) {
726 *this = std::string_view{rhs};
727 return *this;
728 }
729
730 datum_impl &operator=(char const *rhs) {
731 *this = std::string_view{rhs};
732 return *this;
733 }
734
735 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
736 datum_impl &operator=(URL const &rhs) noexcept {
737 if (tt_unlikely(is_phy_pointer())) {
738 delete_pointer();
739 }
740
741 auto * const p = new URL(rhs);
742 u64 = make_pointer(url_ptr_mask, p);
743 return *this;
744 }
745
746 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
747 datum_impl &operator=(URL &&rhs) noexcept {
748 if (tt_unlikely(is_phy_pointer())) {
749 delete_pointer();
750 }
751
752 auto * const p = new URL(std::move(rhs));
753 u64 = make_pointer(url_ptr_mask, p);
754 return *this;
755 }
756
757 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
758 datum_impl &operator=(datum_impl::vector const &rhs) {
759 if (tt_unlikely(is_phy_pointer())) {
760 delete_pointer();
761 }
762
763 auto * const p = new datum_impl::vector(rhs);
764 u64 = make_pointer(vector_ptr_mask, p);
765
766 return *this;
767 }
768
769 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
770 datum_impl &operator=(datum_impl::vector &&rhs) {
771 if (tt_unlikely(is_phy_pointer())) {
772 delete_pointer();
773 }
774
775 auto * const p = new datum_impl::vector(std::move(rhs));
776 u64 = make_pointer(vector_ptr_mask, p);
777
778 return *this;
779 }
780
781
782 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
783 datum_impl &operator=(datum_impl::map const &rhs) {
784 if (tt_unlikely(is_phy_pointer())) {
785 delete_pointer();
786 }
787
788 auto * const p = new datum_impl::map(rhs);
789 u64 = make_pointer(map_ptr_mask, p);
790
791 return *this;
792 }
793
794 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
795 datum_impl &operator=(datum_impl::map &&rhs) {
796 if (tt_unlikely(is_phy_pointer())) {
797 delete_pointer();
798 }
799
800 auto * const p = new datum_impl::map(std::move(rhs));
801 u64 = make_pointer(map_ptr_mask, p);
802
803 return *this;
804 }
805
806 explicit operator double() const {
807 if (is_phy_float()) {
808 return f64;
809 } else if (is_decimal()) {
810 return static_cast<double>(static_cast<decimal>(*this));
811 } else if (is_phy_integer()) {
812 return static_cast<double>(get_signed_integer());
813 } else if (is_phy_integer_ptr()) {
814 return static_cast<double>(*get_pointer<int64_t>());
815 } else {
816 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a double", this->repr(), this->type_name());
817 }
818 }
819
820 explicit operator float() const {
821 return static_cast<float>(static_cast<double>(*this));
822 }
823
824 explicit operator decimal() const {
825 if (is_phy_decimal()) {
826 uint64_t v = get_unsigned_integer();
827 int e = static_cast<int8_t>(v);
828 long long m = static_cast<int64_t>(v << 16) >> 24;
829 return decimal{e, m};
830 } else if (is_phy_decimal_ptr()) {
831 return *get_pointer<decimal>();
832 } else if (is_phy_integer() || is_phy_integer_ptr()) {
833 return decimal{static_cast<signed long long>(*this)};
834 } else if (is_phy_float()) {
835 return decimal{static_cast<double>(*this)};
836 } else {
837 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a decimal", this->repr(), this->type_name());
838 }
839 }
840
841 explicit operator date::year_month_day() const {
842 if (is_phy_ymd()) {
843 ttlet u = get_unsigned_integer();
844 ttlet i = get_signed_integer();
845 ttlet day = static_cast<unsigned>(u & 0x1f);
846 ttlet month = static_cast<unsigned>((u >> 5) & 0xf);
847 ttlet year = static_cast<signed>(i >> 9);
848
849 if (day == 0) {
850 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a year-month-day", this->repr(), this->type_name());
851 }
852 if (month == 0) {
853 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a year-month-day", this->repr(), this->type_name());
854 }
855 return date::year_month_day{date::year{year}, date::month{month}, date::day{day}};
856 } else {
857 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a year-month-day", this->repr(), this->type_name());
858 }
859 }
860
861 explicit operator signed long long () const {
862 if (is_phy_integer()) {
863 return get_signed_integer();
864 } else if (is_phy_integer_ptr()) {
865 return *get_pointer<signed long long>();
866 } else if (is_phy_float()) {
867 return static_cast<signed long long>(f64);
868 } else if (is_phy_small()) {
869 switch (get_unsigned_integer()) {
870 case small_true: return 1;
871 case small_false: return 0;
872 }
873 }
874 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a signed long long", this->repr(), this->type_name());
875 }
876
877 explicit operator signed long () const {
878 ttlet v = static_cast<signed long long>(*this);
880 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a signed long", this->repr(), this->type_name());
881 }
882 return static_cast<signed long>(v);
883 }
884
885 explicit operator signed int () const {
886 ttlet v = static_cast<signed long long>(*this);
888 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a signed int", this->repr(), this->type_name());
889 }
890 return static_cast<signed int>(v);
891 }
892
893 explicit operator signed short () const {
894 ttlet v = static_cast<signed long long>(*this);
896 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a signed short", this->repr(), this->type_name());
897 }
898 return static_cast<signed short>(v);
899 }
900
901 explicit operator signed char () const {
902 ttlet v = static_cast<int64_t>(*this);
904 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a signed char", this->repr(), this->type_name());
905 }
906 return static_cast<signed char>(v);
907 }
908
909 explicit operator unsigned long long () const {
910 ttlet v = static_cast<signed long long>(*this);
911 return static_cast<unsigned long long>(v);
912 }
913
914 explicit operator unsigned long () const {
915 ttlet v = static_cast<unsigned long long>(*this);
917 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a unsigned long", this->repr(), this->type_name());
918 }
919 return static_cast<unsigned long>(v);
920 }
921
922 explicit operator unsigned int () const {
923 ttlet v = static_cast<unsigned long long>(*this);
925 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a unsigned int", this->repr(), this->type_name());
926 }
927 return static_cast<unsigned int>(v);
928 }
929
930 explicit operator unsigned short () const {
931 ttlet v = static_cast<unsigned long long>(*this);
933 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a unsigned short", this->repr(), this->type_name());
934 }
935 return static_cast<unsigned short>(v);
936 }
937
938 explicit operator unsigned char () const {
939 ttlet v = static_cast<unsigned long long>(*this);
941 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a unsigned char", this->repr(), this->type_name());
942 }
943 return static_cast<unsigned char>(v);
944 }
945
946 explicit operator bool() const noexcept {
947 switch (type_id()) {
948 case phy_small_id: return get_unsigned_integer() == small_true;
949 case phy_integer_id0:
950 case phy_integer_id1:
951 case phy_integer_id2:
952 case phy_integer_id3:
953 case phy_integer_id4:
954 case phy_integer_id5:
955 case phy_integer_id6:
956 case phy_integer_id7: return static_cast<int64_t>(*this) != 0;
957 case phy_decimal_id: return static_cast<decimal>(*this) != 0;
958 case phy_ymd_id: return true;
959 case phy_integer_ptr_id: return *get_pointer<int64_t>() != 0;
960 case phy_string_id0:
961 case phy_string_id1:
962 case phy_string_id2:
963 case phy_string_id3:
964 case phy_string_id4:
965 case phy_string_id5:
966 case phy_string_id6:
967 case phy_string_ptr_id: return this->size() > 0;
968 case phy_url_ptr_id: return true;
969 case phy_vector_ptr_id: return this->size() > 0;
970 case phy_map_ptr_id: return this->size() > 0;
971 case phy_decimal_ptr_id: return static_cast<decimal>(*this) != 0;
972 default:
973 if (tt_likely(is_phy_float())) {
974 return static_cast<double>(*this) != 0.0;
975 } else {
976 tt_no_default;
977 };
978 }
979 }
980
981 explicit operator char() const {
982 if (is_phy_string() && size() == 1) {
983 return u64 & 0xff;
984 } else if (is_phy_string_ptr() && size() == 1) {
985 return get_pointer<std::string>()->at(0);
986 } else {
987 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a char", this->repr(), this->type_name());
988 }
989 }
990
991 explicit operator std::string() const noexcept {
992 switch (type_id()) {
993 case phy_small_id:
994 switch (get_unsigned_integer()) {
995 case small_undefined: return "undefined";
996 case small_null: return "null";
997 case small_true: return "true";
998 case small_false: return "false";
999 case small_break: return "break";
1000 case small_continue: return "continue";
1001 default: tt_no_default;
1002 }
1003
1004 case phy_integer_id0:
1005 case phy_integer_id1:
1006 case phy_integer_id2:
1007 case phy_integer_id3:
1008 case phy_integer_id4:
1009 case phy_integer_id5:
1010 case phy_integer_id6:
1011 case phy_integer_id7: return fmt::format("{}", static_cast<int64_t>(*this));
1012 case phy_decimal_id: return fmt::format("{}", static_cast<decimal>(*this));
1013 case phy_ymd_id: return fmt::format("{}", static_cast<date::year_month_day>(*this));
1014 case phy_integer_ptr_id:
1015 if constexpr (HasLargeObjects) {
1016 return fmt::format("{}", static_cast<int64_t>(*this));
1017 } else {
1018 tt_no_default;
1019 }
1020
1021 case phy_string_id0:
1022 case phy_string_id1:
1023 case phy_string_id2:
1024 case phy_string_id3:
1025 case phy_string_id4:
1026 case phy_string_id5:
1027 case phy_string_id6: {
1028 ttlet length = size();
1029 char buffer[6];
1030 for (int i = 0; i < length; i++) {
1031 buffer[i] = (u64 >> ((length - i - 1) * 8)) & 0xff;
1032 }
1033 return std::string(buffer, length);
1034 }
1035
1036 case phy_string_ptr_id:
1037 if constexpr (HasLargeObjects) {
1038 return *get_pointer<std::string>();
1039 } else {
1040 tt_no_default;
1041 }
1042
1043 case phy_url_ptr_id:
1044 if constexpr (HasLargeObjects) {
1045 return get_pointer<URL>()->string();
1046 } else {
1047 tt_no_default;
1048 }
1049
1050 case phy_decimal_ptr_id:
1051 if constexpr (HasLargeObjects) {
1052 return fmt::format("{}", static_cast<decimal>(*this));
1053 } else {
1054 tt_no_default;
1055 }
1056
1057 case phy_vector_ptr_id:
1058 if constexpr (HasLargeObjects) {
1059 std::string r = "[";
1060 auto count = 0;
1061 for (auto i = vector_begin(); i != vector_end(); i++) {
1062 if (count++ > 0) {
1063 r += ", ";
1064 }
1065 r += i->repr();
1066 }
1067 r += "]";
1068 return r;
1069 } else {
1070 tt_no_default;
1071 }
1072
1073 case phy_map_ptr_id:
1074 if constexpr (HasLargeObjects) {
1076 items.reserve(size());
1077 std::copy(map_begin(), map_end(), std::back_inserter(items));
1078 std::sort(items.begin(), items.end(), [](auto &a, auto &b) {
1079 return a.first < b.first;
1080 });
1081
1082 std::string r = "{";
1083 auto count = 0;
1084 for (auto &item: items) {
1085 if (count++ > 0) {
1086 r += ", ";
1087 }
1088 r += item.first.repr();
1089 r += ": ";
1090 r += item.second.repr();
1091 }
1092 r += "}";
1093 return r;
1094 } else {
1095 tt_no_default;
1096 }
1097
1098 default:
1099 if (is_phy_float()) {
1100 auto str = fmt::format("{:g}", static_cast<double>(*this));
1101 if (str.find('.') == str.npos) {
1102 str += ".0";
1103 }
1104 return str;
1105 } else {
1106 tt_no_default;
1107 }
1108 }
1109 }
1110
1111 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1112 explicit operator URL() const {
1113 if (is_string()) {
1114 return URL{static_cast<std::string>(*this)};
1115 } else if (is_url()) {
1116 return *get_pointer<URL>();
1117 } else {
1118 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a URL", this->repr(), this->type_name());
1119 }
1120 }
1121
1122 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1123 explicit operator datum_impl::vector() const {
1124 if (is_vector()) {
1125 return *get_pointer<datum_impl::vector>();
1126 } else {
1127 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a Vector", this->repr(), this->type_name());
1128 }
1129 }
1130
1131 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1132 explicit operator datum_impl::map() const {
1133 if (is_map()) {
1134 return *get_pointer<datum_impl::map>();
1135 } else {
1136 TTAURI_THROW_INVALID_OPERATION_ERROR("Value {} of type {} can not be converted to a Map", this->repr(), this->type_name());
1137 }
1138 }
1139
1147 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1149 if (is_undefined()) {
1150 // When accessing a name on an undefined it means we need replace it with an empty map.
1151 auto *p = new datum_impl::map();
1152 u64 = map_ptr_mask | (reinterpret_cast<uint64_t>(p) & pointer_mask);
1153 }
1154
1155 if (is_map()) {
1156 auto &m = *get_pointer<datum_impl::map>();
1157 auto [i, did_insert] = m.try_emplace(rhs);
1158 return i->second;
1159
1160 } else if (is_vector() && rhs.is_integer()) {
1161 auto index = static_cast<int64_t>(rhs);
1162 auto &v = *get_pointer<datum_impl::vector>();
1163
1164 if (index < 0) {
1165 index = ssize(v) + index;
1166 }
1167
1168 if (index < 0 || index >= ssize(v)) {
1169 TTAURI_THROW_INVALID_OPERATION_ERROR("Index {} out of range to access value in vector of size {}", index, ssize(v));
1170 } else {
1171 return v[index];
1172 }
1173 } else {
1174 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot index value of type {} with {} of type {}", type_name(), rhs.repr(), rhs.type_name());
1175 }
1176 }
1177
1185 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1187 if (is_map()) {
1188 ttlet &m = *get_pointer<datum_impl::map>();
1189 ttlet i = m.find(rhs);
1190 if (i == m.cend()) {
1191 TTAURI_THROW_INVALID_OPERATION_ERROR("Could not find key {} in map of size {}", rhs.repr(), ssize(m));
1192 }
1193 return i->second;
1194
1195 } else if (is_vector() && rhs.is_integer()) {
1196 auto index = static_cast<int64_t>(rhs);
1197 ttlet &v = *get_pointer<datum_impl::vector>();
1198
1199 if (index < 0) {
1200 index = ssize(v) + index;
1201 }
1202
1203 if (index < 0 || index >= ssize(v)) {
1204 TTAURI_THROW_INVALID_OPERATION_ERROR("Index {} out of range to access value in vector of size {}", index, ssize(v));
1205 } else {
1206 return v[index];
1207 }
1208 } else {
1209 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot index value of type {} with {} of type {}", type_name(), rhs.repr(), rhs.type_name());
1210 }
1211 }
1212
1221 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1222 bool contains(datum_impl const &rhs) const noexcept {
1223 if (is_map()) {
1224 ttlet &m = *get_pointer<datum_impl::map>();
1225 ttlet i = m.find(rhs);
1226 return i != m.cend();
1227
1228 } else if (is_vector() && rhs.is_integer()) {
1229 auto index = static_cast<int64_t>(rhs);
1230 ttlet &v = *get_pointer<datum_impl::vector>();
1231
1232 if (index < 0) {
1233 index = ssize(v) + index;
1234 }
1235
1236 return index >= 0 && index < ssize(v);
1237
1238 } else {
1239 return false;
1240 }
1241 }
1242
1248 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1250 if (is_undefined()) {
1251 // When appending on undefined it means we need replace it with an empty vector.
1252 auto *p = new datum_impl::vector();
1253 u64 = vector_ptr_mask | (reinterpret_cast<uint64_t>(p) & pointer_mask);
1254 }
1255
1256 if (is_vector()) {
1257 auto *v = get_pointer<datum_impl::vector>();
1258 v->emplace_back();
1259 return v->back();
1260
1261 } else {
1262 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot append new item onto type {}", type_name());
1263 }
1264 }
1265
1266 template<typename... Args>
1267 void emplace_back(Args &&... args) {
1268 if (is_undefined()) {
1269 // When appending on undefined it means we need replace it with an empty vector.
1270 auto *p = new datum_impl::vector();
1271 u64 = vector_ptr_mask | (reinterpret_cast<uint64_t>(p) & pointer_mask);
1272 }
1273
1274 if (is_vector()) {
1275 auto *v = get_pointer<datum_impl::vector>();
1276 v->emplace_back(std::forward<Args>(args)...);
1277
1278 } else {
1279 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot append new item onto type {}", type_name());
1280 }
1281 }
1282
1283 template<typename Arg>
1284 void push_back(Arg &&arg) {
1285 if (is_undefined()) {
1286 // When appending on undefined it means we need replace it with an empty vector.
1287 auto *p = new datum_impl::vector();
1288 u64 = vector_ptr_mask | (reinterpret_cast<uint64_t>(p) & pointer_mask);
1289 }
1290
1291 if (is_vector()) {
1292 auto *v = get_pointer<datum_impl::vector>();
1293 v->push_back(std::forward<Arg>(arg));
1294
1295 } else {
1296 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot append new item onto type {}", type_name());
1297 }
1298 }
1299
1300 void pop_back() {
1301 if (is_vector()) {
1302 auto *v = get_pointer<datum_impl::vector>();
1303 v->pop_back();
1304
1305 } else {
1306 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot pop_back() onto type {}", type_name());
1307 }
1308 }
1309
1310 datum_impl year() const {
1311 if (is_ymd()) {
1312 return {static_cast<signed>(static_cast<date::year_month_day>(*this).year())};
1313 } else {
1314 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot get year() from type {}", type_name());
1315 }
1316 }
1317
1318 datum_impl quarter() const {
1319 if (is_ymd()) {
1320 auto month = static_cast<unsigned>(static_cast<date::year_month_day>(*this).month());
1321 return {((month-1) / 3) + 1};
1322 } else {
1323 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot get month() from type {}", type_name());
1324 }
1325 }
1326
1327 datum_impl month() const {
1328 if (is_ymd()) {
1329 return {static_cast<unsigned>(static_cast<date::year_month_day>(*this).month())};
1330 } else {
1331 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot get month() from type {}", type_name());
1332 }
1333 }
1334
1335 datum_impl day() const {
1336 if (is_ymd()) {
1337 return {static_cast<unsigned>(static_cast<date::year_month_day>(*this).day())};
1338 } else {
1339 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot get day() from type {}", type_name());
1340 }
1341 }
1342
1343 datum_impl const &front() const {
1344 if (is_vector()) {
1345 ttlet *v = get_pointer<datum_impl::vector>();
1346 return v->front();
1347
1348 } else {
1349 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot front() onto type {}", type_name());
1350 }
1351 }
1352
1353 datum_impl &front() {
1354 if (is_vector()) {
1355 auto *v = get_pointer<datum_impl::vector>();
1356 return v->front();
1357
1358 } else {
1359 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot front() onto type {}", type_name());
1360 }
1361 }
1362
1363 datum_impl const &back() const {
1364 if (is_vector()) {
1365 ttlet *v = get_pointer<datum_impl::vector>();
1366 return v->back();
1367
1368 } else {
1369 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot back() onto type {}", type_name());
1370 }
1371 }
1372
1373 datum_impl &back() {
1374 if (is_vector()) {
1375 auto *v = get_pointer<datum_impl::vector>();
1376 return v->back();
1377
1378 } else {
1379 TTAURI_THROW_INVALID_OPERATION_ERROR("Cannot back() onto type {}", type_name());
1380 }
1381 }
1382
1383
1384 std::string repr() const noexcept {
1385 switch (type_id()) {
1386 case phy_small_id:
1387 switch (get_unsigned_integer()) {
1388 case small_undefined: return "undefined";
1389 case small_null: return "null";
1390 case small_true: return "true";
1391 case small_false: return "false";
1392 case small_break: return "break";
1393 case small_continue: return "continue";
1394 default: tt_no_default;
1395 }
1396 case phy_integer_id0:
1397 case phy_integer_id1:
1398 case phy_integer_id2:
1399 case phy_integer_id3:
1400 case phy_integer_id4:
1401 case phy_integer_id5:
1402 case phy_integer_id6:
1403 case phy_integer_id7:
1404 case phy_integer_ptr_id: return static_cast<std::string>(*this);
1405 case phy_decimal_id:
1406 case phy_decimal_ptr_id: return static_cast<std::string>(*this);
1407 case phy_ymd_id: return static_cast<std::string>(*this);
1408 case phy_string_id0:
1409 case phy_string_id1:
1410 case phy_string_id2:
1411 case phy_string_id3:
1412 case phy_string_id4:
1413 case phy_string_id5:
1414 case phy_string_id6:
1415 case phy_string_ptr_id: return fmt::format("\"{}\"", static_cast<std::string>(*this));
1416 case phy_url_ptr_id: return fmt::format("<URL {}>", static_cast<std::string>(*this));
1417 case phy_vector_ptr_id: return static_cast<std::string>(*this);
1418 case phy_map_ptr_id: return static_cast<std::string>(*this);
1419 default:
1420 if (tt_likely(is_phy_float())) {
1421 return static_cast<std::string>(*this);
1422 } else {
1423 tt_no_default;
1424 }
1425 }
1426 }
1427
1431 int type_order() const noexcept {
1432 if (is_numeric()) {
1433 // Fold all numeric values into the same group (literal integers).
1434 return phy_integer_id0;
1435 } else {
1436 return type_id();
1437 }
1438 }
1439
1440 datum_impl &get_by_path(std::vector<std::string> const &key) {
1441 if (key.size() > 0 && is_map()) {
1442 ttlet index = key.at(0);
1443 auto &next = (*this)[index];
1444 ttlet next_key = std::vector<std::string>{key.begin() + 1, key.end()};
1445 return next.get_by_path(next_key);
1446
1447 } else if (key.size() > 0 && is_vector()) {
1448 size_t const index = std::stoll(key.at(0));
1449 auto &next = (*this)[index];
1450 ttlet next_key = std::vector<std::string>{key.begin() + 1, key.end()};
1451 return next.get_by_path(next_key);
1452
1453 } else if (key.size() > 0) {
1454 TTAURI_THROW_INVALID_OPERATION_ERROR("type {} does not support get() with '{}'", type_name(), key.at(0));
1455 } else {
1456 return *this;
1457 }
1458 }
1459
1460 datum_impl get_by_path(std::vector<std::string> const &key) const {
1461 if (key.size() > 0 && is_map()) {
1462 ttlet index = key.at(0);
1463 ttlet next = (*this)[index];
1464 return next.get_by_path({key.begin() + 1, key.end()});
1465
1466 } else if (key.size() > 0 && is_vector()) {
1467 size_t const index = std::stoll(key.at(0));
1468 ttlet next = (*this)[index];
1469 return next.get_by_path({key.begin() + 1, key.end()});
1470
1471 } else if (key.size() > 0) {
1472 TTAURI_THROW_INVALID_OPERATION_ERROR("type {} does not support get() with '{}'", type_name(), key.at(0));
1473 } else {
1474 return *this;
1475 }
1476 }
1477
1478 tt_force_inline bool is_integer() const noexcept { return is_phy_integer() || is_phy_integer_ptr(); }
1479 tt_force_inline bool is_decimal() const noexcept { return is_phy_decimal() || is_phy_decimal_ptr(); }
1480 tt_force_inline bool is_ymd() const noexcept { return is_phy_ymd(); }
1481 tt_force_inline bool is_float() const noexcept { return is_phy_float(); }
1482 tt_force_inline bool is_string() const noexcept { return is_phy_string() || is_phy_string_ptr(); }
1483
1484 tt_force_inline bool is_bool() const noexcept {
1485 if (is_phy_small()) {
1486 ttlet tmp = get_unsigned_integer();
1487 return tmp == small_true || tmp == small_false;
1488 } else {
1489 return false;
1490 }
1491 }
1492
1493 tt_force_inline bool is_null() const noexcept {
1494 return is_phy_small() && get_unsigned_integer() == small_null;
1495 }
1496
1497 tt_force_inline bool is_undefined() const noexcept {
1498 return is_phy_small() && get_unsigned_integer() == small_undefined;
1499 }
1500
1501 tt_force_inline bool is_break() const noexcept {
1502 return is_phy_small() && get_unsigned_integer() == small_break;
1503 }
1504
1505 tt_force_inline bool is_continue() const noexcept {
1506 return is_phy_small() && get_unsigned_integer() == small_continue;
1507 } bool is_url() const noexcept { return is_phy_url_ptr(); }
1508
1509 tt_force_inline bool is_vector() const noexcept { return is_phy_vector_ptr(); }
1510 tt_force_inline bool is_map() const noexcept { return is_phy_map_ptr(); }
1511 tt_force_inline bool is_numeric() const noexcept { return is_integer() || is_decimal() || is_float(); }
1512
1513 datum_type_t type() const noexcept {
1514 switch (type_id()) {
1515 case phy_small_id:
1516 switch (get_unsigned_integer()) {
1517 case small_undefined: return datum_type_t::Undefined;
1518 case small_null: return datum_type_t::Null;
1519 case small_false: return datum_type_t::Boolean;
1520 case small_true: return datum_type_t::Boolean;
1521 case small_break: return datum_type_t::Break;
1522 case small_continue: return datum_type_t::Continue;
1523 default: tt_no_default;
1524 }
1525
1526 case phy_integer_id0:
1527 case phy_integer_id1:
1528 case phy_integer_id2:
1529 case phy_integer_id3:
1530 case phy_integer_id4:
1531 case phy_integer_id5:
1532 case phy_integer_id6:
1533 case phy_integer_id7:
1534 case phy_integer_ptr_id: return datum_type_t::Integer;
1535 case phy_decimal_id:
1536 case phy_decimal_ptr_id: return datum_type_t::Decimal;
1537 case phy_ymd_id: return datum_type_t::YearMonthDay;
1538 case phy_string_id0:
1539 case phy_string_id1:
1540 case phy_string_id2:
1541 case phy_string_id3:
1542 case phy_string_id4:
1543 case phy_string_id5:
1544 case phy_string_id6:
1545 case phy_string_ptr_id: return datum_type_t::String;
1546 case phy_url_ptr_id: return datum_type_t::URL;
1547 case phy_vector_ptr_id: return datum_type_t::Vector;
1548 case phy_map_ptr_id: return datum_type_t::Map;
1549 default:
1550 if (tt_likely(is_phy_float())) {
1551 return datum_type_t::Float;
1552 } else {
1553 tt_no_default;
1554 }
1555 }
1556 }
1557
1558 char const *type_name() const noexcept{
1559 switch (type_id()) {
1560 case phy_small_id:
1561 switch (get_unsigned_integer()) {
1562 case small_undefined: return "Undefined";
1563 case small_null: return "Null";
1564 case small_false: return "Boolean";
1565 case small_true: return "Boolean";
1566 case small_break: return "Break";
1567 case small_continue: return "Continue";
1568 default: tt_no_default;
1569 }
1570
1571 case phy_integer_id0:
1572 case phy_integer_id1:
1573 case phy_integer_id2:
1574 case phy_integer_id3:
1575 case phy_integer_id4:
1576 case phy_integer_id5:
1577 case phy_integer_id6:
1578 case phy_integer_id7:
1579 case phy_integer_ptr_id: return "Integer";
1580 case phy_decimal_id:
1581 case phy_decimal_ptr_id: return "Decimal";
1582 case phy_ymd_id: return "YearMonthDay";
1583 case phy_string_id0:
1584 case phy_string_id1:
1585 case phy_string_id2:
1586 case phy_string_id3:
1587 case phy_string_id4:
1588 case phy_string_id5:
1589 case phy_string_id6:
1590 case phy_string_ptr_id: return "String";
1591 case phy_url_ptr_id: return "URL";
1592 case phy_vector_ptr_id: return "Vector";
1593 case phy_map_ptr_id: return "Map";
1594 default:
1595 if (tt_likely(is_phy_float())) {
1596 return "Float";
1597 } else {
1598 tt_no_default;
1599 }
1600 }
1601 }
1602
1603 size_t size() const{
1604 switch (type_id()) {
1605 case phy_string_id0:
1606 case phy_string_id1:
1607 case phy_string_id2:
1608 case phy_string_id3:
1609 case phy_string_id4:
1610 case phy_string_id5:
1611 case phy_string_id6: return ((u64 & 0xffff'0000'0000'0000ULL) - string_mask) >> 48;
1612 case phy_string_ptr_id: return get_pointer<std::string>()->size();
1613 case phy_vector_ptr_id: return get_pointer<datum_impl::vector>()->size();
1614 case phy_map_ptr_id: return get_pointer<datum_impl::map>()->size();
1615 default: TTAURI_THROW_INVALID_OPERATION_ERROR("Can't get size of value {} of type {}.", this->repr(), this->type_name());
1616 }
1617 }
1618
1619 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1620 typename map::const_iterator map_begin() const noexcept {
1621 if (is_phy_map_ptr()) {
1622 return get_pointer<datum_impl::map>()->begin();
1623 } else {
1624 TTAURI_THROW_INVALID_OPERATION_ERROR("map_begin() expect datum to be a map, but it is a {}.", this->type_name());
1625 }
1626 }
1627
1628 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1629 typename map::const_iterator map_end() const noexcept {
1630 if (is_phy_map_ptr()) {
1631 return get_pointer<datum_impl::map>()->end();
1632 } else {
1633 TTAURI_THROW_INVALID_OPERATION_ERROR("map_end() expect datum to be a map, but it is a {}.", this->type_name());
1634 }
1635 }
1636
1637 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1638 typename vector::const_iterator vector_begin() const noexcept {
1639 if (is_phy_vector_ptr()) {
1640 return get_pointer<datum_impl::vector>()->begin();
1641 } else {
1642 TTAURI_THROW_INVALID_OPERATION_ERROR("vector_begin() expect datum to be a vector, but it is a {}.", this->type_name());
1643 }
1644 }
1645
1646 template<bool P=HasLargeObjects, std::enable_if_t<P,int> = 0>
1647 typename vector::const_iterator vector_end() const noexcept{
1648 if (is_phy_vector_ptr()) {
1649 return get_pointer<datum_impl::vector>()->end();
1650 } else {
1651 TTAURI_THROW_INVALID_OPERATION_ERROR("vector_end() expect datum to be a vector, but it is a {}.", this->type_name());
1652 }
1653 }
1654
1655 size_t hash() const noexcept{
1656 if (is_phy_float()) {
1657 return std::hash<double>{}(f64);
1658 } else if (tt_unlikely(is_phy_pointer())) {
1659 switch (type_id()) {
1660 case phy_string_ptr_id:
1661 return std::hash<std::string>{}(*get_pointer<std::string>());
1662 case phy_url_ptr_id:
1663 return std::hash<URL>{}(*get_pointer<URL>());
1664 case phy_vector_ptr_id:
1665 return std::accumulate(vector_begin(), vector_end(), size_t{0}, [](size_t a, auto x) {
1666 return a ^ x.hash();
1667 });
1668 case phy_map_ptr_id:
1669 return std::accumulate(map_begin(), map_end(), size_t{0}, [](size_t a, auto x) {
1670 return a ^ (x.first.hash() ^ x.second.hash());
1671 });
1672 case phy_decimal_ptr_id:
1673 return std::hash<decimal>{}(*get_pointer<decimal>());
1674 default: tt_no_default;
1675 }
1676 } else {
1677 return std::hash<uint64_t>{}(u64);
1678 }
1679 }
1680
1681 datum_impl &operator++() {
1682 if (!this->is_numeric()) {
1683 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't increment '++' value {} of type {}",
1684 this->repr(), this->type_name()
1685 );
1686 }
1687
1688 return *this += 1;
1689 }
1690
1691 datum_impl &operator--() {
1692 if (!this->is_numeric()) {
1693 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't increment '--' value {} of type {}",
1694 this->repr(), this->type_name()
1695 );
1696 }
1697
1698 return *this -= 1;
1699 }
1700
1701 datum_impl operator++(int) {
1702 auto tmp = *this;
1703 ++*this;
1704 return tmp;
1705 }
1706
1707 datum_impl operator--(int) {
1708 auto tmp = *this;
1709 --*this;
1710 return tmp;
1711 }
1712
1713 datum_impl &operator+=(datum_impl const &rhs) {
1714 if (this->is_vector()) {
1715 this->push_back(rhs);
1716 } else {
1717 *this = *this + rhs;
1718 }
1719 return *this;
1720 }
1721
1722 datum_impl &operator-=(datum_impl const &rhs) {
1723 return *this = *this - rhs;
1724 }
1725
1726 datum_impl &operator*=(datum_impl const &rhs) {
1727 return *this = *this * rhs;
1728 }
1729
1730 datum_impl &operator/=(datum_impl const &rhs) {
1731 return *this = *this / rhs;
1732 }
1733
1734 datum_impl &operator%=(datum_impl const &rhs) {
1735 return *this = *this % rhs;
1736 }
1737
1738 datum_impl &operator<<=(datum_impl const &rhs) {
1739 return *this = *this << rhs;
1740 }
1741
1742 datum_impl &operator>>=(datum_impl const &rhs) {
1743 return *this = *this >> rhs;
1744 }
1745
1746 datum_impl &operator&=(datum_impl const &rhs) {
1747 return *this = *this & rhs;
1748 }
1749
1750 datum_impl &operator|=(datum_impl const &rhs) {
1751 return *this = *this | rhs;
1752 }
1753
1754 datum_impl &operator^=(datum_impl const &rhs) {
1755 return *this = *this ^ rhs;
1756 }
1757
1758 friend datum_impl operator~(datum_impl const &rhs) {
1759 if (rhs.is_integer()) {
1760 return datum_impl{~static_cast<int64_t>(rhs)};
1761 } else {
1762 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't bit-wise negate '~' value {} of type {}",
1763 rhs.repr(), rhs.type_name()
1764 );
1765 }
1766 }
1767
1768 friend datum_impl operator-(datum_impl const &rhs) {
1769 if (rhs.is_integer()) {
1770 return datum_impl{-static_cast<int64_t>(rhs)};
1771 } else if (rhs.is_decimal()) {
1772 return datum_impl{-static_cast<decimal>(rhs)};
1773 } else if (rhs.is_float()) {
1774 return datum_impl{-static_cast<double>(rhs)};
1775 } else {
1776 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't arithmetic negate '-' value {} of type {}",
1777 rhs.repr(), rhs.type_name()
1778 );
1779 }
1780 }
1781
1782 friend datum_impl operator+(datum_impl const &rhs) {
1783 if (rhs.is_numeric()) {
1784 return rhs;
1785 } else {
1786 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't arithmetic posgate '+' value {} of type {}",
1787 rhs.repr(), rhs.type_name()
1788 );
1789 }
1790 }
1791
1792 friend bool operator==(datum_impl const &lhs, datum_impl const &rhs) noexcept {
1793 switch (lhs.type_id()) {
1794 case datum_impl::phy_small_id:
1795 return rhs.is_phy_small() && lhs.get_unsigned_integer() == rhs.get_unsigned_integer();
1796 case datum_impl::phy_integer_id0:
1797 case datum_impl::phy_integer_id1:
1798 case datum_impl::phy_integer_id2:
1799 case datum_impl::phy_integer_id3:
1800 case datum_impl::phy_integer_id4:
1801 case datum_impl::phy_integer_id5:
1802 case datum_impl::phy_integer_id6:
1803 case datum_impl::phy_integer_id7:
1804 case datum_impl::phy_integer_ptr_id:
1805 return (
1806 (rhs.is_float() && static_cast<double>(lhs) == static_cast<double>(rhs)) ||
1807 (rhs.is_decimal() && static_cast<decimal>(lhs) == static_cast<decimal>(rhs)) ||
1808 (rhs.is_integer() && static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs))
1809 );
1810 case datum_impl::phy_decimal_id:
1811 case datum_impl::phy_decimal_ptr_id:
1812 return (
1813 (rhs.is_float() && static_cast<double>(lhs) == static_cast<double>(rhs)) ||
1814 (rhs.is_decimal() && static_cast<decimal>(lhs) == static_cast<decimal>(rhs)) ||
1815 (rhs.is_integer() && static_cast<decimal>(lhs) == static_cast<decimal>(rhs))
1816 );
1817 case datum_impl::phy_ymd_id:
1818 return rhs.is_ymd() && lhs.get_unsigned_integer() == rhs.get_unsigned_integer();
1819 case datum_impl::phy_string_id0:
1820 case datum_impl::phy_string_id1:
1821 case datum_impl::phy_string_id2:
1822 case datum_impl::phy_string_id3:
1823 case datum_impl::phy_string_id4:
1824 case datum_impl::phy_string_id5:
1825 case datum_impl::phy_string_id6:
1826 case datum_impl::phy_string_ptr_id:
1827 return (
1828 (rhs.is_string() && static_cast<std::string>(lhs) == static_cast<std::string>(rhs)) ||
1829 (rhs.is_url() && static_cast<URL>(lhs) == static_cast<URL>(rhs))
1830 );
1831 case datum_impl::phy_url_ptr_id:
1832 return (rhs.is_url() || rhs.is_string()) && static_cast<URL>(lhs) == static_cast<URL>(rhs);
1833 case datum_impl::phy_vector_ptr_id:
1834 return rhs.is_vector() && *lhs.get_pointer<datum_impl::vector>() == *rhs.get_pointer<datum_impl::vector>();
1835 case datum_impl::phy_map_ptr_id:
1836 return rhs.is_map() && *lhs.get_pointer<datum_impl::map>() == *rhs.get_pointer<datum_impl::map>();
1837 default:
1838 if (lhs.is_phy_float()) {
1839 return rhs.is_numeric() && static_cast<double>(lhs) == static_cast<double>(rhs);
1840 } else {
1841 tt_no_default;
1842 }
1843 }
1844 }
1845
1846 friend bool operator<(datum_impl const &lhs, datum_impl const &rhs) noexcept {
1847 switch (lhs.type_id()) {
1848 case datum_impl::phy_small_id:
1849 if (lhs.is_bool() && rhs.is_bool()) {
1850 return static_cast<bool>(lhs) < static_cast<bool>(rhs);
1851 } else {
1852 return lhs.get_unsigned_integer() < rhs.get_unsigned_integer();
1853 }
1854 case datum_impl::phy_integer_id0:
1855 case datum_impl::phy_integer_id1:
1856 case datum_impl::phy_integer_id2:
1857 case datum_impl::phy_integer_id3:
1858 case datum_impl::phy_integer_id4:
1859 case datum_impl::phy_integer_id5:
1860 case datum_impl::phy_integer_id6:
1861 case datum_impl::phy_integer_id7:
1862 case datum_impl::phy_integer_ptr_id:
1863 if (rhs.is_float()) {
1864 return static_cast<double>(lhs) < static_cast<double>(rhs);
1865 } else if (rhs.is_decimal()) {
1866 return static_cast<decimal>(lhs) < static_cast<decimal>(rhs);
1867 } else if (rhs.is_integer()) {
1868 return static_cast<int64_t>(lhs) < static_cast<int64_t>(rhs);
1869 } else {
1870 return lhs.type_order() < rhs.type_order();
1871 }
1872 case datum_impl::phy_decimal_id:
1873 case datum_impl::phy_decimal_ptr_id:
1874 if (rhs.is_float()) {
1875 return static_cast<double>(lhs) < static_cast<double>(rhs);
1876 } else if (rhs.is_decimal()) {
1877 return static_cast<decimal>(lhs) < static_cast<decimal>(rhs);
1878 } else if (rhs.is_integer()) {
1879 return static_cast<decimal>(lhs) < static_cast<decimal>(rhs);
1880 } else {
1881 return lhs.type_order() < rhs.type_order();
1882 }
1883 case datum_impl::phy_ymd_id:
1884 if (rhs.is_ymd()) {
1885 return static_cast<date::year_month_day>(lhs) < static_cast<date::year_month_day>(rhs);
1886 } else {
1887 return lhs.type_order() < rhs.type_order();
1888 }
1889 case datum_impl::phy_string_id0:
1890 case datum_impl::phy_string_id1:
1891 case datum_impl::phy_string_id2:
1892 case datum_impl::phy_string_id3:
1893 case datum_impl::phy_string_id4:
1894 case datum_impl::phy_string_id5:
1895 case datum_impl::phy_string_id6:
1896 case datum_impl::phy_string_ptr_id:
1897 if (rhs.is_string()) {
1898 return static_cast<std::string>(lhs) < static_cast<std::string>(rhs);
1899 } else if (rhs.is_url()) {
1900 return static_cast<URL>(lhs) < static_cast<URL>(rhs);
1901 } else {
1902 return lhs.type_order() < rhs.type_order();
1903 }
1904 case datum_impl::phy_url_ptr_id:
1905 if (rhs.is_url() || rhs.is_string()) {
1906 return static_cast<URL>(lhs) < static_cast<URL>(rhs);
1907 } else {
1908 return lhs.type_order() < rhs.type_order();
1909 }
1910 case datum_impl::phy_vector_ptr_id:
1911 if (rhs.is_vector()) {
1912 return *lhs.get_pointer<datum_impl::vector>() < *rhs.get_pointer<datum_impl::vector>();
1913 } else {
1914 return lhs.type_order() < rhs.type_order();
1915 }
1916 case datum_impl::phy_map_ptr_id:
1917 if (rhs.is_map()) {
1918 return *lhs.get_pointer<datum_impl::map>() < *rhs.get_pointer<datum_impl::map>();
1919 } else {
1920 return lhs.type_order() < rhs.type_order();
1921 }
1922 default:
1923 if (lhs.is_phy_float()) {
1924 if (rhs.is_numeric()) {
1925 return static_cast<double>(lhs) < static_cast<double>(rhs);
1926 } else {
1927 return lhs.type_order() < rhs.type_order();
1928 }
1929 } else {
1930 tt_no_default;
1931 }
1932 }
1933 }
1934
1935 friend bool operator!=(datum_impl const &lhs, datum_impl const &rhs) noexcept {
1936 return !(lhs == rhs);
1937 }
1938
1939 friend bool operator>(datum_impl const &lhs, datum_impl const &rhs) noexcept {
1940 return rhs < lhs;
1941 }
1942
1943 friend bool operator<=(datum_impl const &lhs, datum_impl const &rhs) noexcept {
1944 return !(rhs < lhs);
1945 }
1946
1947 friend bool operator>=(datum_impl const &lhs, datum_impl const &rhs) noexcept {
1948 return !(lhs < rhs);
1949 }
1950
1951 friend datum_impl operator+(datum_impl const &lhs, datum_impl const &rhs) {
1952 if (lhs.is_float() || rhs.is_float()) {
1953 ttlet lhs_ = static_cast<double>(lhs);
1954 ttlet rhs_ = static_cast<double>(rhs);
1955 return datum_impl{ lhs_ + rhs_ };
1956
1957 } else if (lhs.is_decimal() || rhs.is_decimal()) {
1958 ttlet lhs_ = static_cast<decimal>(lhs);
1959 ttlet rhs_ = static_cast<decimal>(rhs);
1960 return datum_impl{lhs_ + rhs_};
1961
1962 } else if (lhs.is_integer() || rhs.is_integer()) {
1963 ttlet lhs_ = static_cast<long long int>(lhs);
1964 ttlet rhs_ = static_cast<long long int>(rhs);
1965 return datum_impl{ lhs_ + rhs_ };
1966
1967 } else if (lhs.is_string() && rhs.is_string()) {
1968 ttlet lhs_ = static_cast<std::string>(lhs);
1969 ttlet rhs_ = static_cast<std::string>(rhs);
1970 return datum_impl{std::move(lhs_ + rhs_)};
1971
1972 } else if (lhs.is_vector() && rhs.is_vector()) {
1973 auto lhs_ = static_cast<datum_impl::vector>(lhs);
1974 ttlet &rhs_ = *(rhs.get_pointer<datum_impl::vector>());
1975 std::copy(rhs_.begin(), rhs_.end(), std::back_inserter(lhs_));
1976 return datum_impl{std::move(lhs_)};
1977
1978 } else if (lhs.is_map() && rhs.is_map()) {
1979 ttlet &lhs_ = *(lhs.get_pointer<datum_impl::map>());
1980 auto rhs_ = static_cast<datum_impl::map>(rhs);
1981 for (ttlet &item: lhs_) {
1982 rhs_.try_emplace(item.first, item.second);
1983 }
1984 return datum_impl{std::move(rhs_)};
1985
1986 } else {
1987 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't add '+' value {} of type {} to value {} of type {}",
1988 lhs.repr(), lhs.type_name(), rhs.repr(), rhs.type_name()
1989 );
1990 }
1991 }
1992
1993 friend datum_impl operator-(datum_impl const &lhs, datum_impl const &rhs) {
1994 if (lhs.is_float() || rhs.is_float()) {
1995 ttlet lhs_ = static_cast<double>(lhs);
1996 ttlet rhs_ = static_cast<double>(rhs);
1997 return datum_impl{ lhs_ - rhs_ };
1998
1999 } else if (lhs.is_decimal() || rhs.is_decimal()) {
2000 ttlet lhs_ = static_cast<decimal>(lhs);
2001 ttlet rhs_ = static_cast<decimal>(rhs);
2002 return datum_impl{ lhs_ - rhs_ };
2003
2004 } else if (lhs.is_integer() || rhs.is_integer()) {
2005 ttlet lhs_ = static_cast<long long int>(lhs);
2006 ttlet rhs_ = static_cast<long long int>(rhs);
2007 return datum_impl{ lhs_ - rhs_ };
2008
2009 } else {
2010 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't subtract '-' value {} of type {} from value {} of type {}",
2011 rhs.repr(), rhs.type_name(), lhs.repr(), lhs.type_name()
2012 );
2013 }
2014 }
2015
2016 friend datum_impl operator*(datum_impl const &lhs, datum_impl const &rhs) {
2017 if (lhs.is_float() || rhs.is_float()) {
2018 ttlet lhs_ = static_cast<double>(lhs);
2019 ttlet rhs_ = static_cast<double>(rhs);
2020 return datum_impl{ lhs_ * rhs_ };
2021
2022 } else if (lhs.is_decimal() || rhs.is_decimal()) {
2023 ttlet lhs_ = static_cast<decimal>(lhs);
2024 ttlet rhs_ = static_cast<decimal>(rhs);
2025 return datum_impl{ lhs_ * rhs_ };
2026
2027 } else if (lhs.is_integer() || rhs.is_integer()) {
2028 ttlet lhs_ = static_cast<long long int>(lhs);
2029 ttlet rhs_ = static_cast<long long int>(rhs);
2030 return datum_impl{ lhs_ * rhs_ };
2031
2032 } else {
2033 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't multiply '*' value {} of type {} with value {} of type {}",
2034 lhs.repr(), lhs.type_name(), rhs.repr(), rhs.type_name()
2035 );
2036 }
2037 }
2038
2039 friend datum_impl operator/(datum_impl const &lhs, datum_impl const &rhs) {
2040 if (lhs.is_float() || rhs.is_float()) {
2041 ttlet lhs_ = static_cast<double>(lhs);
2042 ttlet rhs_ = static_cast<double>(rhs);
2043 return datum_impl{ lhs_ / rhs_ };
2044
2045 } else if (lhs.is_decimal() || rhs.is_decimal()) {
2046 ttlet lhs_ = static_cast<decimal>(lhs);
2047 ttlet rhs_ = static_cast<decimal>(rhs);
2048 return datum_impl{ lhs_ / rhs_ };
2049
2050 } else if (lhs.is_integer() || rhs.is_integer()) {
2051 ttlet lhs_ = static_cast<long long int>(lhs);
2052 ttlet rhs_ = static_cast<long long int>(rhs);
2053 return datum_impl{ lhs_ / rhs_ };
2054
2055 } else if (lhs.is_url() && (rhs.is_url() || rhs.is_string())) {
2056 ttlet lhs_ = static_cast<URL>(lhs);
2057 ttlet rhs_ = static_cast<URL>(rhs);
2058 return datum_impl{ lhs_ / rhs_ };
2059
2060 } else {
2061 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't divide '/' value {} of type {} by value {} of type {}",
2062 lhs.repr(), lhs.type_name(), rhs.repr(), rhs.type_name()
2063 );
2064 }
2065 }
2066
2067 friend datum_impl operator%(datum_impl const &lhs, datum_impl const &rhs) {
2068 if (lhs.is_float() || rhs.is_float()) {
2069 ttlet lhs_ = static_cast<double>(lhs);
2070 ttlet rhs_ = static_cast<double>(rhs);
2071 return datum_impl{ fmod(lhs_, rhs_) };
2072
2073 } else if (lhs.is_decimal() || rhs.is_decimal()) {
2074 ttlet lhs_ = static_cast<decimal>(lhs);
2075 ttlet rhs_ = static_cast<decimal>(rhs);
2076 return datum_impl{ lhs_ % rhs_ };
2077
2078 } else if (lhs.is_integer() || rhs.is_integer()) {
2079 ttlet lhs_ = static_cast<long long int>(lhs);
2080 ttlet rhs_ = static_cast<long long int>(rhs);
2081 return datum_impl{ lhs_ % rhs_ };
2082
2083 } else {
2084 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't take modulo '%' value {} of type {} by value {} of type {}",
2085 lhs.repr(), lhs.type_name(), rhs.repr(), rhs.type_name()
2086 );
2087 }
2088 }
2089
2090 friend datum_impl operator<<(datum_impl const &lhs, datum_impl const &rhs) {
2091 if (lhs.is_integer() && rhs.is_integer()) {
2092 ttlet lhs_ = static_cast<uint64_t>(lhs);
2093 ttlet rhs_ = static_cast<int64_t>(rhs);
2094 if (rhs_ < -63) {
2095 return datum_impl{0};
2096 } else if (rhs_ < 0) {
2097 // Pretend this is a unsigned shift right.
2098 return datum_impl{lhs_ >> -rhs_};
2099 } else if (rhs_ == 0) {
2100 return lhs;
2101 } else if (rhs_ > 63) {
2102 return datum_impl{0};
2103 } else {
2104 return datum_impl{lhs_ << rhs_};
2105 }
2106
2107 } else {
2108 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't logical shift-left '<<' value {} of type {} with value {} of type {}",
2109 lhs.repr(), lhs.type_name(), rhs.repr(), rhs.type_name()
2110 );
2111 }
2112 }
2113
2114 friend datum_impl operator>>(datum_impl const &lhs, datum_impl const &rhs) {
2115 if (lhs.is_integer() && rhs.is_integer()) {
2116 ttlet lhs_ = static_cast<uint64_t>(lhs);
2117 ttlet rhs_ = static_cast<int64_t>(rhs);
2118 if (rhs_ < -63) {
2119 return datum_impl{0};
2120 } else if (rhs_ < 0) {
2121 return datum_impl{lhs_ << -rhs_};
2122 } else if (rhs_ == 0) {
2123 return lhs;
2124 } else if (rhs_ > 63) {
2125 return (lhs_ >= 0) ? datum_impl{0} : datum_impl{-1};
2126 } else {
2127 return datum_impl{static_cast<int64_t>(lhs_) >> rhs_};
2128 }
2129
2130 } else {
2131 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't arithmetic shift-right '>>' value {} of type {} with value {} of type {}",
2132 lhs.repr(), lhs.type_name(), rhs.repr(), rhs.type_name()
2133 );
2134 }
2135 }
2136
2137 friend datum_impl operator&(datum_impl const &lhs, datum_impl const &rhs) {
2138 if (lhs.is_integer() && rhs.is_integer()) {
2139 ttlet lhs_ = static_cast<uint64_t>(lhs);
2140 ttlet rhs_ = static_cast<uint64_t>(rhs);
2141 return datum_impl{lhs_ & rhs_};
2142
2143 } else {
2144 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't AND '&' value {} of type {} with value {} of type {}",
2145 lhs.repr(), lhs.type_name(), rhs.repr(), rhs.type_name()
2146 );
2147 }
2148 }
2149
2150 friend datum_impl operator|(datum_impl const &lhs, datum_impl const &rhs) {
2151 if (lhs.is_integer() && rhs.is_integer()) {
2152 ttlet lhs_ = static_cast<uint64_t>(lhs);
2153 ttlet rhs_ = static_cast<uint64_t>(rhs);
2154 return datum_impl{lhs_ | rhs_};
2155
2156 } else {
2157 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't OR '|' value {} of type {} with value {} of type {}",
2158 lhs.repr(), lhs.type_name(), rhs.repr(), rhs.type_name()
2159 );
2160 }
2161 }
2162
2163 friend datum_impl operator^(datum_impl const &lhs, datum_impl const &rhs) {
2164 if (lhs.is_integer() && rhs.is_integer()) {
2165 ttlet lhs_ = static_cast<uint64_t>(lhs);
2166 ttlet rhs_ = static_cast<uint64_t>(rhs);
2167 return datum_impl{lhs_ ^ rhs_};
2168
2169 } else {
2170 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't XOR '^' value {} of type {} with value {} of type {}",
2171 lhs.repr(), lhs.type_name(), rhs.repr(), rhs.type_name()
2172 );
2173 }
2174 }
2175
2176 friend std::string to_string(datum_impl const &d) {
2177 return static_cast<std::string>(d);
2178 }
2179
2180 friend std::ostream &operator<<(std::ostream &os, datum_impl const &d) {
2181 return os << static_cast<std::string>(d);
2182 }
2183
2184 friend void swap(datum_impl &lhs, datum_impl &rhs) noexcept {
2185 memswap(lhs, rhs);
2186 }
2187
2188 friend datum_impl pow(datum_impl const &lhs, datum_impl const &rhs) {
2189 if (lhs.is_numeric() || rhs.is_numeric()) {
2190 ttlet lhs_ = static_cast<double>(lhs);
2191 ttlet rhs_ = static_cast<double>(rhs);
2192 return datum_impl{ std::pow(lhs_, rhs_) };
2193
2194 } else {
2195 TTAURI_THROW_INVALID_OPERATION_ERROR("Can't raise to a power '**' value {} of type {} with value {} of type {}",
2196 lhs.repr(), lhs.type_name(), rhs.repr(), rhs.type_name()
2197 );
2198 }
2199 }
2200
2208 friend datum_impl deep_merge(datum_impl const &lhs, datum_impl const &rhs) noexcept {
2209 datum_impl result;
2210
2211 if (lhs.is_map() && rhs.is_map()) {
2212 result = lhs;
2213
2214 auto result_map = result.get_pointer<datum_impl::map>();
2215 for (auto rhs_i = rhs.map_begin(); rhs_i != rhs.map_end(); rhs_i++) {
2216 auto result_i = result_map->find(rhs_i->first);
2217 if (result_i == result_map->end()) {
2218 result_map->insert(*rhs_i);
2219 } else {
2220 result_i->second = deep_merge(result_i->second, rhs_i->second);
2221 }
2222 }
2223
2224 } else if (lhs.is_vector() && rhs.is_vector()) {
2225 result = lhs;
2226
2227 auto result_vector = result.get_pointer<datum_impl::vector>();
2228 for (auto rhs_i = rhs.vector_begin(); rhs_i != rhs.vector_end(); rhs_i++) {
2229 result_vector->push_back(*rhs_i);
2230 }
2231
2232 } else {
2233 result = rhs;
2234 }
2235
2236 return result;
2237 }
2238};
2239
2240template<typename T, bool HasLargeObjects>
2241inline bool will_cast_to(datum_impl<HasLargeObjects> const &rhs) {
2242 if constexpr (std::is_same_v<T, bool>) {
2243 return true;
2244 } else if constexpr (std::is_same_v<T, char>) {
2245 return rhs.is_string();
2246 } else if constexpr (std::is_arithmetic_v<T>) {
2247 return rhs.is_numeric();
2248 } else if constexpr (std::is_same_v<T, typename datum_impl<HasLargeObjects>::undefined>) {
2249 return rhs.is_undefined();
2250 } else if constexpr (std::is_same_v<T, typename datum_impl<HasLargeObjects>::null>) {
2251 return rhs.is_null();
2252 } else if constexpr (std::is_same_v<T, typename datum_impl<HasLargeObjects>::_break>) {
2253 return rhs.is_break();
2254 } else if constexpr (std::is_same_v<T, typename datum_impl<HasLargeObjects>::_continue>) {
2255 return rhs.is_continue();
2256 } else if constexpr (std::is_same_v<T, typename datum_impl<HasLargeObjects>::vector>) {
2257 return rhs.is_vector();
2258 } else if constexpr (std::is_same_v<T, typename datum_impl<HasLargeObjects>::map>) {
2259 return rhs.is_map();
2260 } else if constexpr (std::is_same_v<T, URL>) {
2261 return rhs.is_url() || rhs.is_string();
2262 } else if constexpr (std::is_same_v<T, std::string>) {
2263 return true;
2264 } else {
2265 return false;
2266 }
2267}
2268
2269template<bool HasLargeObjects>
2270bool operator<(typename datum_impl<HasLargeObjects>::map const &lhs, typename datum_impl<HasLargeObjects>::map const &rhs) noexcept {
2271 auto lhs_keys = transform<datum_impl<HasLargeObjects>::vector>(lhs, [](auto x) { return x.first; });
2272 auto rhs_keys = transform<datum_impl<HasLargeObjects>::vector>(lhs, [](auto x) { return x.first; });
2273
2274 if (lhs_keys == rhs_keys) {
2275 for (ttlet &k: lhs_keys) {
2276 if (lhs.at(k) == rhs.at(k)) {
2277 continue;
2278 } else if (lhs.at(k) < rhs.at(k)) {
2279 return true;
2280 } else {
2281 return false;
2282 }
2283 }
2284 } else {
2285 return lhs_keys < rhs_keys;
2286 }
2287 return false;
2288}
2289
2290using datum = datum_impl<true>;
2291using sdatum = datum_impl<false>;
2292
2293}
2294
2295namespace std {
2296
2297template<bool HasLargeObjects>
2298inline size_t hash<tt::datum_impl<HasLargeObjects>>::operator()(tt::datum_impl<HasLargeObjects> const &value) const {
2299 return value.hash();
2300}
2301
2302
2303
2304}
2305
STL namespace.
A fixed size (64 bits) class for a generic value type.
Definition datum.hpp:106
datum_impl & operator[](datum_impl const &rhs)
Index into a datum::map or datum::vector.
Definition datum.hpp:1148
friend datum_impl deep_merge(datum_impl const &lhs, datum_impl const &rhs) noexcept
Merge two datums together, such that the second will override values on the first.
Definition datum.hpp:2208
datum_impl & append()
Append and return a reference to a datum holding undefined to this datum.
Definition datum.hpp:1249
datum_impl operator[](datum_impl const &rhs) const
Index into a datum::map or datum::vector.
Definition datum.hpp:1186
int type_order() const noexcept
Definition datum.hpp:1431
bool contains(datum_impl const &rhs) const noexcept
Check if an index is contained in a datum.
Definition datum.hpp:1222
Definition datum.hpp:387
Definition datum.hpp:388
Definition datum.hpp:389
Definition datum.hpp:390
Definition decimal.hpp:18
Definition range_map.hpp:119
Definition URL.hpp:45
T accumulate(T... args)
T at(T... args)
T back_inserter(T... args)
T begin(T... args)
T copy(T... args)
T count(T... args)
T end(T... args)
T find(T... args)
T fmod(T... args)
T memcpy(T... args)
T move(T... args)
T next(T... args)
T operator()(T... args)
T pow(T... args)
T push_back(T... args)
T reserve(T... args)
T size(T... args)
T sort(T... args)
T stoll(T... args)