HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
datum.hpp
1// Copyright Take Vos 2021.
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 "exception.hpp"
8#include "assert.hpp"
9#include "concepts.hpp"
10#include "required.hpp"
11#include "decimal.hpp"
12#include "URL.hpp"
13#include "byte_string.hpp"
14#include "hash.hpp"
15#include "charconv.hpp"
16#include "codec/base_n.hpp"
17#include "jsonpath.hpp"
18#include <cstdint>
19#include <concepts>
20#include <bit>
21#include <exception>
22#include <chrono>
23#include <limits>
24#include <vector>
25#include <map>
26
27namespace tt {
28class datum;
29}
30
31namespace std {
32
33template<>
34struct hash<tt::datum> {
35 [[nodiscard]] constexpr size_t operator()(tt::datum const &rhs) const noexcept;
36};
37
38} // namespace std
39
40namespace tt {
41namespace detail {
42
47template<typename To>
49public:
50 using value_type = To;
51 static constexpr bool data_is_pointer = sizeof(value_type) > sizeof(void *);
52 static constexpr bool data_is_scalar = not data_is_pointer;
53
54 constexpr void clear() noexcept requires(data_is_scalar) {}
55 constexpr void clear() noexcept requires(data_is_pointer)
56 {
57 if (_owns_lhs) {
58 delete _lhs;
59 }
60 if (_owns_rhs) {
61 delete _rhs;
62 }
63 }
64
65 constexpr ~datum_promotion_result()
66 {
67 clear();
68 }
69
70 constexpr datum_promotion_result() noexcept = default;
71
73 datum_promotion_result &operator=(datum_promotion_result const &) = delete;
74
75 constexpr datum_promotion_result(datum_promotion_result &&other) noexcept :
76 _lhs(other._lhs),
77 _rhs(other._rhs),
78 _is_result(other._is_result),
79 _owns_lhs(std::exchange(other._owns_lhs, false)),
80 _owns_rhs(std::exchange(other._owns_rhs, false))
81 {
82 }
83
84 constexpr datum_promotion_result &operator=(datum_promotion_result &&other) noexcept
85 {
86 clear();
87 _lhs = other.lhs;
88 _rhs = other.rhs;
89 _is_result = other._is_result;
90 _owns_lhs = std::exchange(other._owns_lhs, false);
91 _owns_rhs = std::exchange(other._owns_rhs, false);
92 return *this;
93 }
94
95 constexpr explicit operator bool() const noexcept
96 {
97 return _is_result;
98 }
99
100 constexpr void set(value_type lhs, value_type rhs) noexcept requires(data_is_scalar)
101 {
102 _lhs = lhs;
103 _rhs = rhs;
104 _is_result = true;
105 }
106
107 constexpr void set(value_type const &lhs, value_type const &rhs) noexcept requires(data_is_pointer)
108 {
109 _lhs = &lhs;
110 _rhs = &rhs;
111 _is_result = true;
112 }
113
114 constexpr void set(value_type &&lhs, value_type const &rhs) noexcept requires(data_is_pointer)
115 {
116 _lhs = new value_type(std::move(lhs));
117 _rhs = &rhs;
118 _is_result = true;
119 _owns_lhs = true;
120 }
121
122 constexpr void set(value_type const &lhs, value_type &&rhs) noexcept requires(data_is_pointer)
123 {
124 _lhs = &lhs;
125 _rhs = new value_type(std::move(rhs));
126 _is_result = true;
127 _owns_rhs = true;
128 }
129
130 constexpr void set(value_type &&lhs, value_type &&rhs) noexcept requires(data_is_pointer)
131 {
132 _lhs = new value_type(std::move(lhs));
133 _rhs = new value_type(std::move(rhs));
134 _is_result = true;
135 _owns_lhs = true;
136 _owns_rhs = true;
137 }
138
139 [[nodiscard]] constexpr value_type const &lhs() const noexcept requires(data_is_pointer)
140 {
141 tt_axiom(_is_result);
142 return *_lhs;
143 }
144
145 [[nodiscard]] constexpr value_type const &rhs() const noexcept requires(data_is_pointer)
146 {
147 tt_axiom(_is_result);
148 return *_rhs;
149 }
150
151 [[nodiscard]] constexpr value_type lhs() const noexcept requires(data_is_scalar)
152 {
153 tt_axiom(_is_result);
154 return _lhs;
155 }
156
157 [[nodiscard]] constexpr value_type rhs() const noexcept requires(data_is_scalar)
158 {
159 tt_axiom(_is_result);
160 return _rhs;
161 }
162
163private :
164
165 using data_type = std::conditional_t<data_is_pointer, value_type const *, value_type>;
166 data_type _lhs = data_type{};
167 data_type _rhs = data_type{};
168 bool _is_result = false;
169 bool _owns_lhs = false;
170 bool _owns_rhs = false;
171};
172
173} // namespace detail
174
175template<typename T>
177};
178
179template<>
180class is_datum_type<long long> : public std::true_type {
181};
182template<>
184};
185template<>
186class is_datum_type<double> : public std::true_type {
187};
188template<>
189class is_datum_type<bool> : public std::true_type {
190};
191template<>
192class is_datum_type<std::chrono::year_month_day> : public std::true_type {
193};
194template<>
195class is_datum_type<std::string> : public std::true_type {
196};
197template<>
199};
200
201template<typename T>
202constexpr bool is_datum_type_v = is_datum_type<T>::value;
203
213class datum {
214public:
217 struct break_type {
218 };
220 };
221
222 constexpr ~datum() noexcept
223 {
224 delete_pointer();
225 }
226
227 constexpr datum(datum const &other) noexcept : _tag(other._tag), _value(other._value)
228 {
229 if (other.is_pointer()) {
230 copy_pointer(other);
231 }
232 }
233
234 constexpr datum(datum &&other) noexcept : _tag(other._tag), _value(other._value)
235 {
236 other._tag = tag_type::monostate;
237 other._value._long_long = 0;
238 }
239
240 constexpr datum() noexcept : _tag(tag_type::monostate), _value(0) {}
241 constexpr explicit datum(std::monostate) noexcept : _tag(tag_type::monostate), _value(0) {}
242 constexpr explicit datum(nullptr_t) noexcept : _tag(tag_type::null), _value(0) {}
243 constexpr explicit datum(continue_type) noexcept : _tag(tag_type::flow_continue), _value(0) {}
244 constexpr explicit datum(break_type) noexcept : _tag(tag_type::flow_break), _value(0) {}
245 constexpr explicit datum(bool value) noexcept : _tag(tag_type::boolean), _value(value) {}
246 constexpr explicit datum(std::floating_point auto value) noexcept :
247 _tag(tag_type::floating_point), _value(static_cast<double>(value))
248 {
249 }
250
251 constexpr explicit datum(numeric_integral auto value) noexcept :
252 _tag(tag_type::integral), _value(static_cast<long long>(value))
253 {
254 }
255
256 constexpr explicit datum(decimal value) noexcept : _tag(tag_type::decimal), _value(value) {}
257 constexpr explicit datum(std::chrono::year_month_day value) noexcept : _tag(tag_type::year_month_day), _value(value) {}
258 explicit datum(std::string value) noexcept : _tag(tag_type::string), _value(new std::string{std::move(value)}) {}
259 explicit datum(std::string_view value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
260 explicit datum(char const *value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
261 explicit datum(vector_type value) noexcept : _tag(tag_type::vector), _value(new vector_type{std::move(value)}) {}
262 explicit datum(map_type value) noexcept : _tag(tag_type::map), _value(new map_type{std::move(value)}) {}
263 explicit datum(URL value) noexcept : _tag(tag_type::url), _value(new URL{std::move(value)}) {}
264 explicit datum(bstring value) noexcept : _tag(tag_type::bstring), _value(new bstring{std::move(value)}) {}
265
266 template<typename... Args>
267 [[nodiscard]] static datum make_vector(Args const &...args) noexcept
268 {
269 return datum{vector_type{datum{args}...}};
270 }
271
272 template<typename Key, typename Value, typename... Args>
273 [[nodiscard]] static void populate_map(map_type &r, Key const &key, Value const &value, Args const &...args) noexcept
274 {
275 r.insert(std::pair<datum, datum>{datum{key}, datum{value}});
276 if constexpr (sizeof...(Args) > 0) {
277 populate_map(r, args...);
278 }
279 }
280
281 template<typename... Args>
282 [[nodiscard]] static datum make_map(Args const &...args) noexcept
283 {
284 static_assert(sizeof...(Args) % 2 == 0, "Expect key value pairs for the arguments of make_map()");
285
286 auto r = map_type{};
287 if constexpr (sizeof...(Args) > 0) {
288 populate_map(r, args...);
289 }
290 return datum{std::move(r)};
291 }
292
293 [[nodiscard]] static datum make_break() noexcept
294 {
295 return datum{break_type{}};
296 }
297
298 [[nodiscard]] static datum make_continue() noexcept
299 {
300 return datum{continue_type{}};
301 }
302
303 constexpr datum &operator=(datum const &other) noexcept
304 {
305 tt_return_on_self_assignment(other);
306
307 delete_pointer();
308 _tag = other._tag;
309 _value = other._value;
310 if (other.is_pointer()) {
311 copy_pointer(other);
312 }
313 return *this;
314 }
315
316 constexpr datum &operator=(datum &&other) noexcept
317 {
318 std::swap(_tag, other._tag);
319 std::swap(_value, other._value);
320 return *this;
321 }
322
323 constexpr datum &operator=(std::floating_point auto value) noexcept(sizeof(value) <= 4)
324 {
325 delete_pointer();
326 _tag = tag_type::floating_point;
327 _value = static_cast<double>(value);
328 return *this;
329 }
330
331 constexpr datum &operator=(numeric_integral auto value) noexcept(sizeof(value) <= 4)
332 {
333 delete_pointer();
334 _tag = tag_type::integral;
335 _value = static_cast<long long>(value);
336 return *this;
337 }
338
339 constexpr datum &operator=(decimal value)
340 {
341 delete_pointer();
342 _tag = tag_type::decimal;
343 _value = value;
344 return *this;
345 }
346 constexpr datum &operator=(bool value) noexcept
347 {
348 delete_pointer();
349 _tag = tag_type::boolean;
350 _value = value;
351 return *this;
352 }
353
354 constexpr datum &operator=(std::chrono::year_month_day value) noexcept
355 {
356 delete_pointer();
357 _tag = tag_type::year_month_day;
358 _value = value;
359 return *this;
360 }
361
362 constexpr datum &operator=(std::monostate) noexcept
363 {
364 delete_pointer();
365 _tag = tag_type::monostate;
366 _value = 0;
367 return *this;
368 }
369
370 constexpr datum &operator=(nullptr_t) noexcept
371 {
372 delete_pointer();
373 _tag = tag_type::null;
374 _value = 0;
375 return *this;
376 }
377
378 datum &operator=(std::string value) noexcept
379 {
380 delete_pointer();
381 _tag = tag_type::string;
382 _value = new std::string{std::move(value)};
383 return *this;
384 }
385
386 datum &operator=(char const *value) noexcept
387 {
388 delete_pointer();
389 _tag = tag_type::string;
390 _value = new std::string{value};
391 return *this;
392 }
393
394 datum &operator=(std::string_view value) noexcept
395 {
396 delete_pointer();
397 _tag = tag_type::string;
398 _value = new std::string{value};
399 return *this;
400 }
401
402 datum &operator=(vector_type value) noexcept
403 {
404 delete_pointer();
405 _tag = tag_type::vector;
406 _value = new vector_type{std::move(value)};
407 return *this;
408 }
409
410 datum &operator=(map_type value) noexcept
411 {
412 delete_pointer();
413 _tag = tag_type::map;
414 _value = new map_type{std::move(value)};
415 return *this;
416 }
417
418 datum &operator=(URL value) noexcept
419 {
420 delete_pointer();
421 _tag = tag_type::url;
422 _value = new URL{std::move(value)};
423 return *this;
424 }
425
426 datum &operator=(bstring value) noexcept
427 {
428 delete_pointer();
429 _tag = tag_type::bstring;
430 _value = new bstring{std::move(value)};
431 return *this;
432 }
433
434 constexpr explicit operator bool() const noexcept
435 {
436 switch (_tag) {
437 case tag_type::floating_point: return static_cast<bool>(get<double>(*this));
438 case tag_type::decimal: return static_cast<bool>(get<decimal>(*this));
439 case tag_type::boolean: return get<bool>(*this);
440 case tag_type::integral: return static_cast<bool>(get<long long>(*this));
441 case tag_type::year_month_day: return true;
442 case tag_type::string: return static_cast<bool>(std::size(get<std::string>(*this)));
443 case tag_type::vector: return static_cast<bool>(std::size(get<vector_type>(*this)));
444 case tag_type::map: return static_cast<bool>(std::size(get<map_type>(*this)));
445 case tag_type::url: return static_cast<bool>(get<URL>(*this));
446 case tag_type::bstring: return static_cast<bool>(std::size(get<bstring>(*this)));
447 default: return false;
448 }
449 }
450
451 template<std::floating_point T>
452 constexpr explicit operator T() const
453 {
454 switch (_tag) {
455 case tag_type::floating_point: return static_cast<T>(get<double>(*this));
456 case tag_type::integral: return static_cast<T>(get<long long>(*this));
457 case tag_type::decimal: return static_cast<T>(get<decimal>(*this));
458 case tag_type::boolean: return static_cast<T>(get<bool>(*this));
459 default: throw std::domain_error(std::format("Can't convert {} to floating point", *this));
460 }
461 }
462
463 constexpr explicit operator decimal() const
464 {
465 switch (_tag) {
466 case tag_type::floating_point: return decimal(get<double>(*this));
467 case tag_type::integral: return decimal(get<long long>(*this));
468 case tag_type::decimal: return get<decimal>(*this);
469 case tag_type::boolean: return decimal(get<bool>(*this));
470 default: throw std::domain_error(std::format("Can't convert {} to floating point", *this));
471 }
472 }
473
474 template<numeric_integral T>
475 constexpr explicit operator T() const
476 {
477 if (auto f = get_if<double>(*this)) {
478 errno = 0;
479 auto r = std::round(*f);
480 if (errno == EDOM or errno == ERANGE or r < std::numeric_limits<T>::min() or r > std::numeric_limits<T>::max()) {
481 throw std::overflow_error("double to integral");
482 }
483 return static_cast<T>(r);
484
485 } else if (auto i = get_if<long long>(*this)) {
487 throw std::overflow_error("long long to integral");
488 }
489 return static_cast<T>(*i);
490
491 } else if (auto d = get_if<decimal>(*this)) {
492 auto r = static_cast<long long>(*d);
494 throw std::overflow_error("decimal to integral");
495 }
496 return static_cast<T>(r);
497
498 } else if (auto b = get_if<bool>(*this)) {
499 return static_cast<T>(*b);
500
501 } else {
502 throw std::domain_error(std::format("Can't convert {} to an integral", repr(*this)));
503 }
504 }
505
506 constexpr explicit operator std::chrono::year_month_day() const
507 {
508 if (auto ymd = get_if<std::chrono::year_month_day>(*this)) {
509 return *ymd;
510 } else {
511 throw std::domain_error(std::format("Can't convert {} to an std::chrono::year_month_day", repr(*this)));
512 }
513 }
514
515 explicit operator std::string() const noexcept
516 {
517 switch (_tag) {
518 case tag_type::monostate: return "undefined";
519 case tag_type::floating_point: return tt::to_string(_value._double);
520 case tag_type::decimal: return to_string(_value._decimal);
521 case tag_type::integral: return to_string(_value._long_long);
522 case tag_type::boolean: return _value._bool ? "true" : "false";
523 case tag_type::year_month_day: return std::format("{:%Y-%m-%d}", _value._year_month_day);
524 case tag_type::null: return "null";
525 case tag_type::flow_break: return "break";
526 case tag_type::flow_continue: return "continue";
527 case tag_type::string: return *_value._string;
528 case tag_type::url: return to_string(*_value._url);
529 case tag_type::vector: {
530 auto r = std::string{"["};
531 for (ttlet &item : *_value._vector) {
532 r += repr(item);
533 r += ',';
534 }
535 r += ']';
536 return r;
537 };
538 case tag_type::map: {
539 auto r = std::string{"{"};
540 for (ttlet &item : *_value._map) {
541 r += repr(item.first);
542 r += ':';
543 r += repr(item.second);
544 r += ',';
545 }
546 r += '}';
547 return r;
548 };
549 case tag_type::bstring: return base64::encode(*_value._bstring);
550 default: tt_no_default();
551 }
552 }
553
554 explicit operator std::string_view() const
555 {
556 if (auto s = get_if<std::string>(*this)) {
557 return std::string_view{*s};
558 } else if (auto u = get_if<URL>(*this)) {
559 return std::string_view{to_string(*u)};
560 } else {
561 throw std::domain_error(std::format("Can't convert {} to an std::string_view", repr(*this)));
562 }
563 }
564
565 explicit operator vector_type() const
566 {
567 if (auto v = get_if<vector_type>(*this)) {
568 return *v;
569 } else {
570 throw std::domain_error(std::format("Can't convert {} to an vector", repr(*this)));
571 }
572 }
573
574 explicit operator map_type() const
575 {
576 if (auto m = get_if<map_type>(*this)) {
577 return *m;
578 } else {
579 throw std::domain_error(std::format("Can't convert {} to an map", repr(*this)));
580 }
581 }
582
583 explicit operator URL() const
584 {
585 if (auto u = get_if<URL>(*this)) {
586 return *u;
587 } else if (auto s = get_if<std::string>(*this)) {
588 return URL{*s};
589 } else {
590 throw std::domain_error(std::format("Can't convert {} to an URL", repr(*this)));
591 }
592 }
593
594 explicit operator bstring() const
595 {
596 // XXX should be able to base-64 decode a std::string.
597 if (_tag != tag_type::bstring) {
598 throw std::domain_error(std::format("Can't convert {} to an bstring", repr(*this)));
599 }
600 return get<bstring>(*this);
601 }
602
603 [[nodiscard]] constexpr char const *type_name() const noexcept
604 {
605 switch (_tag) {
606 case tag_type::floating_point: return "float";
607 case tag_type::decimal: return "decimal";
608 case tag_type::integral: return "int";
609 case tag_type::boolean: return "bool";
610 case tag_type::year_month_day: return "date";
611 case tag_type::string: return "string";
612 case tag_type::url: return "url";
613 case tag_type::vector: return "vector";
614 case tag_type::map: return "map";
615 case tag_type::bstring: return "bytes";
616 default: tt_no_default();
617 }
618 }
619
622 [[nodiscard]] constexpr bool is_undefined() const noexcept
623 {
624 return _tag == tag_type::monostate;
625 }
626
630 [[nodiscard]] constexpr bool is_break() const noexcept
631 {
632 return _tag == tag_type::flow_break;
633 }
634
638 [[nodiscard]] constexpr bool is_continue() const noexcept
639 {
640 return _tag == tag_type::flow_continue;
641 }
642
643 [[nodiscard]] constexpr size_t hash() const noexcept
644 {
645 switch (_tag) {
646 case tag_type::floating_point: return std::hash<double>{}(_value._double);
647 case tag_type::decimal: return std::hash<decimal>{}(_value._decimal);
648 case tag_type::integral: return std::hash<long long>{}(_value._long_long);
649 case tag_type::boolean: return std::hash<bool>{}(_value._bool);
650 case tag_type::year_month_day: {
651 uint32_t r = 0;
652 r |= static_cast<uint32_t>(static_cast<int>(_value._year_month_day.year())) << 16;
653 r |= static_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.month())) << 8;
654 r |= static_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.day()));
655 return std::hash<uint32_t>{}(r);
656 }
657 case tag_type::string: return std::hash<std::string>{}(*_value._string);
658 case tag_type::vector: {
659 size_t r = 0;
660 for (ttlet &v : *_value._vector) {
661 r = hash_mix(r, v.hash());
662 }
663 return r;
664 }
665 case tag_type::map: {
666 size_t r = 0;
667 for (ttlet &kv : *_value._map) {
668 r = hash_mix(r, kv.first.hash(), kv.second.hash());
669 }
670 return r;
671 }
672 case tag_type::url: return std::hash<URL>{}(*_value._url);
673 case tag_type::bstring: return std::hash<bstring>{}(*_value._bstring);
674 default: tt_no_default();
675 }
676 }
677
678 [[nodiscard]] constexpr size_t size() const
679 {
680 if (ttlet *s = get_if<std::string>(*this)) {
681 return std::size(*s);
682 } else if (ttlet *v = get_if<vector_type>(*this)) {
683 return std::size(*v);
684 } else if (ttlet *m = get_if<map_type>(*this)) {
685 return std::size(*m);
686 } else if (ttlet *b = get_if<bstring>(*this)) {
687 return std::size(get<bstring>(*this));
688 } else {
689 throw std::domain_error(std::format("Can not evaluate {}.size()", repr(*this)));
690 }
691 }
692
693 [[nodiscard]] constexpr datum const &back() const
694 {
695 if (ttlet *v = get_if<vector_type>(*this)) {
696 if (v->empty()) {
697 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
698 }
699 return v->back();
700 } else {
701 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
702 }
703 }
704
705 [[nodiscard]] constexpr datum &back()
706 {
707 if (auto *v = get_if<vector_type>(*this)) {
708 if (v->empty()) {
709 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
710 }
711 return v->back();
712 } else {
713 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
714 }
715 }
716
717 [[nodiscard]] constexpr datum const &front() const
718 {
719 if (ttlet *v = get_if<vector_type>(*this)) {
720 if (v->empty()) {
721 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
722 }
723 return v->front();
724 } else {
725 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
726 }
727 }
728
729 [[nodiscard]] constexpr datum &front()
730 {
731 if (auto *v = get_if<vector_type>(*this)) {
732 if (v->empty()) {
733 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
734 }
735 return v->front();
736 } else {
737 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
738 }
739 }
740
741 [[nodiscard]] constexpr auto cbegin() const
742 {
743 if (ttlet *v = get_if<vector_type>(*this)) {
744 return v->cbegin();
745 } else {
746 throw std::domain_error(std::format("Can not evaluate {}.cbegin()", repr(*this)));
747 }
748 }
749
750 [[nodiscard]] constexpr auto begin() const
751 {
752 if (ttlet *v = get_if<vector_type>(*this)) {
753 return v->begin();
754 } else {
755 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
756 }
757 }
758
759 [[nodiscard]] constexpr auto begin()
760 {
761 if (ttlet *v = get_if<vector_type>(*this)) {
762 return v->begin();
763 } else {
764 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
765 }
766 }
767
768 [[nodiscard]] constexpr auto cend() const
769 {
770 if (ttlet *v = get_if<vector_type>(*this)) {
771 return v->cend();
772 } else {
773 throw std::domain_error(std::format("Can not evaluate {}.cend()", repr(*this)));
774 }
775 }
776
777 [[nodiscard]] constexpr auto end() const
778 {
779 if (ttlet *v = get_if<vector_type>(*this)) {
780 return v->end();
781 } else {
782 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
783 }
784 }
785
786 [[nodiscard]] constexpr auto end()
787 {
788 if (ttlet *v = get_if<vector_type>(*this)) {
789 return v->end();
790 } else {
791 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
792 }
793 }
794
797 [[nodiscard]] constexpr vector_type keys() const
798 {
799 if (ttlet *m = get_if<map_type>(*this)) {
800 auto r = vector_type{};
801 r.reserve(std::size(*m));
802 for (ttlet &kv : *m) {
803 r.push_back(kv.first);
804 }
805 return r;
806 } else {
807 throw std::domain_error(std::format("Can not evaluate {}.keys()", repr(*this)));
808 }
809 }
810
813 [[nodiscard]] constexpr vector_type values() const
814 {
815 if (ttlet *m = get_if<map_type>(*this)) {
816 auto r = vector_type{};
817 r.reserve(std::size(*m));
818 for (ttlet &kv : *m) {
819 r.push_back(kv.second);
820 }
821 return r;
822 } else {
823 throw std::domain_error(std::format("Can not evaluate {}.values()", repr(*this)));
824 }
825 }
826
829 [[nodiscard]] constexpr vector_type items() const
830 {
831 if (ttlet *m = get_if<map_type>(*this)) {
832 auto r = vector_type{};
833 r.reserve(std::size(*m));
834
835 for (ttlet &item : *m) {
836 r.push_back(make_vector(item.first, item.second));
837 }
838 return r;
839 } else {
840 throw std::domain_error(std::format("Can not evaluate {}.items()", repr(*this)));
841 }
842 }
843
844 constexpr void push_back(datum const &rhs)
845 {
846 if (auto *v = get_if<vector_type>(*this)) {
847 return v->push_back(rhs);
848 } else {
849 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
850 }
851 }
852
853 constexpr void push_back(datum &&rhs)
854 {
855 if (auto *v = get_if<vector_type>(*this)) {
856 return v->push_back(std::move(rhs));
857 } else {
858 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
859 }
860 }
861
862 template<typename Arg>
863 constexpr void push_back(Arg &&arg)
864 {
865 push_back(datum{std::forward<Arg>(arg)});
866 }
867
868 constexpr void pop_back()
869 {
870 if (auto *v = get_if<vector_type>(*this)) {
871 if (v->empty()) {
872 throw std::domain_error(std::format("Empty vector {}.pop_back()", repr(*this)));
873 }
874 return v->pop_back();
875 } else {
876 throw std::domain_error(std::format("Can not evaluate {}.pop_back()", repr(*this)));
877 }
878 }
879
880 [[nodiscard]] constexpr bool contains(datum const &rhs) const
881 {
882 if (auto *m = get_if<map_type>(*this)) {
883 return m->contains(rhs);
884 } else {
885 throw std::domain_error(std::format("Can not evaluate {}.contains({})", repr(*this), repr(rhs)));
886 }
887 }
888
889 template<typename Arg>
890 [[nodiscard]] constexpr bool contains(Arg const &arg) const
891 {
892 return contains(datum{arg});
893 }
894
895 [[nodiscard]] std::vector<datum *> find(jsonpath const &path) noexcept
896 {
897 auto r = std::vector<datum *>{};
898 find(std::cbegin(path), std::cend(path), r);
899 return r;
900 }
901
902 [[nodiscard]] std::vector<datum const *> find(jsonpath const &path) const noexcept
903 {
904 auto tmp = std::vector<datum *>{};
905 const_cast<datum *>(this)->find(std::cbegin(path), std::cend(path), tmp);
907 std::copy(tmp.begin(), tmp.end(), std::back_inserter(r));
908 return r;
909 }
910
919 [[nodiscard]] bool remove(jsonpath const &path) noexcept
920 {
921 return static_cast<bool>(remove(std::cbegin(path), std::cend(path)));
922 }
923
929 [[nodiscard]] datum *find_one(jsonpath const &path) noexcept
930 {
931 tt_axiom(path.is_singular());
932 return find_one(std::cbegin(path), std::cend(path), false);
933 }
934
940 [[nodiscard]] datum *find_one_or_create(jsonpath const &path) noexcept
941 {
942 tt_axiom(path.is_singular());
943 return find_one(std::cbegin(path), std::cend(path), true);
944 }
945
951 [[nodiscard]] datum const *find_one(jsonpath const &path) const noexcept
952 {
953 tt_axiom(path.is_singular());
954 return const_cast<datum *>(this)->find_one(std::cbegin(path), std::cend(path), false);
955 }
956
957 [[nodiscard]] constexpr datum const &operator[](datum const &rhs) const
958 {
959 if (holds_alternative<vector_type>(*this) and holds_alternative<long long>(rhs)) {
960 ttlet &v = get<vector_type>(*this);
961
962 auto index = get<long long>(rhs);
963 if (index < 0) {
964 index = std::ssize(v) + index;
965 }
966 if (index < 0 or index >= std::ssize(v)) {
967 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
968 }
969
970 return v[index];
971
972 } else if (holds_alternative<map_type>(*this)) {
973 ttlet &m = get<map_type>(*this);
974 ttlet it = m.find(rhs);
975 if (it == m.end()) {
976 throw std::overflow_error(std::format("Key {} not found in map", repr(rhs)));
977 }
978
979 return it->second;
980
981 } else {
982 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
983 }
984 }
985
986 [[nodiscard]] constexpr datum &operator[](datum const &rhs)
987 {
988 if (holds_alternative<vector_type>(*this) and holds_alternative<long long>(rhs)) {
989 auto &v = get<vector_type>(*this);
990
991 auto index = get<long long>(rhs);
992 if (index < 0) {
993 index = std::ssize(v) + index;
994 }
995 if (index < 0 or index >= std::ssize(v)) {
996 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
997 }
998
999 return v[index];
1000
1001 } else if (holds_alternative<map_type>(*this)) {
1002 auto &m = get<map_type>(*this);
1003 return m[rhs];
1004
1005 } else {
1006 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
1007 }
1008 }
1009
1010 [[nodiscard]] constexpr datum const &operator[](auto const &rhs) const
1011 {
1012 return (*this)[datum{rhs}];
1013 }
1014
1015 [[nodiscard]] constexpr datum &operator[](auto const &rhs)
1016 {
1017 return (*this)[datum{rhs}];
1018 }
1019
1020 [[nodiscard]] constexpr datum &operator++()
1021 {
1022 if (holds_alternative<long long>(*this)) {
1023 ++_value._long_long;
1024 return *this;
1025 } else {
1026 throw std::domain_error(std::format("Can not evaluate ++{}", repr(*this)));
1027 }
1028 }
1029
1030 [[nodiscard]] constexpr datum &operator--()
1031 {
1032 if (holds_alternative<long long>(*this)) {
1033 --_value._long_long;
1034 return *this;
1035 } else {
1036 throw std::domain_error(std::format("Can not evaluate --{}", repr(*this)));
1037 }
1038 }
1039
1040 [[nodiscard]] constexpr datum operator++(int)
1041 {
1042 if (holds_alternative<long long>(*this)) {
1043 auto tmp = *this;
1044 _value._long_long++;
1045 return tmp;
1046 } else {
1047 throw std::domain_error(std::format("Can not evaluate {}++", repr(*this)));
1048 }
1049 }
1050 [[nodiscard]] constexpr datum operator--(int)
1051 {
1052 if (holds_alternative<long long>(*this)) {
1053 auto tmp = *this;
1054 _value._long_long--;
1055 return tmp;
1056 } else {
1057 throw std::domain_error(std::format("Can not evaluate {}--", repr(*this)));
1058 }
1059 }
1060
1061 constexpr datum &operator+=(auto const &rhs)
1062 {
1063 if (holds_alternative<vector_type>(*this)) {
1064 push_back(rhs);
1065 return *this;
1066 } else {
1067 return (*this) = (*this) + rhs;
1068 }
1069 }
1070
1071#define X(op, inner_op) \
1072 constexpr datum &operator op(auto const &rhs) \
1073 { \
1074 return (*this) = (*this)inner_op rhs; \
1075 }
1076
1077 X(-=, -)
1078 X(*=, *)
1079 X(/=, /)
1080 X(%=, %)
1081 X(&=, &)
1082 X(|=, |)
1083 X(^=, ^)
1084 X(<<=, <<)
1085 X(>>=, >>)
1086#undef X
1087
1088 [[nodiscard]] friend constexpr bool operator==(datum const &lhs, datum const &rhs) noexcept
1089 {
1090 if (ttlet doubles = promote_if<double>(lhs, rhs)) {
1091 return doubles.lhs() == doubles.rhs();
1092
1093 } else if (ttlet decimals = promote_if<decimal>(lhs, rhs)) {
1094 return decimals.lhs() == decimals.rhs();
1095
1096 } else if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1097 return long_longs.lhs() == long_longs.rhs();
1098
1099 } else if (ttlet bools = promote_if<bool>(lhs, rhs)) {
1100 return bools.lhs() == bools.rhs();
1101
1102 } else if (ttlet ymds = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1103 return ymds.lhs() == ymds.rhs();
1104
1105 } else if (ttlet urls = promote_if<URL>(lhs, rhs)) {
1106 return urls.lhs() == urls.rhs();
1107
1108 } else if (ttlet strings = promote_if<std::string>(lhs, rhs)) {
1109 return strings.lhs() == strings.rhs();
1110
1111 } else if (ttlet vectors = promote_if<vector_type>(lhs, rhs)) {
1112 return vectors.lhs() == vectors.rhs();
1113
1114 } else if (ttlet maps = promote_if<map_type>(lhs, rhs)) {
1115 return maps.lhs() == maps.rhs();
1116
1117 } else {
1118 return lhs._tag == rhs._tag;
1119 }
1120 }
1121
1152 [[nodiscard]] friend constexpr std::partial_ordering operator<=>(datum const &lhs, datum const &rhs) noexcept
1153 {
1154 if (ttlet doubles = promote_if<double>(lhs, rhs)) {
1155 return doubles.lhs() <=> doubles.rhs();
1156
1157 } else if (ttlet decimals = promote_if<decimal>(lhs, rhs)) {
1158 return decimals.lhs() <=> decimals.rhs();
1159
1160 } else if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1161 return long_longs.lhs() <=> long_longs.rhs();
1162
1163 } else if (ttlet bools = promote_if<bool>(lhs, rhs)) {
1164 return bools.lhs() <=> bools.rhs();
1165
1166 } else if (ttlet year_month_days = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1167 return year_month_days.lhs() <=> year_month_days.rhs();
1168
1169 } else if (ttlet urls = promote_if<URL>(lhs, rhs)) {
1170 return urls.lhs() <=> urls.rhs();
1171
1172 } else if (ttlet strings = promote_if<std::string>(lhs, rhs)) {
1173 return strings.lhs() <=> strings.rhs();
1174
1175 } else if (ttlet vectors = promote_if<vector_type>(lhs, rhs)) {
1176 return vectors.lhs() <=> vectors.rhs();
1177
1178 } else if (ttlet maps = promote_if<map_type>(lhs, rhs)) {
1179 return maps.lhs() <=> maps.rhs();
1180
1181 } else if (ttlet bstrings = promote_if<bstring>(lhs, rhs)) {
1182 return bstrings.lhs() <=> bstrings.rhs();
1183
1184 } else {
1185 return lhs._tag <=> rhs._tag;
1186 }
1187 }
1188
1199 [[nodiscard]] friend constexpr datum operator-(datum const &rhs)
1200 {
1201 if (ttlet rhs_double = get_if<double>(rhs)) {
1202 return datum{-*rhs_double};
1203
1204 } else if (ttlet rhs_decimal = get_if<decimal>(rhs)) {
1205 return datum{-*rhs_decimal};
1206
1207 } else if (ttlet rhs_long_long = get_if<long long>(rhs)) {
1208 return datum{-*rhs_long_long};
1209
1210 } else {
1211 throw std::domain_error(std::format("Can not evaluate -{}", repr(rhs)));
1212 }
1213 }
1214
1224 [[nodiscard]] friend constexpr datum operator~(datum const &rhs)
1225 {
1226 if (ttlet rhs_long_long = get_if<long long>(rhs)) {
1227 return datum{~*rhs_long_long};
1228
1229 } else {
1230 throw std::domain_error(std::format("Can not evaluate ~{}", repr(rhs)));
1231 }
1232 }
1233
1248 [[nodiscard]] friend constexpr datum operator+(datum const &lhs, datum const &rhs)
1249 {
1250 if (ttlet doubles = promote_if<double>(lhs, rhs)) {
1251 return datum{doubles.lhs() + doubles.rhs()};
1252
1253 } else if (ttlet decimals = promote_if<decimal>(lhs, rhs)) {
1254 return datum{decimals.lhs() + decimals.rhs()};
1255
1256 } else if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1257 return datum{long_longs.lhs() + long_longs.rhs()};
1258
1259 } else if (ttlet strings = promote_if<std::string>(lhs, rhs)) {
1260 return datum{strings.lhs() + strings.rhs()};
1261
1262 } else if (ttlet vectors = promote_if<vector_type>(lhs, rhs)) {
1263 auto r = vectors.lhs();
1264 r.insert(r.end(), vectors.rhs().begin(), vectors.rhs().end());
1265 return datum{std::move(r)};
1266
1267 } else {
1268 throw std::domain_error(std::format("Can not evaluate {} '+' {}", repr(lhs), repr(rhs)));
1269 }
1270 }
1271
1283 [[nodiscard]] friend constexpr datum operator-(datum const &lhs, datum const &rhs)
1284 {
1285 if (ttlet doubles = promote_if<double>(lhs, rhs)) {
1286 return datum{doubles.lhs() - doubles.rhs()};
1287
1288 } else if (ttlet decimals = promote_if<decimal>(lhs, rhs)) {
1289 return datum{decimals.lhs() - decimals.rhs()};
1290
1291 } else if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1292 return datum{long_longs.lhs() - long_longs.rhs()};
1293
1294 } else {
1295 throw std::domain_error(std::format("Can not evaluate {} '-' {}", repr(lhs), repr(rhs)));
1296 }
1297 }
1298
1310 [[nodiscard]] friend constexpr datum operator*(datum const &lhs, datum const &rhs)
1311 {
1312 if (ttlet doubles = promote_if<double>(lhs, rhs)) {
1313 return datum{doubles.lhs() * doubles.rhs()};
1314
1315 } else if (ttlet decimals = promote_if<decimal>(lhs, rhs)) {
1316 return datum{decimals.lhs() * decimals.rhs()};
1317
1318 } else if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1319 return datum{long_longs.lhs() * long_longs.rhs()};
1320
1321 } else {
1322 throw std::domain_error(std::format("Can not evaluate {} '*' {}", repr(lhs), repr(rhs)));
1323 }
1324 }
1325
1339 [[nodiscard]] friend constexpr datum operator/(datum const &lhs, datum const &rhs)
1340 {
1341 if (ttlet doubles = promote_if<double>(lhs, rhs)) {
1342 if (doubles.rhs() == 0) {
1343 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1344 }
1345 return datum{doubles.lhs() / doubles.rhs()};
1346
1347 } else if (ttlet decimals = promote_if<decimal>(lhs, rhs)) {
1348 if (decimals.rhs() == 0) {
1349 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1350 }
1351 return datum{decimals.lhs() / decimals.rhs()};
1352
1353 } else if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1354 if (long_longs.rhs() == 0) {
1355 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1356 }
1357 return datum{long_longs.lhs() / long_longs.rhs()};
1358
1359 } else if (ttlet urls = promote_if<URL>(lhs, rhs)) {
1360 return datum{urls.lhs() / urls.rhs()};
1361
1362 } else {
1363 throw std::domain_error(std::format("Can not evaluate {} '/' {}", repr(lhs), repr(rhs)));
1364 }
1365 }
1366
1378 [[nodiscard]] friend constexpr datum operator%(datum const &lhs, datum const &rhs)
1379 {
1380 if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1381 if (long_longs.rhs() == 0) {
1382 throw std::domain_error(std::format("Divide by zero {} '%' {}", repr(lhs), repr(rhs)));
1383 }
1384 return datum{long_longs.lhs() % long_longs.rhs()};
1385
1386 } else {
1387 throw std::domain_error(std::format("Can not evaluate {} '%' {}", repr(lhs), repr(rhs)));
1388 }
1389 }
1390
1401 [[nodiscard]] friend constexpr datum pow(datum const &lhs, datum const &rhs)
1402 {
1403 if (ttlet doubles = promote_if<double>(lhs, rhs)) {
1404 return datum{pow(doubles.lhs(), doubles.rhs())};
1405
1406 } else if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1407 return datum{pow(long_longs.lhs(), long_longs.rhs())};
1408
1409 } else {
1410 throw std::domain_error(std::format("Can not evaluate pow({}, {})", repr(lhs), repr(rhs)));
1411 }
1412 }
1413
1424 [[nodiscard]] friend constexpr datum operator&(datum const &lhs, datum const &rhs)
1425 {
1426 if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1427 return datum{long_longs.lhs() & long_longs.rhs()};
1428
1429 } else if (ttlet bools = promote_if<bool>(lhs, rhs)) {
1430 return datum{bools.lhs() and bools.rhs()};
1431
1432 } else {
1433 throw std::domain_error(std::format("Can not evaluate {} '&' {}", repr(lhs), repr(rhs)));
1434 }
1435 }
1436
1447 [[nodiscard]] friend constexpr datum operator|(datum const &lhs, datum const &rhs)
1448 {
1449 if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1450 return datum{long_longs.lhs() | long_longs.rhs()};
1451
1452 } else if (ttlet bools = promote_if<bool>(lhs, rhs)) {
1453 return datum{bools.lhs() or bools.rhs()};
1454
1455 } else {
1456 throw std::domain_error(std::format("Can not evaluate {} '|' {}", repr(lhs), repr(rhs)));
1457 }
1458 }
1459
1470 [[nodiscard]] friend constexpr datum operator^(datum const &lhs, datum const &rhs)
1471 {
1472 if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1473 return datum{long_longs.lhs() ^ long_longs.rhs()};
1474
1475 } else if (ttlet bools = promote_if<bool>(lhs, rhs)) {
1476 return datum{bools.lhs() != bools.rhs()};
1477
1478 } else {
1479 throw std::domain_error(std::format("Can not evaluate {} '^' {}", repr(lhs), repr(rhs)));
1480 }
1481 }
1482
1495 [[nodiscard]] friend constexpr datum operator<<(datum const &lhs, datum const &rhs)
1496 {
1497 if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1498 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1499 throw std::domain_error(std::format("Invalid shift count {} '<<' {}", repr(lhs), repr(rhs)));
1500 }
1501 return datum{long_longs.lhs() << long_longs.rhs()};
1502
1503 } else {
1504 throw std::domain_error(std::format("Can not evaluate {} '<<' {}", repr(lhs), repr(rhs)));
1505 }
1506 }
1507
1519 [[nodiscard]] friend constexpr datum operator>>(datum const &lhs, datum const &rhs)
1520 {
1521 if (ttlet long_longs = promote_if<long long>(lhs, rhs)) {
1522 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1523 throw std::domain_error(std::format("Invalid shift count {} '>>' {}", repr(lhs), repr(rhs)));
1524 }
1525 return datum{long_longs.lhs() >> long_longs.rhs()};
1526
1527 } else {
1528 throw std::domain_error(std::format("Can not evaluate {} '>>' {}", repr(lhs), repr(rhs)));
1529 }
1530 }
1531
1532 friend std::ostream &operator<<(std::ostream &lhs, datum const &rhs)
1533 {
1534 return lhs << to_string(rhs);
1535 }
1536
1537#define X(op) \
1538 [[nodiscard]] friend constexpr auto operator op(datum const &lhs, auto const &rhs) noexcept(noexcept(lhs op datum{rhs})) \
1539 { \
1540 return lhs op datum{rhs}; \
1541 } \
1542 [[nodiscard]] friend constexpr auto operator op(auto const &lhs, datum const &rhs) noexcept(noexcept(datum{lhs} op rhs)) \
1543 { \
1544 return datum{lhs} op rhs; \
1545 }
1546
1547 X(==)
1548 X(<=>)
1549 X(+)
1550 X(-)
1551 X(*)
1552 X(/)
1553 X(%)
1554 X(&)
1555 X(|)
1556 X(^) X(<<) X(>>)
1557#undef X
1558
1561 [[nodiscard]] friend std::string repr(datum const &rhs) noexcept
1562 {
1563 switch (rhs._tag) {
1564 case tag_type::monostate: return "undefined";
1565 case tag_type::floating_point: return std::format("{:.1f}", rhs._value._double);
1566 case tag_type::decimal: return to_string(rhs._value._decimal);
1567 case tag_type::integral: return std::format("{}", rhs._value._long_long);
1568 case tag_type::boolean: return rhs._value._bool ? "true" : "false";
1569 case tag_type::year_month_day: return std::format("{:%Y-%m-%d}", rhs._value._year_month_day);
1570 case tag_type::null: return "null";
1571 case tag_type::flow_break: return "break";
1572 case tag_type::flow_continue: return "continue";
1573 case tag_type::string: return std::format("\"{}\"", *rhs._value._string);
1574 case tag_type::url: return to_string(*rhs._value._url);
1575 case tag_type::vector: {
1576 auto r = std::string{"["};
1577 for (ttlet &item : *rhs._value._vector) {
1578 r += repr(item);
1579 r += ',';
1580 }
1581 r += ']';
1582 return r;
1583 };
1584 case tag_type::map: {
1585 auto r = std::string{"{"};
1586 for (ttlet &item : *rhs._value._map) {
1587 r += repr(item.first);
1588 r += ':';
1589 r += repr(item.second);
1590 r += ',';
1591 }
1592 r += '}';
1593 return r;
1594 };
1595 case tag_type::bstring: return base64::encode(*rhs._value._bstring);
1596 default: tt_no_default();
1597 }
1598 }
1599
1602 [[nodiscard]] friend std::string to_string(datum const &rhs) noexcept
1603 {
1604 return static_cast<std::string>(rhs);
1605 }
1606
1613 template<typename T>
1614 [[nodiscard]] friend constexpr bool holds_alternative(datum const &rhs) noexcept
1615 {
1616 if constexpr (std::is_same_v<T, double>) {
1617 return rhs._tag == tag_type::floating_point;
1618 } else if constexpr (std::is_same_v<T, decimal>) {
1619 return rhs._tag == tag_type::decimal;
1620 } else if constexpr (std::is_same_v<T, long long>) {
1621 return rhs._tag == tag_type::integral;
1622 } else if constexpr (std::is_same_v<T, bool>) {
1623 return rhs._tag == tag_type::boolean;
1624 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1625 return rhs._tag == tag_type::year_month_day;
1626 } else if constexpr (std::is_same_v<T, nullptr_t>) {
1627 return rhs._tag == tag_type::null;
1628 } else if constexpr (std::is_same_v<T, std::monostate>) {
1629 return rhs._tag == tag_type::monostate;
1630 } else if constexpr (std::is_same_v<T, break_type>) {
1631 return rhs._tag == tag_type::flow_break;
1632 } else if constexpr (std::is_same_v<T, continue_type>) {
1633 return rhs._tag == tag_type::flow_continue;
1634 } else if constexpr (std::is_same_v<T, std::string>) {
1635 return rhs._tag == tag_type::string;
1636 } else if constexpr (std::is_same_v<T, vector_type>) {
1637 return rhs._tag == tag_type::vector;
1638 } else if constexpr (std::is_same_v<T, map_type>) {
1639 return rhs._tag == tag_type::map;
1640 } else if constexpr (std::is_same_v<T, URL>) {
1641 return rhs._tag == tag_type::url;
1642 } else if constexpr (std::is_same_v<T, bstring>) {
1643 return rhs._tag == tag_type::bstring;
1644 } else {
1645 tt_static_no_default();
1646 }
1647 }
1648
1662 template<typename To>
1663 [[nodiscard]] friend constexpr bool promotable_to(datum const &rhs) noexcept
1664 {
1665 if constexpr (std::is_same_v<To, double>) {
1666 return holds_alternative<double>(rhs) or holds_alternative<decimal>(rhs) or holds_alternative<long long>(rhs) or
1667 holds_alternative<bool>(rhs);
1668 } else if constexpr (std::is_same_v<To, decimal>) {
1669 return holds_alternative<decimal>(rhs) or holds_alternative<long long>(rhs) or holds_alternative<bool>(rhs);
1670 } else if constexpr (std::is_same_v<To, long long>) {
1671 return holds_alternative<long long>(rhs) or holds_alternative<bool>(rhs);
1672 } else if constexpr (std::is_same_v<To, std::string>) {
1673 return holds_alternative<URL>(rhs) or holds_alternative<std::string>(rhs);
1674 } else if constexpr (std::is_same_v<To, URL>) {
1675 return holds_alternative<URL>(rhs) or holds_alternative<std::string>(rhs);
1676 } else {
1677 return holds_alternative<To>(rhs);
1678 }
1679 }
1680
1689 template<typename T>
1690 [[nodiscard]] friend constexpr T const &get(datum const &rhs) noexcept
1691 {
1692 tt_axiom(holds_alternative<T>(rhs));
1693 if constexpr (std::is_same_v<T, double>) {
1694 return rhs._value._double;
1695 } else if constexpr (std::is_same_v<T, decimal>) {
1696 return rhs._value._decimal;
1697 } else if constexpr (std::is_same_v<T, long long>) {
1698 return rhs._value._long_long;
1699 } else if constexpr (std::is_same_v<T, bool>) {
1700 return rhs._value._bool;
1701 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1702 return rhs._value._year_month_day;
1703 } else if constexpr (std::is_same_v<T, std::string>) {
1704 return *rhs._value._string;
1705 } else if constexpr (std::is_same_v<T, vector_type>) {
1706 return *rhs._value._vector;
1707 } else if constexpr (std::is_same_v<T, map_type>) {
1708 return *rhs._value._map;
1709 } else if constexpr (std::is_same_v<T, URL>) {
1710 return *rhs._value._url;
1711 } else if constexpr (std::is_same_v<T, bstring>) {
1712 return *rhs._value._bstring;
1713 } else {
1714 tt_static_no_default();
1715 }
1716 }
1717
1726 template<typename T>
1727 [[nodiscard]] friend constexpr T &get(datum &rhs) noexcept
1728 {
1729 tt_axiom(holds_alternative<T>(rhs));
1730 if constexpr (std::is_same_v<T, double>) {
1731 return rhs._value._double;
1732 } else if constexpr (std::is_same_v<T, decimal>) {
1733 return rhs._value._decimal;
1734 } else if constexpr (std::is_same_v<T, long long>) {
1735 return rhs._value._long_long;
1736 } else if constexpr (std::is_same_v<T, bool>) {
1737 return rhs._value._bool;
1738 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1739 return rhs._value._year_month_day;
1740 } else if constexpr (std::is_same_v<T, std::string>) {
1741 return *rhs._value._string;
1742 } else if constexpr (std::is_same_v<T, vector_type>) {
1743 return *rhs._value._vector;
1744 } else if constexpr (std::is_same_v<T, map_type>) {
1745 return *rhs._value._map;
1746 } else if constexpr (std::is_same_v<T, URL>) {
1747 return *rhs._value._url;
1748 } else if constexpr (std::is_same_v<T, bstring>) {
1749 return *rhs._value._bstring;
1750 } else {
1751 tt_static_no_default();
1752 }
1753 }
1754
1763 template<typename T>
1764 [[nodiscard]] friend constexpr T *get_if(datum &rhs) noexcept
1765 {
1766 if (holds_alternative<T>(rhs)) {
1767 return &get<T>(rhs);
1768 } else {
1769 return nullptr;
1770 }
1771 }
1772
1781 template<typename T>
1782 [[nodiscard]] friend constexpr T const *get_if(datum const &rhs) noexcept
1783 {
1784 if (holds_alternative<T>(rhs)) {
1785 return &get<T>(rhs);
1786 } else {
1787 return nullptr;
1788 }
1789 }
1790
1800 template<typename T>
1801 [[nodiscard]] friend T *get_if(datum &rhs, jsonpath const &path) noexcept
1802 {
1803 if (auto *value = rhs.find_one(path)) {
1804 if (holds_alternative<T>(*value)) {
1805 return &get<T>(*value);
1806 } else {
1807 return nullptr;
1808 }
1809 } else {
1810 return nullptr;
1811 }
1812 }
1813
1823 template<typename T>
1824 [[nodiscard]] friend T const *get_if(datum const &rhs, jsonpath const &path) noexcept
1825 {
1826 if (auto *value = const_cast<datum &>(rhs).find_one(path)) {
1827 if (holds_alternative<T>(*value)) {
1828 return &get<T>(*value);
1829 } else {
1830 return nullptr;
1831 }
1832 } else {
1833 return nullptr;
1834 }
1835 }
1836
1843 template<typename To>
1844 [[nodiscard]] friend constexpr auto promote_if(datum const &lhs, datum const &rhs) noexcept
1845 {
1847 if (holds_alternative<To>(lhs) and holds_alternative<To>(rhs)) {
1848 r.set(get<To>(lhs), get<To>(rhs));
1849
1850 } else if (holds_alternative<To>(lhs) and promotable_to<To>(rhs)) {
1851 r.set(get<To>(lhs), static_cast<To>(rhs));
1852
1853 } else if (promotable_to<To>(lhs) and holds_alternative<To>(rhs)) {
1854 r.set(static_cast<To>(lhs), get<To>(rhs));
1855 }
1856
1857 return r;
1858 }
1859
1860private:
1861 enum class tag_type : signed char {
1862 // scalars are detected by: `to_underlying(tag_type) >= 0`
1863 monostate = 0,
1864 floating_point = 1,
1865 integral = 2,
1866 decimal = 3,
1867 boolean = 4,
1868 null = 5,
1869 year_month_day = 6,
1870 flow_continue = 7,
1871 flow_break = 8,
1872
1873 // pointers are detected by: `to_underlying(tag_type) < 0`.
1874 string = -1,
1875 vector = -2,
1876 map = -3,
1877 url = -4,
1878 bstring = -5,
1879 };
1880
1881 tag_type _tag = tag_type::monostate;
1882 union value_type {
1883 double _double;
1884 long long _long_long;
1885 decimal _decimal;
1886 bool _bool;
1887 std::chrono::year_month_day _year_month_day;
1888 std::string *_string;
1889 vector_type *_vector;
1890 map_type *_map;
1891 URL *_url;
1892 bstring *_bstring;
1893
1894 constexpr value_type(numeric_integral auto value) noexcept : _long_long(static_cast<long long>(value)) {}
1895 constexpr value_type(std::floating_point auto value) noexcept : _double(static_cast<double>(value)) {}
1896 constexpr value_type(decimal value) noexcept : _decimal(value) {}
1897 constexpr value_type(bool value) noexcept : _bool(value) {}
1898 constexpr value_type(std::chrono::year_month_day value) noexcept : _year_month_day(value) {}
1899 constexpr value_type(std::string *value) noexcept : _string(value) {}
1900 constexpr value_type(vector_type *value) noexcept : _vector(value) {}
1901 constexpr value_type(map_type *value) noexcept : _map(value) {}
1902 constexpr value_type(URL *value) noexcept : _url(value) {}
1903 constexpr value_type(bstring *value) noexcept : _bstring(value) {}
1904 };
1905
1906 value_type _value;
1907
1908 [[nodiscard]] constexpr bool is_scalar() const noexcept
1909 {
1910 return to_underlying(_tag) >= 0;
1911 }
1912
1913 [[nodiscard]] constexpr bool is_pointer() const noexcept
1914 {
1915 return to_underlying(_tag) < 0;
1916 }
1917
1918 tt_no_inline void copy_pointer(datum const &other) noexcept
1919 {
1920 tt_axiom(other.is_pointer());
1921 switch (other._tag) {
1922 case tag_type::string: _value._string = new std::string{*other._value._string}; return;
1923 case tag_type::vector: _value._vector = new vector_type{*other._value._vector}; return;
1924 case tag_type::map: _value._map = new map_type{*other._value._map}; return;
1925 case tag_type::url: _value._url = new URL{*other._value._url}; return;
1926 case tag_type::bstring: _value._bstring = new bstring{*other._value._bstring}; return;
1927 default: tt_no_default();
1928 }
1929 }
1930
1931 tt_no_inline void _delete_pointer() noexcept
1932 {
1933 tt_axiom(is_pointer());
1934 switch (_tag) {
1935 case tag_type::string: delete _value._string; return;
1936 case tag_type::vector: delete _value._vector; return;
1937 case tag_type::map: delete _value._map; return;
1938 case tag_type::url: delete _value._url; return;
1939 case tag_type::bstring: delete _value._bstring; return;
1940 default: tt_no_default();
1941 }
1942 }
1943
1944 constexpr void delete_pointer() noexcept
1945 {
1946 if (is_pointer()) {
1947 _delete_pointer();
1948 }
1949 }
1950
1951 void find_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *> &r) noexcept
1952 {
1953 if (auto vector = get_if<datum::vector_type>(*this)) {
1954 for (auto &item : *vector) {
1955 item.find(it + 1, it_end, r);
1956 }
1957
1958 } else if (auto map = get_if<datum::map_type>(*this)) {
1959 for (auto &item : *map) {
1960 item.second.find(it + 1, it_end, r);
1961 }
1962 }
1963 }
1964
1965 void find_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *> &r) noexcept
1966 {
1967 this->find(it + 1, it_end, r);
1968
1969 if (auto vector = get_if<datum::vector_type>(*this)) {
1970 for (auto &item : *vector) {
1971 item.find(it, it_end, r);
1972 }
1973
1974 } else if (auto map = get_if<datum::map_type>(*this)) {
1975 for (auto &item : *map) {
1976 item.second.find(it, it_end, r);
1977 }
1978 }
1979 }
1980
1981 void find_indices(
1982 jsonpath_indices const &indices,
1983 jsonpath::const_iterator it,
1984 jsonpath::const_iterator it_end,
1985 std::vector<datum *> &r) noexcept
1986 {
1987 if (auto vector = get_if<datum::vector_type>(*this)) {
1988 for (ttlet index : indices.filter(std::ssize(*vector))) {
1989 (*vector)[index].find(it + 1, it_end, r);
1990 }
1991 }
1992 }
1993
1994 void find_names(
1995 jsonpath_names const &names,
1996 jsonpath::const_iterator it,
1997 jsonpath::const_iterator it_end,
1998 std::vector<datum *> &r) noexcept
1999 {
2000 if (auto map = get_if<datum::map_type>(*this)) {
2001 for (ttlet &name : names) {
2002 ttlet name_ = datum{name};
2003 auto jt = map->find(name_);
2004 if (jt != map->cend()) {
2005 jt->second.find(it + 1, it_end, r);
2006 }
2007 }
2008 }
2009 }
2010
2011 void find_slice(
2012 jsonpath_slice const &slice,
2013 jsonpath::const_iterator it,
2014 jsonpath::const_iterator it_end,
2015 std::vector<datum *> &r) noexcept
2016 {
2017 if (auto vector = get_if<datum::vector_type>(*this)) {
2018 ttlet first = slice.begin(vector->size());
2019 ttlet last = slice.end(vector->size());
2020
2021 for (auto index = first; index != last; index += slice.step) {
2022 if (index >= 0 and index < vector->size()) {
2023 (*this)[index].find(it + 1, it_end, r);
2024 }
2025 }
2026 }
2027 }
2028
2029 void find(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *> &r) noexcept
2030 {
2031 if (it == it_end) {
2032 r.push_back(this);
2033
2034 } else if (std::holds_alternative<jsonpath_root>(*it)) {
2035 find(it + 1, it_end, r);
2036
2037 } else if (std::holds_alternative<jsonpath_current>(*it)) {
2038 find(it + 1, it_end, r);
2039
2040 } else if (std::holds_alternative<jsonpath_wildcard>(*it)) {
2041 find_wildcard(it, it_end, r);
2042
2043 } else if (std::holds_alternative<jsonpath_descend>(*it)) {
2044 find_descend(it, it_end, r);
2045
2046 } else if (auto indices = std::get_if<jsonpath_indices>(&*it)) {
2047 find_indices(*indices, it, it_end, r);
2048
2049 } else if (auto names = std::get_if<jsonpath_names>(&*it)) {
2050 find_names(*names, it, it_end, r);
2051
2052 } else if (auto slice = std::get_if<jsonpath_slice>(&*it)) {
2053 find_slice(*slice, it, it_end, r);
2054
2055 } else {
2056 tt_no_default();
2057 }
2058 }
2059
2060 [[nodiscard]] int remove_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2061 {
2062 int r = 0;
2063
2064 if (auto vector = get_if<datum::vector_type>(*this)) {
2065 auto jt = vector->begin();
2066 while (jt != vector->end()) {
2067 ttlet match = jt->remove(it + 1, it_end);
2068 r |= match ? 1 : 0;
2069
2070 if (match == 2) {
2071 jt = vector->erase(jt);
2072 } else {
2073 ++jt;
2074 }
2075 }
2076 return vector->empty() ? 2 : r;
2077
2078 } else if (auto map = get_if<datum::map_type>(*this)) {
2079 auto jt = map->begin();
2080 while (jt != map->end()) {
2081 ttlet match = jt->second.remove(it + 1, it_end);
2082 r |= match ? 1 : 0;
2083
2084 if (match == 2) {
2085 jt = map->erase(jt);
2086 } else {
2087 ++jt;
2088 }
2089 }
2090 return map->empty() ? 2 : r;
2091
2092 } else {
2093 return 0;
2094 }
2095 }
2096
2097 [[nodiscard]] int remove_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2098 {
2099 int r = 0;
2100
2101 {
2102 ttlet match = this->remove(it + 1, it_end);
2103 if (match == 2) {
2104 return 2;
2105 }
2106 r |= match ? 1 : 0;
2107 }
2108
2109 if (auto vector = get_if<datum::vector_type>(*this)) {
2110 auto jt = vector->begin();
2111 while (jt != vector->end()) {
2112 ttlet match = jt->remove(it, it_end);
2113 r |= match ? 1 : 0;
2114
2115 if (match == 2) {
2116 jt = vector->erase(jt);
2117 } else {
2118 ++jt;
2119 }
2120 }
2121 return vector->empty() ? 2 : r;
2122
2123 } else if (auto map = get_if<datum::map_type>(*this)) {
2124 auto jt = map->begin();
2125 while (jt != map->end()) {
2126 ttlet match = jt->second.remove(it, it_end);
2127 r |= match ? 1 : 0;
2128
2129 if (match == 2) {
2130 jt = map->erase(jt);
2131 } else {
2132 ++jt;
2133 }
2134 }
2135 return map->empty() ? 2 : r;
2136
2137 } else {
2138 return 0;
2139 }
2140 }
2141
2142 [[nodiscard]] int
2143 remove_indices(jsonpath_indices const &indices, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2144 {
2145 if (auto vector = get_if<datum::vector_type>(*this)) {
2146 int r = 0;
2147 size_t offset = 0;
2148
2149 for (ttlet index : indices.filter(std::ssize(*vector))) {
2150 ttlet match = (*vector)[index - offset].remove(it + 1, it_end);
2151 r |= match ? 1 : 0;
2152 if (match == 2) {
2153 vector->erase(vector->begin() + (index - offset));
2154 ++offset;
2155 }
2156 }
2157
2158 return vector->empty() ? 2 : r;
2159
2160 } else {
2161 return 0;
2162 }
2163 }
2164
2165 [[nodiscard]] int
2166 remove_names(jsonpath_names const &names, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2167 {
2168 if (auto map = get_if<datum::map_type>(*this)) {
2169 int r = 0;
2170
2171 for (ttlet &name : names) {
2172 ttlet name_ = datum{name};
2173 auto jt = map->find(name_);
2174 if (jt != map->cend()) {
2175 ttlet match = jt->second.remove(it + 1, it_end);
2176 r |= match ? 1 : 0;
2177 if (match == 2) {
2178 map->erase(jt);
2179 }
2180 }
2181 }
2182
2183 return map->empty() ? 2 : r;
2184
2185 } else {
2186 return 0;
2187 }
2188 }
2189
2190 [[nodiscard]] int
2191 remove_slice(jsonpath_slice const &slice, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2192 {
2193 if (auto vector = get_if<datum::vector_type>(*this)) {
2194 int r = 0;
2195
2196 ttlet first = slice.begin(vector->size());
2197 ttlet last = slice.end(vector->size());
2198
2199 size_t offset = 0;
2200 for (auto index = first; index != last; index += slice.step) {
2201 if (index >= 0 and index < vector->size()) {
2202 ttlet match = (*this)[index - offset].remove(it + 1, it_end);
2203 r |= match ? 1 : 0;
2204
2205 if (match == 2) {
2206 vector->erase(vector->begin() + (index - offset));
2207 ++offset;
2208 }
2209 }
2210 }
2211
2212 return vector->empty() ? 2 : r;
2213
2214 } else {
2215 return 0;
2216 }
2217 }
2218
2219 [[nodiscard]] int remove(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2220 {
2221 if (it == it_end) {
2222 // Reached end, remove matching name or index in parent.
2223 return 2;
2224
2225 } else if (std::holds_alternative<jsonpath_root>(*it)) {
2226 return remove(it + 1, it_end);
2227
2228 } else if (std::holds_alternative<jsonpath_current>(*it)) {
2229 return remove(it + 1, it_end);
2230
2231 } else if (std::holds_alternative<jsonpath_wildcard>(*it)) {
2232 return remove_wildcard(it, it_end);
2233
2234 } else if (std::holds_alternative<jsonpath_descend>(*it)) {
2235 return remove_descend(it, it_end);
2236
2237 } else if (auto indices = std::get_if<jsonpath_indices>(&*it)) {
2238 return remove_indices(*indices, it, it_end);
2239
2240 } else if (auto names = std::get_if<jsonpath_names>(&*it)) {
2241 return remove_names(*names, it, it_end);
2242
2243 } else if (auto slice = std::get_if<jsonpath_slice>(&*it)) {
2244 return remove_slice(*slice, it, it_end);
2245
2246 } else {
2247 tt_no_default();
2248 }
2249 }
2250
2251 [[nodiscard]] datum *
2252 find_one_name(datum const &name, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2253 {
2254 tt_axiom(holds_alternative<std::string>(name));
2255
2256 if (auto *map = get_if<map_type>(*this)) {
2257 auto i = map->find(name);
2258 if (i != map->end()) {
2259 return i->second.find_one(it + 1, it_end, create);
2260
2261 } else if (create) {
2262 (*map)[name] = datum{std::monostate{}};
2263 return find_one_name(name, it, it_end, create);
2264
2265 } else {
2266 return nullptr;
2267 }
2268
2269 } else if (holds_alternative<std::monostate>(*this) and create) {
2270 *this = datum::make_map(name, std::monostate{});
2271 return find_one_name(name, it, it_end, create);
2272
2273 } else {
2274 return nullptr;
2275 }
2276 }
2277
2278 [[nodiscard]] datum *
2279 find_one_index(size_t index, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2280 {
2281 if (auto *vector = get_if<vector_type>(*this)) {
2282 if (index < vector->size()) {
2283 return (*vector)[index].find_one(it + 1, it_end, create);
2284 } else if (index == vector->size() and create) {
2285 vector->push_back(datum{std::monostate{}});
2286 return find_one_index(index, it, it_end, create);
2287 } else {
2288 return nullptr;
2289 }
2290
2291 } else if (holds_alternative<std::monostate>(*this) and index == 0 and create) {
2292 *this = datum::make_vector(std::monostate{});
2293 return find_one_index(index, it, it_end, create);
2294
2295 } else {
2296 return nullptr;
2297 }
2298 }
2299
2300 [[nodiscard]] datum *find_one(jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2301 {
2302 if (it == it_end) {
2303 return this;
2304
2305 } else if (std::holds_alternative<jsonpath_root>(*it)) {
2306 return find_one(it + 1, it_end, create);
2307
2308 } else if (std::holds_alternative<jsonpath_current>(*it)) {
2309 return find_one(it + 1, it_end, create);
2310
2311 } else if (ttlet *indices = std::get_if<jsonpath_indices>(&*it)) {
2312 tt_axiom(indices->size() == 1);
2313 return find_one_index(indices->front(), it, it_end, create);
2314
2315 } else if (ttlet *names = std::get_if<jsonpath_names>(&*it)) {
2316 tt_axiom(names->size() == 1);
2317 return find_one_name(datum{names->front()}, it, it_end, create);
2318
2319 } else {
2320 tt_no_default();
2321 }
2322 }
2323};
2324
2325} // namespace tt
2326
2327namespace std {
2328[[nodiscard]] constexpr size_t hash<tt::datum>::operator()(tt::datum const &rhs) const noexcept
2329{
2330 return rhs.hash();
2331}
2332
2333template<typename CharT>
2334struct std::formatter<tt::datum, CharT> : std::formatter<std::string_view, CharT> {
2335 auto format(tt::datum const &t, auto &fc)
2336 {
2337 return std::formatter<std::string_view, CharT>::format(to_string(t), fc);
2338 }
2339};
2340
2341} // namespace std
constexpr bool operator==(alignment lhs, horizontal_alignment rhs) noexcept
Check if the horizontal alignments are equal.
Definition alignment.hpp:136
constexpr alignment operator|(vertical_alignment lhs, horizontal_alignment rhs) noexcept
Combine vertical and horizontal alignment.
Definition alignment.hpp:91
STL namespace.
static constexpr void encode(ItIn ptr, ItIn last, ItOut output)
Encode bytes into a string.
Definition base_n.hpp:147
Promotion result.
Definition datum.hpp:48
Definition datum.hpp:176
A dynamic data type.
Definition datum.hpp:213
friend constexpr T & get(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1727
constexpr vector_type keys() const
Get the sorted list of keys of a map.
Definition datum.hpp:797
constexpr bool is_continue() const noexcept
Check if the result of a expression was a continue flow control statement.
Definition datum.hpp:638
friend constexpr bool promotable_to(datum const &rhs) noexcept
Check if the type held by the datum can be promoted.
Definition datum.hpp:1663
datum * find_one_or_create(jsonpath const &path) noexcept
Find a object by path potentially creating intermediate objects.
Definition datum.hpp:940
friend constexpr auto promote_if(datum const &lhs, datum const &rhs) noexcept
Promote two datum-arguments to a common type.
Definition datum.hpp:1844
friend std::string to_string(datum const &rhs) noexcept
Get the string representation of the value.
Definition datum.hpp:1602
friend constexpr T const * get_if(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1782
friend constexpr bool holds_alternative(datum const &rhs) noexcept
Check if the stored value is of a specific type.
Definition datum.hpp:1614
bool remove(jsonpath const &path) noexcept
Remove the object by path.
Definition datum.hpp:919
friend T * get_if(datum &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1801
constexpr vector_type items() const
Get key value pairs of items of a map sorted by the key.
Definition datum.hpp:829
constexpr vector_type values() const
Get the list of values of a map.
Definition datum.hpp:813
datum * find_one(jsonpath const &path) noexcept
Find a object by path.
Definition datum.hpp:929
constexpr bool is_break() const noexcept
Check if the result of a expression was a break flow control statement.
Definition datum.hpp:630
friend T const * get_if(datum const &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1824
constexpr bool is_undefined() const noexcept
Check if the datum has an undefined value.
Definition datum.hpp:622
friend constexpr T const & get(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1690
datum const * find_one(jsonpath const &path) const noexcept
Find a object by path.
Definition datum.hpp:951
friend constexpr T * get_if(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1764
Definition datum.hpp:217
Definition datum.hpp:219
Definition decimal.hpp:18
Definition jsonpath.hpp:379
T back_inserter(T... args)
T copy(T... args)
T max(T... args)
T move(T... args)
T operator()(T... args)
T pow(T... args)
T reserve(T... args)
T round(T... args)
T swap(T... args)
T to_string(T... args)