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