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