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