HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
datum.hpp
1// Copyright Take Vos 2019-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "../utility/utility.hpp"
8#include "../numeric/numeric.hpp"
9#include "../container/container.hpp"
10#include "../macros.hpp"
11#include "base_n.hpp"
12#include "jsonpath.hpp"
13#include <cstdint>
14#include <concepts>
15#include <bit>
16#include <exception>
17#include <chrono>
18#include <limits>
19#include <vector>
20#include <map>
21
22hi_warning_push();
23// C26476: Expression/symbol '...' uses a naked union '...' with multiple type pointers: Use variant instead (type.7.).
24// This implements `datum` which is simular to a std::variant.
25hi_warning_ignore_msvc(26476);
26// C26409: Avoid calling new and delete explicitly, use std::make_unique<T> instead (r.11).
27// This implements `datum` which implements RAII for large objects.
28hi_warning_ignore_msvc(26409);
29// C26492: Don't use const_cast to cast away const or volatile (type.3).
30// Needed until c++23 deducing this.
31hi_warning_ignore_msvc(26492);
32
33hi_export_module(hikogui.codec.datum);
34
35hi_export namespace hi { inline namespace v1 {
36namespace detail {
37
42template<typename To>
44public:
45 using value_type = To;
46 constexpr static bool data_is_pointer = sizeof(value_type) > sizeof(void *);
47 constexpr static bool data_is_scalar = not data_is_pointer;
48
49 constexpr void clear() noexcept
50 requires(data_is_scalar)
51 {
52 }
53 constexpr void clear() noexcept
54 requires(data_is_pointer)
55 {
56 if (_owns_lhs) {
57 delete _lhs;
58 }
59 if (_owns_rhs) {
60 delete _rhs;
61 }
62 }
63
64 constexpr ~datum_promotion_result()
65 {
66 clear();
67 }
68
69 constexpr datum_promotion_result() noexcept = default;
70
72 datum_promotion_result& operator=(datum_promotion_result const&) = delete;
73
75 _lhs(other._lhs),
76 _rhs(other._rhs),
77 _is_result(other._is_result),
78 _owns_lhs(std::exchange(other._owns_lhs, false)),
79 _owns_rhs(std::exchange(other._owns_rhs, false))
80 {
81 }
82
83 constexpr datum_promotion_result& operator=(datum_promotion_result&& other) noexcept
84 {
85 clear();
86 _lhs = other.lhs;
87 _rhs = other.rhs;
88 _is_result = other._is_result;
89 _owns_lhs = std::exchange(other._owns_lhs, false);
90 _owns_rhs = std::exchange(other._owns_rhs, false);
91 return *this;
92 }
93
94 constexpr explicit operator bool() const noexcept
95 {
96 return _is_result;
97 }
98
99 constexpr void set(value_type lhs, value_type rhs) noexcept
100 requires(data_is_scalar)
101 {
102 _lhs = lhs;
103 _rhs = rhs;
104 _is_result = true;
105 }
106
107 constexpr void set(value_type const& lhs, value_type const& rhs) noexcept
108 requires(data_is_pointer)
109 {
110 _lhs = &lhs;
111 _rhs = &rhs;
112 _is_result = true;
113 }
114
115 constexpr void set(value_type&& lhs, value_type const& rhs) noexcept
116 requires(data_is_pointer)
117 {
118 _lhs = new value_type(std::move(lhs));
119 _rhs = &rhs;
120 _is_result = true;
121 _owns_lhs = true;
122 }
123
124 constexpr void set(value_type const& lhs, value_type&& rhs) noexcept
125 requires(data_is_pointer)
126 {
127 _lhs = &lhs;
128 _rhs = new value_type(std::move(rhs));
129 _is_result = true;
130 _owns_rhs = true;
131 }
132
133 constexpr void set(value_type&& lhs, value_type&& rhs) noexcept
134 requires(data_is_pointer)
135 {
136 _lhs = new value_type(std::move(lhs));
137 _rhs = new value_type(std::move(rhs));
138 _is_result = true;
139 _owns_lhs = true;
140 _owns_rhs = true;
141 }
142
143 [[nodiscard]] constexpr value_type const& lhs() const noexcept
144 requires(data_is_pointer)
145 {
146 hi_axiom(_is_result);
147 return *_lhs;
148 }
149
150 [[nodiscard]] constexpr value_type const& rhs() const noexcept
151 requires(data_is_pointer)
152 {
153 hi_axiom(_is_result);
154 return *_rhs;
155 }
156
157 [[nodiscard]] constexpr value_type lhs() const noexcept
158 requires(data_is_scalar)
159 {
160 hi_axiom(_is_result);
161 return _lhs;
162 }
163
164 [[nodiscard]] constexpr value_type rhs() const noexcept
165 requires(data_is_scalar)
166 {
167 hi_axiom(_is_result);
168 return _rhs;
169 }
170
171private:
172 using data_type = std::conditional_t<data_is_pointer, value_type const *, value_type>;
173 data_type _lhs = data_type{};
174 data_type _rhs = data_type{};
175 bool _is_result = false;
176 bool _owns_lhs = false;
177 bool _owns_rhs = false;
178};
179
180} // namespace detail
181
182hi_export template<typename T>
184
185hi_export template<>
187hi_export template<>
189hi_export template<>
191hi_export template<>
192class is_datum_type<std::chrono::year_month_day> : public std::true_type {};
193hi_export template<>
194class is_datum_type<std::string> : public std::true_type {};
195hi_export template<>
196class is_datum_type<bstring> : public std::true_type {};
197
198hi_export template<typename T>
199constexpr bool is_datum_type_v = is_datum_type<T>::value;
200
210hi_export class datum {
211public:
212 using vector_type = std::vector<datum>;
213 using map_type = std::map<datum, datum>;
214 struct break_type {};
215 struct continue_type {};
216
223 template<typename To>
224 [[nodiscard]] friend constexpr auto promote_if(datum const& lhs, datum const& rhs) noexcept
225 {
228 r.set(get<To>(lhs), get<To>(rhs));
229
230 } else if (holds_alternative<To>(lhs) and promotable_to<To>(rhs)) {
231 r.set(get<To>(lhs), static_cast<To>(rhs));
232
233 } else if (promotable_to<To>(lhs) and holds_alternative<To>(rhs)) {
234 r.set(static_cast<To>(lhs), get<To>(rhs));
235 }
236
237 return r;
238 }
239
240 constexpr ~datum() noexcept
241 {
242 delete_pointer();
243 }
244
245 constexpr datum(datum const& other) noexcept : _tag(other._tag), _value(other._value)
246 {
247 if (other.is_pointer()) {
248 copy_pointer(other);
249 }
250 }
251
252 constexpr datum(datum&& other) noexcept : _tag(other._tag), _value(other._value)
253 {
254 other._tag = tag_type::monostate;
255 other._value._long_long = 0;
256 }
257
258 constexpr datum() noexcept : _tag(tag_type::monostate), _value(0) {}
259 constexpr explicit datum(std::monostate) noexcept : _tag(tag_type::monostate), _value(0) {}
260 constexpr explicit datum(nullptr_t) noexcept : _tag(tag_type::null), _value(0) {}
261 constexpr explicit datum(continue_type) noexcept : _tag(tag_type::flow_continue), _value(0) {}
262 constexpr explicit datum(break_type) noexcept : _tag(tag_type::flow_break), _value(0) {}
263 constexpr explicit datum(bool value) noexcept : _tag(tag_type::boolean), _value(value) {}
264 constexpr explicit datum(std::floating_point auto value) noexcept :
265 _tag(tag_type::floating_point), _value(narrow_cast<double>(value))
266 {
267 }
268
269 constexpr explicit datum(numeric_integral auto value) noexcept :
270 _tag(tag_type::integral), _value(narrow_cast<long long>(value))
271 {
272 }
273
274 constexpr explicit datum(std::chrono::year_month_day value) noexcept : _tag(tag_type::year_month_day), _value(value) {}
275 explicit datum(std::string value) noexcept : _tag(tag_type::string), _value(new std::string{std::move(value)}) {}
276 explicit datum(std::string_view value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
277 explicit datum(char const *value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
278 explicit datum(vector_type value) noexcept : _tag(tag_type::vector), _value(new vector_type{std::move(value)}) {}
279 explicit datum(map_type value) noexcept : _tag(tag_type::map), _value(new map_type{std::move(value)}) {}
280 explicit datum(bstring value) noexcept : _tag(tag_type::bstring), _value(new bstring{std::move(value)}) {}
281
282 template<typename... Args>
283 [[nodiscard]] static datum make_vector(Args const&...args) noexcept
284 {
285 return datum{vector_type{datum{args}...}};
286 }
287
288 template<typename Key, typename Value, typename... Args>
289 static void populate_map(map_type& r, Key const& key, Value const& value, Args const&...args) noexcept
290 {
291 r.insert(std::pair<datum, datum>{datum{key}, datum{value}});
292 if constexpr (sizeof...(Args) > 0) {
293 populate_map(r, args...);
294 }
295 }
296
297 template<typename... Args>
298 [[nodiscard]] static datum make_map(Args const&...args) noexcept
299 {
300 static_assert(sizeof...(Args) % 2 == 0, "Expect key value pairs for the arguments of make_map()");
301
302 auto r = map_type{};
303 if constexpr (sizeof...(Args) > 0) {
304 populate_map(r, args...);
305 }
306 return datum{std::move(r)};
307 }
308
309 [[nodiscard]] static datum make_break() noexcept
310 {
311 return datum{break_type{}};
312 }
313
314 [[nodiscard]] static datum make_continue() noexcept
315 {
316 return datum{continue_type{}};
317 }
318
319 constexpr datum& operator=(datum const& other) noexcept
320 {
321 hi_return_on_self_assignment(other);
322
323 delete_pointer();
324 _tag = other._tag;
325 _value = other._value;
326 if (other.is_pointer()) {
327 copy_pointer(other);
328 }
329 return *this;
330 }
331
332 constexpr datum& operator=(datum&& other) noexcept
333 {
334 std::swap(_tag, other._tag);
335 std::swap(_value, other._value);
336 return *this;
337 }
338
339 constexpr datum& operator=(std::floating_point auto value) noexcept(sizeof(value) <= 4)
340 {
341 delete_pointer();
342 _tag = tag_type::floating_point;
343 _value = static_cast<double>(value);
344 return *this;
345 }
346
347 constexpr datum& operator=(numeric_integral auto value) noexcept(sizeof(value) <= 4)
348 {
349 delete_pointer();
350 _tag = tag_type::integral;
351 _value = static_cast<long long>(value);
352 return *this;
353 }
354
355 constexpr datum& operator=(bool value) noexcept
356 {
357 delete_pointer();
358 _tag = tag_type::boolean;
359 _value = value;
360 return *this;
361 }
362
363 constexpr datum& operator=(std::chrono::year_month_day value) noexcept
364 {
365 delete_pointer();
366 _tag = tag_type::year_month_day;
367 _value = value;
368 return *this;
369 }
370
371 constexpr datum& operator=(std::monostate) noexcept
372 {
373 delete_pointer();
374 _tag = tag_type::monostate;
375 _value = 0;
376 return *this;
377 }
378
379 constexpr datum& operator=(nullptr_t) noexcept
380 {
381 delete_pointer();
382 _tag = tag_type::null;
383 _value = 0;
384 return *this;
385 }
386
387 datum& operator=(std::string value) noexcept
388 {
389 delete_pointer();
390 _tag = tag_type::string;
391 _value = new std::string{std::move(value)};
392 return *this;
393 }
394
395 datum& operator=(char const *value) noexcept
396 {
397 delete_pointer();
398 _tag = tag_type::string;
399 _value = new std::string{value};
400 return *this;
401 }
402
403 datum& operator=(std::string_view value) noexcept
404 {
405 delete_pointer();
406 _tag = tag_type::string;
407 _value = new std::string{value};
408 return *this;
409 }
410
411 datum& operator=(vector_type value) noexcept
412 {
413 delete_pointer();
414 _tag = tag_type::vector;
415 _value = new vector_type{std::move(value)};
416 return *this;
417 }
418
419 datum& operator=(map_type value) noexcept
420 {
421 delete_pointer();
422 _tag = tag_type::map;
423 _value = new map_type{std::move(value)};
424 return *this;
425 }
426
427 datum& operator=(bstring value) noexcept
428 {
429 delete_pointer();
430 _tag = tag_type::bstring;
431 _value = new bstring{std::move(value)};
432 return *this;
433 }
434
435 constexpr explicit operator bool() const noexcept
436 {
437 switch (_tag) {
438 case tag_type::floating_point:
439 return to_bool(get<double>(*this));
440 case tag_type::boolean:
441 return get<bool>(*this);
442 case tag_type::integral:
443 return to_bool(get<long long>(*this));
444 case tag_type::year_month_day:
445 return true;
446 case tag_type::string:
447 return not get<std::string>(*this).empty();
448 case tag_type::vector:
449 return not get<vector_type>(*this).empty();
450 case tag_type::map:
451 return not get<map_type>(*this).empty();
452 case tag_type::bstring:
453 return not get<bstring>(*this).empty();
454 default:
455 return false;
456 }
457 }
458
459 [[nodiscard]] constexpr bool empty() const
460 {
461 switch (_tag) {
462 case tag_type::string:
463 return get<std::string>(*this).empty();
464 case tag_type::vector:
465 return get<vector_type>(*this).empty();
466 case tag_type::map:
467 return get<map_type>(*this).empty();
468 case tag_type::bstring:
469 return get<bstring>(*this).empty();
470 default:
471 throw std::domain_error(std::format("Type {} can not be checked for empty", repr(*this)));
472 }
473 }
474
475 template<std::floating_point T>
476 constexpr explicit operator T() const
477 {
478 switch (_tag) {
479 case tag_type::floating_point:
480 return static_cast<T>(get<double>(*this));
481 case tag_type::integral:
482 return static_cast<T>(get<long long>(*this));
483 case tag_type::boolean:
484 return static_cast<T>(get<bool>(*this));
485 default:
486 throw std::domain_error(std::format("Can't convert {} to floating point", repr(*this)));
487 }
488 }
489
490 template<numeric_integral T>
491 constexpr explicit operator T() const
492 {
493 if (auto f = get_if<double>(*this)) {
494 errno = 0;
495 auto const r = std::round(*f);
498 throw std::overflow_error("double to integral");
499 }
500 return round_cast<T>(r);
501
502 } else if (auto i = get_if<long long>(*this)) {
504 throw std::overflow_error("long long to integral");
505 }
506 return narrow_cast<T>(*i);
507
508 } else if (auto b = get_if<bool>(*this)) {
509 return narrow_cast<T>(*b);
510
511 } else {
512 throw std::domain_error(std::format("Can't convert {} to an integral", repr(*this)));
513 }
514 }
515
516 constexpr explicit operator std::chrono::year_month_day() const
517 {
518 if (auto ymd = get_if<std::chrono::year_month_day>(*this)) {
519 return *ymd;
520 } else {
521 throw std::domain_error(std::format("Can't convert {} to an std::chrono::year_month_day", repr(*this)));
522 }
523 }
524
525 explicit operator std::string() const noexcept
526 {
527 switch (_tag) {
528 case tag_type::monostate:
529 return "undefined";
530 case tag_type::floating_point:
531 return hi::to_string(_value._double);
532 case tag_type::integral:
533 return to_string(_value._long_long);
534 case tag_type::boolean:
535 return _value._bool ? "true" : "false";
536 case tag_type::year_month_day:
537 return std::format("{:%Y-%m-%d}", _value._year_month_day);
538 case tag_type::null:
539 return "null";
540 case tag_type::flow_break:
541 return "break";
542 case tag_type::flow_continue:
543 return "continue";
544 case tag_type::string:
545 return *_value._string;
546 case tag_type::vector:
547 {
548 auto r = std::string{"["};
549 for (auto const& item : *_value._vector) {
550 r += repr(item);
551 r += ',';
552 }
553 r += ']';
554 return r;
555 };
556 case tag_type::map:
557 {
558 auto r = std::string{"{"};
559 for (auto const& item : *_value._map) {
560 r += repr(item.first);
561 r += ':';
562 r += repr(item.second);
563 r += ',';
564 }
565 r += '}';
566 return r;
567 };
568 case tag_type::bstring:
569 return base64::encode(*_value._bstring);
570 default:
571 hi_no_default();
572 }
573 }
574
575 explicit operator std::string_view() const
576 {
577 if (auto s = get_if<std::string>(*this)) {
578 return std::string_view{*s};
579 } else {
580 throw std::domain_error(std::format("Can't convert {} to an std::string_view", repr(*this)));
581 }
582 }
583
584 explicit operator vector_type() const
585 {
586 if (auto v = get_if<vector_type>(*this)) {
587 return *v;
588 } else {
589 throw std::domain_error(std::format("Can't convert {} to an vector", repr(*this)));
590 }
591 }
592
593 explicit operator map_type() const
594 {
595 if (auto m = get_if<map_type>(*this)) {
596 return *m;
597 } else {
598 throw std::domain_error(std::format("Can't convert {} to an map", repr(*this)));
599 }
600 }
601
602 explicit operator bstring() const
603 {
604 // XXX should be able to base-64 decode a std::string.
605 if (_tag != tag_type::bstring) {
606 throw std::domain_error(std::format("Can't convert {} to an bstring", repr(*this)));
607 }
608 return get<bstring>(*this);
609 }
610
611 [[nodiscard]] constexpr char const *type_name() const noexcept
612 {
613 switch (_tag) {
614 case tag_type::floating_point:
615 return "float";
616 case tag_type::integral:
617 return "int";
618 case tag_type::boolean:
619 return "bool";
620 case tag_type::year_month_day:
621 return "date";
622 case tag_type::string:
623 return "string";
624 case tag_type::vector:
625 return "vector";
626 case tag_type::map:
627 return "map";
628 case tag_type::bstring:
629 return "bytes";
630 default:
631 hi_no_default();
632 }
633 }
634
638 {
639 return _tag == tag_type::monostate;
640 }
641
645 [[nodiscard]] constexpr bool is_break() const noexcept
646 {
647 return _tag == tag_type::flow_break;
648 }
649
653 [[nodiscard]] constexpr bool is_continue() const noexcept
654 {
655 return _tag == tag_type::flow_continue;
656 }
657
659 {
660 switch (_tag) {
661 case tag_type::floating_point:
662 return std::hash<double>{}(_value._double);
663 case tag_type::integral:
664 return std::hash<long long>{}(_value._long_long);
665 case tag_type::boolean:
666 return std::hash<bool>{}(_value._bool);
667 case tag_type::year_month_day:
668 {
669 uint32_t r = 0;
670 r |= narrow_cast<uint32_t>(static_cast<int>(_value._year_month_day.year())) << 16;
671 r |= narrow_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.month())) << 8;
672 r |= narrow_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.day()));
673 return std::hash<uint32_t>{}(r);
674 }
675 case tag_type::string:
676 return std::hash<std::string>{}(*_value._string);
677 case tag_type::vector:
678 {
679 std::size_t r = 0;
680 for (auto const& v : *_value._vector) {
681 r = hash_mix(r, v.hash());
682 }
683 return r;
684 }
685 case tag_type::map:
686 {
687 std::size_t r = 0;
688 for (auto const& kv : *_value._map) {
689 r = hash_mix(r, kv.first.hash(), kv.second.hash());
690 }
691 return r;
692 }
693 case tag_type::bstring:
694 return std::hash<bstring>{}(*_value._bstring);
695 default:
696 hi_no_default();
697 }
698 }
699
700 [[nodiscard]] constexpr std::size_t size() const
701 {
702 if (auto const *s = get_if<std::string>(*this)) {
703 return s->size();
704 } else if (auto const *v = get_if<vector_type>(*this)) {
705 return v->size();
706 } else if (auto const *m = get_if<map_type>(*this)) {
707 return m->size();
708 } else if (auto const *b = get_if<bstring>(*this)) {
709 return b->size();
710 } else {
711 throw std::domain_error(std::format("Can not evaluate {}.size()", repr(*this)));
712 }
713 }
714
715 [[nodiscard]] constexpr friend std::size_t size(datum const& rhs)
716 {
717 return rhs.size();
718 }
719
720 [[nodiscard]] constexpr datum const& back() const
721 {
722 if (auto const *v = get_if<vector_type>(*this)) {
723 if (v->empty()) {
724 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
725 }
726 return v->back();
727 } else {
728 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
729 }
730 }
731
732 [[nodiscard]] constexpr datum& back()
733 {
734 if (auto *v = get_if<vector_type>(*this)) {
735 if (v->empty()) {
736 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
737 }
738 return v->back();
739 } else {
740 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
741 }
742 }
743
744 [[nodiscard]] constexpr datum const& front() const
745 {
746 if (auto const *v = get_if<vector_type>(*this)) {
747 if (v->empty()) {
748 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
749 }
750 return v->front();
751 } else {
752 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
753 }
754 }
755
756 [[nodiscard]] constexpr datum& front()
757 {
758 if (auto *v = get_if<vector_type>(*this)) {
759 if (v->empty()) {
760 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
761 }
762 return v->front();
763 } else {
764 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
765 }
766 }
767
768 [[nodiscard]] constexpr auto cbegin() const
769 {
770 if (auto const *v = get_if<vector_type>(*this)) {
771 return v->cbegin();
772 } else {
773 throw std::domain_error(std::format("Can not evaluate {}.cbegin()", repr(*this)));
774 }
775 }
776
777 [[nodiscard]] constexpr auto begin() const
778 {
779 if (auto const *v = get_if<vector_type>(*this)) {
780 return v->begin();
781 } else {
782 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
783 }
784 }
785
786 [[nodiscard]] constexpr auto begin()
787 {
788 if (auto const *v = get_if<vector_type>(*this)) {
789 return v->begin();
790 } else {
791 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
792 }
793 }
794
795 [[nodiscard]] constexpr auto cend() const
796 {
797 if (auto const *v = get_if<vector_type>(*this)) {
798 return v->cend();
799 } else {
800 throw std::domain_error(std::format("Can not evaluate {}.cend()", repr(*this)));
801 }
802 }
803
804 [[nodiscard]] constexpr auto end() const
805 {
806 if (auto const *v = get_if<vector_type>(*this)) {
807 return v->end();
808 } else {
809 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
810 }
811 }
812
813 [[nodiscard]] constexpr auto end()
814 {
815 if (auto const *v = get_if<vector_type>(*this)) {
816 return v->end();
817 } else {
818 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
819 }
820 }
821
825 {
826 if (auto const *m = get_if<map_type>(*this)) {
827 auto r = vector_type{};
828 r.reserve(m->size());
829 for (auto const& kv : *m) {
830 r.push_back(kv.first);
831 }
832 return r;
833 } else {
834 throw std::domain_error(std::format("Can not evaluate {}.keys()", repr(*this)));
835 }
836 }
837
841 {
842 if (auto const *m = get_if<map_type>(*this)) {
843 auto r = vector_type{};
844 r.reserve(m->size());
845 for (auto const& kv : *m) {
846 r.push_back(kv.second);
847 }
848 return r;
849 } else {
850 throw std::domain_error(std::format("Can not evaluate {}.values()", repr(*this)));
851 }
852 }
853
857 {
858 if (auto const *m = get_if<map_type>(*this)) {
859 auto r = vector_type{};
860 r.reserve(m->size());
861
862 for (auto const& item : *m) {
863 r.push_back(make_vector(item.first, item.second));
864 }
865 return r;
866 } else {
867 throw std::domain_error(std::format("Can not evaluate {}.items()", repr(*this)));
868 }
869 }
870
871 constexpr void push_back(datum const& rhs)
872 {
873 if (auto *v = get_if<vector_type>(*this)) {
874 return v->push_back(rhs);
875 } else {
876 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
877 }
878 }
879
880 constexpr void push_back(datum&& rhs)
881 {
882 if (auto *v = get_if<vector_type>(*this)) {
883 return v->push_back(std::move(rhs));
884 } else {
885 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
886 }
887 }
888
889 template<typename Arg>
890 constexpr void push_back(Arg&& arg)
891 {
892 push_back(datum{std::forward<Arg>(arg)});
893 }
894
895 constexpr void pop_back()
896 {
897 if (auto *v = get_if<vector_type>(*this)) {
898 if (v->empty()) {
899 throw std::domain_error(std::format("Empty vector {}.pop_back()", repr(*this)));
900 }
901 return v->pop_back();
902 } else {
903 throw std::domain_error(std::format("Can not evaluate {}.pop_back()", repr(*this)));
904 }
905 }
906
907 [[nodiscard]] constexpr bool contains(datum const& rhs) const
908 {
909 if (auto *m = get_if<map_type>(*this)) {
910 return m->contains(rhs);
911 } else {
912 throw std::domain_error(std::format("Can not evaluate {}.contains({})", repr(*this), repr(rhs)));
913 }
914 }
915
916 template<typename Arg>
917 [[nodiscard]] constexpr bool contains(Arg const& arg) const
918 {
919 return contains(datum{arg});
920 }
921
922 [[nodiscard]] std::vector<datum *> find(jsonpath const& path) noexcept
923 {
924 auto r = std::vector<datum *>{};
925 find(path.cbegin(), path.cend(), r);
926 return r;
927 }
928
929 [[nodiscard]] std::vector<datum const *> find(jsonpath const& path) const noexcept
930 {
931 auto tmp = std::vector<datum *>{};
932 const_cast<datum *>(this)->find(path.cbegin(), path.cend(), tmp);
934 std::copy(tmp.begin(), tmp.end(), std::back_inserter(r));
935 return r;
936 }
937
946 [[nodiscard]] bool remove(jsonpath const& path) noexcept
947 {
948 return to_bool(remove(path.cbegin(), path.cend()));
949 }
950
956 [[nodiscard]] datum *find_one(jsonpath const& path) noexcept
957 {
958 hi_axiom(path.is_singular());
959 return find_one(path.cbegin(), path.cend(), false);
960 }
961
967 [[nodiscard]] datum *find_one_or_create(jsonpath const& path) noexcept
968 {
969 hi_axiom(path.is_singular());
970 return find_one(path.cbegin(), path.cend(), true);
971 }
972
978 [[nodiscard]] datum const *find_one(jsonpath const& path) const noexcept
979 {
980 hi_axiom(path.is_singular());
981 return const_cast<datum *>(this)->find_one(path.cbegin(), path.cend(), false);
982 }
983
984 [[nodiscard]] datum const& operator[](datum const& rhs) const
985 {
987 auto const& v = get<vector_type>(*this);
988
989 auto index = get<long long>(rhs);
990 if (index < 0) {
991 index = ssize(v) + index;
992 }
993 if (index < 0 or index >= ssize(v)) {
994 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
995 }
996
997 return v[index];
998
999 } else if (holds_alternative<map_type>(*this)) {
1000 auto const& m = get<map_type>(*this);
1001 auto const it = m.find(rhs);
1002 if (it == m.end()) {
1003 throw std::overflow_error(std::format("Key {} not found in map", repr(rhs)));
1004 }
1005
1006 return it->second;
1007
1008 } else {
1009 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
1010 }
1011 }
1012
1013 [[nodiscard]] constexpr datum& operator[](datum const& rhs)
1014 {
1016 auto& v = get<vector_type>(*this);
1017
1018 auto index = get<long long>(rhs);
1019 if (index < 0) {
1020 index = ssize(v) + index;
1021 }
1022 if (index < 0 or index >= ssize(v)) {
1023 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
1024 }
1025
1026 return v[index];
1027
1028 } else if (holds_alternative<map_type>(*this)) {
1029 auto& m = get<map_type>(*this);
1030 return m[rhs];
1031
1032 } else {
1033 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
1034 }
1035 }
1036
1037 [[nodiscard]] constexpr datum const& operator[](auto const& rhs) const
1038 {
1039 return (*this)[datum{rhs}];
1040 }
1041
1042 [[nodiscard]] constexpr datum& operator[](auto const& rhs)
1043 {
1044 return (*this)[datum{rhs}];
1045 }
1046
1047 [[nodiscard]] constexpr datum& operator++()
1048 {
1049 if (holds_alternative<long long>(*this)) {
1050 ++_value._long_long;
1051 return *this;
1052 } else {
1053 throw std::domain_error(std::format("Can not evaluate ++{}", repr(*this)));
1054 }
1055 }
1056
1057 [[nodiscard]] constexpr datum& operator--()
1058 {
1059 if (holds_alternative<long long>(*this)) {
1060 --_value._long_long;
1061 return *this;
1062 } else {
1063 throw std::domain_error(std::format("Can not evaluate --{}", repr(*this)));
1064 }
1065 }
1066
1067 [[nodiscard]] constexpr datum operator++(int)
1068 {
1069 if (holds_alternative<long long>(*this)) {
1070 auto tmp = *this;
1071 _value._long_long++;
1072 return tmp;
1073 } else {
1074 throw std::domain_error(std::format("Can not evaluate {}++", repr(*this)));
1075 }
1076 }
1077 [[nodiscard]] constexpr datum operator--(int)
1078 {
1079 if (holds_alternative<long long>(*this)) {
1080 auto tmp = *this;
1081 _value._long_long--;
1082 return tmp;
1083 } else {
1084 throw std::domain_error(std::format("Can not evaluate {}--", repr(*this)));
1085 }
1086 }
1087
1088 constexpr datum& operator+=(auto const& rhs)
1089 {
1090 if (holds_alternative<vector_type>(*this)) {
1091 push_back(rhs);
1092 return *this;
1093 } else {
1094 return (*this) = (*this) + rhs;
1095 }
1096 }
1097
1098#define X(op, inner_op) \
1099 constexpr datum& operator op(auto const& rhs) \
1100 { \
1101 return (*this) = (*this)inner_op rhs; \
1102 }
1103
1104 X(-=, -)
1105 X(*=, *)
1106 X(/=, /)
1107 X(%=, %)
1108 X(&=, &)
1109 X(|=, |)
1110 X(^=, ^)
1111 X(<<=, <<)
1112 X(>>=, >>)
1113#undef X
1114
1115 [[nodiscard]] friend constexpr bool operator==(datum const& lhs, datum const& rhs) noexcept
1116 {
1117 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1118 return doubles.lhs() == doubles.rhs();
1119
1120 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1121 return long_longs.lhs() == long_longs.rhs();
1122
1123 } else if (auto const bools = promote_if<bool>(lhs, rhs)) {
1124 return bools.lhs() == bools.rhs();
1125
1126 } else if (auto const ymds = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1127 return ymds.lhs() == ymds.rhs();
1128
1129 } else if (auto const strings = promote_if<std::string>(lhs, rhs)) {
1130 return strings.lhs() == strings.rhs();
1131
1132 } else if (auto const vectors = promote_if<vector_type>(lhs, rhs)) {
1133 return vectors.lhs() == vectors.rhs();
1134
1135 } else if (auto const maps = promote_if<map_type>(lhs, rhs)) {
1136 return maps.lhs() == maps.rhs();
1137
1138 } else {
1139 return lhs._tag == rhs._tag;
1140 }
1141 }
1142
1169 [[nodiscard]] friend constexpr std::partial_ordering operator<=>(datum const& lhs, datum const& rhs) noexcept
1170 {
1171 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1172 return doubles.lhs() <=> doubles.rhs();
1173
1174 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1175 return long_longs.lhs() <=> long_longs.rhs();
1176
1177 } else if (auto const bools = promote_if<bool>(lhs, rhs)) {
1178 return bools.lhs() <=> bools.rhs();
1179
1180 } else if (auto const year_month_days = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1181 return year_month_days.lhs() <=> year_month_days.rhs();
1182
1183 } else if (auto const strings = promote_if<std::string>(lhs, rhs)) {
1184 return strings.lhs() <=> strings.rhs();
1185
1186 } else if (auto const vectors = promote_if<vector_type>(lhs, rhs)) {
1187 return vectors.lhs() <=> vectors.rhs();
1188
1189 } else if (auto const maps = promote_if<map_type>(lhs, rhs)) {
1190 return maps.lhs() <=> maps.rhs();
1191
1192 } else if (auto const bstrings = promote_if<bstring>(lhs, rhs)) {
1193 return bstrings.lhs() <=> bstrings.rhs();
1194
1195 } else {
1196 return lhs._tag <=> rhs._tag;
1197 }
1198 }
1199
1210 [[nodiscard]] friend constexpr datum operator-(datum const& rhs)
1211 {
1212 if (auto const rhs_double = get_if<double>(rhs)) {
1213 return datum{-*rhs_double};
1214
1215 } else if (auto const rhs_long_long = get_if<long long>(rhs)) {
1216 return datum{-*rhs_long_long};
1217
1218 } else {
1219 throw std::domain_error(std::format("Can not evaluate -{}", repr(rhs)));
1220 }
1221 }
1222
1232 [[nodiscard]] friend constexpr datum operator~(datum const& rhs)
1233 {
1234 if (auto const rhs_long_long = get_if<long long>(rhs)) {
1235 return datum{~*rhs_long_long};
1236
1237 } else {
1238 throw std::domain_error(std::format("Can not evaluate ~{}", repr(rhs)));
1239 }
1240 }
1241
1256 [[nodiscard]] friend constexpr datum operator+(datum const& lhs, datum const& rhs)
1257 {
1258 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1259 return datum{doubles.lhs() + doubles.rhs()};
1260
1261 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1262 return datum{long_longs.lhs() + long_longs.rhs()};
1263
1264 } else if (auto const strings = promote_if<std::string>(lhs, rhs)) {
1265 return datum{strings.lhs() + strings.rhs()};
1266
1267 } else if (auto const vectors = promote_if<vector_type>(lhs, rhs)) {
1268 auto r = vectors.lhs();
1269 r.insert(r.end(), vectors.rhs().begin(), vectors.rhs().end());
1270 return datum{std::move(r)};
1271
1272 } else {
1273 throw std::domain_error(std::format("Can not evaluate {} '+' {}", repr(lhs), repr(rhs)));
1274 }
1275 }
1276
1288 [[nodiscard]] friend constexpr datum operator-(datum const& lhs, datum const& rhs)
1289 {
1290 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1291 return datum{doubles.lhs() - doubles.rhs()};
1292
1293 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1294 return datum{long_longs.lhs() - long_longs.rhs()};
1295
1296 } else {
1297 throw std::domain_error(std::format("Can not evaluate {} '-' {}", repr(lhs), repr(rhs)));
1298 }
1299 }
1300
1312 [[nodiscard]] friend constexpr datum operator*(datum const& lhs, datum const& rhs)
1313 {
1314 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1315 return datum{doubles.lhs() * doubles.rhs()};
1316
1317 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1318 return datum{long_longs.lhs() * long_longs.rhs()};
1319
1320 } else {
1321 throw std::domain_error(std::format("Can not evaluate {} '*' {}", repr(lhs), repr(rhs)));
1322 }
1323 }
1324
1336 [[nodiscard]] friend constexpr datum operator/(datum const& lhs, datum const& rhs)
1337 {
1338 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1339 if (doubles.rhs() == 0) {
1340 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1341 }
1342 return datum{doubles.lhs() / doubles.rhs()};
1343
1344 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1345 if (long_longs.rhs() == 0) {
1346 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1347 }
1348 return datum{long_longs.lhs() / long_longs.rhs()};
1349
1350 } else {
1351 throw std::domain_error(std::format("Can not evaluate {} '/' {}", repr(lhs), repr(rhs)));
1352 }
1353 }
1354
1366 [[nodiscard]] friend constexpr datum operator%(datum const& lhs, datum const& rhs)
1367 {
1368 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1369 if (long_longs.rhs() == 0) {
1370 throw std::domain_error(std::format("Divide by zero {} '%' {}", repr(lhs), repr(rhs)));
1371 }
1372 return datum{long_longs.lhs() % long_longs.rhs()};
1373
1374 } else {
1375 throw std::domain_error(std::format("Can not evaluate {} '%' {}", repr(lhs), repr(rhs)));
1376 }
1377 }
1378
1389 [[nodiscard]] friend constexpr datum pow(datum const& lhs, datum const& rhs)
1390 {
1391 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1392 return datum{pow(doubles.lhs(), doubles.rhs())};
1393
1394 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1395 return datum{pow(long_longs.lhs(), long_longs.rhs())};
1396
1397 } else {
1398 throw std::domain_error(std::format("Can not evaluate pow({}, {})", repr(lhs), repr(rhs)));
1399 }
1400 }
1401
1412 [[nodiscard]] friend constexpr datum operator&(datum const& lhs, datum const& rhs)
1413 {
1414 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1415 return datum{long_longs.lhs() & long_longs.rhs()};
1416
1417 } else if (auto const bools = promote_if<bool>(lhs, rhs)) {
1418 return datum{bools.lhs() and bools.rhs()};
1419
1420 } else {
1421 throw std::domain_error(std::format("Can not evaluate {} '&' {}", repr(lhs), repr(rhs)));
1422 }
1423 }
1424
1435 [[nodiscard]] friend constexpr datum operator|(datum const& lhs, datum const& rhs)
1436 {
1437 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1438 return datum{long_longs.lhs() | long_longs.rhs()};
1439
1440 } else if (auto const bools = promote_if<bool>(lhs, rhs)) {
1441 return datum{bools.lhs() or bools.rhs()};
1442
1443 } else {
1444 throw std::domain_error(std::format("Can not evaluate {} '|' {}", repr(lhs), repr(rhs)));
1445 }
1446 }
1447
1458 [[nodiscard]] friend constexpr datum operator^(datum const& lhs, datum const& rhs)
1459 {
1460 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1461 return datum{long_longs.lhs() ^ long_longs.rhs()};
1462
1463 } else if (auto const bools = promote_if<bool>(lhs, rhs)) {
1464 return datum{bools.lhs() != bools.rhs()};
1465
1466 } else {
1467 throw std::domain_error(std::format("Can not evaluate {} '^' {}", repr(lhs), repr(rhs)));
1468 }
1469 }
1470
1483 [[nodiscard]] friend constexpr datum operator<<(datum const& lhs, datum const& rhs)
1484 {
1485 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1486 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1487 throw std::domain_error(std::format("Invalid shift count {} '<<' {}", repr(lhs), repr(rhs)));
1488 }
1489 return datum{long_longs.lhs() << long_longs.rhs()};
1490
1491 } else {
1492 throw std::domain_error(std::format("Can not evaluate {} '<<' {}", repr(lhs), repr(rhs)));
1493 }
1494 }
1495
1507 [[nodiscard]] friend constexpr datum operator>>(datum const& lhs, datum const& rhs)
1508 {
1509 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1510 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1511 throw std::domain_error(std::format("Invalid shift count {} '>>' {}", repr(lhs), repr(rhs)));
1512 }
1513 return datum{long_longs.lhs() >> long_longs.rhs()};
1514
1515 } else {
1516 throw std::domain_error(std::format("Can not evaluate {} '>>' {}", repr(lhs), repr(rhs)));
1517 }
1518 }
1519
1520 friend std::ostream& operator<<(std::ostream& lhs, datum const& rhs)
1521 {
1522 return lhs << to_string(rhs);
1523 }
1524
1525#define X(op) \
1526 [[nodiscard]] friend constexpr auto operator op(datum const& lhs, auto const& rhs) \
1527 { \
1528 return lhs op datum{rhs}; \
1529 } \
1530 [[nodiscard]] friend constexpr auto operator op(auto const& lhs, datum const& rhs) \
1531 { \
1532 return datum{lhs} op rhs; \
1533 }
1534
1535 X(==)
1536 X(<=>)
1537 X(+)
1538 X(-)
1539 X(*)
1540 X(/)
1541 X(%)
1542 X(&)
1543 X(|)
1544 X(^) X(<<) X(>>)
1545#undef X
1546
1549 [[nodiscard]] friend std::string repr(datum const& rhs) noexcept
1550 {
1551 switch (rhs._tag) {
1552 case tag_type::monostate:
1553 return "undefined";
1554 case tag_type::floating_point:
1555 return std::format("{:.1f}", rhs._value._double);
1556 case tag_type::integral:
1557 return std::format("{}", rhs._value._long_long);
1558 case tag_type::boolean:
1559 return rhs._value._bool ? "true" : "false";
1560 case tag_type::year_month_day:
1561 return std::format("{:%Y-%m-%d}", rhs._value._year_month_day);
1562 case tag_type::null:
1563 return "null";
1564 case tag_type::flow_break:
1565 return "break";
1566 case tag_type::flow_continue:
1567 return "continue";
1568 case tag_type::string:
1569 return std::format("\"{}\"", *rhs._value._string);
1570 case tag_type::vector:
1571 {
1572 auto r = std::string{"["};
1573 for (auto const& item : *rhs._value._vector) {
1574 r += repr(item);
1575 r += ',';
1576 }
1577 r += ']';
1578 return r;
1579 };
1580 case tag_type::map:
1581 {
1582 auto r = std::string{"{"};
1583 for (auto const& item : *rhs._value._map) {
1584 r += repr(item.first);
1585 r += ':';
1586 r += repr(item.second);
1587 r += ',';
1588 }
1589 r += '}';
1590 return r;
1591 };
1592 case tag_type::bstring:
1593 return base64::encode(*rhs._value._bstring);
1594 default:
1595 hi_no_default();
1596 }
1597 }
1598
1601 [[nodiscard]] friend std::string to_string(datum const& rhs) noexcept
1602 {
1603 return static_cast<std::string>(rhs);
1604 }
1605
1612 template<typename T>
1613 [[nodiscard]] friend constexpr bool holds_alternative(datum const& rhs) noexcept
1614 {
1615 if constexpr (std::is_same_v<T, double>) {
1616 return rhs._tag == tag_type::floating_point;
1617 } else if constexpr (std::is_same_v<T, long long>) {
1618 return rhs._tag == tag_type::integral;
1619 } else if constexpr (std::is_same_v<T, bool>) {
1620 return rhs._tag == tag_type::boolean;
1621 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1622 return rhs._tag == tag_type::year_month_day;
1623 } else if constexpr (std::is_same_v<T, nullptr_t>) {
1624 return rhs._tag == tag_type::null;
1625 } else if constexpr (std::is_same_v<T, std::monostate>) {
1626 return rhs._tag == tag_type::monostate;
1627 } else if constexpr (std::is_same_v<T, break_type>) {
1628 return rhs._tag == tag_type::flow_break;
1629 } else if constexpr (std::is_same_v<T, continue_type>) {
1630 return rhs._tag == tag_type::flow_continue;
1631 } else if constexpr (std::is_same_v<T, std::string>) {
1632 return rhs._tag == tag_type::string;
1633 } else if constexpr (std::is_same_v<T, vector_type>) {
1634 return rhs._tag == tag_type::vector;
1635 } else if constexpr (std::is_same_v<T, map_type>) {
1636 return rhs._tag == tag_type::map;
1637 } else if constexpr (std::is_same_v<T, bstring>) {
1638 return rhs._tag == tag_type::bstring;
1639 } else {
1640 hi_static_no_default();
1641 }
1642 }
1643
1653 template<typename To>
1654 [[nodiscard]] friend constexpr bool promotable_to(datum const& rhs) noexcept
1655 {
1656 if constexpr (std::is_same_v<To, double>) {
1659 } else if constexpr (std::is_same_v<To, long long>) {
1661 } else {
1662 return holds_alternative<To>(rhs);
1663 }
1664 }
1665
1674 template<typename T>
1675 [[nodiscard]] friend constexpr T const& get(datum const& rhs) noexcept
1676 {
1677 hi_axiom(holds_alternative<T>(rhs));
1678 if constexpr (std::is_same_v<T, double>) {
1679 return rhs._value._double;
1680 } else if constexpr (std::is_same_v<T, long long>) {
1681 return rhs._value._long_long;
1682 } else if constexpr (std::is_same_v<T, bool>) {
1683 return rhs._value._bool;
1684 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1685 return rhs._value._year_month_day;
1686 } else if constexpr (std::is_same_v<T, std::string>) {
1687 return *rhs._value._string;
1688 } else if constexpr (std::is_same_v<T, vector_type>) {
1689 return *rhs._value._vector;
1690 } else if constexpr (std::is_same_v<T, map_type>) {
1691 return *rhs._value._map;
1692 } else if constexpr (std::is_same_v<T, bstring>) {
1693 return *rhs._value._bstring;
1694 } else {
1695 hi_static_no_default();
1696 }
1697 }
1698
1707 template<typename T>
1708 [[nodiscard]] friend constexpr T& get(datum& rhs) noexcept
1709 {
1710 hi_axiom(holds_alternative<T>(rhs));
1711 if constexpr (std::is_same_v<T, double>) {
1712 return rhs._value._double;
1713 } else if constexpr (std::is_same_v<T, long long>) {
1714 return rhs._value._long_long;
1715 } else if constexpr (std::is_same_v<T, bool>) {
1716 return rhs._value._bool;
1717 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1718 return rhs._value._year_month_day;
1719 } else if constexpr (std::is_same_v<T, std::string>) {
1720 return *rhs._value._string;
1721 } else if constexpr (std::is_same_v<T, vector_type>) {
1722 return *rhs._value._vector;
1723 } else if constexpr (std::is_same_v<T, map_type>) {
1724 return *rhs._value._map;
1725 } else if constexpr (std::is_same_v<T, bstring>) {
1726 return *rhs._value._bstring;
1727 } else {
1728 hi_static_no_default();
1729 }
1730 }
1731
1740 template<typename T>
1741 [[nodiscard]] friend constexpr T *get_if(datum& rhs) noexcept
1742 {
1743 if (holds_alternative<T>(rhs)) {
1744 return &get<T>(rhs);
1745 } else {
1746 return nullptr;
1747 }
1748 }
1749
1758 template<typename T>
1759 [[nodiscard]] friend constexpr T const *get_if(datum const& rhs) noexcept
1760 {
1761 if (holds_alternative<T>(rhs)) {
1762 return &get<T>(rhs);
1763 } else {
1764 return nullptr;
1765 }
1766 }
1767
1777 template<typename T>
1778 [[nodiscard]] friend T *get_if(datum& rhs, jsonpath const& path) noexcept
1779 {
1780 if (auto *value = rhs.find_one(path)) {
1781 if (holds_alternative<T>(*value)) {
1782 return &get<T>(*value);
1783 } else {
1784 return nullptr;
1785 }
1786 } else {
1787 return nullptr;
1788 }
1789 }
1790
1800 template<typename T>
1801 [[nodiscard]] friend T const *get_if(datum const& rhs, jsonpath const& path) noexcept
1802 {
1803 if (auto *value = const_cast<datum&>(rhs).find_one(path)) {
1804 if (holds_alternative<T>(*value)) {
1805 return &get<T>(*value);
1806 } else {
1807 return nullptr;
1808 }
1809 } else {
1810 return nullptr;
1811 }
1812 }
1813
1814private:
1815 enum class tag_type : signed char {
1816 // scalars are detected by: `std::to_underlying(tag_type) >= 0`
1817 monostate = 0,
1818 floating_point = 1,
1819 integral = 2,
1820 boolean = 3,
1821 null = 4,
1822 year_month_day = 5,
1823 flow_continue = 6,
1824 flow_break = 7,
1825
1826 // pointers are detected by: `std::to_underlying(tag_type) < 0`.
1827 string = -1,
1828 vector = -2,
1829 map = -3,
1830 bstring = -5
1831 };
1832
1833 tag_type _tag = tag_type::monostate;
1834 union value_type {
1835 double _double;
1836 long long _long_long;
1837 bool _bool;
1838 std::chrono::year_month_day _year_month_day;
1839 std::string *_string;
1840 vector_type *_vector;
1841 map_type *_map;
1842 bstring *_bstring;
1843
1844 constexpr value_type(numeric_integral auto value) noexcept : _long_long(narrow_cast<long long>(value)) {}
1845 constexpr value_type(std::floating_point auto value) noexcept : _double(narrow_cast<double>(value)) {}
1846 constexpr value_type(bool value) noexcept : _bool(value) {}
1847 constexpr value_type(std::chrono::year_month_day value) noexcept : _year_month_day(value) {}
1848 constexpr value_type(std::string *value) noexcept : _string(value) {}
1849 constexpr value_type(vector_type *value) noexcept : _vector(value) {}
1850 constexpr value_type(map_type *value) noexcept : _map(value) {}
1851 constexpr value_type(bstring *value) noexcept : _bstring(value) {}
1852 };
1853
1854 value_type _value;
1855
1856 [[nodiscard]] constexpr bool is_scalar() const noexcept
1857 {
1858 return std::to_underlying(_tag) >= 0;
1859 }
1860
1861 [[nodiscard]] constexpr bool is_pointer() const noexcept
1862 {
1863 return std::to_underlying(_tag) < 0;
1864 }
1865
1866 hi_no_inline void copy_pointer(datum const& other) noexcept
1867 {
1868 hi_axiom(other.is_pointer());
1869 switch (other._tag) {
1870 case tag_type::string:
1871 _value._string = new std::string{*other._value._string};
1872 return;
1873 case tag_type::vector:
1874 _value._vector = new vector_type{*other._value._vector};
1875 return;
1876 case tag_type::map:
1877 _value._map = new map_type{*other._value._map};
1878 return;
1879 case tag_type::bstring:
1880 _value._bstring = new bstring{*other._value._bstring};
1881 return;
1882 default:
1883 hi_no_default();
1884 }
1885 }
1886
1887 hi_no_inline void _delete_pointer() noexcept
1888 {
1889 hi_axiom(is_pointer());
1890 switch (_tag) {
1891 case tag_type::string:
1892 delete _value._string;
1893 return;
1894 case tag_type::vector:
1895 delete _value._vector;
1896 return;
1897 case tag_type::map:
1898 delete _value._map;
1899 return;
1900 case tag_type::bstring:
1901 delete _value._bstring;
1902 return;
1903 default:
1904 hi_no_default();
1905 }
1906 }
1907
1908 constexpr void delete_pointer() noexcept
1909 {
1910 if (is_pointer()) {
1911 _delete_pointer();
1912 }
1913 }
1914
1915 void find_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *>& r) noexcept
1916 {
1917 if (auto vector = get_if<datum::vector_type>(*this)) {
1918 for (auto& item : *vector) {
1919 item.find(it + 1, it_end, r);
1920 }
1921
1922 } else if (auto map = get_if<datum::map_type>(*this)) {
1923 for (auto& item : *map) {
1924 item.second.find(it + 1, it_end, r);
1925 }
1926 }
1927 }
1928
1929 void find_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *>& r) noexcept
1930 {
1931 this->find(it + 1, it_end, r);
1932
1933 if (auto vector = get_if<datum::vector_type>(*this)) {
1934 for (auto& item : *vector) {
1935 item.find(it, it_end, r);
1936 }
1937
1938 } else if (auto map = get_if<datum::map_type>(*this)) {
1939 for (auto& item : *map) {
1940 item.second.find(it, it_end, r);
1941 }
1942 }
1943 }
1944
1945 void find_indices(
1946 jsonpath::indices const& indices,
1947 jsonpath::const_iterator it,
1948 jsonpath::const_iterator it_end,
1949 std::vector<datum *>& r) noexcept
1950 {
1951 if (auto vector = get_if<datum::vector_type>(*this)) {
1952 for (auto const index : indices.filter(ssize(*vector))) {
1953 (*vector)[index].find(it + 1, it_end, r);
1954 }
1955 }
1956 }
1957
1958 void find_names(
1959 jsonpath::names const& names,
1960 jsonpath::const_iterator it,
1961 jsonpath::const_iterator it_end,
1962 std::vector<datum *>& r) noexcept
1963 {
1964 if (auto map = get_if<datum::map_type>(*this)) {
1965 for (auto const& name : names) {
1966 auto const name_ = datum{name};
1967 auto jt = map->find(name_);
1968 if (jt != map->cend()) {
1969 jt->second.find(it + 1, it_end, r);
1970 }
1971 }
1972 }
1973 }
1974
1975 void find_slice(
1976 jsonpath::slice const& slice,
1977 jsonpath::const_iterator it,
1978 jsonpath::const_iterator it_end,
1979 std::vector<datum *>& r) noexcept
1980 {
1981 if (auto vector = get_if<datum::vector_type>(*this)) {
1982 auto const first = slice.begin(vector->size());
1983 auto const last = slice.end(vector->size());
1984
1985 for (auto index = first; index != last; index += slice.step) {
1986 if (index >= 0 and index < vector->size()) {
1987 (*this)[index].find(it + 1, it_end, r);
1988 }
1989 }
1990 }
1991 }
1992
1993 void find(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *>& r) noexcept
1994 {
1995 if (it == it_end) {
1996 r.push_back(this);
1997
1998 } else if (std::holds_alternative<jsonpath::root>(*it)) {
1999 find(it + 1, it_end, r);
2000
2001 } else if (std::holds_alternative<jsonpath::current>(*it)) {
2002 find(it + 1, it_end, r);
2003
2004 } else if (std::holds_alternative<jsonpath::wildcard>(*it)) {
2005 find_wildcard(it, it_end, r);
2006
2007 } else if (std::holds_alternative<jsonpath::descend>(*it)) {
2008 find_descend(it, it_end, r);
2009
2010 } else if (auto indices = std::get_if<jsonpath::indices>(&*it)) {
2011 find_indices(*indices, it, it_end, r);
2012
2013 } else if (auto names = std::get_if<jsonpath::names>(&*it)) {
2014 find_names(*names, it, it_end, r);
2015
2016 } else if (auto slice = std::get_if<jsonpath::slice>(&*it)) {
2017 find_slice(*slice, it, it_end, r);
2018
2019 } else {
2020 hi_no_default();
2021 }
2022 }
2023
2024 [[nodiscard]] int remove_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2025 {
2026 int r = 0;
2027
2028 if (auto vector = get_if<datum::vector_type>(*this)) {
2029 auto jt = vector->begin();
2030 while (jt != vector->end()) {
2031 auto const match = jt->remove(it + 1, it_end);
2032 r |= match ? 1 : 0;
2033
2034 if (match == 2) {
2035 jt = vector->erase(jt);
2036 } else {
2037 ++jt;
2038 }
2039 }
2040 return vector->empty() ? 2 : r;
2041
2042 } else if (auto map = get_if<datum::map_type>(*this)) {
2043 auto jt = map->begin();
2044 while (jt != map->end()) {
2045 auto const match = jt->second.remove(it + 1, it_end);
2046 r |= match ? 1 : 0;
2047
2048 if (match == 2) {
2049 jt = map->erase(jt);
2050 } else {
2051 ++jt;
2052 }
2053 }
2054 return map->empty() ? 2 : r;
2055
2056 } else {
2057 return 0;
2058 }
2059 }
2060
2061 [[nodiscard]] int remove_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2062 {
2063 int r = 0;
2064
2065 {
2066 auto const match = this->remove(it + 1, it_end);
2067 if (match == 2) {
2068 return 2;
2069 }
2070 r |= match ? 1 : 0;
2071 }
2072
2073 if (auto vector = get_if<datum::vector_type>(*this)) {
2074 auto jt = vector->begin();
2075 while (jt != vector->end()) {
2076 auto const match = jt->remove(it, it_end);
2077 r |= match ? 1 : 0;
2078
2079 if (match == 2) {
2080 jt = vector->erase(jt);
2081 } else {
2082 ++jt;
2083 }
2084 }
2085 return vector->empty() ? 2 : r;
2086
2087 } else if (auto map = get_if<datum::map_type>(*this)) {
2088 auto jt = map->begin();
2089 while (jt != map->end()) {
2090 auto const match = jt->second.remove(it, it_end);
2091 r |= match ? 1 : 0;
2092
2093 if (match == 2) {
2094 jt = map->erase(jt);
2095 } else {
2096 ++jt;
2097 }
2098 }
2099 return map->empty() ? 2 : r;
2100
2101 } else {
2102 return 0;
2103 }
2104 }
2105
2106 [[nodiscard]] int
2107 remove_indices(jsonpath::indices const& indices, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2108 {
2109 if (auto vector = get_if<datum::vector_type>(*this)) {
2110 int r = 0;
2111 std::size_t offset = 0;
2112
2113 for (auto const index : indices.filter(ssize(*vector))) {
2114 auto const match = (*vector)[index - offset].remove(it + 1, it_end);
2115 r |= match ? 1 : 0;
2116 if (match == 2) {
2117 vector->erase(vector->begin() + (index - offset));
2118 ++offset;
2119 }
2120 }
2121
2122 return vector->empty() ? 2 : r;
2123
2124 } else {
2125 return 0;
2126 }
2127 }
2128
2129 [[nodiscard]] int
2130 remove_names(jsonpath::names const& names, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2131 {
2132 if (auto map = get_if<datum::map_type>(*this)) {
2133 int r = 0;
2134
2135 for (auto const& name : names) {
2136 auto const name_ = datum{name};
2137 auto jt = map->find(name_);
2138 if (jt != map->cend()) {
2139 auto const match = jt->second.remove(it + 1, it_end);
2140 r |= match ? 1 : 0;
2141 if (match == 2) {
2142 map->erase(jt);
2143 }
2144 }
2145 }
2146
2147 return map->empty() ? 2 : r;
2148
2149 } else {
2150 return 0;
2151 }
2152 }
2153
2154 [[nodiscard]] int
2155 remove_slice(jsonpath::slice const& slice, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2156 {
2157 if (auto vector = get_if<datum::vector_type>(*this)) {
2158 int r = 0;
2159
2160 auto const first = slice.begin(vector->size());
2161 auto const last = slice.end(vector->size());
2162
2163 std::size_t offset = 0;
2164 for (auto index = first; index != last; index += slice.step) {
2165 if (index >= 0 and index < vector->size()) {
2166 auto const match = (*this)[index - offset].remove(it + 1, it_end);
2167 r |= match ? 1 : 0;
2168
2169 if (match == 2) {
2170 vector->erase(vector->begin() + (index - offset));
2171 ++offset;
2172 }
2173 }
2174 }
2175
2176 return vector->empty() ? 2 : r;
2177
2178 } else {
2179 return 0;
2180 }
2181 }
2182
2183 [[nodiscard]] int remove(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2184 {
2185 if (it == it_end) {
2186 // Reached end, remove matching name or index in parent.
2187 return 2;
2188
2189 } else if (std::holds_alternative<jsonpath::root>(*it)) {
2190 return remove(it + 1, it_end);
2191
2192 } else if (std::holds_alternative<jsonpath::current>(*it)) {
2193 return remove(it + 1, it_end);
2194
2195 } else if (std::holds_alternative<jsonpath::wildcard>(*it)) {
2196 return remove_wildcard(it, it_end);
2197
2198 } else if (std::holds_alternative<jsonpath::descend>(*it)) {
2199 return remove_descend(it, it_end);
2200
2201 } else if (auto indices = std::get_if<jsonpath::indices>(&*it)) {
2202 return remove_indices(*indices, it, it_end);
2203
2204 } else if (auto names = std::get_if<jsonpath::names>(&*it)) {
2205 return remove_names(*names, it, it_end);
2206
2207 } else if (auto slice = std::get_if<jsonpath::slice>(&*it)) {
2208 return remove_slice(*slice, it, it_end);
2209
2210 } else {
2211 hi_no_default();
2212 }
2213 }
2214
2215 [[nodiscard]] datum *
2216 find_one_name(datum const& name, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2217 {
2218 hi_axiom(holds_alternative<std::string>(name));
2219
2220 if (auto *map = get_if<map_type>(*this)) {
2221 auto i = map->find(name);
2222 if (i != map->end()) {
2223 return i->second.find_one(it + 1, it_end, create);
2224
2225 } else if (create) {
2226 (*map)[name] = datum{std::monostate{}};
2227 return find_one_name(name, it, it_end, create);
2228
2229 } else {
2230 return nullptr;
2231 }
2232
2233 } else if (holds_alternative<std::monostate>(*this) and create) {
2234 *this = datum::make_map(name, std::monostate{});
2235 return find_one_name(name, it, it_end, create);
2236
2237 } else {
2238 return nullptr;
2239 }
2240 }
2241
2242 [[nodiscard]] datum *
2243 find_one_index(std::size_t index, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2244 {
2245 if (auto *vector = get_if<vector_type>(*this)) {
2246 if (index < vector->size()) {
2247 return (*vector)[index].find_one(it + 1, it_end, create);
2248 } else if (index == vector->size() and create) {
2249 vector->push_back(datum{std::monostate{}});
2250 return find_one_index(index, it, it_end, create);
2251 } else {
2252 return nullptr;
2253 }
2254
2255 } else if (holds_alternative<std::monostate>(*this) and index == 0 and create) {
2256 *this = datum::make_vector(std::monostate{});
2257 return find_one_index(index, it, it_end, create);
2258
2259 } else {
2260 return nullptr;
2261 }
2262 }
2263
2264 [[nodiscard]] datum *find_one(jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2265 {
2266 if (it == it_end) {
2267 return this;
2268
2269 } else if (std::holds_alternative<jsonpath::root>(*it)) {
2270 return find_one(it + 1, it_end, create);
2271
2272 } else if (std::holds_alternative<jsonpath::current>(*it)) {
2273 return find_one(it + 1, it_end, create);
2274
2275 } else if (auto const *indices = std::get_if<jsonpath::indices>(&*it)) {
2276 hi_axiom(indices->size() == 1);
2277 return find_one_index(indices->front(), it, it_end, create);
2278
2279 } else if (auto const *names = std::get_if<jsonpath::names>(&*it)) {
2280 hi_axiom(names->size() == 1);
2281 return find_one_name(datum{names->front()}, it, it_end, create);
2282
2283 } else {
2284 hi_no_default();
2285 }
2286 }
2287};
2288
2289}} // namespace hi::v1
2290
2291hi_export template<>
2292struct std::hash<hi::datum> {
2293 [[nodiscard]] hi_inline std::size_t operator()(hi::datum const& rhs) const noexcept
2294 {
2295 return rhs.hash();
2296 }
2297};
2298
2299// XXX #617 MSVC bug does not handle partial specialization in modules.
2300hi_export template<>
2301struct std::formatter<hi::datum, char> : std::formatter<std::string, char> {
2302 auto format(hi::datum const& t, auto& fc) const
2303 {
2304 return std::formatter<std::string, char>{}.format(to_string(t), fc);
2305 }
2306};
2307
2308hi_warning_pop();
@ create
Create file if it does not exist, or fail.
@ other
The gui_event does not have associated data.
STL namespace.
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
The HikoGUI namespace.
Definition recursive_iterator.hpp:15
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:378
constexpr matrix2 operator*(matrix2 const &lhs, matrix2 const &rhs) noexcept
Matrix/Matrix multiplication.
Definition transform.hpp:69
Promotion result.
Definition datum.hpp:43
Definition datum.hpp:183
A dynamic data type.
Definition datum.hpp:210
vector_type keys() const
Get the sorted list of keys of a map.
Definition datum.hpp:824
constexpr bool is_break() const noexcept
Check if the result of a expression was a break flow control statement.
Definition datum.hpp:645
friend constexpr T & get(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1708
friend constexpr bool promotable_to(datum const &rhs) noexcept
Check if the type held by the datum can be promoted.
Definition datum.hpp:1654
constexpr bool is_continue() const noexcept
Check if the result of a expression was a continue flow control statement.
Definition datum.hpp:653
bool remove(jsonpath const &path) noexcept
Remove the object by path.
Definition datum.hpp:946
friend constexpr auto promote_if(datum const &lhs, datum const &rhs) noexcept
Promote two datum-arguments to a common type.
Definition datum.hpp:224
friend std::string to_string(datum const &rhs) noexcept
Get the string representation of the value.
Definition datum.hpp:1601
friend constexpr T const * get_if(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1759
friend constexpr bool holds_alternative(datum const &rhs) noexcept
Check if the stored value is of a specific type.
Definition datum.hpp:1613
constexpr bool is_undefined() const noexcept
Check if the datum has an undefined value.
Definition datum.hpp:637
vector_type items() const
Get key value pairs of items of a map sorted by the key.
Definition datum.hpp:856
friend T * get_if(datum &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1778
datum const * find_one(jsonpath const &path) const noexcept
Find a object by path.
Definition datum.hpp:978
friend T const * get_if(datum const &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1801
datum * find_one_or_create(jsonpath const &path) noexcept
Find a object by path potentially creating intermediate objects.
Definition datum.hpp:967
friend constexpr T const & get(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1675
datum * find_one(jsonpath const &path) noexcept
Find a object by path.
Definition datum.hpp:956
friend constexpr T * get_if(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1741
vector_type values() const
Get the list of values of a map.
Definition datum.hpp:840
Definition datum.hpp:214
Definition datum.hpp:215
Definition jsonpath.hpp:22
T back_inserter(T... args)
T copy(T... args)
T move(T... args)
T operator()(T... args)
T pow(T... args)
T reserve(T... args)
T round(T... args)
T swap(T... args)
T to_string(T... args)