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