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