HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
datum.hpp
1// Copyright Take Vos 2019-2022.
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 "utility/module.hpp"
8#include "decimal.hpp"
9#include "byte_string.hpp"
10#include "codec/base_n.hpp"
11#include "jsonpath.hpp"
12#include <cstdint>
13#include <concepts>
14#include <bit>
15#include <exception>
16#include <chrono>
17#include <limits>
18#include <vector>
19#include <map>
20
21hi_warning_push();
22// C26476: Expression/symbol '...' uses a naked union '...' with multiple type pointers: Use variant instead (type.7.).
23// This implements `datum` which is simular to a std::variant.
24hi_warning_ignore_msvc(26476);
25// C26409: Avoid calling new and delete explicitly, use std::make_unique<T> instead (r.11).
26// This implements `datum` which implements RAII for large objects.
27hi_warning_ignore_msvc(26409);
28// C26492: Don't use const_cast to cast away const or volatile (type.3).
29// Needed until c++23 deducing this.
30hi_warning_ignore_msvc(26492);
31
32namespace hi::inline v1 {
33class datum;
34}
35
36template<>
37struct std::hash<hi::datum> {
38 [[nodiscard]] std::size_t operator()(hi::datum const& rhs) const noexcept;
39};
40
41template<typename CharT>
42struct std::formatter<hi::datum, CharT> : std::formatter<std::string, CharT> {
43 auto format(hi::datum const& t, auto& fc) const -> decltype(std::formatter<std::string, CharT>{}.format(std::string{}, fc));
44};
45
46namespace hi::inline v1 {
47namespace detail {
48
53template<typename To>
55public:
56 using value_type = To;
57 static constexpr bool data_is_pointer = sizeof(value_type) > sizeof(void *);
58 static constexpr bool data_is_scalar = not data_is_pointer;
59
60 constexpr void clear() noexcept
61 requires(data_is_scalar)
62 {
63 }
64 constexpr void clear() noexcept
65 requires(data_is_pointer)
66 {
67 if (_owns_lhs) {
68 delete _lhs;
69 }
70 if (_owns_rhs) {
71 delete _rhs;
72 }
73 }
74
75 constexpr ~datum_promotion_result()
76 {
77 clear();
78 }
79
80 constexpr datum_promotion_result() noexcept = default;
81
83 datum_promotion_result& operator=(datum_promotion_result const&) = delete;
84
85 constexpr datum_promotion_result(datum_promotion_result&& other) noexcept :
86 _lhs(other._lhs),
87 _rhs(other._rhs),
88 _is_result(other._is_result),
89 _owns_lhs(std::exchange(other._owns_lhs, false)),
90 _owns_rhs(std::exchange(other._owns_rhs, false))
91 {
92 }
93
94 constexpr datum_promotion_result& operator=(datum_promotion_result&& other) noexcept
95 {
96 clear();
97 _lhs = other.lhs;
98 _rhs = other.rhs;
99 _is_result = other._is_result;
100 _owns_lhs = std::exchange(other._owns_lhs, false);
101 _owns_rhs = std::exchange(other._owns_rhs, false);
102 return *this;
103 }
104
105 constexpr explicit operator bool() const noexcept
106 {
107 return _is_result;
108 }
109
110 constexpr void set(value_type lhs, value_type rhs) noexcept
111 requires(data_is_scalar)
112 {
113 _lhs = lhs;
114 _rhs = rhs;
115 _is_result = true;
116 }
117
118 constexpr void set(value_type const& lhs, value_type const& rhs) noexcept
119 requires(data_is_pointer)
120 {
121 _lhs = &lhs;
122 _rhs = &rhs;
123 _is_result = true;
124 }
125
126 constexpr void set(value_type&& lhs, value_type const& rhs) noexcept
127 requires(data_is_pointer)
128 {
129 _lhs = new value_type(std::move(lhs));
130 _rhs = &rhs;
131 _is_result = true;
132 _owns_lhs = true;
133 }
134
135 constexpr void set(value_type const& lhs, value_type&& rhs) noexcept
136 requires(data_is_pointer)
137 {
138 _lhs = &lhs;
139 _rhs = new value_type(std::move(rhs));
140 _is_result = true;
141 _owns_rhs = true;
142 }
143
144 constexpr void set(value_type&& lhs, value_type&& rhs) noexcept
145 requires(data_is_pointer)
146 {
147 _lhs = new value_type(std::move(lhs));
148 _rhs = new value_type(std::move(rhs));
149 _is_result = true;
150 _owns_lhs = true;
151 _owns_rhs = true;
152 }
153
154 [[nodiscard]] constexpr value_type const& lhs() const noexcept
155 requires(data_is_pointer)
156 {
157 hi_axiom(_is_result);
158 return *_lhs;
159 }
160
161 [[nodiscard]] constexpr value_type const& rhs() const noexcept
162 requires(data_is_pointer)
163 {
164 hi_axiom(_is_result);
165 return *_rhs;
166 }
167
168 [[nodiscard]] constexpr value_type lhs() const noexcept
169 requires(data_is_scalar)
170 {
171 hi_axiom(_is_result);
172 return _lhs;
173 }
174
175 [[nodiscard]] constexpr value_type rhs() const noexcept
176 requires(data_is_scalar)
177 {
178 hi_axiom(_is_result);
179 return _rhs;
180 }
181
182private:
183 using data_type = std::conditional_t<data_is_pointer, value_type const *, value_type>;
184 data_type _lhs = data_type{};
185 data_type _rhs = data_type{};
186 bool _is_result = false;
187 bool _owns_lhs = false;
188 bool _owns_rhs = false;
189};
190
191} // namespace detail
192
193template<typename T>
195
196template<>
197class is_datum_type<long long> : public std::true_type {};
198template<>
200template<>
201class is_datum_type<double> : public std::true_type {};
202template<>
203class is_datum_type<bool> : public std::true_type {};
204template<>
205class is_datum_type<std::chrono::year_month_day> : public std::true_type {};
206template<>
207class is_datum_type<std::string> : public std::true_type {};
208template<>
210
211template<typename T>
212constexpr bool is_datum_type_v = is_datum_type<T>::value;
213
223class datum {
224public:
227 struct break_type {};
228 struct continue_type {};
229
236 template<typename To>
237 [[nodiscard]] friend constexpr auto promote_if(datum const& lhs, datum const& rhs) noexcept
238 {
240 if (holds_alternative<To>(lhs) and holds_alternative<To>(rhs)) {
241 r.set(get<To>(lhs), get<To>(rhs));
242
243 } else if (holds_alternative<To>(lhs) and promotable_to<To>(rhs)) {
244 r.set(get<To>(lhs), static_cast<To>(rhs));
245
246 } else if (promotable_to<To>(lhs) and holds_alternative<To>(rhs)) {
247 r.set(static_cast<To>(lhs), get<To>(rhs));
248 }
249
250 return r;
251 }
252
253 constexpr ~datum() noexcept
254 {
255 delete_pointer();
256 }
257
258 constexpr datum(datum const& other) noexcept : _tag(other._tag), _value(other._value)
259 {
260 if (other.is_pointer()) {
261 copy_pointer(other);
262 }
263 }
264
265 constexpr datum(datum&& other) noexcept : _tag(other._tag), _value(other._value)
266 {
267 other._tag = tag_type::monostate;
268 other._value._long_long = 0;
269 }
270
271 constexpr datum() noexcept : _tag(tag_type::monostate), _value(0) {}
272 constexpr explicit datum(std::monostate) noexcept : _tag(tag_type::monostate), _value(0) {}
273 constexpr explicit datum(nullptr_t) noexcept : _tag(tag_type::null), _value(0) {}
274 constexpr explicit datum(continue_type) noexcept : _tag(tag_type::flow_continue), _value(0) {}
275 constexpr explicit datum(break_type) noexcept : _tag(tag_type::flow_break), _value(0) {}
276 constexpr explicit datum(bool value) noexcept : _tag(tag_type::boolean), _value(value) {}
277 constexpr explicit datum(std::floating_point auto value) noexcept :
278 _tag(tag_type::floating_point), _value(narrow_cast<double>(value))
279 {
280 }
281
282 constexpr explicit datum(numeric_integral auto value) noexcept :
283 _tag(tag_type::integral), _value(narrow_cast<long long>(value))
284 {
285 }
286
287 constexpr explicit datum(decimal value) noexcept : _tag(tag_type::decimal), _value(value) {}
288 constexpr explicit datum(std::chrono::year_month_day value) noexcept : _tag(tag_type::year_month_day), _value(value) {}
289 explicit datum(std::string value) noexcept : _tag(tag_type::string), _value(new std::string{std::move(value)}) {}
290 explicit datum(std::string_view value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
291 explicit datum(char const *value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
292 explicit datum(vector_type value) noexcept : _tag(tag_type::vector), _value(new vector_type{std::move(value)}) {}
293 explicit datum(map_type value) noexcept : _tag(tag_type::map), _value(new map_type{std::move(value)}) {}
294 explicit datum(bstring value) noexcept : _tag(tag_type::bstring), _value(new bstring{std::move(value)}) {}
295
296 template<typename... Args>
297 [[nodiscard]] static datum make_vector(Args const&...args) noexcept
298 {
299 return datum{vector_type{datum{args}...}};
300 }
301
302 template<typename Key, typename Value, typename... Args>
303 static void populate_map(map_type& r, Key const& key, Value const& value, Args const&...args) noexcept
304 {
305 r.insert(std::pair<datum, datum>{datum{key}, datum{value}});
306 if constexpr (sizeof...(Args) > 0) {
307 populate_map(r, args...);
308 }
309 }
310
311 template<typename... Args>
312 [[nodiscard]] static datum make_map(Args const&...args) noexcept
313 {
314 static_assert(sizeof...(Args) % 2 == 0, "Expect key value pairs for the arguments of make_map()");
315
316 auto r = map_type{};
317 if constexpr (sizeof...(Args) > 0) {
318 populate_map(r, args...);
319 }
320 return datum{std::move(r)};
321 }
322
323 [[nodiscard]] static datum make_break() noexcept
324 {
325 return datum{break_type{}};
326 }
327
328 [[nodiscard]] static datum make_continue() noexcept
329 {
330 return datum{continue_type{}};
331 }
332
333 constexpr datum& operator=(datum const& other) noexcept
334 {
335 hi_return_on_self_assignment(other);
336
337 delete_pointer();
338 _tag = other._tag;
339 _value = other._value;
340 if (other.is_pointer()) {
341 copy_pointer(other);
342 }
343 return *this;
344 }
345
346 constexpr datum& operator=(datum&& other) noexcept
347 {
348 std::swap(_tag, other._tag);
349 std::swap(_value, other._value);
350 return *this;
351 }
352
353 constexpr datum& operator=(std::floating_point auto value) noexcept(sizeof(value) <= 4)
354 {
355 delete_pointer();
356 _tag = tag_type::floating_point;
357 _value = static_cast<double>(value);
358 return *this;
359 }
360
361 constexpr datum& operator=(numeric_integral auto value) noexcept(sizeof(value) <= 4)
362 {
363 delete_pointer();
364 _tag = tag_type::integral;
365 _value = static_cast<long long>(value);
366 return *this;
367 }
368
369 constexpr datum& operator=(decimal value)
370 {
371 delete_pointer();
372 _tag = tag_type::decimal;
373 _value = value;
374 return *this;
375 }
376 constexpr datum& operator=(bool value) noexcept
377 {
378 delete_pointer();
379 _tag = tag_type::boolean;
380 _value = value;
381 return *this;
382 }
383
384 constexpr datum& operator=(std::chrono::year_month_day value) noexcept
385 {
386 delete_pointer();
387 _tag = tag_type::year_month_day;
388 _value = value;
389 return *this;
390 }
391
392 constexpr datum& operator=(std::monostate) noexcept
393 {
394 delete_pointer();
395 _tag = tag_type::monostate;
396 _value = 0;
397 return *this;
398 }
399
400 constexpr datum& operator=(nullptr_t) noexcept
401 {
402 delete_pointer();
403 _tag = tag_type::null;
404 _value = 0;
405 return *this;
406 }
407
408 datum& operator=(std::string value) noexcept
409 {
410 delete_pointer();
411 _tag = tag_type::string;
412 _value = new std::string{std::move(value)};
413 return *this;
414 }
415
416 datum& operator=(char const *value) noexcept
417 {
418 delete_pointer();
419 _tag = tag_type::string;
420 _value = new std::string{value};
421 return *this;
422 }
423
424 datum& operator=(std::string_view value) noexcept
425 {
426 delete_pointer();
427 _tag = tag_type::string;
428 _value = new std::string{value};
429 return *this;
430 }
431
432 datum& operator=(vector_type value) noexcept
433 {
434 delete_pointer();
435 _tag = tag_type::vector;
436 _value = new vector_type{std::move(value)};
437 return *this;
438 }
439
440 datum& operator=(map_type value) noexcept
441 {
442 delete_pointer();
443 _tag = tag_type::map;
444 _value = new map_type{std::move(value)};
445 return *this;
446 }
447
448 datum& operator=(bstring value) noexcept
449 {
450 delete_pointer();
451 _tag = tag_type::bstring;
452 _value = new bstring{std::move(value)};
453 return *this;
454 }
455
456 constexpr explicit operator bool() const noexcept
457 {
458 switch (_tag) {
459 case tag_type::floating_point:
460 return to_bool(get<double>(*this));
461 case tag_type::decimal:
462 return to_bool(get<decimal>(*this));
463 case tag_type::boolean:
464 return get<bool>(*this);
465 case tag_type::integral:
466 return to_bool(get<long long>(*this));
467 case tag_type::year_month_day:
468 return true;
469 case tag_type::string:
470 return not get<std::string>(*this).empty();
471 case tag_type::vector:
472 return not get<vector_type>(*this).empty();
473 case tag_type::map:
474 return not get<map_type>(*this).empty();
475 case tag_type::bstring:
476 return not get<bstring>(*this).empty();
477 default:
478 return false;
479 }
480 }
481
482 [[nodiscard]] constexpr bool empty() const
483 {
484 switch (_tag) {
485 case tag_type::string:
486 return get<std::string>(*this).empty();
487 case tag_type::vector:
488 return get<vector_type>(*this).empty();
489 case tag_type::map:
490 return get<map_type>(*this).empty();
491 case tag_type::bstring:
492 return get<bstring>(*this).empty();
493 default:
494 throw std::domain_error(std::format("Type {} can not be checked for empty", *this));
495 }
496 }
497
498 template<std::floating_point T>
499 constexpr explicit operator T() const
500 {
501 switch (_tag) {
502 case tag_type::floating_point:
503 return static_cast<T>(get<double>(*this));
504 case tag_type::integral:
505 return static_cast<T>(get<long long>(*this));
506 case tag_type::decimal:
507 return static_cast<T>(get<decimal>(*this));
508 case tag_type::boolean:
509 return static_cast<T>(get<bool>(*this));
510 default:
511 throw std::domain_error(std::format("Can't convert {} to floating point", *this));
512 }
513 }
514
515 constexpr explicit operator decimal() const
516 {
517 switch (_tag) {
518 case tag_type::floating_point:
519 return decimal(get<double>(*this));
520 case tag_type::integral:
521 return decimal(get<long long>(*this));
522 case tag_type::decimal:
523 return get<decimal>(*this);
524 case tag_type::boolean:
525 return decimal(get<bool>(*this));
526 default:
527 throw std::domain_error(std::format("Can't convert {} to floating point", *this));
528 }
529 }
530
531 template<numeric_integral T>
532 constexpr explicit operator T() const
533 {
534 if (auto f = get_if<double>(this)) {
535 if (not can_round_cast<T>(*f)) {
536 throw std::overflow_error("double to integral");
537 }
538 return round_cast<T>(*f);
539
540 } else if (auto i = get_if<long long>(this)) {
541 if (not can_narrow_cast<T>(*i)) {
542 throw std::overflow_error("long long to integral");
543 }
544 return narrow_cast<T>(*i);
545
546 } else if (auto d = get_if<decimal>(this)) {
547 hilet r = static_cast<long long>(*d);
549 throw std::overflow_error("decimal to integral");
550 }
551 return narrow_cast<T>(r);
552
553 } else if (auto b = get_if<bool>(this)) {
554 return narrow_cast<T>(*b);
555
556 } else {
557 throw std::domain_error(std::format("Can't convert {} to an integral", repr(*this)));
558 }
559 }
560
561 constexpr explicit operator std::chrono::year_month_day() const
562 {
563 if (auto ymd = get_if<std::chrono::year_month_day>(this)) {
564 return *ymd;
565 } else {
566 throw std::domain_error(std::format("Can't convert {} to an std::chrono::year_month_day", repr(*this)));
567 }
568 }
569
570 explicit operator std::string() const noexcept
571 {
572 switch (_tag) {
573 case tag_type::monostate:
574 return "undefined";
575 case tag_type::floating_point:
576 return hi::to_string(_value._double);
577 case tag_type::decimal:
578 return to_string(_value._decimal);
579 case tag_type::integral:
580 return to_string(_value._long_long);
581 case tag_type::boolean:
582 return _value._bool ? "true" : "false";
583 case tag_type::year_month_day:
584 return std::format("{:%Y-%m-%d}", _value._year_month_day);
585 case tag_type::null:
586 return "null";
587 case tag_type::flow_break:
588 return "break";
589 case tag_type::flow_continue:
590 return "continue";
591 case tag_type::string:
592 return *_value._string;
593 case tag_type::vector:
594 {
595 auto r = std::string{"["};
596 for (hilet& item : *_value._vector) {
597 r += repr(item);
598 r += ',';
599 }
600 r += ']';
601 return r;
602 };
603 case tag_type::map:
604 {
605 auto r = std::string{"{"};
606 for (hilet& item : *_value._map) {
607 r += repr(item.first);
608 r += ':';
609 r += repr(item.second);
610 r += ',';
611 }
612 r += '}';
613 return r;
614 };
615 case tag_type::bstring:
616 return base64::encode(*_value._bstring);
617 default:
619 }
620 }
621
622 explicit operator std::string_view() const
623 {
624 if (auto s = get_if<std::string>(this)) {
625 return std::string_view{*s};
626 } else {
627 throw std::domain_error(std::format("Can't convert {} to an std::string_view", repr(*this)));
628 }
629 }
630
631 explicit operator vector_type() const
632 {
633 if (auto v = get_if<vector_type>(this)) {
634 return *v;
635 } else {
636 throw std::domain_error(std::format("Can't convert {} to an vector", repr(*this)));
637 }
638 }
639
640 explicit operator map_type() const
641 {
642 if (auto m = get_if<map_type>(this)) {
643 return *m;
644 } else {
645 throw std::domain_error(std::format("Can't convert {} to an map", repr(*this)));
646 }
647 }
648
649 explicit operator bstring() const
650 {
651 // XXX should be able to base-64 decode a std::string.
652 if (_tag != tag_type::bstring) {
653 throw std::domain_error(std::format("Can't convert {} to an bstring", repr(*this)));
654 }
655 return get<bstring>(*this);
656 }
657
658 [[nodiscard]] constexpr char const *type_name() const noexcept
659 {
660 switch (_tag) {
661 case tag_type::floating_point:
662 return "float";
663 case tag_type::decimal:
664 return "decimal";
665 case tag_type::integral:
666 return "int";
667 case tag_type::boolean:
668 return "bool";
669 case tag_type::year_month_day:
670 return "date";
671 case tag_type::string:
672 return "string";
673 case tag_type::vector:
674 return "vector";
675 case tag_type::map:
676 return "map";
677 case tag_type::bstring:
678 return "bytes";
679 default:
681 }
682 }
683
686 [[nodiscard]] constexpr bool is_undefined() const noexcept
687 {
688 return _tag == tag_type::monostate;
689 }
690
694 [[nodiscard]] constexpr bool is_break() const noexcept
695 {
696 return _tag == tag_type::flow_break;
697 }
698
702 [[nodiscard]] constexpr bool is_continue() const noexcept
703 {
704 return _tag == tag_type::flow_continue;
705 }
706
707 [[nodiscard]] std::size_t hash() const noexcept
708 {
709 switch (_tag) {
710 case tag_type::floating_point:
711 return std::hash<double>{}(_value._double);
712 case tag_type::decimal:
713 return std::hash<decimal>{}(_value._decimal);
714 case tag_type::integral:
715 return std::hash<long long>{}(_value._long_long);
716 case tag_type::boolean:
717 return std::hash<bool>{}(_value._bool);
718 case tag_type::year_month_day:
719 {
720 uint32_t r = 0;
721 r |= narrow_cast<uint32_t>(static_cast<int>(_value._year_month_day.year())) << 16;
722 r |= narrow_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.month())) << 8;
723 r |= narrow_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.day()));
724 return std::hash<uint32_t>{}(r);
725 }
726 case tag_type::string:
727 return std::hash<std::string>{}(*_value._string);
728 case tag_type::vector:
729 {
730 std::size_t r = 0;
731 for (hilet& v : *_value._vector) {
732 r = hash_mix(r, v.hash());
733 }
734 return r;
735 }
736 case tag_type::map:
737 {
738 std::size_t r = 0;
739 for (hilet& kv : *_value._map) {
740 r = hash_mix(r, kv.first.hash(), kv.second.hash());
741 }
742 return r;
743 }
744 case tag_type::bstring:
745 return std::hash<bstring>{}(*_value._bstring);
746 default:
748 }
749 }
750
751 [[nodiscard]] constexpr std::size_t size() const
752 {
753 if (hilet *s = get_if<std::string>(this)) {
754 return s->size();
755 } else if (hilet *v = get_if<vector_type>(this)) {
756 return v->size();
757 } else if (hilet *m = get_if<map_type>(this)) {
758 return m->size();
759 } else if (hilet *b = get_if<bstring>(this)) {
760 return b->size();
761 } else {
762 throw std::domain_error(std::format("Can not evaluate {}.size()", repr(*this)));
763 }
764 }
765
766 [[nodiscard]] constexpr friend std::size_t size(datum const& rhs)
767 {
768 return rhs.size();
769 }
770
771 [[nodiscard]] constexpr datum const& back() const
772 {
773 if (hilet *v = get_if<vector_type>(this)) {
774 if (v->empty()) {
775 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
776 }
777 return v->back();
778 } else {
779 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
780 }
781 }
782
783 [[nodiscard]] constexpr datum& back()
784 {
785 if (auto *v = get_if<vector_type>(this)) {
786 if (v->empty()) {
787 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
788 }
789 return v->back();
790 } else {
791 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
792 }
793 }
794
795 [[nodiscard]] constexpr datum const& front() const
796 {
797 if (hilet *v = get_if<vector_type>(this)) {
798 if (v->empty()) {
799 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
800 }
801 return v->front();
802 } else {
803 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
804 }
805 }
806
807 [[nodiscard]] constexpr datum& front()
808 {
809 if (auto *v = get_if<vector_type>(this)) {
810 if (v->empty()) {
811 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
812 }
813 return v->front();
814 } else {
815 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
816 }
817 }
818
819 [[nodiscard]] constexpr auto cbegin() const
820 {
821 if (hilet *v = get_if<vector_type>(this)) {
822 return v->cbegin();
823 } else {
824 throw std::domain_error(std::format("Can not evaluate {}.cbegin()", repr(*this)));
825 }
826 }
827
828 [[nodiscard]] constexpr auto begin() const
829 {
830 if (hilet *v = get_if<vector_type>(this)) {
831 return v->begin();
832 } else {
833 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
834 }
835 }
836
837 [[nodiscard]] constexpr auto begin()
838 {
839 if (hilet *v = get_if<vector_type>(this)) {
840 return v->begin();
841 } else {
842 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
843 }
844 }
845
846 [[nodiscard]] constexpr auto cend() const
847 {
848 if (hilet *v = get_if<vector_type>(this)) {
849 return v->cend();
850 } else {
851 throw std::domain_error(std::format("Can not evaluate {}.cend()", repr(*this)));
852 }
853 }
854
855 [[nodiscard]] constexpr auto end() const
856 {
857 if (hilet *v = get_if<vector_type>(this)) {
858 return v->end();
859 } else {
860 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
861 }
862 }
863
864 [[nodiscard]] constexpr auto end()
865 {
866 if (hilet *v = get_if<vector_type>(this)) {
867 return v->end();
868 } else {
869 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
870 }
871 }
872
875 [[nodiscard]] vector_type keys() const
876 {
877 if (hilet *m = get_if<map_type>(this)) {
878 auto r = vector_type{};
879 r.reserve(m->size());
880 for (hilet& kv : *m) {
881 r.push_back(kv.first);
882 }
883 return r;
884 } else {
885 throw std::domain_error(std::format("Can not evaluate {}.keys()", repr(*this)));
886 }
887 }
888
891 [[nodiscard]] vector_type values() const
892 {
893 if (hilet *m = get_if<map_type>(this)) {
894 auto r = vector_type{};
895 r.reserve(m->size());
896 for (hilet& kv : *m) {
897 r.push_back(kv.second);
898 }
899 return r;
900 } else {
901 throw std::domain_error(std::format("Can not evaluate {}.values()", repr(*this)));
902 }
903 }
904
907 [[nodiscard]] vector_type items() const
908 {
909 if (hilet *m = get_if<map_type>(this)) {
910 auto r = vector_type{};
911 r.reserve(m->size());
912
913 for (hilet& item : *m) {
914 r.push_back(make_vector(item.first, item.second));
915 }
916 return r;
917 } else {
918 throw std::domain_error(std::format("Can not evaluate {}.items()", repr(*this)));
919 }
920 }
921
922 constexpr void push_back(datum const& rhs)
923 {
924 if (auto *v = get_if<vector_type>(this)) {
925 return v->push_back(rhs);
926 } else {
927 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
928 }
929 }
930
931 constexpr void push_back(datum&& rhs)
932 {
933 if (auto *v = get_if<vector_type>(this)) {
934 return v->push_back(std::move(rhs));
935 } else {
936 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
937 }
938 }
939
940 template<typename Arg>
941 constexpr void push_back(Arg&& arg)
942 {
943 push_back(datum{std::forward<Arg>(arg)});
944 }
945
946 constexpr void pop_back()
947 {
948 if (auto *v = get_if<vector_type>(this)) {
949 if (v->empty()) {
950 throw std::domain_error(std::format("Empty vector {}.pop_back()", repr(*this)));
951 }
952 return v->pop_back();
953 } else {
954 throw std::domain_error(std::format("Can not evaluate {}.pop_back()", repr(*this)));
955 }
956 }
957
958 [[nodiscard]] constexpr bool contains(datum const& rhs) const
959 {
960 if (auto *m = get_if<map_type>(this)) {
961 return m->contains(rhs);
962 } else {
963 throw std::domain_error(std::format("Can not evaluate {}.contains({})", repr(*this), repr(rhs)));
964 }
965 }
966
967 template<typename Arg>
968 [[nodiscard]] constexpr bool contains(Arg const& arg) const
969 {
970 return contains(datum{arg});
971 }
972
973 [[nodiscard]] std::vector<datum *> find(jsonpath const& path) noexcept
974 {
975 auto r = std::vector<datum *>{};
976 find(path.cbegin(), path.cend(), r);
977 return r;
978 }
979
980 [[nodiscard]] std::vector<datum const *> find(jsonpath const& path) const noexcept
981 {
982 auto tmp = std::vector<datum *>{};
983 const_cast<datum *>(this)->find(path.cbegin(), path.cend(), tmp);
985 std::copy(tmp.begin(), tmp.end(), std::back_inserter(r));
986 return r;
987 }
988
997 [[nodiscard]] bool remove(jsonpath const& path) noexcept
998 {
999 return to_bool(remove(path.cbegin(), path.cend()));
1000 }
1001
1007 [[nodiscard]] datum *find_one(jsonpath const& path) noexcept
1008 {
1009 hi_axiom(path.is_singular());
1010 return find_one(path.cbegin(), path.cend(), false);
1011 }
1012
1018 [[nodiscard]] datum *find_one_or_create(jsonpath const& path) noexcept
1019 {
1020 hi_axiom(path.is_singular());
1021 return find_one(path.cbegin(), path.cend(), true);
1022 }
1023
1029 [[nodiscard]] datum const *find_one(jsonpath const& path) const noexcept
1030 {
1031 hi_axiom(path.is_singular());
1032 return const_cast<datum *>(this)->find_one(path.cbegin(), path.cend(), false);
1033 }
1034
1035 [[nodiscard]] datum const& operator[](datum const& rhs) const
1036 {
1037 if (holds_alternative<vector_type>(*this) and holds_alternative<long long>(rhs)) {
1038 hilet& v = get<vector_type>(*this);
1039
1040 auto index = get<long long>(rhs);
1041 if (index < 0) {
1042 index = ssize(v) + index;
1043 }
1044 if (index < 0 or index >= ssize(v)) {
1045 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
1046 }
1047
1048 return v[index];
1049
1050 } else if (holds_alternative<map_type>(*this)) {
1051 hilet& m = get<map_type>(*this);
1052 hilet it = m.find(rhs);
1053 if (it == m.end()) {
1054 throw std::overflow_error(std::format("Key {} not found in map", repr(rhs)));
1055 }
1056
1057 return it->second;
1058
1059 } else {
1060 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
1061 }
1062 }
1063
1064 [[nodiscard]] constexpr datum& operator[](datum const& rhs)
1065 {
1066 if (holds_alternative<vector_type>(*this) and holds_alternative<long long>(rhs)) {
1067 auto& v = get<vector_type>(*this);
1068
1069 auto index = get<long long>(rhs);
1070 if (index < 0) {
1071 index = ssize(v) + index;
1072 }
1073 if (index < 0 or index >= ssize(v)) {
1074 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
1075 }
1076
1077 return v[index];
1078
1079 } else if (holds_alternative<map_type>(*this)) {
1080 auto& m = get<map_type>(*this);
1081 return m[rhs];
1082
1083 } else {
1084 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
1085 }
1086 }
1087
1088 [[nodiscard]] constexpr datum const& operator[](auto const& rhs) const
1089 {
1090 return (*this)[datum{rhs}];
1091 }
1092
1093 [[nodiscard]] constexpr datum& operator[](auto const& rhs)
1094 {
1095 return (*this)[datum{rhs}];
1096 }
1097
1098 [[nodiscard]] constexpr datum& operator++()
1099 {
1100 if (holds_alternative<long long>(*this)) {
1101 ++_value._long_long;
1102 return *this;
1103 } else {
1104 throw std::domain_error(std::format("Can not evaluate ++{}", repr(*this)));
1105 }
1106 }
1107
1108 [[nodiscard]] constexpr datum& operator--()
1109 {
1110 if (holds_alternative<long long>(*this)) {
1111 --_value._long_long;
1112 return *this;
1113 } else {
1114 throw std::domain_error(std::format("Can not evaluate --{}", repr(*this)));
1115 }
1116 }
1117
1118 [[nodiscard]] constexpr datum operator++(int)
1119 {
1120 if (holds_alternative<long long>(*this)) {
1121 auto tmp = *this;
1122 _value._long_long++;
1123 return tmp;
1124 } else {
1125 throw std::domain_error(std::format("Can not evaluate {}++", repr(*this)));
1126 }
1127 }
1128 [[nodiscard]] constexpr datum operator--(int)
1129 {
1130 if (holds_alternative<long long>(*this)) {
1131 auto tmp = *this;
1132 _value._long_long--;
1133 return tmp;
1134 } else {
1135 throw std::domain_error(std::format("Can not evaluate {}--", repr(*this)));
1136 }
1137 }
1138
1139 constexpr datum& operator+=(auto const& rhs)
1140 {
1141 if (holds_alternative<vector_type>(*this)) {
1142 push_back(rhs);
1143 return *this;
1144 } else {
1145 return (*this) = (*this) + rhs;
1146 }
1147 }
1148
1149#define X(op, inner_op) \
1150 constexpr datum& operator op(auto const& rhs) \
1151 { \
1152 return (*this) = (*this)inner_op rhs; \
1153 }
1154
1155 X(-=, -)
1156 X(*=, *)
1157 X(/=, /)
1158 X(%=, %)
1159 X(&=, &)
1160 X(|=, |)
1161 X(^=, ^)
1162 X(<<=, <<)
1163 X(>>=, >>)
1164#undef X
1165
1166 [[nodiscard]] friend constexpr bool operator==(datum const& lhs, datum const& rhs) noexcept
1167 {
1168 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1169 return doubles.lhs() == doubles.rhs();
1170
1171 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1172 return decimals.lhs() == decimals.rhs();
1173
1174 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1175 return long_longs.lhs() == long_longs.rhs();
1176
1177 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1178 return bools.lhs() == bools.rhs();
1179
1180 } else if (hilet ymds = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1181 return ymds.lhs() == ymds.rhs();
1182
1183 } else if (hilet strings = promote_if<std::string>(lhs, rhs)) {
1184 return strings.lhs() == strings.rhs();
1185
1186 } else if (hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1187 return vectors.lhs() == vectors.rhs();
1188
1189 } else if (hilet maps = promote_if<map_type>(lhs, rhs)) {
1190 return maps.lhs() == maps.rhs();
1191
1192 } else {
1193 return lhs._tag == rhs._tag;
1194 }
1195 }
1196
1225 [[nodiscard]] friend constexpr std::partial_ordering operator<=>(datum const& lhs, datum const& rhs) noexcept
1226 {
1227 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1228 return doubles.lhs() <=> doubles.rhs();
1229
1230 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1231 return decimals.lhs() <=> decimals.rhs();
1232
1233 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1234 return long_longs.lhs() <=> long_longs.rhs();
1235
1236 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1237 return bools.lhs() <=> bools.rhs();
1238
1239 } else if (hilet year_month_days = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1240 return year_month_days.lhs() <=> year_month_days.rhs();
1241
1242 } else if (hilet strings = promote_if<std::string>(lhs, rhs)) {
1243 return strings.lhs() <=> strings.rhs();
1244
1245 } else if (hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1246 return vectors.lhs() <=> vectors.rhs();
1247
1248 } else if (hilet maps = promote_if<map_type>(lhs, rhs)) {
1249 return maps.lhs() <=> maps.rhs();
1250
1251 } else if (hilet bstrings = promote_if<bstring>(lhs, rhs)) {
1252 return bstrings.lhs() <=> bstrings.rhs();
1253
1254 } else {
1255 return lhs._tag <=> rhs._tag;
1256 }
1257 }
1258
1269 [[nodiscard]] friend constexpr datum operator-(datum const& rhs)
1270 {
1271 if (hilet rhs_double = get_if<double>(&rhs)) {
1272 return datum{-*rhs_double};
1273
1274 } else if (hilet rhs_decimal = get_if<decimal>(&rhs)) {
1275 return datum{-*rhs_decimal};
1276
1277 } else if (hilet rhs_long_long = get_if<long long>(&rhs)) {
1278 return datum{-*rhs_long_long};
1279
1280 } else {
1281 throw std::domain_error(std::format("Can not evaluate -{}", repr(rhs)));
1282 }
1283 }
1284
1294 [[nodiscard]] friend constexpr datum operator~(datum const& rhs)
1295 {
1296 if (hilet rhs_long_long = get_if<long long>(&rhs)) {
1297 return datum{~*rhs_long_long};
1298
1299 } else {
1300 throw std::domain_error(std::format("Can not evaluate ~{}", repr(rhs)));
1301 }
1302 }
1303
1318 [[nodiscard]] friend constexpr datum operator+(datum const& lhs, datum const& rhs)
1319 {
1320 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1321 return datum{doubles.lhs() + doubles.rhs()};
1322
1323 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1324 return datum{decimals.lhs() + decimals.rhs()};
1325
1326 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1327 return datum{long_longs.lhs() + long_longs.rhs()};
1328
1329 } else if (hilet strings = promote_if<std::string>(lhs, rhs)) {
1330 return datum{strings.lhs() + strings.rhs()};
1331
1332 } else if (hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1333 auto r = vectors.lhs();
1334 r.insert(r.end(), vectors.rhs().begin(), vectors.rhs().end());
1335 return datum{std::move(r)};
1336
1337 } else {
1338 throw std::domain_error(std::format("Can not evaluate {} '+' {}", repr(lhs), repr(rhs)));
1339 }
1340 }
1341
1353 [[nodiscard]] friend constexpr datum operator-(datum const& lhs, datum const& rhs)
1354 {
1355 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1356 return datum{doubles.lhs() - doubles.rhs()};
1357
1358 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1359 return datum{decimals.lhs() - decimals.rhs()};
1360
1361 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1362 return datum{long_longs.lhs() - long_longs.rhs()};
1363
1364 } else {
1365 throw std::domain_error(std::format("Can not evaluate {} '-' {}", repr(lhs), repr(rhs)));
1366 }
1367 }
1368
1380 [[nodiscard]] friend constexpr datum operator*(datum const& lhs, datum const& rhs)
1381 {
1382 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1383 return datum{doubles.lhs() * doubles.rhs()};
1384
1385 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1386 return datum{decimals.lhs() * decimals.rhs()};
1387
1388 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1389 return datum{long_longs.lhs() * long_longs.rhs()};
1390
1391 } else {
1392 throw std::domain_error(std::format("Can not evaluate {} '*' {}", repr(lhs), repr(rhs)));
1393 }
1394 }
1395
1407 [[nodiscard]] friend constexpr datum operator/(datum const& lhs, datum const& rhs)
1408 {
1409 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1410 if (doubles.rhs() == 0) {
1411 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1412 }
1413 return datum{doubles.lhs() / doubles.rhs()};
1414
1415 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1416 if (decimals.rhs() == 0) {
1417 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1418 }
1419 return datum{decimals.lhs() / decimals.rhs()};
1420
1421 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1422 if (long_longs.rhs() == 0) {
1423 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1424 }
1425 return datum{long_longs.lhs() / long_longs.rhs()};
1426
1427 } else {
1428 throw std::domain_error(std::format("Can not evaluate {} '/' {}", repr(lhs), repr(rhs)));
1429 }
1430 }
1431
1443 [[nodiscard]] friend constexpr datum operator%(datum const& lhs, datum const& rhs)
1444 {
1445 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1446 if (long_longs.rhs() == 0) {
1447 throw std::domain_error(std::format("Divide by zero {} '%' {}", repr(lhs), repr(rhs)));
1448 }
1449 return datum{long_longs.lhs() % long_longs.rhs()};
1450
1451 } else {
1452 throw std::domain_error(std::format("Can not evaluate {} '%' {}", repr(lhs), repr(rhs)));
1453 }
1454 }
1455
1466 [[nodiscard]] friend constexpr datum pow(datum const& lhs, datum const& rhs)
1467 {
1468 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1469 return datum{pow(doubles.lhs(), doubles.rhs())};
1470
1471 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1472 return datum{pow(long_longs.lhs(), long_longs.rhs())};
1473
1474 } else {
1475 throw std::domain_error(std::format("Can not evaluate pow({}, {})", repr(lhs), repr(rhs)));
1476 }
1477 }
1478
1489 [[nodiscard]] friend constexpr datum operator&(datum const& lhs, datum const& rhs)
1490 {
1491 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1492 return datum{long_longs.lhs() & long_longs.rhs()};
1493
1494 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1495 return datum{bools.lhs() and bools.rhs()};
1496
1497 } else {
1498 throw std::domain_error(std::format("Can not evaluate {} '&' {}", repr(lhs), repr(rhs)));
1499 }
1500 }
1501
1512 [[nodiscard]] friend constexpr datum operator|(datum const& lhs, datum const& rhs)
1513 {
1514 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1515 return datum{long_longs.lhs() | long_longs.rhs()};
1516
1517 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1518 return datum{bools.lhs() or bools.rhs()};
1519
1520 } else {
1521 throw std::domain_error(std::format("Can not evaluate {} '|' {}", repr(lhs), repr(rhs)));
1522 }
1523 }
1524
1535 [[nodiscard]] friend constexpr datum operator^(datum const& lhs, datum const& rhs)
1536 {
1537 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1538 return datum{long_longs.lhs() ^ long_longs.rhs()};
1539
1540 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1541 return datum{bools.lhs() != bools.rhs()};
1542
1543 } else {
1544 throw std::domain_error(std::format("Can not evaluate {} '^' {}", repr(lhs), repr(rhs)));
1545 }
1546 }
1547
1560 [[nodiscard]] friend constexpr datum operator<<(datum const& lhs, datum const& rhs)
1561 {
1562 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1563 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1564 throw std::domain_error(std::format("Invalid shift count {} '<<' {}", repr(lhs), repr(rhs)));
1565 }
1566 return datum{long_longs.lhs() << long_longs.rhs()};
1567
1568 } else {
1569 throw std::domain_error(std::format("Can not evaluate {} '<<' {}", repr(lhs), repr(rhs)));
1570 }
1571 }
1572
1584 [[nodiscard]] friend constexpr datum operator>>(datum const& lhs, datum const& rhs)
1585 {
1586 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1587 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1588 throw std::domain_error(std::format("Invalid shift count {} '>>' {}", repr(lhs), repr(rhs)));
1589 }
1590 return datum{long_longs.lhs() >> long_longs.rhs()};
1591
1592 } else {
1593 throw std::domain_error(std::format("Can not evaluate {} '>>' {}", repr(lhs), repr(rhs)));
1594 }
1595 }
1596
1597 friend std::ostream& operator<<(std::ostream& lhs, datum const& rhs)
1598 {
1599 return lhs << to_string(rhs);
1600 }
1601
1602#define X(op) \
1603 [[nodiscard]] friend constexpr auto operator op(datum const& lhs, auto const& rhs) \
1604 { \
1605 return lhs op datum{rhs}; \
1606 } \
1607 [[nodiscard]] friend constexpr auto operator op(auto const& lhs, datum const& rhs) \
1608 { \
1609 return datum{lhs} op rhs; \
1610 }
1611
1612 X(==)
1613 X(<=>)
1614 X(+)
1615 X(-)
1616 X(*)
1617 X(/)
1618 X(%)
1619 X(&)
1620 X(|)
1621 X(^) X(<<) X(>>)
1622#undef X
1623
1626 [[nodiscard]] friend std::string repr(datum const& rhs) noexcept
1627 {
1628 switch (rhs._tag) {
1629 case tag_type::monostate:
1630 return "undefined";
1631 case tag_type::floating_point:
1632 return std::format("{:.1f}", rhs._value._double);
1633 case tag_type::decimal:
1634 return to_string(rhs._value._decimal);
1635 case tag_type::integral:
1636 return std::format("{}", rhs._value._long_long);
1637 case tag_type::boolean:
1638 return rhs._value._bool ? "true" : "false";
1639 case tag_type::year_month_day:
1640 return std::format("{:%Y-%m-%d}", rhs._value._year_month_day);
1641 case tag_type::null:
1642 return "null";
1643 case tag_type::flow_break:
1644 return "break";
1645 case tag_type::flow_continue:
1646 return "continue";
1647 case tag_type::string:
1648 return std::format("\"{}\"", *rhs._value._string);
1649 case tag_type::vector:
1650 {
1651 auto r = std::string{"["};
1652 for (hilet& item : *rhs._value._vector) {
1653 r += repr(item);
1654 r += ',';
1655 }
1656 r += ']';
1657 return r;
1658 };
1659 case tag_type::map:
1660 {
1661 auto r = std::string{"{"};
1662 for (hilet& item : *rhs._value._map) {
1663 r += repr(item.first);
1664 r += ':';
1665 r += repr(item.second);
1666 r += ',';
1667 }
1668 r += '}';
1669 return r;
1670 };
1671 case tag_type::bstring:
1672 return base64::encode(*rhs._value._bstring);
1673 default:
1674 hi_no_default();
1675 }
1676 }
1677
1680 [[nodiscard]] friend std::string to_string(datum const& rhs) noexcept
1681 {
1682 return static_cast<std::string>(rhs);
1683 }
1684
1691 template<typename T>
1692 [[nodiscard]] friend constexpr bool holds_alternative(datum const& rhs) noexcept
1693 {
1694 if constexpr (std::is_same_v<T, double>) {
1695 return rhs._tag == tag_type::floating_point;
1696 } else if constexpr (std::is_same_v<T, decimal>) {
1697 return rhs._tag == tag_type::decimal;
1698 } else if constexpr (std::is_same_v<T, long long>) {
1699 return rhs._tag == tag_type::integral;
1700 } else if constexpr (std::is_same_v<T, bool>) {
1701 return rhs._tag == tag_type::boolean;
1702 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1703 return rhs._tag == tag_type::year_month_day;
1704 } else if constexpr (std::is_same_v<T, nullptr_t>) {
1705 return rhs._tag == tag_type::null;
1706 } else if constexpr (std::is_same_v<T, std::monostate>) {
1707 return rhs._tag == tag_type::monostate;
1708 } else if constexpr (std::is_same_v<T, break_type>) {
1709 return rhs._tag == tag_type::flow_break;
1710 } else if constexpr (std::is_same_v<T, continue_type>) {
1711 return rhs._tag == tag_type::flow_continue;
1712 } else if constexpr (std::is_same_v<T, std::string>) {
1713 return rhs._tag == tag_type::string;
1714 } else if constexpr (std::is_same_v<T, vector_type>) {
1715 return rhs._tag == tag_type::vector;
1716 } else if constexpr (std::is_same_v<T, map_type>) {
1717 return rhs._tag == tag_type::map;
1718 } else if constexpr (std::is_same_v<T, bstring>) {
1719 return rhs._tag == tag_type::bstring;
1720 } else {
1722 }
1723 }
1724
1736 template<typename To>
1737 [[nodiscard]] friend constexpr bool promotable_to(datum const& rhs) noexcept
1738 {
1739 if constexpr (std::is_same_v<To, double>) {
1740 return holds_alternative<double>(rhs) or holds_alternative<decimal>(rhs) or holds_alternative<long long>(rhs) or
1741 holds_alternative<bool>(rhs);
1742 } else if constexpr (std::is_same_v<To, decimal>) {
1743 return holds_alternative<decimal>(rhs) or holds_alternative<long long>(rhs) or holds_alternative<bool>(rhs);
1744 } else if constexpr (std::is_same_v<To, long long>) {
1745 return holds_alternative<long long>(rhs) or holds_alternative<bool>(rhs);
1746 } else {
1747 return holds_alternative<To>(rhs);
1748 }
1749 }
1750
1759 template<typename T>
1760 [[nodiscard]] friend constexpr T const& get(datum const& rhs) noexcept
1761 {
1762 hi_axiom(holds_alternative<T>(rhs));
1763 if constexpr (std::is_same_v<T, double>) {
1764 return rhs._value._double;
1765 } else if constexpr (std::is_same_v<T, decimal>) {
1766 return rhs._value._decimal;
1767 } else if constexpr (std::is_same_v<T, long long>) {
1768 return rhs._value._long_long;
1769 } else if constexpr (std::is_same_v<T, bool>) {
1770 return rhs._value._bool;
1771 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1772 return rhs._value._year_month_day;
1773 } else if constexpr (std::is_same_v<T, std::string>) {
1774 return *rhs._value._string;
1775 } else if constexpr (std::is_same_v<T, vector_type>) {
1776 return *rhs._value._vector;
1777 } else if constexpr (std::is_same_v<T, map_type>) {
1778 return *rhs._value._map;
1779 } else if constexpr (std::is_same_v<T, bstring>) {
1780 return *rhs._value._bstring;
1781 } else {
1783 }
1784 }
1785
1794 template<typename T>
1795 [[nodiscard]] friend constexpr T& get(datum& rhs) noexcept
1796 {
1797 hi_axiom(holds_alternative<T>(rhs));
1798 if constexpr (std::is_same_v<T, double>) {
1799 return rhs._value._double;
1800 } else if constexpr (std::is_same_v<T, decimal>) {
1801 return rhs._value._decimal;
1802 } else if constexpr (std::is_same_v<T, long long>) {
1803 return rhs._value._long_long;
1804 } else if constexpr (std::is_same_v<T, bool>) {
1805 return rhs._value._bool;
1806 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1807 return rhs._value._year_month_day;
1808 } else if constexpr (std::is_same_v<T, std::string>) {
1809 return *rhs._value._string;
1810 } else if constexpr (std::is_same_v<T, vector_type>) {
1811 return *rhs._value._vector;
1812 } else if constexpr (std::is_same_v<T, map_type>) {
1813 return *rhs._value._map;
1814 } else if constexpr (std::is_same_v<T, bstring>) {
1815 return *rhs._value._bstring;
1816 } else {
1818 }
1819 }
1820
1829 template<typename T>
1830 [[deprecated]] [[nodiscard]] friend constexpr T *get_if(datum& rhs) noexcept
1831 {
1832 if (holds_alternative<T>(rhs)) {
1833 return &get<T>(rhs);
1834 } else {
1835 return nullptr;
1836 }
1837 }
1838
1847 template<typename T>
1848 [[deprecated]] [[nodiscard]] friend constexpr T const *get_if(datum const& rhs) noexcept
1849 {
1850 if (holds_alternative<T>(rhs)) {
1851 return &get<T>(rhs);
1852 } else {
1853 return nullptr;
1854 }
1855 }
1856
1865 template<typename T>
1866 [[nodiscard]] friend constexpr T *get_if(datum *rhs) noexcept
1867 {
1868 if (rhs == nullptr or not holds_alternative<T>(*rhs)) {
1869 return nullptr;
1870 }
1871 return &get<T>(*rhs);
1872 }
1873
1882 template<typename T>
1883 [[nodiscard]] friend constexpr T const *get_if(datum const *rhs) noexcept
1884 {
1885 if (rhs == nullptr or not holds_alternative<T>(*rhs)) {
1886 return nullptr;
1887 }
1888 return &get<T>(*rhs);
1889 }
1890
1900 template<typename T>
1901 [[nodiscard]] friend T *get_if(datum& rhs, jsonpath const& path) noexcept
1902 {
1903 if (auto *value = rhs.find_one(path)) {
1904 if (holds_alternative<T>(*value)) {
1905 return &get<T>(*value);
1906 } else {
1907 return nullptr;
1908 }
1909 } else {
1910 return nullptr;
1911 }
1912 }
1913
1923 template<typename T>
1924 [[nodiscard]] friend T const *get_if(datum const& rhs, jsonpath const& path) noexcept
1925 {
1926 if (auto *value = const_cast<datum&>(rhs).find_one(path)) {
1927 if (holds_alternative<T>(*value)) {
1928 return &get<T>(*value);
1929 } else {
1930 return nullptr;
1931 }
1932 } else {
1933 return nullptr;
1934 }
1935 }
1936
1937private:
1938 enum class tag_type : signed char {
1939 // scalars are detected by: `to_underlying(tag_type) >= 0`
1940 monostate = 0,
1941 floating_point = 1,
1942 integral = 2,
1943 decimal = 3,
1944 boolean = 4,
1945 null = 5,
1946 year_month_day = 6,
1947 flow_continue = 7,
1948 flow_break = 8,
1949
1950 // pointers are detected by: `to_underlying(tag_type) < 0`.
1951 string = -1,
1952 vector = -2,
1953 map = -3,
1954 bstring = -5
1955 };
1956
1957 tag_type _tag = tag_type::monostate;
1958 union value_type {
1959 double _double;
1960 long long _long_long;
1961 decimal _decimal;
1962 bool _bool;
1963 std::chrono::year_month_day _year_month_day;
1964 std::string *_string;
1965 vector_type *_vector;
1966 map_type *_map;
1967 bstring *_bstring;
1968
1969 constexpr value_type(numeric_integral auto value) noexcept : _long_long(narrow_cast<long long>(value)) {}
1970 constexpr value_type(std::floating_point auto value) noexcept : _double(narrow_cast<double>(value)) {}
1971 constexpr value_type(decimal value) noexcept : _decimal(value) {}
1972 constexpr value_type(bool value) noexcept : _bool(value) {}
1973 constexpr value_type(std::chrono::year_month_day value) noexcept : _year_month_day(value) {}
1974 constexpr value_type(std::string *value) noexcept : _string(value) {}
1975 constexpr value_type(vector_type *value) noexcept : _vector(value) {}
1976 constexpr value_type(map_type *value) noexcept : _map(value) {}
1977 constexpr value_type(bstring *value) noexcept : _bstring(value) {}
1978 };
1979
1980 value_type _value;
1981
1982 [[nodiscard]] constexpr bool is_scalar() const noexcept
1983 {
1984 return to_underlying(_tag) >= 0;
1985 }
1986
1987 [[nodiscard]] constexpr bool is_pointer() const noexcept
1988 {
1989 return to_underlying(_tag) < 0;
1990 }
1991
1992 hi_no_inline void copy_pointer(datum const& other) noexcept
1993 {
1994 hi_axiom(other.is_pointer());
1995 switch (other._tag) {
1996 case tag_type::string:
1997 _value._string = new std::string{*other._value._string};
1998 return;
1999 case tag_type::vector:
2000 _value._vector = new vector_type{*other._value._vector};
2001 return;
2002 case tag_type::map:
2003 _value._map = new map_type{*other._value._map};
2004 return;
2005 case tag_type::bstring:
2006 _value._bstring = new bstring{*other._value._bstring};
2007 return;
2008 default:
2009 hi_no_default();
2010 }
2011 }
2012
2013 hi_no_inline void _delete_pointer() noexcept
2014 {
2015 hi_axiom(is_pointer());
2016 switch (_tag) {
2017 case tag_type::string:
2018 delete _value._string;
2019 return;
2020 case tag_type::vector:
2021 delete _value._vector;
2022 return;
2023 case tag_type::map:
2024 delete _value._map;
2025 return;
2026 case tag_type::bstring:
2027 delete _value._bstring;
2028 return;
2029 default:
2030 hi_no_default();
2031 }
2032 }
2033
2034 constexpr void delete_pointer() noexcept
2035 {
2036 if (is_pointer()) {
2037 _delete_pointer();
2038 }
2039 }
2040
2041 void find_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *>& r) noexcept
2042 {
2043 if (auto vector = get_if<datum::vector_type>(this)) {
2044 for (auto& item : *vector) {
2045 item.find(it + 1, it_end, r);
2046 }
2047
2048 } else if (auto map = get_if<datum::map_type>(this)) {
2049 for (auto& item : *map) {
2050 item.second.find(it + 1, it_end, r);
2051 }
2052 }
2053 }
2054
2055 void find_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *>& r) noexcept
2056 {
2057 this->find(it + 1, it_end, r);
2058
2059 if (auto vector = get_if<datum::vector_type>(this)) {
2060 for (auto& item : *vector) {
2061 item.find(it, it_end, r);
2062 }
2063
2064 } else if (auto map = get_if<datum::map_type>(this)) {
2065 for (auto& item : *map) {
2066 item.second.find(it, it_end, r);
2067 }
2068 }
2069 }
2070
2071 void find_indices(
2072 jsonpath_indices const& indices,
2073 jsonpath::const_iterator it,
2074 jsonpath::const_iterator it_end,
2075 std::vector<datum *>& r) noexcept
2076 {
2077 if (auto vector = get_if<datum::vector_type>(this)) {
2078 for (hilet index : indices.filter(ssize(*vector))) {
2079 (*vector)[index].find(it + 1, it_end, r);
2080 }
2081 }
2082 }
2083
2084 void find_names(
2085 jsonpath_names const& names,
2086 jsonpath::const_iterator it,
2087 jsonpath::const_iterator it_end,
2088 std::vector<datum *>& r) noexcept
2089 {
2090 if (auto map = get_if<datum::map_type>(this)) {
2091 for (hilet& name : names) {
2092 hilet name_ = datum{name};
2093 auto jt = map->find(name_);
2094 if (jt != map->cend()) {
2095 jt->second.find(it + 1, it_end, r);
2096 }
2097 }
2098 }
2099 }
2100
2101 void find_slice(
2102 jsonpath_slice const& slice,
2103 jsonpath::const_iterator it,
2104 jsonpath::const_iterator it_end,
2105 std::vector<datum *>& r) noexcept
2106 {
2107 if (auto vector = get_if<datum::vector_type>(this)) {
2108 hilet first = slice.begin(vector->size());
2109 hilet last = slice.end(vector->size());
2110
2111 for (auto index = first; index != last; index += slice.step) {
2112 if (index >= 0 and index < vector->size()) {
2113 (*this)[index].find(it + 1, it_end, r);
2114 }
2115 }
2116 }
2117 }
2118
2119 void find(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *>& r) noexcept
2120 {
2121 if (it == it_end) {
2122 r.push_back(this);
2123
2124 } else if (std::holds_alternative<jsonpath_root>(*it)) {
2125 find(it + 1, it_end, r);
2126
2127 } else if (std::holds_alternative<jsonpath_current>(*it)) {
2128 find(it + 1, it_end, r);
2129
2130 } else if (std::holds_alternative<jsonpath_wildcard>(*it)) {
2131 find_wildcard(it, it_end, r);
2132
2133 } else if (std::holds_alternative<jsonpath_descend>(*it)) {
2134 find_descend(it, it_end, r);
2135
2136 } else if (auto indices = std::get_if<jsonpath_indices>(&*it)) {
2137 find_indices(*indices, it, it_end, r);
2138
2139 } else if (auto names = std::get_if<jsonpath_names>(&*it)) {
2140 find_names(*names, it, it_end, r);
2141
2142 } else if (auto slice = std::get_if<jsonpath_slice>(&*it)) {
2143 find_slice(*slice, it, it_end, r);
2144
2145 } else {
2146 hi_no_default();
2147 }
2148 }
2149
2150 [[nodiscard]] int remove_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2151 {
2152 int r = 0;
2153
2154 if (auto vector = get_if<datum::vector_type>(this)) {
2155 auto jt = vector->begin();
2156 while (jt != vector->end()) {
2157 hilet match = jt->remove(it + 1, it_end);
2158 r |= match ? 1 : 0;
2159
2160 if (match == 2) {
2161 jt = vector->erase(jt);
2162 } else {
2163 ++jt;
2164 }
2165 }
2166 return vector->empty() ? 2 : r;
2167
2168 } else if (auto map = get_if<datum::map_type>(this)) {
2169 auto jt = map->begin();
2170 while (jt != map->end()) {
2171 hilet match = jt->second.remove(it + 1, it_end);
2172 r |= match ? 1 : 0;
2173
2174 if (match == 2) {
2175 jt = map->erase(jt);
2176 } else {
2177 ++jt;
2178 }
2179 }
2180 return map->empty() ? 2 : r;
2181
2182 } else {
2183 return 0;
2184 }
2185 }
2186
2187 [[nodiscard]] int remove_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2188 {
2189 int r = 0;
2190
2191 {
2192 hilet match = this->remove(it + 1, it_end);
2193 if (match == 2) {
2194 return 2;
2195 }
2196 r |= match ? 1 : 0;
2197 }
2198
2199 if (auto vector = get_if<datum::vector_type>(this)) {
2200 auto jt = vector->begin();
2201 while (jt != vector->end()) {
2202 hilet match = jt->remove(it, it_end);
2203 r |= match ? 1 : 0;
2204
2205 if (match == 2) {
2206 jt = vector->erase(jt);
2207 } else {
2208 ++jt;
2209 }
2210 }
2211 return vector->empty() ? 2 : r;
2212
2213 } else if (auto map = get_if<datum::map_type>(this)) {
2214 auto jt = map->begin();
2215 while (jt != map->end()) {
2216 hilet match = jt->second.remove(it, it_end);
2217 r |= match ? 1 : 0;
2218
2219 if (match == 2) {
2220 jt = map->erase(jt);
2221 } else {
2222 ++jt;
2223 }
2224 }
2225 return map->empty() ? 2 : r;
2226
2227 } else {
2228 return 0;
2229 }
2230 }
2231
2232 [[nodiscard]] int
2233 remove_indices(jsonpath_indices const& indices, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2234 {
2235 if (auto vector = get_if<datum::vector_type>(this)) {
2236 int r = 0;
2237 std::size_t offset = 0;
2238
2239 for (hilet index : indices.filter(ssize(*vector))) {
2240 hilet match = (*vector)[index - offset].remove(it + 1, it_end);
2241 r |= match ? 1 : 0;
2242 if (match == 2) {
2243 vector->erase(vector->begin() + (index - offset));
2244 ++offset;
2245 }
2246 }
2247
2248 return vector->empty() ? 2 : r;
2249
2250 } else {
2251 return 0;
2252 }
2253 }
2254
2255 [[nodiscard]] int
2256 remove_names(jsonpath_names const& names, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2257 {
2258 if (auto map = get_if<datum::map_type>(this)) {
2259 int r = 0;
2260
2261 for (hilet& name : names) {
2262 hilet name_ = datum{name};
2263 auto jt = map->find(name_);
2264 if (jt != map->cend()) {
2265 hilet match = jt->second.remove(it + 1, it_end);
2266 r |= match ? 1 : 0;
2267 if (match == 2) {
2268 map->erase(jt);
2269 }
2270 }
2271 }
2272
2273 return map->empty() ? 2 : r;
2274
2275 } else {
2276 return 0;
2277 }
2278 }
2279
2280 [[nodiscard]] int
2281 remove_slice(jsonpath_slice const& slice, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2282 {
2283 if (auto vector = get_if<datum::vector_type>(this)) {
2284 int r = 0;
2285
2286 hilet first = slice.begin(vector->size());
2287 hilet last = slice.end(vector->size());
2288
2289 std::size_t offset = 0;
2290 for (auto index = first; index != last; index += slice.step) {
2291 if (index >= 0 and index < vector->size()) {
2292 hilet match = (*this)[index - offset].remove(it + 1, it_end);
2293 r |= match ? 1 : 0;
2294
2295 if (match == 2) {
2296 vector->erase(vector->begin() + (index - offset));
2297 ++offset;
2298 }
2299 }
2300 }
2301
2302 return vector->empty() ? 2 : r;
2303
2304 } else {
2305 return 0;
2306 }
2307 }
2308
2309 [[nodiscard]] int remove(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2310 {
2311 if (it == it_end) {
2312 // Reached end, remove matching name or index in parent.
2313 return 2;
2314
2315 } else if (std::holds_alternative<jsonpath_root>(*it)) {
2316 return remove(it + 1, it_end);
2317
2318 } else if (std::holds_alternative<jsonpath_current>(*it)) {
2319 return remove(it + 1, it_end);
2320
2321 } else if (std::holds_alternative<jsonpath_wildcard>(*it)) {
2322 return remove_wildcard(it, it_end);
2323
2324 } else if (std::holds_alternative<jsonpath_descend>(*it)) {
2325 return remove_descend(it, it_end);
2326
2327 } else if (auto indices = std::get_if<jsonpath_indices>(&*it)) {
2328 return remove_indices(*indices, it, it_end);
2329
2330 } else if (auto names = std::get_if<jsonpath_names>(&*it)) {
2331 return remove_names(*names, it, it_end);
2332
2333 } else if (auto slice = std::get_if<jsonpath_slice>(&*it)) {
2334 return remove_slice(*slice, it, it_end);
2335
2336 } else {
2337 hi_no_default();
2338 }
2339 }
2340
2341 [[nodiscard]] datum *
2342 find_one_name(datum const& name, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2343 {
2344 hi_axiom(holds_alternative<std::string>(name));
2345
2346 if (auto *map = get_if<map_type>(this)) {
2347 auto i = map->find(name);
2348 if (i != map->end()) {
2349 return i->second.find_one(it + 1, it_end, create);
2350
2351 } else if (create) {
2352 (*map)[name] = datum{std::monostate{}};
2353 return find_one_name(name, it, it_end, create);
2354
2355 } else {
2356 return nullptr;
2357 }
2358
2359 } else if (holds_alternative<std::monostate>(*this) and create) {
2360 *this = datum::make_map(name, std::monostate{});
2361 return find_one_name(name, it, it_end, create);
2362
2363 } else {
2364 return nullptr;
2365 }
2366 }
2367
2368 [[nodiscard]] datum *
2369 find_one_index(std::size_t index, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2370 {
2371 if (auto *vector = get_if<vector_type>(this)) {
2372 if (index < vector->size()) {
2373 return (*vector)[index].find_one(it + 1, it_end, create);
2374 } else if (index == vector->size() and create) {
2375 vector->push_back(datum{std::monostate{}});
2376 return find_one_index(index, it, it_end, create);
2377 } else {
2378 return nullptr;
2379 }
2380
2381 } else if (holds_alternative<std::monostate>(*this) and index == 0 and create) {
2382 *this = datum::make_vector(std::monostate{});
2383 return find_one_index(index, it, it_end, create);
2384
2385 } else {
2386 return nullptr;
2387 }
2388 }
2389
2390 [[nodiscard]] datum *find_one(jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2391 {
2392 if (it == it_end) {
2393 return this;
2394
2395 } else if (std::holds_alternative<jsonpath_root>(*it)) {
2396 return find_one(it + 1, it_end, create);
2397
2398 } else if (std::holds_alternative<jsonpath_current>(*it)) {
2399 return find_one(it + 1, it_end, create);
2400
2401 } else if (hilet *indices = std::get_if<jsonpath_indices>(&*it)) {
2402 hi_axiom(indices->size() == 1);
2403 return find_one_index(indices->front(), it, it_end, create);
2404
2405 } else if (hilet *names = std::get_if<jsonpath_names>(&*it)) {
2406 hi_axiom(names->size() == 1);
2407 return find_one_name(datum{names->front()}, it, it_end, create);
2408
2409 } else {
2410 hi_no_default();
2411 }
2412 }
2413};
2414
2415} // namespace hi::inline v1
2416
2417[[nodiscard]] inline std::size_t std::hash<hi::datum>::operator()(hi::datum const& rhs) const noexcept
2418{
2419 return rhs.hash();
2420}
2421
2422template<typename CharT>
2423auto std::formatter<hi::datum, CharT>::format(hi::datum const& t, auto& fc) const
2424 -> decltype(std::formatter<std::string, CharT>{}.format(std::string{}, fc))
2425{
2426 return std::formatter<std::string, CharT>{}.format(to_string(t), fc);
2427}
2428
2429hi_warning_pop();
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:323
#define hi_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:279
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
constexpr std::string to_string(std::u32string_view rhs) noexcept
Conversion from UTF-32 to UTF-8.
Definition to_string.hpp:215
@ create
Create file if it does not exist, or fail.
@ other
The gui_event does not have associated data.
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:13
constexpr std::vector< Value > make_vector(Range &&range)
Make a vector from a view.
Definition ranges.hpp:43
geometry/margins.hpp
Definition cache.hpp:11
Promotion result.
Definition datum.hpp:54
Definition datum.hpp:194
A dynamic data type.
Definition datum.hpp:223
friend constexpr T & get(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1795
friend constexpr bool promotable_to(datum const &rhs) noexcept
Check if the type held by the datum can be promoted.
Definition datum.hpp:1737
constexpr bool is_break() const noexcept
Check if the result of a expression was a break flow control statement.
Definition datum.hpp:694
friend constexpr auto promote_if(datum const &lhs, datum const &rhs) noexcept
Promote two datum-arguments to a common type.
Definition datum.hpp:237
datum const * find_one(jsonpath const &path) const noexcept
Find a object by path.
Definition datum.hpp:1029
friend std::string to_string(datum const &rhs) noexcept
Get the string representation of the value.
Definition datum.hpp:1680
friend constexpr T const * get_if(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1848
friend constexpr bool holds_alternative(datum const &rhs) noexcept
Check if the stored value is of a specific type.
Definition datum.hpp:1692
bool remove(jsonpath const &path) noexcept
Remove the object by path.
Definition datum.hpp:997
vector_type keys() const
Get the sorted list of keys of a map.
Definition datum.hpp:875
friend constexpr T * get_if(datum *rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1866
friend T * get_if(datum &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1901
friend constexpr T const * get_if(datum const *rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1883
vector_type items() const
Get key value pairs of items of a map sorted by the key.
Definition datum.hpp:907
friend T const * get_if(datum const &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1924
friend constexpr T const & get(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1760
vector_type values() const
Get the list of values of a map.
Definition datum.hpp:891
datum * find_one_or_create(jsonpath const &path) noexcept
Find a object by path potentially creating intermediate objects.
Definition datum.hpp:1018
constexpr bool is_continue() const noexcept
Check if the result of a expression was a continue flow control statement.
Definition datum.hpp:702
datum * find_one(jsonpath const &path) noexcept
Find a object by path.
Definition datum.hpp:1007
constexpr bool is_undefined() const noexcept
Check if the datum has an undefined value.
Definition datum.hpp:686
friend constexpr T * get_if(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1830
Definition datum.hpp:227
Definition datum.hpp:228
Definition decimal.hpp:18
Definition jsonpath.hpp:379
T back_inserter(T... args)
T begin(T... args)
T copy(T... args)
T end(T... args)
T find(T... args)
T move(T... args)
T operator()(T... args)
T pow(T... args)
T remove(T... args)
T reserve(T... args)
T swap(T... args)
T to_string(T... args)