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 {
36inline namespace v1 {
37namespace detail {
38
43template<typename To>
45public:
46 using value_type = To;
47 constexpr static bool data_is_pointer = sizeof(value_type) > sizeof(void*);
48 constexpr static bool data_is_scalar = not data_is_pointer;
49
50 constexpr void clear() noexcept requires(data_is_scalar) {}
51 constexpr void clear() noexcept requires(data_is_pointer)
52 {
53 if (_owns_lhs) {
54 delete _lhs;
55 }
56 if (_owns_rhs) {
57 delete _rhs;
58 }
59 }
60
61 constexpr ~datum_promotion_result()
62 {
63 clear();
64 }
65
66 constexpr datum_promotion_result() noexcept = default;
67
69 datum_promotion_result& operator=(datum_promotion_result const&) = delete;
70
72 _lhs(other._lhs),
73 _rhs(other._rhs),
74 _is_result(other._is_result),
75 _owns_lhs(std::exchange(other._owns_lhs, false)),
76 _owns_rhs(std::exchange(other._owns_rhs, false))
77 {
78 }
79
80 constexpr datum_promotion_result& operator=(datum_promotion_result&& other) noexcept
81 {
82 clear();
83 _lhs = other.lhs;
84 _rhs = other.rhs;
85 _is_result = other._is_result;
86 _owns_lhs = std::exchange(other._owns_lhs, false);
87 _owns_rhs = std::exchange(other._owns_rhs, false);
88 return *this;
89 }
90
91 constexpr explicit operator bool() const noexcept
92 {
93 return _is_result;
94 }
95
96 constexpr void set(value_type lhs, value_type rhs) noexcept requires(data_is_scalar)
97 {
98 _lhs = lhs;
99 _rhs = rhs;
100 _is_result = true;
101 }
102
103 constexpr void set(value_type const& lhs, value_type const& rhs) noexcept requires(data_is_pointer)
104 {
105 _lhs = &lhs;
106 _rhs = &rhs;
107 _is_result = true;
108 }
109
110 constexpr void set(value_type&& lhs, value_type const& rhs) noexcept requires(data_is_pointer)
111 {
112 _lhs = new value_type(std::move(lhs));
113 _rhs = &rhs;
114 _is_result = true;
115 _owns_lhs = true;
116 }
117
118 constexpr void set(value_type const& lhs, value_type&& rhs) noexcept requires(data_is_pointer)
119 {
120 _lhs = &lhs;
121 _rhs = new value_type(std::move(rhs));
122 _is_result = true;
123 _owns_rhs = true;
124 }
125
126 constexpr void set(value_type&& lhs, value_type&& rhs) noexcept requires(data_is_pointer)
127 {
128 _lhs = new value_type(std::move(lhs));
129 _rhs = new value_type(std::move(rhs));
130 _is_result = true;
131 _owns_lhs = true;
132 _owns_rhs = true;
133 }
134
135 [[nodiscard]] constexpr value_type const& lhs() const noexcept requires(data_is_pointer)
136 {
137 hi_axiom(_is_result);
138 return *_lhs;
139 }
140
141 [[nodiscard]] constexpr value_type const& rhs() const noexcept requires(data_is_pointer)
142 {
143 hi_axiom(_is_result);
144 return *_rhs;
145 }
146
147 [[nodiscard]] constexpr value_type lhs() const noexcept requires(data_is_scalar)
148 {
149 hi_axiom(_is_result);
150 return _lhs;
151 }
152
153 [[nodiscard]] constexpr value_type rhs() const noexcept requires(data_is_scalar)
154 {
155 hi_axiom(_is_result);
156 return _rhs;
157 }
158
159private:
160 using data_type = std::conditional_t<data_is_pointer, value_type const*, value_type>;
161 data_type _lhs = data_type{};
162 data_type _rhs = data_type{};
163 bool _is_result = false;
164 bool _owns_lhs = false;
165 bool _owns_rhs = false;
166};
167
168} // namespace detail
169
170hi_export template<typename T>
172
173hi_export template<>
174class is_datum_type<long long> : public std::true_type {};
175hi_export template<>
176class is_datum_type<double> : public std::true_type {};
177hi_export template<>
178class is_datum_type<bool> : public std::true_type {};
179hi_export template<>
180class is_datum_type<std::chrono::year_month_day> : public std::true_type {};
181hi_export template<>
182class is_datum_type<std::string> : public std::true_type {};
183hi_export template<>
184class is_datum_type<bstring> : public std::true_type {};
185
186hi_export template<typename T>
187constexpr bool is_datum_type_v = is_datum_type<T>::value;
188
198hi_export class datum {
199public:
200 using vector_type = std::vector<datum>;
201 using map_type = std::map<datum, datum>;
202 struct break_type {};
203 struct continue_type {};
204
211 template<typename To>
212 [[nodiscard]] friend constexpr auto promote_if(datum const& lhs, datum const& rhs) noexcept
213 {
216 r.set(get<To>(lhs), get<To>(rhs));
217
218 } else if (holds_alternative<To>(lhs) and promotable_to<To>(rhs)) {
219 r.set(get<To>(lhs), static_cast<To>(rhs));
220
221 } else if (promotable_to<To>(lhs) and holds_alternative<To>(rhs)) {
222 r.set(static_cast<To>(lhs), get<To>(rhs));
223 }
224
225 return r;
226 }
227
228 constexpr ~datum() noexcept
229 {
230 delete_pointer();
231 }
232
233 constexpr datum(datum const& other) noexcept : _tag(other._tag), _value(other._value)
234 {
235 if (other.is_pointer()) {
236 copy_pointer(other);
237 }
238 }
239
240 constexpr datum(datum&& other) noexcept : _tag(other._tag), _value(other._value)
241 {
242 other._tag = tag_type::monostate;
243 other._value._long_long = 0;
244 }
245
246 constexpr datum() noexcept : _tag(tag_type::monostate), _value(0) {}
247 constexpr explicit datum(std::monostate) noexcept : _tag(tag_type::monostate), _value(0) {}
248 constexpr explicit datum(nullptr_t) noexcept : _tag(tag_type::null), _value(0) {}
249 constexpr explicit datum(continue_type) noexcept : _tag(tag_type::flow_continue), _value(0) {}
250 constexpr explicit datum(break_type) noexcept : _tag(tag_type::flow_break), _value(0) {}
251 constexpr explicit datum(bool value) noexcept : _tag(tag_type::boolean), _value(value) {}
252 constexpr explicit datum(std::floating_point auto value) noexcept :
253 _tag(tag_type::floating_point), _value(narrow_cast<double>(value))
254 {
255 }
256
257 constexpr explicit datum(numeric_integral auto value) noexcept :
258 _tag(tag_type::integral), _value(narrow_cast<long long>(value))
259 {
260 }
261
262 constexpr explicit datum(std::chrono::year_month_day value) noexcept : _tag(tag_type::year_month_day), _value(value) {}
263 explicit datum(std::string value) noexcept : _tag(tag_type::string), _value(new std::string{std::move(value)}) {}
264 explicit datum(std::string_view value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
265 explicit datum(char const* value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
266 explicit datum(vector_type value) noexcept : _tag(tag_type::vector), _value(new vector_type{std::move(value)}) {}
267 explicit datum(map_type value) noexcept : _tag(tag_type::map), _value(new map_type{std::move(value)}) {}
268 explicit datum(bstring value) noexcept : _tag(tag_type::bstring), _value(new bstring{std::move(value)}) {}
269
270 template<typename... Args>
271 [[nodiscard]] static datum make_vector(Args const&... args) noexcept
272 {
273 return datum{vector_type{datum{args}...}};
274 }
275
276 template<typename Key, typename Value, typename... Args>
277 static void populate_map(map_type& r, Key const& key, Value const& value, Args const&... args) noexcept
278 {
279 r.insert(std::pair<datum, datum>{datum{key}, datum{value}});
280 if constexpr (sizeof...(Args) > 0) {
281 populate_map(r, args...);
282 }
283 }
284
285 template<typename... Args>
286 [[nodiscard]] static datum make_map(Args const&... args) noexcept
287 {
288 static_assert(sizeof...(Args) % 2 == 0, "Expect key value pairs for the arguments of make_map()");
289
290 auto r = map_type{};
291 if constexpr (sizeof...(Args) > 0) {
292 populate_map(r, args...);
293 }
294 return datum{std::move(r)};
295 }
296
297 [[nodiscard]] static datum make_break() noexcept
298 {
299 return datum{break_type{}};
300 }
301
302 [[nodiscard]] static datum make_continue() noexcept
303 {
304 return datum{continue_type{}};
305 }
306
307 constexpr datum& operator=(datum const& other) noexcept
308 {
309 hi_return_on_self_assignment(other);
310
311 delete_pointer();
312 _tag = other._tag;
313 _value = other._value;
314 if (other.is_pointer()) {
315 copy_pointer(other);
316 }
317 return *this;
318 }
319
320 constexpr datum& operator=(datum&& other) noexcept
321 {
322 std::swap(_tag, other._tag);
323 std::swap(_value, other._value);
324 return *this;
325 }
326
327 constexpr datum& operator=(std::floating_point auto value) noexcept(sizeof(value) <= 4)
328 {
329 delete_pointer();
330 _tag = tag_type::floating_point;
331 _value = static_cast<double>(value);
332 return *this;
333 }
334
335 constexpr datum& operator=(numeric_integral auto value) noexcept(sizeof(value) <= 4)
336 {
337 delete_pointer();
338 _tag = tag_type::integral;
339 _value = static_cast<long long>(value);
340 return *this;
341 }
342
343 constexpr datum& operator=(bool value) noexcept
344 {
345 delete_pointer();
346 _tag = tag_type::boolean;
347 _value = value;
348 return *this;
349 }
350
351 constexpr datum& operator=(std::chrono::year_month_day value) noexcept
352 {
353 delete_pointer();
354 _tag = tag_type::year_month_day;
355 _value = value;
356 return *this;
357 }
358
359 constexpr datum& operator=(std::monostate) noexcept
360 {
361 delete_pointer();
362 _tag = tag_type::monostate;
363 _value = 0;
364 return *this;
365 }
366
367 constexpr datum& operator=(nullptr_t) noexcept
368 {
369 delete_pointer();
370 _tag = tag_type::null;
371 _value = 0;
372 return *this;
373 }
374
375 datum& operator=(std::string value) noexcept
376 {
377 delete_pointer();
378 _tag = tag_type::string;
379 _value = new std::string{std::move(value)};
380 return *this;
381 }
382
383 datum& operator=(char const* value) noexcept
384 {
385 delete_pointer();
386 _tag = tag_type::string;
387 _value = new std::string{value};
388 return *this;
389 }
390
391 datum& operator=(std::string_view value) noexcept
392 {
393 delete_pointer();
394 _tag = tag_type::string;
395 _value = new std::string{value};
396 return *this;
397 }
398
399 datum& operator=(vector_type value) noexcept
400 {
401 delete_pointer();
402 _tag = tag_type::vector;
403 _value = new vector_type{std::move(value)};
404 return *this;
405 }
406
407 datum& operator=(map_type value) noexcept
408 {
409 delete_pointer();
410 _tag = tag_type::map;
411 _value = new map_type{std::move(value)};
412 return *this;
413 }
414
415 datum& operator=(bstring value) noexcept
416 {
417 delete_pointer();
418 _tag = tag_type::bstring;
419 _value = new bstring{std::move(value)};
420 return *this;
421 }
422
423 constexpr explicit operator bool() const noexcept
424 {
425 switch (_tag) {
426 case tag_type::floating_point:
427 return to_bool(get<double>(*this));
428 case tag_type::boolean:
429 return get<bool>(*this);
430 case tag_type::integral:
431 return to_bool(get<long long>(*this));
432 case tag_type::year_month_day:
433 return true;
434 case tag_type::string:
435 return not get<std::string>(*this).empty();
436 case tag_type::vector:
437 return not get<vector_type>(*this).empty();
438 case tag_type::map:
439 return not get<map_type>(*this).empty();
440 case tag_type::bstring:
441 return not get<bstring>(*this).empty();
442 default:
443 return false;
444 }
445 }
446
447 [[nodiscard]] constexpr bool empty() const
448 {
449 switch (_tag) {
450 case tag_type::string:
451 return get<std::string>(*this).empty();
452 case tag_type::vector:
453 return get<vector_type>(*this).empty();
454 case tag_type::map:
455 return get<map_type>(*this).empty();
456 case tag_type::bstring:
457 return get<bstring>(*this).empty();
458 default:
459 throw std::domain_error(std::format("Type {} can not be checked for empty", repr(*this)));
460 }
461 }
462
463 template<std::floating_point T>
464 constexpr explicit operator T() const
465 {
466 switch (_tag) {
467 case tag_type::floating_point:
468 return static_cast<T>(get<double>(*this));
469 case tag_type::integral:
470 return static_cast<T>(get<long long>(*this));
471 case tag_type::boolean:
472 return static_cast<T>(get<bool>(*this));
473 default:
474 throw std::domain_error(std::format("Can't convert {} to floating point", repr(*this)));
475 }
476 }
477
478 template<numeric_integral T>
479 constexpr explicit operator T() const
480 {
481 if (auto f = get_if<double>(*this)) {
482 errno = 0;
483 auto const r = std::round(*f);
486 throw std::overflow_error("double to integral");
487 }
488 return round_cast<T>(r);
489
490 } else if (auto i = get_if<long long>(*this)) {
492 throw std::overflow_error("long long to integral");
493 }
494 return narrow_cast<T>(*i);
495
496 } else if (auto b = get_if<bool>(*this)) {
497 return narrow_cast<T>(*b);
498
499 } else {
500 throw std::domain_error(std::format("Can't convert {} to an integral", repr(*this)));
501 }
502 }
503
504 constexpr explicit operator std::chrono::year_month_day() const
505 {
506 if (auto ymd = get_if<std::chrono::year_month_day>(*this)) {
507 return *ymd;
508 } else {
509 throw std::domain_error(std::format("Can't convert {} to an std::chrono::year_month_day", repr(*this)));
510 }
511 }
512
513 explicit operator std::string() const noexcept
514 {
515 switch (_tag) {
516 case tag_type::monostate:
517 return "undefined";
518 case tag_type::floating_point:
519 return hi::to_string(_value._double);
520 case tag_type::integral:
521 return to_string(_value._long_long);
522 case tag_type::boolean:
523 return _value._bool ? "true" : "false";
524 case tag_type::year_month_day:
525 return std::format("{:%Y-%m-%d}", _value._year_month_day);
526 case tag_type::null:
527 return "null";
528 case tag_type::flow_break:
529 return "break";
530 case tag_type::flow_continue:
531 return "continue";
532 case tag_type::string:
533 return *_value._string;
534 case tag_type::vector:
535 {
536 auto r = std::string{"["};
537 for (auto const& item : *_value._vector) {
538 r += repr(item);
539 r += ',';
540 }
541 r += ']';
542 return r;
543 };
544 case tag_type::map:
545 {
546 auto r = std::string{"{"};
547 for (auto const& item : *_value._map) {
548 r += repr(item.first);
549 r += ':';
550 r += repr(item.second);
551 r += ',';
552 }
553 r += '}';
554 return r;
555 };
556 case tag_type::bstring:
557 return base64::encode(*_value._bstring);
558 default:
559 hi_no_default();
560 }
561 }
562
563 explicit operator std::string_view() const
564 {
565 if (auto s = get_if<std::string>(*this)) {
566 return std::string_view{*s};
567 } else {
568 throw std::domain_error(std::format("Can't convert {} to an std::string_view", repr(*this)));
569 }
570 }
571
572 explicit operator vector_type() const
573 {
574 if (auto v = get_if<vector_type>(*this)) {
575 return *v;
576 } else {
577 throw std::domain_error(std::format("Can't convert {} to an vector", repr(*this)));
578 }
579 }
580
581 explicit operator map_type() const
582 {
583 if (auto m = get_if<map_type>(*this)) {
584 return *m;
585 } else {
586 throw std::domain_error(std::format("Can't convert {} to an map", repr(*this)));
587 }
588 }
589
590 explicit operator bstring() const
591 {
592 // XXX should be able to base-64 decode a std::string.
593 if (_tag != tag_type::bstring) {
594 throw std::domain_error(std::format("Can't convert {} to an bstring", repr(*this)));
595 }
596 return get<bstring>(*this);
597 }
598
599 [[nodiscard]] constexpr char const* type_name() const noexcept
600 {
601 switch (_tag) {
602 case tag_type::floating_point:
603 return "float";
604 case tag_type::integral:
605 return "int";
606 case tag_type::boolean:
607 return "bool";
608 case tag_type::year_month_day:
609 return "date";
610 case tag_type::string:
611 return "string";
612 case tag_type::vector:
613 return "vector";
614 case tag_type::map:
615 return "map";
616 case tag_type::bstring:
617 return "bytes";
618 default:
619 hi_no_default();
620 }
621 }
622
626 {
627 return _tag == tag_type::monostate;
628 }
629
633 [[nodiscard]] constexpr bool is_break() const noexcept
634 {
635 return _tag == tag_type::flow_break;
636 }
637
641 [[nodiscard]] constexpr bool is_continue() const noexcept
642 {
643 return _tag == tag_type::flow_continue;
644 }
645
647 {
648 switch (_tag) {
649 case tag_type::floating_point:
650 return std::hash<double>{}(_value._double);
651 case tag_type::integral:
652 return std::hash<long long>{}(_value._long_long);
653 case tag_type::boolean:
654 return std::hash<bool>{}(_value._bool);
655 case tag_type::year_month_day:
656 {
657 uint32_t r = 0;
658 r |= narrow_cast<uint32_t>(static_cast<int>(_value._year_month_day.year())) << 16;
659 r |= narrow_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.month())) << 8;
660 r |= narrow_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.day()));
661 return std::hash<uint32_t>{}(r);
662 }
663 case tag_type::string:
664 return std::hash<std::string>{}(*_value._string);
665 case tag_type::vector:
666 {
667 std::size_t r = 0;
668 for (auto const& v : *_value._vector) {
669 r = hash_mix(r, v.hash());
670 }
671 return r;
672 }
673 case tag_type::map:
674 {
675 std::size_t r = 0;
676 for (auto const& kv : *_value._map) {
677 r = hash_mix(r, kv.first.hash(), kv.second.hash());
678 }
679 return r;
680 }
681 case tag_type::bstring:
682 return std::hash<bstring>{}(*_value._bstring);
683 default:
684 hi_no_default();
685 }
686 }
687
688 [[nodiscard]] constexpr std::size_t size() const
689 {
690 if (auto const* s = get_if<std::string>(*this)) {
691 return s->size();
692 } else if (auto const* v = get_if<vector_type>(*this)) {
693 return v->size();
694 } else if (auto const* m = get_if<map_type>(*this)) {
695 return m->size();
696 } else if (auto const* b = get_if<bstring>(*this)) {
697 return b->size();
698 } else {
699 throw std::domain_error(std::format("Can not evaluate {}.size()", repr(*this)));
700 }
701 }
702
703 [[nodiscard]] constexpr friend std::size_t size(datum const& rhs)
704 {
705 return rhs.size();
706 }
707
708 [[nodiscard]] constexpr datum const& back() const
709 {
710 if (auto const* v = get_if<vector_type>(*this)) {
711 if (v->empty()) {
712 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
713 }
714 return v->back();
715 } else {
716 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
717 }
718 }
719
720 [[nodiscard]] constexpr datum& back()
721 {
722 if (auto* 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 const& front() const
733 {
734 if (auto const* v = get_if<vector_type>(*this)) {
735 if (v->empty()) {
736 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
737 }
738 return v->front();
739 } else {
740 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
741 }
742 }
743
744 [[nodiscard]] constexpr datum& front()
745 {
746 if (auto* 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 auto cbegin() const
757 {
758 if (auto const* v = get_if<vector_type>(*this)) {
759 return v->cbegin();
760 } else {
761 throw std::domain_error(std::format("Can not evaluate {}.cbegin()", repr(*this)));
762 }
763 }
764
765 [[nodiscard]] constexpr auto begin() const
766 {
767 if (auto const* v = get_if<vector_type>(*this)) {
768 return v->begin();
769 } else {
770 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
771 }
772 }
773
774 [[nodiscard]] constexpr auto begin()
775 {
776 if (auto const* v = get_if<vector_type>(*this)) {
777 return v->begin();
778 } else {
779 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
780 }
781 }
782
783 [[nodiscard]] constexpr auto cend() const
784 {
785 if (auto const* v = get_if<vector_type>(*this)) {
786 return v->cend();
787 } else {
788 throw std::domain_error(std::format("Can not evaluate {}.cend()", repr(*this)));
789 }
790 }
791
792 [[nodiscard]] constexpr auto end() const
793 {
794 if (auto const* v = get_if<vector_type>(*this)) {
795 return v->end();
796 } else {
797 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
798 }
799 }
800
801 [[nodiscard]] constexpr auto end()
802 {
803 if (auto const* v = get_if<vector_type>(*this)) {
804 return v->end();
805 } else {
806 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
807 }
808 }
809
813 {
814 if (auto const* m = get_if<map_type>(*this)) {
815 auto r = vector_type{};
816 r.reserve(m->size());
817 for (auto const& kv : *m) {
818 r.push_back(kv.first);
819 }
820 return r;
821 } else {
822 throw std::domain_error(std::format("Can not evaluate {}.keys()", repr(*this)));
823 }
824 }
825
829 {
830 if (auto const* m = get_if<map_type>(*this)) {
831 auto r = vector_type{};
832 r.reserve(m->size());
833 for (auto const& kv : *m) {
834 r.push_back(kv.second);
835 }
836 return r;
837 } else {
838 throw std::domain_error(std::format("Can not evaluate {}.values()", repr(*this)));
839 }
840 }
841
845 {
846 if (auto const* m = get_if<map_type>(*this)) {
847 auto r = vector_type{};
848 r.reserve(m->size());
849
850 for (auto const& item : *m) {
851 r.push_back(make_vector(item.first, item.second));
852 }
853 return r;
854 } else {
855 throw std::domain_error(std::format("Can not evaluate {}.items()", repr(*this)));
856 }
857 }
858
859 constexpr void push_back(datum const& rhs)
860 {
861 if (auto* v = get_if<vector_type>(*this)) {
862 return v->push_back(rhs);
863 } else {
864 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
865 }
866 }
867
868 constexpr void push_back(datum&& rhs)
869 {
870 if (auto* v = get_if<vector_type>(*this)) {
871 return v->push_back(std::move(rhs));
872 } else {
873 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
874 }
875 }
876
877 template<typename Arg>
878 constexpr void push_back(Arg&& arg)
879 {
880 push_back(datum{std::forward<Arg>(arg)});
881 }
882
883 constexpr void pop_back()
884 {
885 if (auto* v = get_if<vector_type>(*this)) {
886 if (v->empty()) {
887 throw std::domain_error(std::format("Empty vector {}.pop_back()", repr(*this)));
888 }
889 return v->pop_back();
890 } else {
891 throw std::domain_error(std::format("Can not evaluate {}.pop_back()", repr(*this)));
892 }
893 }
894
895 [[nodiscard]] constexpr bool contains(datum const& rhs) const
896 {
897 if (auto* m = get_if<map_type>(*this)) {
898 return m->contains(rhs);
899 } else {
900 throw std::domain_error(std::format("Can not evaluate {}.contains({})", repr(*this), repr(rhs)));
901 }
902 }
903
904 template<typename Arg>
905 [[nodiscard]] constexpr bool contains(Arg const& arg) const
906 {
907 return contains(datum{arg});
908 }
909
910 [[nodiscard]] std::vector<datum*> find(jsonpath const& path) noexcept
911 {
912 auto r = std::vector<datum*>{};
913 find(path.cbegin(), path.cend(), r);
914 return r;
915 }
916
917 [[nodiscard]] std::vector<datum const*> find(jsonpath const& path) const noexcept
918 {
919 auto tmp = std::vector<datum*>{};
920 const_cast<datum*>(this)->find(path.cbegin(), path.cend(), tmp);
921 auto r = std::vector<datum const*>{};
922 std::copy(tmp.begin(), tmp.end(), std::back_inserter(r));
923 return r;
924 }
925
934 [[nodiscard]] bool remove(jsonpath const& path) noexcept
935 {
936 return to_bool(remove(path.cbegin(), path.cend()));
937 }
938
944 [[nodiscard]] datum* find_one(jsonpath const& path) noexcept
945 {
946 hi_axiom(path.is_singular());
947 return find_one(path.cbegin(), path.cend(), false);
948 }
949
955 [[nodiscard]] datum* find_one_or_create(jsonpath const& path) noexcept
956 {
957 hi_axiom(path.is_singular());
958 return find_one(path.cbegin(), path.cend(), true);
959 }
960
966 [[nodiscard]] datum const* find_one(jsonpath const& path) const noexcept
967 {
968 hi_axiom(path.is_singular());
969 return const_cast<datum*>(this)->find_one(path.cbegin(), path.cend(), false);
970 }
971
972 [[nodiscard]] datum const& operator[](datum const& rhs) const
973 {
975 auto const& v = get<vector_type>(*this);
976
977 auto index = get<long long>(rhs);
978 if (index < 0) {
979 index = ssize(v) + index;
980 }
981 if (index < 0 or index >= ssize(v)) {
982 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
983 }
984
985 return v[index];
986
987 } else if (holds_alternative<map_type>(*this)) {
988 auto const& m = get<map_type>(*this);
989 auto const it = m.find(rhs);
990 if (it == m.end()) {
991 throw std::overflow_error(std::format("Key {} not found in map", repr(rhs)));
992 }
993
994 return it->second;
995
996 } else {
997 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
998 }
999 }
1000
1001 [[nodiscard]] constexpr datum& operator[](datum const& rhs)
1002 {
1004 auto& v = get<vector_type>(*this);
1005
1006 auto index = get<long long>(rhs);
1007 if (index < 0) {
1008 index = ssize(v) + index;
1009 }
1010 if (index < 0 or index >= ssize(v)) {
1011 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
1012 }
1013
1014 return v[index];
1015
1016 } else if (holds_alternative<map_type>(*this)) {
1017 auto& m = get<map_type>(*this);
1018 return m[rhs];
1019
1020 } else {
1021 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
1022 }
1023 }
1024
1025 [[nodiscard]] constexpr datum const& operator[](auto const& rhs) const
1026 {
1027 return (*this)[datum{rhs}];
1028 }
1029
1030 [[nodiscard]] constexpr datum& operator[](auto const& rhs)
1031 {
1032 return (*this)[datum{rhs}];
1033 }
1034
1035 [[nodiscard]] constexpr datum& operator++()
1036 {
1037 if (holds_alternative<long long>(*this)) {
1038 ++_value._long_long;
1039 return *this;
1040 } else {
1041 throw std::domain_error(std::format("Can not evaluate ++{}", repr(*this)));
1042 }
1043 }
1044
1045 [[nodiscard]] constexpr datum& operator--()
1046 {
1047 if (holds_alternative<long long>(*this)) {
1048 --_value._long_long;
1049 return *this;
1050 } else {
1051 throw std::domain_error(std::format("Can not evaluate --{}", repr(*this)));
1052 }
1053 }
1054
1055 [[nodiscard]] constexpr datum operator++(int)
1056 {
1057 if (holds_alternative<long long>(*this)) {
1058 auto tmp = *this;
1059 _value._long_long++;
1060 return tmp;
1061 } else {
1062 throw std::domain_error(std::format("Can not evaluate {}++", repr(*this)));
1063 }
1064 }
1065 [[nodiscard]] constexpr datum operator--(int)
1066 {
1067 if (holds_alternative<long long>(*this)) {
1068 auto tmp = *this;
1069 _value._long_long--;
1070 return tmp;
1071 } else {
1072 throw std::domain_error(std::format("Can not evaluate {}--", repr(*this)));
1073 }
1074 }
1075
1076 constexpr datum& operator+=(auto const& rhs)
1077 {
1078 if (holds_alternative<vector_type>(*this)) {
1079 push_back(rhs);
1080 return *this;
1081 } else {
1082 return (*this) = (*this) + rhs;
1083 }
1084 }
1085
1086#define X(op, inner_op) \
1087 constexpr datum& operator op(auto const& rhs) \
1088 { \
1089 return (*this) = (*this)inner_op rhs; \
1090 }
1091
1092 X(-=, -)
1093 X(*=, *)
1094 X(/=, /)
1095 X(%=, %)
1096 X(&=, &)
1097 X(|=, |)
1098 X(^=, ^)
1099 X(<<=, <<)
1100 X(>>=, >>)
1101#undef X
1102
1103 [[nodiscard]] friend constexpr bool operator==(datum const& lhs, datum const& rhs) noexcept
1104 {
1105 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1106 return doubles.lhs() == doubles.rhs();
1107
1108 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1109 return long_longs.lhs() == long_longs.rhs();
1110
1111 } else if (auto const bools = promote_if<bool>(lhs, rhs)) {
1112 return bools.lhs() == bools.rhs();
1113
1114 } else if (auto const ymds = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1115 return ymds.lhs() == ymds.rhs();
1116
1117 } else if (auto const strings = promote_if<std::string>(lhs, rhs)) {
1118 return strings.lhs() == strings.rhs();
1119
1120 } else if (auto const vectors = promote_if<vector_type>(lhs, rhs)) {
1121 return vectors.lhs() == vectors.rhs();
1122
1123 } else if (auto const maps = promote_if<map_type>(lhs, rhs)) {
1124 return maps.lhs() == maps.rhs();
1125
1126 } else {
1127 return lhs._tag == rhs._tag;
1128 }
1129 }
1130
1157 [[nodiscard]] friend constexpr std::partial_ordering operator<=>(datum const& lhs, datum const& rhs) noexcept
1158 {
1159 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1160 return doubles.lhs() <=> doubles.rhs();
1161
1162 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1163 return long_longs.lhs() <=> long_longs.rhs();
1164
1165 } else if (auto const bools = promote_if<bool>(lhs, rhs)) {
1166 return bools.lhs() <=> bools.rhs();
1167
1168 } else if (auto const year_month_days = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1169 return year_month_days.lhs() <=> year_month_days.rhs();
1170
1171 } else if (auto const strings = promote_if<std::string>(lhs, rhs)) {
1172 return strings.lhs() <=> strings.rhs();
1173
1174 } else if (auto const vectors = promote_if<vector_type>(lhs, rhs)) {
1175 return vectors.lhs() <=> vectors.rhs();
1176
1177 } else if (auto const maps = promote_if<map_type>(lhs, rhs)) {
1178 return maps.lhs() <=> maps.rhs();
1179
1180 } else if (auto const bstrings = promote_if<bstring>(lhs, rhs)) {
1181 return bstrings.lhs() <=> bstrings.rhs();
1182
1183 } else {
1184 return lhs._tag <=> rhs._tag;
1185 }
1186 }
1187
1198 [[nodiscard]] friend constexpr datum operator-(datum const& rhs)
1199 {
1200 if (auto const rhs_double = get_if<double>(rhs)) {
1201 return datum{-*rhs_double};
1202
1203 } else if (auto const rhs_long_long = get_if<long long>(rhs)) {
1204 return datum{-*rhs_long_long};
1205
1206 } else {
1207 throw std::domain_error(std::format("Can not evaluate -{}", repr(rhs)));
1208 }
1209 }
1210
1220 [[nodiscard]] friend constexpr datum operator~(datum const& rhs)
1221 {
1222 if (auto const rhs_long_long = get_if<long long>(rhs)) {
1223 return datum{~*rhs_long_long};
1224
1225 } else {
1226 throw std::domain_error(std::format("Can not evaluate ~{}", repr(rhs)));
1227 }
1228 }
1229
1244 [[nodiscard]] friend constexpr datum operator+(datum const& lhs, datum const& rhs)
1245 {
1246 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1247 return datum{doubles.lhs() + doubles.rhs()};
1248
1249 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1250 return datum{long_longs.lhs() + long_longs.rhs()};
1251
1252 } else if (auto const strings = promote_if<std::string>(lhs, rhs)) {
1253 return datum{strings.lhs() + strings.rhs()};
1254
1255 } else if (auto const vectors = promote_if<vector_type>(lhs, rhs)) {
1256 auto r = vectors.lhs();
1257 r.insert(r.end(), vectors.rhs().begin(), vectors.rhs().end());
1258 return datum{std::move(r)};
1259
1260 } else {
1261 throw std::domain_error(std::format("Can not evaluate {} '+' {}", repr(lhs), repr(rhs)));
1262 }
1263 }
1264
1276 [[nodiscard]] friend constexpr datum operator-(datum const& lhs, datum const& rhs)
1277 {
1278 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1279 return datum{doubles.lhs() - doubles.rhs()};
1280
1281 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1282 return datum{long_longs.lhs() - long_longs.rhs()};
1283
1284 } else {
1285 throw std::domain_error(std::format("Can not evaluate {} '-' {}", repr(lhs), repr(rhs)));
1286 }
1287 }
1288
1300 [[nodiscard]] friend constexpr datum operator*(datum const& lhs, datum const& rhs)
1301 {
1302 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1303 return datum{doubles.lhs() * doubles.rhs()};
1304
1305 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1306 return datum{long_longs.lhs() * long_longs.rhs()};
1307
1308 } else {
1309 throw std::domain_error(std::format("Can not evaluate {} '*' {}", repr(lhs), repr(rhs)));
1310 }
1311 }
1312
1324 [[nodiscard]] friend constexpr datum operator/(datum const& lhs, datum const& rhs)
1325 {
1326 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1327 if (doubles.rhs() == 0) {
1328 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1329 }
1330 return datum{doubles.lhs() / doubles.rhs()};
1331
1332 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1333 if (long_longs.rhs() == 0) {
1334 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1335 }
1336 return datum{long_longs.lhs() / long_longs.rhs()};
1337
1338 } else {
1339 throw std::domain_error(std::format("Can not evaluate {} '/' {}", repr(lhs), repr(rhs)));
1340 }
1341 }
1342
1354 [[nodiscard]] friend constexpr datum operator%(datum const& lhs, datum const& rhs)
1355 {
1356 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1357 if (long_longs.rhs() == 0) {
1358 throw std::domain_error(std::format("Divide by zero {} '%' {}", repr(lhs), repr(rhs)));
1359 }
1360 return datum{long_longs.lhs() % long_longs.rhs()};
1361
1362 } else {
1363 throw std::domain_error(std::format("Can not evaluate {} '%' {}", repr(lhs), repr(rhs)));
1364 }
1365 }
1366
1377 [[nodiscard]] friend constexpr datum pow(datum const& lhs, datum const& rhs)
1378 {
1379 if (auto const doubles = promote_if<double>(lhs, rhs)) {
1380 return datum{pow(doubles.lhs(), doubles.rhs())};
1381
1382 } else if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1383 return datum{pow(long_longs.lhs(), long_longs.rhs())};
1384
1385 } else {
1386 throw std::domain_error(std::format("Can not evaluate pow({}, {})", repr(lhs), repr(rhs)));
1387 }
1388 }
1389
1400 [[nodiscard]] friend constexpr datum operator&(datum const& lhs, datum const& rhs)
1401 {
1402 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1403 return datum{long_longs.lhs() & long_longs.rhs()};
1404
1405 } else if (auto const bools = promote_if<bool>(lhs, rhs)) {
1406 return datum{bools.lhs() and bools.rhs()};
1407
1408 } else {
1409 throw std::domain_error(std::format("Can not evaluate {} '&' {}", repr(lhs), repr(rhs)));
1410 }
1411 }
1412
1423 [[nodiscard]] friend constexpr datum operator|(datum const& lhs, datum const& rhs)
1424 {
1425 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1426 return datum{long_longs.lhs() | long_longs.rhs()};
1427
1428 } else if (auto const bools = promote_if<bool>(lhs, rhs)) {
1429 return datum{bools.lhs() or bools.rhs()};
1430
1431 } else {
1432 throw std::domain_error(std::format("Can not evaluate {} '|' {}", repr(lhs), repr(rhs)));
1433 }
1434 }
1435
1446 [[nodiscard]] friend constexpr datum operator^(datum const& lhs, datum const& rhs)
1447 {
1448 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1449 return datum{long_longs.lhs() ^ long_longs.rhs()};
1450
1451 } else if (auto const bools = promote_if<bool>(lhs, rhs)) {
1452 return datum{bools.lhs() != bools.rhs()};
1453
1454 } else {
1455 throw std::domain_error(std::format("Can not evaluate {} '^' {}", repr(lhs), repr(rhs)));
1456 }
1457 }
1458
1471 [[nodiscard]] friend constexpr datum operator<<(datum const& lhs, datum const& rhs)
1472 {
1473 if (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1474 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1475 throw std::domain_error(std::format("Invalid shift count {} '<<' {}", repr(lhs), repr(rhs)));
1476 }
1477 return datum{long_longs.lhs() << long_longs.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 (auto const long_longs = promote_if<long long>(lhs, rhs)) {
1498 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1499 throw std::domain_error(std::format("Invalid shift count {} '>>' {}", 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
1508 friend std::ostream& operator<<(std::ostream& lhs, datum const& rhs)
1509 {
1510 return lhs << to_string(rhs);
1511 }
1512
1513#define X(op) \
1514 template<typename RHS> \
1515 [[nodiscard]] friend constexpr auto operator op(datum const& lhs, RHS&& rhs) \
1516 requires( requires { datum{std::forward<RHS>(rhs)}; } and not std::same_as<std::remove_cvref_t<RHS>, datum>) \
1517 { \
1518 return lhs op datum{std::forward<RHS>(rhs)}; \
1519 } \
1520 template<typename LHS> \
1521 [[nodiscard]] friend constexpr auto operator op(LHS&& lhs, datum const& rhs) \
1522 requires( requires { datum{std::forward<LHS>(lhs)}; } and not std::same_as<std::remove_cvref_t<LHS>, datum>) \
1523 { \
1524 return datum{std::forward<LHS>(lhs)} op rhs; \
1525 }
1526
1527 X(==)
1528 X(<=>)
1529 X(+)
1530 X(-)
1531 X(*)
1532 X(/)
1533 X(%)
1534 X(&)
1535 X(|)
1536 X(^)
1537 X(<<)
1538 X(>>)
1539#undef X
1540
1543 [[nodiscard]] friend std::string repr(datum const& rhs) noexcept
1544 {
1545 switch (rhs._tag) {
1546 case tag_type::monostate:
1547 return "undefined";
1548 case tag_type::floating_point:
1549 return std::format("{:.1f}", rhs._value._double);
1550 case tag_type::integral:
1551 return std::format("{}", rhs._value._long_long);
1552 case tag_type::boolean:
1553 return rhs._value._bool ? "true" : "false";
1554 case tag_type::year_month_day:
1555 return std::format("{:%Y-%m-%d}", rhs._value._year_month_day);
1556 case tag_type::null:
1557 return "null";
1558 case tag_type::flow_break:
1559 return "break";
1560 case tag_type::flow_continue:
1561 return "continue";
1562 case tag_type::string:
1563 return std::format("\"{}\"", *rhs._value._string);
1564 case tag_type::vector:
1565 {
1566 auto r = std::string{"["};
1567 for (auto const& item : *rhs._value._vector) {
1568 r += repr(item);
1569 r += ',';
1570 }
1571 r += ']';
1572 return r;
1573 };
1574 case tag_type::map:
1575 {
1576 auto r = std::string{"{"};
1577 for (auto const& item : *rhs._value._map) {
1578 r += repr(item.first);
1579 r += ':';
1580 r += repr(item.second);
1581 r += ',';
1582 }
1583 r += '}';
1584 return r;
1585 };
1586 case tag_type::bstring:
1587 return base64::encode(*rhs._value._bstring);
1588 default:
1589 hi_no_default();
1590 }
1591 }
1592
1595 [[nodiscard]] friend std::string to_string(datum const& rhs) noexcept
1596 {
1597 return static_cast<std::string>(rhs);
1598 }
1599
1606 template<typename T>
1607 [[nodiscard]] friend constexpr bool holds_alternative(datum const& rhs) noexcept
1608 {
1609 if constexpr (std::is_same_v<T, double>) {
1610 return rhs._tag == tag_type::floating_point;
1611 } else if constexpr (std::is_same_v<T, long long>) {
1612 return rhs._tag == tag_type::integral;
1613 } else if constexpr (std::is_same_v<T, bool>) {
1614 return rhs._tag == tag_type::boolean;
1615 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1616 return rhs._tag == tag_type::year_month_day;
1617 } else if constexpr (std::is_same_v<T, nullptr_t>) {
1618 return rhs._tag == tag_type::null;
1619 } else if constexpr (std::is_same_v<T, std::monostate>) {
1620 return rhs._tag == tag_type::monostate;
1621 } else if constexpr (std::is_same_v<T, break_type>) {
1622 return rhs._tag == tag_type::flow_break;
1623 } else if constexpr (std::is_same_v<T, continue_type>) {
1624 return rhs._tag == tag_type::flow_continue;
1625 } else if constexpr (std::is_same_v<T, std::string>) {
1626 return rhs._tag == tag_type::string;
1627 } else if constexpr (std::is_same_v<T, vector_type>) {
1628 return rhs._tag == tag_type::vector;
1629 } else if constexpr (std::is_same_v<T, map_type>) {
1630 return rhs._tag == tag_type::map;
1631 } else if constexpr (std::is_same_v<T, bstring>) {
1632 return rhs._tag == tag_type::bstring;
1633 } else {
1634 hi_static_no_default();
1635 }
1636 }
1637
1647 template<typename To>
1648 [[nodiscard]] friend constexpr bool promotable_to(datum const& rhs) noexcept
1649 {
1650 if constexpr (std::is_same_v<To, double>) {
1652 } else if constexpr (std::is_same_v<To, long long>) {
1654 } else {
1655 return holds_alternative<To>(rhs);
1656 }
1657 }
1658
1667 template<typename T>
1668 [[nodiscard]] friend constexpr T const& get(datum const& rhs) noexcept
1669 {
1670 hi_axiom(holds_alternative<T>(rhs));
1671 if constexpr (std::is_same_v<T, double>) {
1672 return rhs._value._double;
1673 } else if constexpr (std::is_same_v<T, long long>) {
1674 return rhs._value._long_long;
1675 } else if constexpr (std::is_same_v<T, bool>) {
1676 return rhs._value._bool;
1677 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1678 return rhs._value._year_month_day;
1679 } else if constexpr (std::is_same_v<T, std::string>) {
1680 return *rhs._value._string;
1681 } else if constexpr (std::is_same_v<T, vector_type>) {
1682 return *rhs._value._vector;
1683 } else if constexpr (std::is_same_v<T, map_type>) {
1684 return *rhs._value._map;
1685 } else if constexpr (std::is_same_v<T, bstring>) {
1686 return *rhs._value._bstring;
1687 } else {
1688 hi_static_no_default();
1689 }
1690 }
1691
1700 template<typename T>
1701 [[nodiscard]] friend constexpr T& get(datum& rhs) noexcept
1702 {
1703 hi_axiom(holds_alternative<T>(rhs));
1704 if constexpr (std::is_same_v<T, double>) {
1705 return rhs._value._double;
1706 } else if constexpr (std::is_same_v<T, long long>) {
1707 return rhs._value._long_long;
1708 } else if constexpr (std::is_same_v<T, bool>) {
1709 return rhs._value._bool;
1710 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1711 return rhs._value._year_month_day;
1712 } else if constexpr (std::is_same_v<T, std::string>) {
1713 return *rhs._value._string;
1714 } else if constexpr (std::is_same_v<T, vector_type>) {
1715 return *rhs._value._vector;
1716 } else if constexpr (std::is_same_v<T, map_type>) {
1717 return *rhs._value._map;
1718 } else if constexpr (std::is_same_v<T, bstring>) {
1719 return *rhs._value._bstring;
1720 } else {
1721 hi_static_no_default();
1722 }
1723 }
1724
1733 template<typename T>
1734 [[nodiscard]] friend constexpr T* get_if(datum& rhs) noexcept
1735 {
1736 if (holds_alternative<T>(rhs)) {
1737 return &get<T>(rhs);
1738 } else {
1739 return nullptr;
1740 }
1741 }
1742
1751 template<typename T>
1752 [[nodiscard]] friend constexpr T const* get_if(datum const& rhs) noexcept
1753 {
1754 if (holds_alternative<T>(rhs)) {
1755 return &get<T>(rhs);
1756 } else {
1757 return nullptr;
1758 }
1759 }
1760
1770 template<typename T>
1771 [[nodiscard]] friend T* get_if(datum& rhs, jsonpath const& path) noexcept
1772 {
1773 if (auto* value = rhs.find_one(path)) {
1774 if (holds_alternative<T>(*value)) {
1775 return &get<T>(*value);
1776 } else {
1777 return nullptr;
1778 }
1779 } else {
1780 return nullptr;
1781 }
1782 }
1783
1793 template<typename T>
1794 [[nodiscard]] friend T const* get_if(datum const& rhs, jsonpath const& path) noexcept
1795 {
1796 if (auto* value = const_cast<datum&>(rhs).find_one(path)) {
1797 if (holds_alternative<T>(*value)) {
1798 return &get<T>(*value);
1799 } else {
1800 return nullptr;
1801 }
1802 } else {
1803 return nullptr;
1804 }
1805 }
1806
1807private:
1808 enum class tag_type : signed char {
1809 // scalars are detected by: `std::to_underlying(tag_type) >= 0`
1810 monostate = 0,
1811 floating_point = 1,
1812 integral = 2,
1813 boolean = 3,
1814 null = 4,
1815 year_month_day = 5,
1816 flow_continue = 6,
1817 flow_break = 7,
1818
1819 // pointers are detected by: `std::to_underlying(tag_type) < 0`.
1820 string = -1,
1821 vector = -2,
1822 map = -3,
1823 bstring = -5
1824 };
1825
1826 tag_type _tag = tag_type::monostate;
1827 union value_type {
1828 double _double;
1829 long long _long_long;
1830 bool _bool;
1831 std::chrono::year_month_day _year_month_day;
1832 std::string* _string;
1833 vector_type* _vector;
1834 map_type* _map;
1835 bstring* _bstring;
1836
1837 constexpr value_type(numeric_integral auto value) noexcept : _long_long(narrow_cast<long long>(value)) {}
1838 constexpr value_type(std::floating_point auto value) noexcept : _double(narrow_cast<double>(value)) {}
1839 constexpr value_type(bool value) noexcept : _bool(value) {}
1840 constexpr value_type(std::chrono::year_month_day value) noexcept : _year_month_day(value) {}
1841 constexpr value_type(std::string* value) noexcept : _string(value) {}
1842 constexpr value_type(vector_type* value) noexcept : _vector(value) {}
1843 constexpr value_type(map_type* value) noexcept : _map(value) {}
1844 constexpr value_type(bstring* value) noexcept : _bstring(value) {}
1845 };
1846
1847 value_type _value;
1848
1849 [[nodiscard]] constexpr bool is_scalar() const noexcept
1850 {
1851 return std::to_underlying(_tag) >= 0;
1852 }
1853
1854 [[nodiscard]] constexpr bool is_pointer() const noexcept
1855 {
1856 return std::to_underlying(_tag) < 0;
1857 }
1858
1859 hi_no_inline void copy_pointer(datum const& other) noexcept
1860 {
1861 hi_axiom(other.is_pointer());
1862 switch (other._tag) {
1863 case tag_type::string:
1864 _value._string = new std::string{*other._value._string};
1865 return;
1866 case tag_type::vector:
1867 _value._vector = new vector_type{*other._value._vector};
1868 return;
1869 case tag_type::map:
1870 _value._map = new map_type{*other._value._map};
1871 return;
1872 case tag_type::bstring:
1873 _value._bstring = new bstring{*other._value._bstring};
1874 return;
1875 default:
1876 hi_no_default();
1877 }
1878 }
1879
1880 hi_no_inline void _delete_pointer() noexcept
1881 {
1882 hi_axiom(is_pointer());
1883 switch (_tag) {
1884 case tag_type::string:
1885 delete _value._string;
1886 return;
1887 case tag_type::vector:
1888 delete _value._vector;
1889 return;
1890 case tag_type::map:
1891 delete _value._map;
1892 return;
1893 case tag_type::bstring:
1894 delete _value._bstring;
1895 return;
1896 default:
1897 hi_no_default();
1898 }
1899 }
1900
1901 constexpr void delete_pointer() noexcept
1902 {
1903 if (is_pointer()) {
1904 _delete_pointer();
1905 }
1906 }
1907
1908 void find_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum*>& r) noexcept
1909 {
1910 if (auto vector = get_if<datum::vector_type>(*this)) {
1911 for (auto& item : *vector) {
1912 item.find(it + 1, it_end, r);
1913 }
1914
1915 } else if (auto map = get_if<datum::map_type>(*this)) {
1916 for (auto& item : *map) {
1917 item.second.find(it + 1, it_end, r);
1918 }
1919 }
1920 }
1921
1922 void find_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum*>& r) noexcept
1923 {
1924 this->find(it + 1, it_end, r);
1925
1926 if (auto vector = get_if<datum::vector_type>(*this)) {
1927 for (auto& item : *vector) {
1928 item.find(it, it_end, r);
1929 }
1930
1931 } else if (auto map = get_if<datum::map_type>(*this)) {
1932 for (auto& item : *map) {
1933 item.second.find(it, it_end, r);
1934 }
1935 }
1936 }
1937
1938 void find_indices(
1939 jsonpath::indices const& indices,
1940 jsonpath::const_iterator it,
1941 jsonpath::const_iterator it_end,
1942 std::vector<datum*>& r) noexcept
1943 {
1944 if (auto vector = get_if<datum::vector_type>(*this)) {
1945 for (auto const index : indices.filter(ssize(*vector))) {
1946 (*vector)[index].find(it + 1, it_end, r);
1947 }
1948 }
1949 }
1950
1951 void find_names(
1952 jsonpath::names const& names,
1953 jsonpath::const_iterator it,
1954 jsonpath::const_iterator it_end,
1955 std::vector<datum*>& r) noexcept
1956 {
1957 if (auto map = get_if<datum::map_type>(*this)) {
1958 for (auto const& name : names) {
1959 auto const name_ = datum{name};
1960 auto jt = map->find(name_);
1961 if (jt != map->cend()) {
1962 jt->second.find(it + 1, it_end, r);
1963 }
1964 }
1965 }
1966 }
1967
1968 void find_slice(
1969 jsonpath::slice const& slice,
1970 jsonpath::const_iterator it,
1971 jsonpath::const_iterator it_end,
1972 std::vector<datum*>& r) noexcept
1973 {
1974 if (auto vector = get_if<datum::vector_type>(*this)) {
1975 auto const first = slice.begin(vector->size());
1976 auto const last = slice.end(vector->size());
1977
1978 for (auto index = first; index != last; index += slice.step) {
1979 if (index >= 0 and index < vector->size()) {
1980 (*this)[index].find(it + 1, it_end, r);
1981 }
1982 }
1983 }
1984 }
1985
1986 void find(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum*>& r) noexcept
1987 {
1988 if (it == it_end) {
1989 r.push_back(this);
1990
1991 } else if (std::holds_alternative<jsonpath::root>(*it)) {
1992 find(it + 1, it_end, r);
1993
1994 } else if (std::holds_alternative<jsonpath::current>(*it)) {
1995 find(it + 1, it_end, r);
1996
1997 } else if (std::holds_alternative<jsonpath::wildcard>(*it)) {
1998 find_wildcard(it, it_end, r);
1999
2000 } else if (std::holds_alternative<jsonpath::descend>(*it)) {
2001 find_descend(it, it_end, r);
2002
2003 } else if (auto indices = std::get_if<jsonpath::indices>(&*it)) {
2004 find_indices(*indices, it, it_end, r);
2005
2006 } else if (auto names = std::get_if<jsonpath::names>(&*it)) {
2007 find_names(*names, it, it_end, r);
2008
2009 } else if (auto slice = std::get_if<jsonpath::slice>(&*it)) {
2010 find_slice(*slice, it, it_end, r);
2011
2012 } else {
2013 hi_no_default();
2014 }
2015 }
2016
2017 [[nodiscard]] int remove_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2018 {
2019 int r = 0;
2020
2021 if (auto vector = get_if<datum::vector_type>(*this)) {
2022 auto jt = vector->begin();
2023 while (jt != vector->end()) {
2024 auto const match = jt->remove(it + 1, it_end);
2025 r |= match ? 1 : 0;
2026
2027 if (match == 2) {
2028 jt = vector->erase(jt);
2029 } else {
2030 ++jt;
2031 }
2032 }
2033 return vector->empty() ? 2 : r;
2034
2035 } else if (auto map = get_if<datum::map_type>(*this)) {
2036 auto jt = map->begin();
2037 while (jt != map->end()) {
2038 auto const match = jt->second.remove(it + 1, it_end);
2039 r |= match ? 1 : 0;
2040
2041 if (match == 2) {
2042 jt = map->erase(jt);
2043 } else {
2044 ++jt;
2045 }
2046 }
2047 return map->empty() ? 2 : r;
2048
2049 } else {
2050 return 0;
2051 }
2052 }
2053
2054 [[nodiscard]] int remove_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2055 {
2056 int r = 0;
2057
2058 {
2059 auto const match = this->remove(it + 1, it_end);
2060 if (match == 2) {
2061 return 2;
2062 }
2063 r |= match ? 1 : 0;
2064 }
2065
2066 if (auto vector = get_if<datum::vector_type>(*this)) {
2067 auto jt = vector->begin();
2068 while (jt != vector->end()) {
2069 auto const match = jt->remove(it, it_end);
2070 r |= match ? 1 : 0;
2071
2072 if (match == 2) {
2073 jt = vector->erase(jt);
2074 } else {
2075 ++jt;
2076 }
2077 }
2078 return vector->empty() ? 2 : r;
2079
2080 } else if (auto map = get_if<datum::map_type>(*this)) {
2081 auto jt = map->begin();
2082 while (jt != map->end()) {
2083 auto const match = jt->second.remove(it, it_end);
2084 r |= match ? 1 : 0;
2085
2086 if (match == 2) {
2087 jt = map->erase(jt);
2088 } else {
2089 ++jt;
2090 }
2091 }
2092 return map->empty() ? 2 : r;
2093
2094 } else {
2095 return 0;
2096 }
2097 }
2098
2099 [[nodiscard]] int
2100 remove_indices(jsonpath::indices const& indices, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2101 {
2102 if (auto vector = get_if<datum::vector_type>(*this)) {
2103 int r = 0;
2104 std::size_t offset = 0;
2105
2106 for (auto const index : indices.filter(ssize(*vector))) {
2107 auto const match = (*vector)[index - offset].remove(it + 1, it_end);
2108 r |= match ? 1 : 0;
2109 if (match == 2) {
2110 vector->erase(vector->begin() + (index - offset));
2111 ++offset;
2112 }
2113 }
2114
2115 return vector->empty() ? 2 : r;
2116
2117 } else {
2118 return 0;
2119 }
2120 }
2121
2122 [[nodiscard]] int
2123 remove_names(jsonpath::names const& names, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2124 {
2125 if (auto map = get_if<datum::map_type>(*this)) {
2126 int r = 0;
2127
2128 for (auto const& name : names) {
2129 auto const name_ = datum{name};
2130 auto jt = map->find(name_);
2131 if (jt != map->cend()) {
2132 auto const match = jt->second.remove(it + 1, it_end);
2133 r |= match ? 1 : 0;
2134 if (match == 2) {
2135 map->erase(jt);
2136 }
2137 }
2138 }
2139
2140 return map->empty() ? 2 : r;
2141
2142 } else {
2143 return 0;
2144 }
2145 }
2146
2147 [[nodiscard]] int
2148 remove_slice(jsonpath::slice const& slice, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2149 {
2150 if (auto vector = get_if<datum::vector_type>(*this)) {
2151 int r = 0;
2152
2153 auto const first = slice.begin(vector->size());
2154 auto const last = slice.end(vector->size());
2155
2156 std::size_t offset = 0;
2157 for (auto index = first; index != last; index += slice.step) {
2158 if (index >= 0 and index < vector->size()) {
2159 auto const match = (*this)[index - offset].remove(it + 1, it_end);
2160 r |= match ? 1 : 0;
2161
2162 if (match == 2) {
2163 vector->erase(vector->begin() + (index - offset));
2164 ++offset;
2165 }
2166 }
2167 }
2168
2169 return vector->empty() ? 2 : r;
2170
2171 } else {
2172 return 0;
2173 }
2174 }
2175
2176 [[nodiscard]] int remove(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2177 {
2178 if (it == it_end) {
2179 // Reached end, remove matching name or index in parent.
2180 return 2;
2181
2182 } else if (std::holds_alternative<jsonpath::root>(*it)) {
2183 return remove(it + 1, it_end);
2184
2185 } else if (std::holds_alternative<jsonpath::current>(*it)) {
2186 return remove(it + 1, it_end);
2187
2188 } else if (std::holds_alternative<jsonpath::wildcard>(*it)) {
2189 return remove_wildcard(it, it_end);
2190
2191 } else if (std::holds_alternative<jsonpath::descend>(*it)) {
2192 return remove_descend(it, it_end);
2193
2194 } else if (auto indices = std::get_if<jsonpath::indices>(&*it)) {
2195 return remove_indices(*indices, it, it_end);
2196
2197 } else if (auto names = std::get_if<jsonpath::names>(&*it)) {
2198 return remove_names(*names, it, it_end);
2199
2200 } else if (auto slice = std::get_if<jsonpath::slice>(&*it)) {
2201 return remove_slice(*slice, it, it_end);
2202
2203 } else {
2204 hi_no_default();
2205 }
2206 }
2207
2208 [[nodiscard]] datum*
2209 find_one_name(datum const& name, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2210 {
2211 hi_axiom(holds_alternative<std::string>(name));
2212
2213 if (auto* map = get_if<map_type>(*this)) {
2214 auto i = map->find(name);
2215 if (i != map->end()) {
2216 return i->second.find_one(it + 1, it_end, create);
2217
2218 } else if (create) {
2219 (*map)[name] = datum{std::monostate{}};
2220 return find_one_name(name, it, it_end, create);
2221
2222 } else {
2223 return nullptr;
2224 }
2225
2226 } else if (holds_alternative<std::monostate>(*this) and create) {
2227 *this = datum::make_map(name, std::monostate{});
2228 return find_one_name(name, it, it_end, create);
2229
2230 } else {
2231 return nullptr;
2232 }
2233 }
2234
2235 [[nodiscard]] datum*
2236 find_one_index(std::size_t index, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2237 {
2238 if (auto* vector = get_if<vector_type>(*this)) {
2239 if (index < vector->size()) {
2240 return (*vector)[index].find_one(it + 1, it_end, create);
2241 } else if (index == vector->size() and create) {
2242 vector->push_back(datum{std::monostate{}});
2243 return find_one_index(index, it, it_end, create);
2244 } else {
2245 return nullptr;
2246 }
2247
2248 } else if (holds_alternative<std::monostate>(*this) and index == 0 and create) {
2249 *this = datum::make_vector(std::monostate{});
2250 return find_one_index(index, it, it_end, create);
2251
2252 } else {
2253 return nullptr;
2254 }
2255 }
2256
2257 [[nodiscard]] datum* find_one(jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2258 {
2259 if (it == it_end) {
2260 return this;
2261
2262 } else if (std::holds_alternative<jsonpath::root>(*it)) {
2263 return find_one(it + 1, it_end, create);
2264
2265 } else if (std::holds_alternative<jsonpath::current>(*it)) {
2266 return find_one(it + 1, it_end, create);
2267
2268 } else if (auto const* indices = std::get_if<jsonpath::indices>(&*it)) {
2269 hi_axiom(indices->size() == 1);
2270 return find_one_index(indices->front(), it, it_end, create);
2271
2272 } else if (auto const* names = std::get_if<jsonpath::names>(&*it)) {
2273 hi_axiom(names->size() == 1);
2274 return find_one_name(datum{names->front()}, it, it_end, create);
2275
2276 } else {
2277 hi_no_default();
2278 }
2279 }
2280};
2281
2282} // namespace v1
2283} // namespace hi::v1
2284
2285hi_export template<>
2286struct std::hash<hi::datum> {
2287 [[nodiscard]] inline std::size_t operator()(hi::datum const& rhs) const noexcept
2288 {
2289 return rhs.hash();
2290 }
2291};
2292
2293// XXX #617 MSVC bug does not handle partial specialization in modules.
2294hi_export template<>
2295struct std::formatter<hi::datum, char> : std::formatter<std::string, char> {
2296 auto format(hi::datum const& t, auto& fc) const
2297 {
2298 return std::formatter<std::string, char>{}.format(to_string(t), fc);
2299 }
2300};
2301
2302hi_warning_pop();
@ create
Create file if it does not exist, or fail.
@ other
The gui_event does not have associated data.
STL namespace.
The HikoGUI namespace.
Definition array_generic.hpp:20
constexpr matrix2 operator*(matrix2 const &lhs, matrix2 const &rhs) noexcept
Matrix/Matrix multiplication.
Definition transform.hpp:69
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
Promotion result.
Definition datum.hpp:44
Definition datum.hpp:171
A dynamic data type.
Definition datum.hpp:198
vector_type keys() const
Get the sorted list of keys of a map.
Definition datum.hpp:812
constexpr bool is_break() const noexcept
Check if the result of a expression was a break flow control statement.
Definition datum.hpp:633
friend constexpr T & get(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1701
friend constexpr bool promotable_to(datum const &rhs) noexcept
Check if the type held by the datum can be promoted.
Definition datum.hpp:1648
constexpr bool is_continue() const noexcept
Check if the result of a expression was a continue flow control statement.
Definition datum.hpp:641
bool remove(jsonpath const &path) noexcept
Remove the object by path.
Definition datum.hpp:934
friend constexpr auto promote_if(datum const &lhs, datum const &rhs) noexcept
Promote two datum-arguments to a common type.
Definition datum.hpp:212
friend std::string to_string(datum const &rhs) noexcept
Get the string representation of the value.
Definition datum.hpp:1595
friend constexpr T const * get_if(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1752
friend constexpr bool holds_alternative(datum const &rhs) noexcept
Check if the stored value is of a specific type.
Definition datum.hpp:1607
constexpr bool is_undefined() const noexcept
Check if the datum has an undefined value.
Definition datum.hpp:625
vector_type items() const
Get key value pairs of items of a map sorted by the key.
Definition datum.hpp:844
friend T * get_if(datum &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1771
datum const * find_one(jsonpath const &path) const noexcept
Find a object by path.
Definition datum.hpp:966
friend T const * get_if(datum const &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1794
datum * find_one_or_create(jsonpath const &path) noexcept
Find a object by path potentially creating intermediate objects.
Definition datum.hpp:955
friend constexpr T const & get(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1668
datum * find_one(jsonpath const &path) noexcept
Find a object by path.
Definition datum.hpp:944
friend constexpr T * get_if(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1734
vector_type values() const
Get the list of values of a map.
Definition datum.hpp:828
Definition datum.hpp:202
Definition datum.hpp:203
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)