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/module.hpp"
9#include "../container/module.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
35namespace 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<>
188class is_datum_type<decimal> : public std::true_type {};
189hi_export template<>
191hi_export template<>
193hi_export template<>
194class is_datum_type<std::chrono::year_month_day> : public std::true_type {};
195hi_export template<>
196class is_datum_type<std::string> : public std::true_type {};
197hi_export template<>
198class is_datum_type<bstring> : public std::true_type {};
199
200hi_export template<typename T>
201constexpr bool is_datum_type_v = is_datum_type<T>::value;
202
212hi_export class datum {
213public:
214 using vector_type = std::vector<datum>;
215 using map_type = std::map<datum, datum>;
216 struct break_type {};
217 struct continue_type {};
218
225 template<typename To>
226 [[nodiscard]] friend constexpr auto promote_if(datum const& lhs, datum const& rhs) noexcept
227 {
230 r.set(get<To>(lhs), get<To>(rhs));
231
232 } else if (holds_alternative<To>(lhs) and promotable_to<To>(rhs)) {
233 r.set(get<To>(lhs), static_cast<To>(rhs));
234
235 } else if (promotable_to<To>(lhs) and holds_alternative<To>(rhs)) {
236 r.set(static_cast<To>(lhs), get<To>(rhs));
237 }
238
239 return r;
240 }
241
242 constexpr ~datum() noexcept
243 {
244 delete_pointer();
245 }
246
247 constexpr datum(datum const& other) noexcept : _tag(other._tag), _value(other._value)
248 {
249 if (other.is_pointer()) {
250 copy_pointer(other);
251 }
252 }
253
254 constexpr datum(datum&& other) noexcept : _tag(other._tag), _value(other._value)
255 {
256 other._tag = tag_type::monostate;
257 other._value._long_long = 0;
258 }
259
260 constexpr datum() noexcept : _tag(tag_type::monostate), _value(0) {}
261 constexpr explicit datum(std::monostate) noexcept : _tag(tag_type::monostate), _value(0) {}
262 constexpr explicit datum(nullptr_t) noexcept : _tag(tag_type::null), _value(0) {}
263 constexpr explicit datum(continue_type) noexcept : _tag(tag_type::flow_continue), _value(0) {}
264 constexpr explicit datum(break_type) noexcept : _tag(tag_type::flow_break), _value(0) {}
265 constexpr explicit datum(bool value) noexcept : _tag(tag_type::boolean), _value(value) {}
266 constexpr explicit datum(std::floating_point auto value) noexcept :
267 _tag(tag_type::floating_point), _value(narrow_cast<double>(value))
268 {
269 }
270
271 constexpr explicit datum(numeric_integral auto value) noexcept :
272 _tag(tag_type::integral), _value(narrow_cast<long long>(value))
273 {
274 }
275
276 constexpr explicit datum(decimal value) noexcept : _tag(tag_type::decimal), _value(value) {}
277 constexpr explicit datum(std::chrono::year_month_day value) noexcept : _tag(tag_type::year_month_day), _value(value) {}
278 explicit datum(std::string value) noexcept : _tag(tag_type::string), _value(new std::string{std::move(value)}) {}
279 explicit datum(std::string_view value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
280 explicit datum(char const *value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
281 explicit datum(vector_type value) noexcept : _tag(tag_type::vector), _value(new vector_type{std::move(value)}) {}
282 explicit datum(map_type value) noexcept : _tag(tag_type::map), _value(new map_type{std::move(value)}) {}
283 explicit datum(bstring value) noexcept : _tag(tag_type::bstring), _value(new bstring{std::move(value)}) {}
284
285 template<typename... Args>
286 [[nodiscard]] static datum make_vector(Args const&...args) noexcept
287 {
288 return datum{vector_type{datum{args}...}};
289 }
290
291 template<typename Key, typename Value, typename... Args>
292 static void populate_map(map_type& r, Key const& key, Value const& value, Args const&...args) noexcept
293 {
294 r.insert(std::pair<datum, datum>{datum{key}, datum{value}});
295 if constexpr (sizeof...(Args) > 0) {
296 populate_map(r, args...);
297 }
298 }
299
300 template<typename... Args>
301 [[nodiscard]] static datum make_map(Args const&...args) noexcept
302 {
303 static_assert(sizeof...(Args) % 2 == 0, "Expect key value pairs for the arguments of make_map()");
304
305 auto r = map_type{};
306 if constexpr (sizeof...(Args) > 0) {
307 populate_map(r, args...);
308 }
309 return datum{std::move(r)};
310 }
311
312 [[nodiscard]] static datum make_break() noexcept
313 {
314 return datum{break_type{}};
315 }
316
317 [[nodiscard]] static datum make_continue() noexcept
318 {
319 return datum{continue_type{}};
320 }
321
322 constexpr datum& operator=(datum const& other) noexcept
323 {
324 hi_return_on_self_assignment(other);
325
326 delete_pointer();
327 _tag = other._tag;
328 _value = other._value;
329 if (other.is_pointer()) {
330 copy_pointer(other);
331 }
332 return *this;
333 }
334
335 constexpr datum& operator=(datum&& other) noexcept
336 {
337 std::swap(_tag, other._tag);
338 std::swap(_value, other._value);
339 return *this;
340 }
341
342 constexpr datum& operator=(std::floating_point auto value) noexcept(sizeof(value) <= 4)
343 {
344 delete_pointer();
345 _tag = tag_type::floating_point;
346 _value = static_cast<double>(value);
347 return *this;
348 }
349
350 constexpr datum& operator=(numeric_integral auto value) noexcept(sizeof(value) <= 4)
351 {
352 delete_pointer();
353 _tag = tag_type::integral;
354 _value = static_cast<long long>(value);
355 return *this;
356 }
357
358 constexpr datum& operator=(decimal value)
359 {
360 delete_pointer();
361 _tag = tag_type::decimal;
362 _value = value;
363 return *this;
364 }
365 constexpr datum& operator=(bool value) noexcept
366 {
367 delete_pointer();
368 _tag = tag_type::boolean;
369 _value = value;
370 return *this;
371 }
372
373 constexpr datum& operator=(std::chrono::year_month_day value) noexcept
374 {
375 delete_pointer();
376 _tag = tag_type::year_month_day;
377 _value = value;
378 return *this;
379 }
380
381 constexpr datum& operator=(std::monostate) noexcept
382 {
383 delete_pointer();
384 _tag = tag_type::monostate;
385 _value = 0;
386 return *this;
387 }
388
389 constexpr datum& operator=(nullptr_t) noexcept
390 {
391 delete_pointer();
392 _tag = tag_type::null;
393 _value = 0;
394 return *this;
395 }
396
397 datum& operator=(std::string value) noexcept
398 {
399 delete_pointer();
400 _tag = tag_type::string;
401 _value = new std::string{std::move(value)};
402 return *this;
403 }
404
405 datum& operator=(char const *value) noexcept
406 {
407 delete_pointer();
408 _tag = tag_type::string;
409 _value = new std::string{value};
410 return *this;
411 }
412
413 datum& operator=(std::string_view value) noexcept
414 {
415 delete_pointer();
416 _tag = tag_type::string;
417 _value = new std::string{value};
418 return *this;
419 }
420
421 datum& operator=(vector_type value) noexcept
422 {
423 delete_pointer();
424 _tag = tag_type::vector;
425 _value = new vector_type{std::move(value)};
426 return *this;
427 }
428
429 datum& operator=(map_type value) noexcept
430 {
431 delete_pointer();
432 _tag = tag_type::map;
433 _value = new map_type{std::move(value)};
434 return *this;
435 }
436
437 datum& operator=(bstring value) noexcept
438 {
439 delete_pointer();
440 _tag = tag_type::bstring;
441 _value = new bstring{std::move(value)};
442 return *this;
443 }
444
445 constexpr explicit operator bool() const noexcept
446 {
447 switch (_tag) {
448 case tag_type::floating_point:
449 return to_bool(get<double>(*this));
450 case tag_type::decimal:
451 return to_bool(get<decimal>(*this));
452 case tag_type::boolean:
453 return get<bool>(*this);
454 case tag_type::integral:
455 return to_bool(get<long long>(*this));
456 case tag_type::year_month_day:
457 return true;
458 case tag_type::string:
459 return not get<std::string>(*this).empty();
460 case tag_type::vector:
461 return not get<vector_type>(*this).empty();
462 case tag_type::map:
463 return not get<map_type>(*this).empty();
464 case tag_type::bstring:
465 return not get<bstring>(*this).empty();
466 default:
467 return false;
468 }
469 }
470
471 [[nodiscard]] constexpr bool empty() const
472 {
473 switch (_tag) {
474 case tag_type::string:
475 return get<std::string>(*this).empty();
476 case tag_type::vector:
477 return get<vector_type>(*this).empty();
478 case tag_type::map:
479 return get<map_type>(*this).empty();
480 case tag_type::bstring:
481 return get<bstring>(*this).empty();
482 default:
483 throw std::domain_error(std::format("Type {} can not be checked for empty", *this));
484 }
485 }
486
487 template<std::floating_point T>
488 constexpr explicit operator T() const
489 {
490 switch (_tag) {
491 case tag_type::floating_point:
492 return static_cast<T>(get<double>(*this));
493 case tag_type::integral:
494 return static_cast<T>(get<long long>(*this));
495 case tag_type::decimal:
496 return static_cast<T>(get<decimal>(*this));
497 case tag_type::boolean:
498 return static_cast<T>(get<bool>(*this));
499 default:
500 throw std::domain_error(std::format("Can't convert {} to floating point", *this));
501 }
502 }
503
504 constexpr explicit operator decimal() const
505 {
506 switch (_tag) {
507 case tag_type::floating_point:
508 return decimal(get<double>(*this));
509 case tag_type::integral:
510 return decimal(get<long long>(*this));
511 case tag_type::decimal:
512 return get<decimal>(*this);
513 case tag_type::boolean:
514 return decimal(get<bool>(*this));
515 default:
516 throw std::domain_error(std::format("Can't convert {} to floating point", *this));
517 }
518 }
519
520 template<numeric_integral T>
521 constexpr explicit operator T() const
522 {
523 if (auto f = get_if<double>(*this)) {
524 errno = 0;
525 hilet r = std::round(*f);
528 throw std::overflow_error("double to integral");
529 }
530 return round_cast<T>(r);
531
532 } else if (auto i = get_if<long long>(*this)) {
534 throw std::overflow_error("long long to integral");
535 }
536 return narrow_cast<T>(*i);
537
538 } else if (auto d = get_if<decimal>(*this)) {
539 hilet r = static_cast<long long>(*d);
541 throw std::overflow_error("decimal to integral");
542 }
543 return narrow_cast<T>(r);
544
545 } else if (auto b = get_if<bool>(*this)) {
546 return narrow_cast<T>(*b);
547
548 } else {
549 throw std::domain_error(std::format("Can't convert {} to an integral", repr(*this)));
550 }
551 }
552
553 constexpr explicit operator std::chrono::year_month_day() const
554 {
555 if (auto ymd = get_if<std::chrono::year_month_day>(*this)) {
556 return *ymd;
557 } else {
558 throw std::domain_error(std::format("Can't convert {} to an std::chrono::year_month_day", repr(*this)));
559 }
560 }
561
562 explicit operator std::string() const noexcept
563 {
564 switch (_tag) {
565 case tag_type::monostate:
566 return "undefined";
567 case tag_type::floating_point:
568 return hi::to_string(_value._double);
569 case tag_type::decimal:
570 return to_string(_value._decimal);
571 case tag_type::integral:
572 return to_string(_value._long_long);
573 case tag_type::boolean:
574 return _value._bool ? "true" : "false";
575 case tag_type::year_month_day:
576 return std::format("{:%Y-%m-%d}", _value._year_month_day);
577 case tag_type::null:
578 return "null";
579 case tag_type::flow_break:
580 return "break";
581 case tag_type::flow_continue:
582 return "continue";
583 case tag_type::string:
584 return *_value._string;
585 case tag_type::vector:
586 {
587 auto r = std::string{"["};
588 for (hilet& item : *_value._vector) {
589 r += repr(item);
590 r += ',';
591 }
592 r += ']';
593 return r;
594 };
595 case tag_type::map:
596 {
597 auto r = std::string{"{"};
598 for (hilet& item : *_value._map) {
599 r += repr(item.first);
600 r += ':';
601 r += repr(item.second);
602 r += ',';
603 }
604 r += '}';
605 return r;
606 };
607 case tag_type::bstring:
608 return base64::encode(*_value._bstring);
609 default:
610 hi_no_default();
611 }
612 }
613
614 explicit operator std::string_view() const
615 {
616 if (auto s = get_if<std::string>(*this)) {
617 return std::string_view{*s};
618 } else {
619 throw std::domain_error(std::format("Can't convert {} to an std::string_view", repr(*this)));
620 }
621 }
622
623 explicit operator vector_type() const
624 {
625 if (auto v = get_if<vector_type>(*this)) {
626 return *v;
627 } else {
628 throw std::domain_error(std::format("Can't convert {} to an vector", repr(*this)));
629 }
630 }
631
632 explicit operator map_type() const
633 {
634 if (auto m = get_if<map_type>(*this)) {
635 return *m;
636 } else {
637 throw std::domain_error(std::format("Can't convert {} to an map", repr(*this)));
638 }
639 }
640
641 explicit operator bstring() const
642 {
643 // XXX should be able to base-64 decode a std::string.
644 if (_tag != tag_type::bstring) {
645 throw std::domain_error(std::format("Can't convert {} to an bstring", repr(*this)));
646 }
647 return get<bstring>(*this);
648 }
649
650 [[nodiscard]] constexpr char const *type_name() const noexcept
651 {
652 switch (_tag) {
653 case tag_type::floating_point:
654 return "float";
655 case tag_type::decimal:
656 return "decimal";
657 case tag_type::integral:
658 return "int";
659 case tag_type::boolean:
660 return "bool";
661 case tag_type::year_month_day:
662 return "date";
663 case tag_type::string:
664 return "string";
665 case tag_type::vector:
666 return "vector";
667 case tag_type::map:
668 return "map";
669 case tag_type::bstring:
670 return "bytes";
671 default:
672 hi_no_default();
673 }
674 }
675
679 {
680 return _tag == tag_type::monostate;
681 }
682
686 [[nodiscard]] constexpr bool is_break() const noexcept
687 {
688 return _tag == tag_type::flow_break;
689 }
690
694 [[nodiscard]] constexpr bool is_continue() const noexcept
695 {
696 return _tag == tag_type::flow_continue;
697 }
698
700 {
701 switch (_tag) {
702 case tag_type::floating_point:
703 return std::hash<double>{}(_value._double);
704 case tag_type::decimal:
705 return std::hash<decimal>{}(_value._decimal);
706 case tag_type::integral:
707 return std::hash<long long>{}(_value._long_long);
708 case tag_type::boolean:
709 return std::hash<bool>{}(_value._bool);
710 case tag_type::year_month_day:
711 {
712 uint32_t r = 0;
713 r |= narrow_cast<uint32_t>(static_cast<int>(_value._year_month_day.year())) << 16;
714 r |= narrow_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.month())) << 8;
715 r |= narrow_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.day()));
716 return std::hash<uint32_t>{}(r);
717 }
718 case tag_type::string:
719 return std::hash<std::string>{}(*_value._string);
720 case tag_type::vector:
721 {
722 std::size_t r = 0;
723 for (hilet& v : *_value._vector) {
724 r = hash_mix(r, v.hash());
725 }
726 return r;
727 }
728 case tag_type::map:
729 {
730 std::size_t r = 0;
731 for (hilet& kv : *_value._map) {
732 r = hash_mix(r, kv.first.hash(), kv.second.hash());
733 }
734 return r;
735 }
736 case tag_type::bstring:
737 return std::hash<bstring>{}(*_value._bstring);
738 default:
739 hi_no_default();
740 }
741 }
742
743 [[nodiscard]] constexpr std::size_t size() const
744 {
745 if (hilet *s = get_if<std::string>(*this)) {
746 return s->size();
747 } else if (hilet *v = get_if<vector_type>(*this)) {
748 return v->size();
749 } else if (hilet *m = get_if<map_type>(*this)) {
750 return m->size();
751 } else if (hilet *b = get_if<bstring>(*this)) {
752 return b->size();
753 } else {
754 throw std::domain_error(std::format("Can not evaluate {}.size()", repr(*this)));
755 }
756 }
757
758 [[nodiscard]] constexpr friend std::size_t size(datum const& rhs)
759 {
760 return rhs.size();
761 }
762
763 [[nodiscard]] constexpr datum const& back() const
764 {
765 if (hilet *v = get_if<vector_type>(*this)) {
766 if (v->empty()) {
767 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
768 }
769 return v->back();
770 } else {
771 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
772 }
773 }
774
775 [[nodiscard]] constexpr datum& back()
776 {
777 if (auto *v = get_if<vector_type>(*this)) {
778 if (v->empty()) {
779 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
780 }
781 return v->back();
782 } else {
783 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
784 }
785 }
786
787 [[nodiscard]] constexpr datum const& front() const
788 {
789 if (hilet *v = get_if<vector_type>(*this)) {
790 if (v->empty()) {
791 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
792 }
793 return v->front();
794 } else {
795 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
796 }
797 }
798
799 [[nodiscard]] constexpr datum& front()
800 {
801 if (auto *v = get_if<vector_type>(*this)) {
802 if (v->empty()) {
803 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
804 }
805 return v->front();
806 } else {
807 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
808 }
809 }
810
811 [[nodiscard]] constexpr auto cbegin() const
812 {
813 if (hilet *v = get_if<vector_type>(*this)) {
814 return v->cbegin();
815 } else {
816 throw std::domain_error(std::format("Can not evaluate {}.cbegin()", repr(*this)));
817 }
818 }
819
820 [[nodiscard]] constexpr auto begin() const
821 {
822 if (hilet *v = get_if<vector_type>(*this)) {
823 return v->begin();
824 } else {
825 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
826 }
827 }
828
829 [[nodiscard]] constexpr auto begin()
830 {
831 if (hilet *v = get_if<vector_type>(*this)) {
832 return v->begin();
833 } else {
834 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
835 }
836 }
837
838 [[nodiscard]] constexpr auto cend() const
839 {
840 if (hilet *v = get_if<vector_type>(*this)) {
841 return v->cend();
842 } else {
843 throw std::domain_error(std::format("Can not evaluate {}.cend()", repr(*this)));
844 }
845 }
846
847 [[nodiscard]] constexpr auto end() const
848 {
849 if (hilet *v = get_if<vector_type>(*this)) {
850 return v->end();
851 } else {
852 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
853 }
854 }
855
856 [[nodiscard]] constexpr auto end()
857 {
858 if (hilet *v = get_if<vector_type>(*this)) {
859 return v->end();
860 } else {
861 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
862 }
863 }
864
868 {
869 if (hilet *m = get_if<map_type>(*this)) {
870 auto r = vector_type{};
871 r.reserve(m->size());
872 for (hilet& kv : *m) {
873 r.push_back(kv.first);
874 }
875 return r;
876 } else {
877 throw std::domain_error(std::format("Can not evaluate {}.keys()", repr(*this)));
878 }
879 }
880
884 {
885 if (hilet *m = get_if<map_type>(*this)) {
886 auto r = vector_type{};
887 r.reserve(m->size());
888 for (hilet& kv : *m) {
889 r.push_back(kv.second);
890 }
891 return r;
892 } else {
893 throw std::domain_error(std::format("Can not evaluate {}.values()", repr(*this)));
894 }
895 }
896
900 {
901 if (hilet *m = get_if<map_type>(*this)) {
902 auto r = vector_type{};
903 r.reserve(m->size());
904
905 for (hilet& item : *m) {
906 r.push_back(make_vector(item.first, item.second));
907 }
908 return r;
909 } else {
910 throw std::domain_error(std::format("Can not evaluate {}.items()", repr(*this)));
911 }
912 }
913
914 constexpr void push_back(datum const& rhs)
915 {
916 if (auto *v = get_if<vector_type>(*this)) {
917 return v->push_back(rhs);
918 } else {
919 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
920 }
921 }
922
923 constexpr void push_back(datum&& rhs)
924 {
925 if (auto *v = get_if<vector_type>(*this)) {
926 return v->push_back(std::move(rhs));
927 } else {
928 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
929 }
930 }
931
932 template<typename Arg>
933 constexpr void push_back(Arg&& arg)
934 {
935 push_back(datum{std::forward<Arg>(arg)});
936 }
937
938 constexpr void pop_back()
939 {
940 if (auto *v = get_if<vector_type>(*this)) {
941 if (v->empty()) {
942 throw std::domain_error(std::format("Empty vector {}.pop_back()", repr(*this)));
943 }
944 return v->pop_back();
945 } else {
946 throw std::domain_error(std::format("Can not evaluate {}.pop_back()", repr(*this)));
947 }
948 }
949
950 [[nodiscard]] constexpr bool contains(datum const& rhs) const
951 {
952 if (auto *m = get_if<map_type>(*this)) {
953 return m->contains(rhs);
954 } else {
955 throw std::domain_error(std::format("Can not evaluate {}.contains({})", repr(*this), repr(rhs)));
956 }
957 }
958
959 template<typename Arg>
960 [[nodiscard]] constexpr bool contains(Arg const& arg) const
961 {
962 return contains(datum{arg});
963 }
964
965 [[nodiscard]] std::vector<datum *> find(jsonpath const& path) noexcept
966 {
967 auto r = std::vector<datum *>{};
968 find(path.cbegin(), path.cend(), r);
969 return r;
970 }
971
972 [[nodiscard]] std::vector<datum const *> find(jsonpath const& path) const noexcept
973 {
974 auto tmp = std::vector<datum *>{};
975 const_cast<datum *>(this)->find(path.cbegin(), path.cend(), tmp);
977 std::copy(tmp.begin(), tmp.end(), std::back_inserter(r));
978 return r;
979 }
980
989 [[nodiscard]] bool remove(jsonpath const& path) noexcept
990 {
991 return to_bool(remove(path.cbegin(), path.cend()));
992 }
993
999 [[nodiscard]] datum *find_one(jsonpath const& path) noexcept
1000 {
1001 hi_axiom(path.is_singular());
1002 return find_one(path.cbegin(), path.cend(), false);
1003 }
1004
1010 [[nodiscard]] datum *find_one_or_create(jsonpath const& path) noexcept
1011 {
1012 hi_axiom(path.is_singular());
1013 return find_one(path.cbegin(), path.cend(), true);
1014 }
1015
1021 [[nodiscard]] datum const *find_one(jsonpath const& path) const noexcept
1022 {
1023 hi_axiom(path.is_singular());
1024 return const_cast<datum *>(this)->find_one(path.cbegin(), path.cend(), false);
1025 }
1026
1027 [[nodiscard]] datum const& operator[](datum const& rhs) const
1028 {
1030 hilet& v = get<vector_type>(*this);
1031
1032 auto index = get<long long>(rhs);
1033 if (index < 0) {
1034 index = ssize(v) + index;
1035 }
1036 if (index < 0 or index >= ssize(v)) {
1037 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
1038 }
1039
1040 return v[index];
1041
1042 } else if (holds_alternative<map_type>(*this)) {
1043 hilet& m = get<map_type>(*this);
1044 hilet it = m.find(rhs);
1045 if (it == m.end()) {
1046 throw std::overflow_error(std::format("Key {} not found in map", repr(rhs)));
1047 }
1048
1049 return it->second;
1050
1051 } else {
1052 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
1053 }
1054 }
1055
1056 [[nodiscard]] constexpr datum& operator[](datum const& rhs)
1057 {
1059 auto& v = get<vector_type>(*this);
1060
1061 auto index = get<long long>(rhs);
1062 if (index < 0) {
1063 index = ssize(v) + index;
1064 }
1065 if (index < 0 or index >= ssize(v)) {
1066 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
1067 }
1068
1069 return v[index];
1070
1071 } else if (holds_alternative<map_type>(*this)) {
1072 auto& m = get<map_type>(*this);
1073 return m[rhs];
1074
1075 } else {
1076 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
1077 }
1078 }
1079
1080 [[nodiscard]] constexpr datum const& operator[](auto const& rhs) const
1081 {
1082 return (*this)[datum{rhs}];
1083 }
1084
1085 [[nodiscard]] constexpr datum& operator[](auto const& rhs)
1086 {
1087 return (*this)[datum{rhs}];
1088 }
1089
1090 [[nodiscard]] constexpr datum& operator++()
1091 {
1092 if (holds_alternative<long long>(*this)) {
1093 ++_value._long_long;
1094 return *this;
1095 } else {
1096 throw std::domain_error(std::format("Can not evaluate ++{}", repr(*this)));
1097 }
1098 }
1099
1100 [[nodiscard]] constexpr datum& operator--()
1101 {
1102 if (holds_alternative<long long>(*this)) {
1103 --_value._long_long;
1104 return *this;
1105 } else {
1106 throw std::domain_error(std::format("Can not evaluate --{}", repr(*this)));
1107 }
1108 }
1109
1110 [[nodiscard]] constexpr datum operator++(int)
1111 {
1112 if (holds_alternative<long long>(*this)) {
1113 auto tmp = *this;
1114 _value._long_long++;
1115 return tmp;
1116 } else {
1117 throw std::domain_error(std::format("Can not evaluate {}++", repr(*this)));
1118 }
1119 }
1120 [[nodiscard]] constexpr datum operator--(int)
1121 {
1122 if (holds_alternative<long long>(*this)) {
1123 auto tmp = *this;
1124 _value._long_long--;
1125 return tmp;
1126 } else {
1127 throw std::domain_error(std::format("Can not evaluate {}--", repr(*this)));
1128 }
1129 }
1130
1131 constexpr datum& operator+=(auto const& rhs)
1132 {
1133 if (holds_alternative<vector_type>(*this)) {
1134 push_back(rhs);
1135 return *this;
1136 } else {
1137 return (*this) = (*this) + rhs;
1138 }
1139 }
1140
1141#define X(op, inner_op) \
1142 constexpr datum& operator op(auto const& rhs) \
1143 { \
1144 return (*this) = (*this)inner_op rhs; \
1145 }
1146
1147 X(-=, -)
1148 X(*=, *)
1149 X(/=, /)
1150 X(%=, %)
1151 X(&=, &)
1152 X(|=, |)
1153 X(^=, ^)
1154 X(<<=, <<)
1155 X(>>=, >>)
1156#undef X
1157
1158 [[nodiscard]] friend constexpr bool operator==(datum const& lhs, datum const& rhs) noexcept
1159 {
1160 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1161 return doubles.lhs() == doubles.rhs();
1162
1163 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1164 return decimals.lhs() == decimals.rhs();
1165
1166 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1167 return long_longs.lhs() == long_longs.rhs();
1168
1169 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1170 return bools.lhs() == bools.rhs();
1171
1172 } else if (hilet ymds = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1173 return ymds.lhs() == ymds.rhs();
1174
1175 } else if (hilet strings = promote_if<std::string>(lhs, rhs)) {
1176 return strings.lhs() == strings.rhs();
1177
1178 } else if (hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1179 return vectors.lhs() == vectors.rhs();
1180
1181 } else if (hilet maps = promote_if<map_type>(lhs, rhs)) {
1182 return maps.lhs() == maps.rhs();
1183
1184 } else {
1185 return lhs._tag == rhs._tag;
1186 }
1187 }
1188
1217 [[nodiscard]] friend constexpr std::partial_ordering operator<=>(datum const& lhs, datum const& rhs) noexcept
1218 {
1219 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1220 return doubles.lhs() <=> doubles.rhs();
1221
1222 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1223 return decimals.lhs() <=> decimals.rhs();
1224
1225 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1226 return long_longs.lhs() <=> long_longs.rhs();
1227
1228 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1229 return bools.lhs() <=> bools.rhs();
1230
1231 } else if (hilet year_month_days = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1232 return year_month_days.lhs() <=> year_month_days.rhs();
1233
1234 } else if (hilet strings = promote_if<std::string>(lhs, rhs)) {
1235 return strings.lhs() <=> strings.rhs();
1236
1237 } else if (hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1238 return vectors.lhs() <=> vectors.rhs();
1239
1240 } else if (hilet maps = promote_if<map_type>(lhs, rhs)) {
1241 return maps.lhs() <=> maps.rhs();
1242
1243 } else if (hilet bstrings = promote_if<bstring>(lhs, rhs)) {
1244 return bstrings.lhs() <=> bstrings.rhs();
1245
1246 } else {
1247 return lhs._tag <=> rhs._tag;
1248 }
1249 }
1250
1261 [[nodiscard]] friend constexpr datum operator-(datum const& rhs)
1262 {
1263 if (hilet rhs_double = get_if<double>(rhs)) {
1264 return datum{-*rhs_double};
1265
1266 } else if (hilet rhs_decimal = get_if<decimal>(rhs)) {
1267 return datum{-*rhs_decimal};
1268
1269 } else if (hilet rhs_long_long = get_if<long long>(rhs)) {
1270 return datum{-*rhs_long_long};
1271
1272 } else {
1273 throw std::domain_error(std::format("Can not evaluate -{}", repr(rhs)));
1274 }
1275 }
1276
1286 [[nodiscard]] friend constexpr datum operator~(datum const& rhs)
1287 {
1288 if (hilet rhs_long_long = get_if<long long>(rhs)) {
1289 return datum{~*rhs_long_long};
1290
1291 } else {
1292 throw std::domain_error(std::format("Can not evaluate ~{}", repr(rhs)));
1293 }
1294 }
1295
1310 [[nodiscard]] friend constexpr datum operator+(datum const& lhs, datum const& rhs)
1311 {
1312 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1313 return datum{doubles.lhs() + doubles.rhs()};
1314
1315 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1316 return datum{decimals.lhs() + decimals.rhs()};
1317
1318 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1319 return datum{long_longs.lhs() + long_longs.rhs()};
1320
1321 } else if (hilet strings = promote_if<std::string>(lhs, rhs)) {
1322 return datum{strings.lhs() + strings.rhs()};
1323
1324 } else if (hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1325 auto r = vectors.lhs();
1326 r.insert(r.end(), vectors.rhs().begin(), vectors.rhs().end());
1327 return datum{std::move(r)};
1328
1329 } else {
1330 throw std::domain_error(std::format("Can not evaluate {} '+' {}", repr(lhs), repr(rhs)));
1331 }
1332 }
1333
1345 [[nodiscard]] friend constexpr datum operator-(datum const& lhs, datum const& rhs)
1346 {
1347 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1348 return datum{doubles.lhs() - doubles.rhs()};
1349
1350 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1351 return datum{decimals.lhs() - decimals.rhs()};
1352
1353 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1354 return datum{long_longs.lhs() - long_longs.rhs()};
1355
1356 } else {
1357 throw std::domain_error(std::format("Can not evaluate {} '-' {}", repr(lhs), repr(rhs)));
1358 }
1359 }
1360
1372 [[nodiscard]] friend constexpr datum operator*(datum const& lhs, datum const& rhs)
1373 {
1374 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1375 return datum{doubles.lhs() * doubles.rhs()};
1376
1377 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1378 return datum{decimals.lhs() * decimals.rhs()};
1379
1380 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1381 return datum{long_longs.lhs() * long_longs.rhs()};
1382
1383 } else {
1384 throw std::domain_error(std::format("Can not evaluate {} '*' {}", repr(lhs), repr(rhs)));
1385 }
1386 }
1387
1399 [[nodiscard]] friend constexpr datum operator/(datum const& lhs, datum const& rhs)
1400 {
1401 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1402 if (doubles.rhs() == 0) {
1403 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1404 }
1405 return datum{doubles.lhs() / doubles.rhs()};
1406
1407 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1408 if (decimals.rhs() == 0) {
1409 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1410 }
1411 return datum{decimals.lhs() / decimals.rhs()};
1412
1413 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1414 if (long_longs.rhs() == 0) {
1415 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1416 }
1417 return datum{long_longs.lhs() / long_longs.rhs()};
1418
1419 } else {
1420 throw std::domain_error(std::format("Can not evaluate {} '/' {}", repr(lhs), repr(rhs)));
1421 }
1422 }
1423
1435 [[nodiscard]] friend constexpr datum operator%(datum const& lhs, datum const& rhs)
1436 {
1437 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1438 if (long_longs.rhs() == 0) {
1439 throw std::domain_error(std::format("Divide by zero {} '%' {}", repr(lhs), repr(rhs)));
1440 }
1441 return datum{long_longs.lhs() % long_longs.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 pow(datum const& lhs, datum const& rhs)
1459 {
1460 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1461 return datum{pow(doubles.lhs(), doubles.rhs())};
1462
1463 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1464 return datum{pow(long_longs.lhs(), long_longs.rhs())};
1465
1466 } else {
1467 throw std::domain_error(std::format("Can not evaluate pow({}, {})", repr(lhs), repr(rhs)));
1468 }
1469 }
1470
1481 [[nodiscard]] friend constexpr datum operator&(datum const& lhs, datum const& rhs)
1482 {
1483 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1484 return datum{long_longs.lhs() & long_longs.rhs()};
1485
1486 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1487 return datum{bools.lhs() and bools.rhs()};
1488
1489 } else {
1490 throw std::domain_error(std::format("Can not evaluate {} '&' {}", repr(lhs), repr(rhs)));
1491 }
1492 }
1493
1504 [[nodiscard]] friend constexpr datum operator|(datum const& lhs, datum const& rhs)
1505 {
1506 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1507 return datum{long_longs.lhs() | long_longs.rhs()};
1508
1509 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1510 return datum{bools.lhs() or bools.rhs()};
1511
1512 } else {
1513 throw std::domain_error(std::format("Can not evaluate {} '|' {}", repr(lhs), repr(rhs)));
1514 }
1515 }
1516
1527 [[nodiscard]] friend constexpr datum operator^(datum const& lhs, datum const& rhs)
1528 {
1529 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1530 return datum{long_longs.lhs() ^ long_longs.rhs()};
1531
1532 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1533 return datum{bools.lhs() != bools.rhs()};
1534
1535 } else {
1536 throw std::domain_error(std::format("Can not evaluate {} '^' {}", repr(lhs), repr(rhs)));
1537 }
1538 }
1539
1552 [[nodiscard]] friend constexpr datum operator<<(datum const& lhs, datum const& rhs)
1553 {
1554 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1555 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1556 throw std::domain_error(std::format("Invalid shift count {} '<<' {}", repr(lhs), repr(rhs)));
1557 }
1558 return datum{long_longs.lhs() << long_longs.rhs()};
1559
1560 } else {
1561 throw std::domain_error(std::format("Can not evaluate {} '<<' {}", repr(lhs), repr(rhs)));
1562 }
1563 }
1564
1576 [[nodiscard]] friend constexpr datum operator>>(datum const& lhs, datum const& rhs)
1577 {
1578 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1579 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1580 throw std::domain_error(std::format("Invalid shift count {} '>>' {}", repr(lhs), repr(rhs)));
1581 }
1582 return datum{long_longs.lhs() >> long_longs.rhs()};
1583
1584 } else {
1585 throw std::domain_error(std::format("Can not evaluate {} '>>' {}", repr(lhs), repr(rhs)));
1586 }
1587 }
1588
1589 friend std::ostream& operator<<(std::ostream& lhs, datum const& rhs)
1590 {
1591 return lhs << to_string(rhs);
1592 }
1593
1594#define X(op) \
1595 [[nodiscard]] friend constexpr auto operator op(datum const& lhs, auto const& rhs) \
1596 { \
1597 return lhs op datum{rhs}; \
1598 } \
1599 [[nodiscard]] friend constexpr auto operator op(auto const& lhs, datum const& rhs) \
1600 { \
1601 return datum{lhs} op rhs; \
1602 }
1603
1604 X(==)
1605 X(<=>)
1606 X(+)
1607 X(-)
1608 X(*)
1609 X(/)
1610 X(%)
1611 X(&)
1612 X(|)
1613 X(^) X(<<) X(>>)
1614#undef X
1615
1618 [[nodiscard]] friend std::string repr(datum const& rhs) noexcept
1619 {
1620 switch (rhs._tag) {
1621 case tag_type::monostate:
1622 return "undefined";
1623 case tag_type::floating_point:
1624 return std::format("{:.1f}", rhs._value._double);
1625 case tag_type::decimal:
1626 return to_string(rhs._value._decimal);
1627 case tag_type::integral:
1628 return std::format("{}", rhs._value._long_long);
1629 case tag_type::boolean:
1630 return rhs._value._bool ? "true" : "false";
1631 case tag_type::year_month_day:
1632 return std::format("{:%Y-%m-%d}", rhs._value._year_month_day);
1633 case tag_type::null:
1634 return "null";
1635 case tag_type::flow_break:
1636 return "break";
1637 case tag_type::flow_continue:
1638 return "continue";
1639 case tag_type::string:
1640 return std::format("\"{}\"", *rhs._value._string);
1641 case tag_type::vector:
1642 {
1643 auto r = std::string{"["};
1644 for (hilet& item : *rhs._value._vector) {
1645 r += repr(item);
1646 r += ',';
1647 }
1648 r += ']';
1649 return r;
1650 };
1651 case tag_type::map:
1652 {
1653 auto r = std::string{"{"};
1654 for (hilet& item : *rhs._value._map) {
1655 r += repr(item.first);
1656 r += ':';
1657 r += repr(item.second);
1658 r += ',';
1659 }
1660 r += '}';
1661 return r;
1662 };
1663 case tag_type::bstring:
1664 return base64::encode(*rhs._value._bstring);
1665 default:
1666 hi_no_default();
1667 }
1668 }
1669
1672 [[nodiscard]] friend std::string to_string(datum const& rhs) noexcept
1673 {
1674 return static_cast<std::string>(rhs);
1675 }
1676
1683 template<typename T>
1684 [[nodiscard]] friend constexpr bool holds_alternative(datum const& rhs) noexcept
1685 {
1686 if constexpr (std::is_same_v<T, double>) {
1687 return rhs._tag == tag_type::floating_point;
1688 } else if constexpr (std::is_same_v<T, decimal>) {
1689 return rhs._tag == tag_type::decimal;
1690 } else if constexpr (std::is_same_v<T, long long>) {
1691 return rhs._tag == tag_type::integral;
1692 } else if constexpr (std::is_same_v<T, bool>) {
1693 return rhs._tag == tag_type::boolean;
1694 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1695 return rhs._tag == tag_type::year_month_day;
1696 } else if constexpr (std::is_same_v<T, nullptr_t>) {
1697 return rhs._tag == tag_type::null;
1698 } else if constexpr (std::is_same_v<T, std::monostate>) {
1699 return rhs._tag == tag_type::monostate;
1700 } else if constexpr (std::is_same_v<T, break_type>) {
1701 return rhs._tag == tag_type::flow_break;
1702 } else if constexpr (std::is_same_v<T, continue_type>) {
1703 return rhs._tag == tag_type::flow_continue;
1704 } else if constexpr (std::is_same_v<T, std::string>) {
1705 return rhs._tag == tag_type::string;
1706 } else if constexpr (std::is_same_v<T, vector_type>) {
1707 return rhs._tag == tag_type::vector;
1708 } else if constexpr (std::is_same_v<T, map_type>) {
1709 return rhs._tag == tag_type::map;
1710 } else if constexpr (std::is_same_v<T, bstring>) {
1711 return rhs._tag == tag_type::bstring;
1712 } else {
1713 hi_static_no_default();
1714 }
1715 }
1716
1728 template<typename To>
1729 [[nodiscard]] friend constexpr bool promotable_to(datum const& rhs) noexcept
1730 {
1731 if constexpr (std::is_same_v<To, double>) {
1734 } else if constexpr (std::is_same_v<To, decimal>) {
1736 } else if constexpr (std::is_same_v<To, long long>) {
1738 } else {
1739 return holds_alternative<To>(rhs);
1740 }
1741 }
1742
1751 template<typename T>
1752 [[nodiscard]] friend constexpr T const& get(datum const& rhs) noexcept
1753 {
1754 hi_axiom(holds_alternative<T>(rhs));
1755 if constexpr (std::is_same_v<T, double>) {
1756 return rhs._value._double;
1757 } else if constexpr (std::is_same_v<T, decimal>) {
1758 return rhs._value._decimal;
1759 } else if constexpr (std::is_same_v<T, long long>) {
1760 return rhs._value._long_long;
1761 } else if constexpr (std::is_same_v<T, bool>) {
1762 return rhs._value._bool;
1763 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1764 return rhs._value._year_month_day;
1765 } else if constexpr (std::is_same_v<T, std::string>) {
1766 return *rhs._value._string;
1767 } else if constexpr (std::is_same_v<T, vector_type>) {
1768 return *rhs._value._vector;
1769 } else if constexpr (std::is_same_v<T, map_type>) {
1770 return *rhs._value._map;
1771 } else if constexpr (std::is_same_v<T, bstring>) {
1772 return *rhs._value._bstring;
1773 } else {
1774 hi_static_no_default();
1775 }
1776 }
1777
1786 template<typename T>
1787 [[nodiscard]] friend constexpr T& get(datum& rhs) noexcept
1788 {
1789 hi_axiom(holds_alternative<T>(rhs));
1790 if constexpr (std::is_same_v<T, double>) {
1791 return rhs._value._double;
1792 } else if constexpr (std::is_same_v<T, decimal>) {
1793 return rhs._value._decimal;
1794 } else if constexpr (std::is_same_v<T, long long>) {
1795 return rhs._value._long_long;
1796 } else if constexpr (std::is_same_v<T, bool>) {
1797 return rhs._value._bool;
1798 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1799 return rhs._value._year_month_day;
1800 } else if constexpr (std::is_same_v<T, std::string>) {
1801 return *rhs._value._string;
1802 } else if constexpr (std::is_same_v<T, vector_type>) {
1803 return *rhs._value._vector;
1804 } else if constexpr (std::is_same_v<T, map_type>) {
1805 return *rhs._value._map;
1806 } else if constexpr (std::is_same_v<T, bstring>) {
1807 return *rhs._value._bstring;
1808 } else {
1809 hi_static_no_default();
1810 }
1811 }
1812
1821 template<typename T>
1822 [[nodiscard]] friend constexpr T *get_if(datum& rhs) noexcept
1823 {
1824 if (holds_alternative<T>(rhs)) {
1825 return &get<T>(rhs);
1826 } else {
1827 return nullptr;
1828 }
1829 }
1830
1839 template<typename T>
1840 [[nodiscard]] friend constexpr T const *get_if(datum const& rhs) noexcept
1841 {
1842 if (holds_alternative<T>(rhs)) {
1843 return &get<T>(rhs);
1844 } else {
1845 return nullptr;
1846 }
1847 }
1848
1858 template<typename T>
1859 [[nodiscard]] friend T *get_if(datum& rhs, jsonpath const& path) noexcept
1860 {
1861 if (auto *value = rhs.find_one(path)) {
1862 if (holds_alternative<T>(*value)) {
1863 return &get<T>(*value);
1864 } else {
1865 return nullptr;
1866 }
1867 } else {
1868 return nullptr;
1869 }
1870 }
1871
1881 template<typename T>
1882 [[nodiscard]] friend T const *get_if(datum const& rhs, jsonpath const& path) noexcept
1883 {
1884 if (auto *value = const_cast<datum&>(rhs).find_one(path)) {
1885 if (holds_alternative<T>(*value)) {
1886 return &get<T>(*value);
1887 } else {
1888 return nullptr;
1889 }
1890 } else {
1891 return nullptr;
1892 }
1893 }
1894
1895private:
1896 enum class tag_type : signed char {
1897 // scalars are detected by: `std::to_underlying(tag_type) >= 0`
1898 monostate = 0,
1899 floating_point = 1,
1900 integral = 2,
1901 decimal = 3,
1902 boolean = 4,
1903 null = 5,
1904 year_month_day = 6,
1905 flow_continue = 7,
1906 flow_break = 8,
1907
1908 // pointers are detected by: `std::to_underlying(tag_type) < 0`.
1909 string = -1,
1910 vector = -2,
1911 map = -3,
1912 bstring = -5
1913 };
1914
1915 tag_type _tag = tag_type::monostate;
1916 union value_type {
1917 double _double;
1918 long long _long_long;
1919 decimal _decimal;
1920 bool _bool;
1921 std::chrono::year_month_day _year_month_day;
1922 std::string *_string;
1923 vector_type *_vector;
1924 map_type *_map;
1925 bstring *_bstring;
1926
1927 constexpr value_type(numeric_integral auto value) noexcept : _long_long(narrow_cast<long long>(value)) {}
1928 constexpr value_type(std::floating_point auto value) noexcept : _double(narrow_cast<double>(value)) {}
1929 constexpr value_type(decimal value) noexcept : _decimal(value) {}
1930 constexpr value_type(bool value) noexcept : _bool(value) {}
1931 constexpr value_type(std::chrono::year_month_day value) noexcept : _year_month_day(value) {}
1932 constexpr value_type(std::string *value) noexcept : _string(value) {}
1933 constexpr value_type(vector_type *value) noexcept : _vector(value) {}
1934 constexpr value_type(map_type *value) noexcept : _map(value) {}
1935 constexpr value_type(bstring *value) noexcept : _bstring(value) {}
1936 };
1937
1938 value_type _value;
1939
1940 [[nodiscard]] constexpr bool is_scalar() const noexcept
1941 {
1942 return std::to_underlying(_tag) >= 0;
1943 }
1944
1945 [[nodiscard]] constexpr bool is_pointer() const noexcept
1946 {
1947 return std::to_underlying(_tag) < 0;
1948 }
1949
1950 hi_no_inline void copy_pointer(datum const& other) noexcept
1951 {
1952 hi_axiom(other.is_pointer());
1953 switch (other._tag) {
1954 case tag_type::string:
1955 _value._string = new std::string{*other._value._string};
1956 return;
1957 case tag_type::vector:
1958 _value._vector = new vector_type{*other._value._vector};
1959 return;
1960 case tag_type::map:
1961 _value._map = new map_type{*other._value._map};
1962 return;
1963 case tag_type::bstring:
1964 _value._bstring = new bstring{*other._value._bstring};
1965 return;
1966 default:
1967 hi_no_default();
1968 }
1969 }
1970
1971 hi_no_inline void _delete_pointer() noexcept
1972 {
1973 hi_axiom(is_pointer());
1974 switch (_tag) {
1975 case tag_type::string:
1976 delete _value._string;
1977 return;
1978 case tag_type::vector:
1979 delete _value._vector;
1980 return;
1981 case tag_type::map:
1982 delete _value._map;
1983 return;
1984 case tag_type::bstring:
1985 delete _value._bstring;
1986 return;
1987 default:
1988 hi_no_default();
1989 }
1990 }
1991
1992 constexpr void delete_pointer() noexcept
1993 {
1994 if (is_pointer()) {
1995 _delete_pointer();
1996 }
1997 }
1998
1999 void find_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *>& r) noexcept
2000 {
2001 if (auto vector = get_if<datum::vector_type>(*this)) {
2002 for (auto& item : *vector) {
2003 item.find(it + 1, it_end, r);
2004 }
2005
2006 } else if (auto map = get_if<datum::map_type>(*this)) {
2007 for (auto& item : *map) {
2008 item.second.find(it + 1, it_end, r);
2009 }
2010 }
2011 }
2012
2013 void find_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *>& r) noexcept
2014 {
2015 this->find(it + 1, it_end, r);
2016
2017 if (auto vector = get_if<datum::vector_type>(*this)) {
2018 for (auto& item : *vector) {
2019 item.find(it, it_end, r);
2020 }
2021
2022 } else if (auto map = get_if<datum::map_type>(*this)) {
2023 for (auto& item : *map) {
2024 item.second.find(it, it_end, r);
2025 }
2026 }
2027 }
2028
2029 void find_indices(
2030 jsonpath::indices const& indices,
2031 jsonpath::const_iterator it,
2032 jsonpath::const_iterator it_end,
2033 std::vector<datum *>& r) noexcept
2034 {
2035 if (auto vector = get_if<datum::vector_type>(*this)) {
2036 for (hilet index : indices.filter(ssize(*vector))) {
2037 (*vector)[index].find(it + 1, it_end, r);
2038 }
2039 }
2040 }
2041
2042 void find_names(
2043 jsonpath::names const& names,
2044 jsonpath::const_iterator it,
2045 jsonpath::const_iterator it_end,
2046 std::vector<datum *>& r) noexcept
2047 {
2048 if (auto map = get_if<datum::map_type>(*this)) {
2049 for (hilet& name : names) {
2050 hilet name_ = datum{name};
2051 auto jt = map->find(name_);
2052 if (jt != map->cend()) {
2053 jt->second.find(it + 1, it_end, r);
2054 }
2055 }
2056 }
2057 }
2058
2059 void find_slice(
2060 jsonpath::slice const& slice,
2061 jsonpath::const_iterator it,
2062 jsonpath::const_iterator it_end,
2063 std::vector<datum *>& r) noexcept
2064 {
2065 if (auto vector = get_if<datum::vector_type>(*this)) {
2066 hilet first = slice.begin(vector->size());
2067 hilet last = slice.end(vector->size());
2068
2069 for (auto index = first; index != last; index += slice.step) {
2070 if (index >= 0 and index < vector->size()) {
2071 (*this)[index].find(it + 1, it_end, r);
2072 }
2073 }
2074 }
2075 }
2076
2077 void find(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *>& r) noexcept
2078 {
2079 if (it == it_end) {
2080 r.push_back(this);
2081
2082 } else if (std::holds_alternative<jsonpath::root>(*it)) {
2083 find(it + 1, it_end, r);
2084
2085 } else if (std::holds_alternative<jsonpath::current>(*it)) {
2086 find(it + 1, it_end, r);
2087
2088 } else if (std::holds_alternative<jsonpath::wildcard>(*it)) {
2089 find_wildcard(it, it_end, r);
2090
2091 } else if (std::holds_alternative<jsonpath::descend>(*it)) {
2092 find_descend(it, it_end, r);
2093
2094 } else if (auto indices = std::get_if<jsonpath::indices>(&*it)) {
2095 find_indices(*indices, it, it_end, r);
2096
2097 } else if (auto names = std::get_if<jsonpath::names>(&*it)) {
2098 find_names(*names, it, it_end, r);
2099
2100 } else if (auto slice = std::get_if<jsonpath::slice>(&*it)) {
2101 find_slice(*slice, it, it_end, r);
2102
2103 } else {
2104 hi_no_default();
2105 }
2106 }
2107
2108 [[nodiscard]] int remove_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2109 {
2110 int r = 0;
2111
2112 if (auto vector = get_if<datum::vector_type>(*this)) {
2113 auto jt = vector->begin();
2114 while (jt != vector->end()) {
2115 hilet match = jt->remove(it + 1, it_end);
2116 r |= match ? 1 : 0;
2117
2118 if (match == 2) {
2119 jt = vector->erase(jt);
2120 } else {
2121 ++jt;
2122 }
2123 }
2124 return vector->empty() ? 2 : r;
2125
2126 } else if (auto map = get_if<datum::map_type>(*this)) {
2127 auto jt = map->begin();
2128 while (jt != map->end()) {
2129 hilet match = jt->second.remove(it + 1, it_end);
2130 r |= match ? 1 : 0;
2131
2132 if (match == 2) {
2133 jt = map->erase(jt);
2134 } else {
2135 ++jt;
2136 }
2137 }
2138 return map->empty() ? 2 : r;
2139
2140 } else {
2141 return 0;
2142 }
2143 }
2144
2145 [[nodiscard]] int remove_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2146 {
2147 int r = 0;
2148
2149 {
2150 hilet match = this->remove(it + 1, it_end);
2151 if (match == 2) {
2152 return 2;
2153 }
2154 r |= match ? 1 : 0;
2155 }
2156
2157 if (auto vector = get_if<datum::vector_type>(*this)) {
2158 auto jt = vector->begin();
2159 while (jt != vector->end()) {
2160 hilet match = jt->remove(it, it_end);
2161 r |= match ? 1 : 0;
2162
2163 if (match == 2) {
2164 jt = vector->erase(jt);
2165 } else {
2166 ++jt;
2167 }
2168 }
2169 return vector->empty() ? 2 : r;
2170
2171 } else if (auto map = get_if<datum::map_type>(*this)) {
2172 auto jt = map->begin();
2173 while (jt != map->end()) {
2174 hilet match = jt->second.remove(it, it_end);
2175 r |= match ? 1 : 0;
2176
2177 if (match == 2) {
2178 jt = map->erase(jt);
2179 } else {
2180 ++jt;
2181 }
2182 }
2183 return map->empty() ? 2 : r;
2184
2185 } else {
2186 return 0;
2187 }
2188 }
2189
2190 [[nodiscard]] int
2191 remove_indices(jsonpath::indices const& indices, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2192 {
2193 if (auto vector = get_if<datum::vector_type>(*this)) {
2194 int r = 0;
2195 std::size_t offset = 0;
2196
2197 for (hilet index : indices.filter(ssize(*vector))) {
2198 hilet match = (*vector)[index - offset].remove(it + 1, it_end);
2199 r |= match ? 1 : 0;
2200 if (match == 2) {
2201 vector->erase(vector->begin() + (index - offset));
2202 ++offset;
2203 }
2204 }
2205
2206 return vector->empty() ? 2 : r;
2207
2208 } else {
2209 return 0;
2210 }
2211 }
2212
2213 [[nodiscard]] int
2214 remove_names(jsonpath::names const& names, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2215 {
2216 if (auto map = get_if<datum::map_type>(*this)) {
2217 int r = 0;
2218
2219 for (hilet& name : names) {
2220 hilet name_ = datum{name};
2221 auto jt = map->find(name_);
2222 if (jt != map->cend()) {
2223 hilet match = jt->second.remove(it + 1, it_end);
2224 r |= match ? 1 : 0;
2225 if (match == 2) {
2226 map->erase(jt);
2227 }
2228 }
2229 }
2230
2231 return map->empty() ? 2 : r;
2232
2233 } else {
2234 return 0;
2235 }
2236 }
2237
2238 [[nodiscard]] int
2239 remove_slice(jsonpath::slice const& slice, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2240 {
2241 if (auto vector = get_if<datum::vector_type>(*this)) {
2242 int r = 0;
2243
2244 hilet first = slice.begin(vector->size());
2245 hilet last = slice.end(vector->size());
2246
2247 std::size_t offset = 0;
2248 for (auto index = first; index != last; index += slice.step) {
2249 if (index >= 0 and index < vector->size()) {
2250 hilet match = (*this)[index - offset].remove(it + 1, it_end);
2251 r |= match ? 1 : 0;
2252
2253 if (match == 2) {
2254 vector->erase(vector->begin() + (index - offset));
2255 ++offset;
2256 }
2257 }
2258 }
2259
2260 return vector->empty() ? 2 : r;
2261
2262 } else {
2263 return 0;
2264 }
2265 }
2266
2267 [[nodiscard]] int remove(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2268 {
2269 if (it == it_end) {
2270 // Reached end, remove matching name or index in parent.
2271 return 2;
2272
2273 } else if (std::holds_alternative<jsonpath::root>(*it)) {
2274 return remove(it + 1, it_end);
2275
2276 } else if (std::holds_alternative<jsonpath::current>(*it)) {
2277 return remove(it + 1, it_end);
2278
2279 } else if (std::holds_alternative<jsonpath::wildcard>(*it)) {
2280 return remove_wildcard(it, it_end);
2281
2282 } else if (std::holds_alternative<jsonpath::descend>(*it)) {
2283 return remove_descend(it, it_end);
2284
2285 } else if (auto indices = std::get_if<jsonpath::indices>(&*it)) {
2286 return remove_indices(*indices, it, it_end);
2287
2288 } else if (auto names = std::get_if<jsonpath::names>(&*it)) {
2289 return remove_names(*names, it, it_end);
2290
2291 } else if (auto slice = std::get_if<jsonpath::slice>(&*it)) {
2292 return remove_slice(*slice, it, it_end);
2293
2294 } else {
2295 hi_no_default();
2296 }
2297 }
2298
2299 [[nodiscard]] datum *
2300 find_one_name(datum const& name, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2301 {
2302 hi_axiom(holds_alternative<std::string>(name));
2303
2304 if (auto *map = get_if<map_type>(*this)) {
2305 auto i = map->find(name);
2306 if (i != map->end()) {
2307 return i->second.find_one(it + 1, it_end, create);
2308
2309 } else if (create) {
2310 (*map)[name] = datum{std::monostate{}};
2311 return find_one_name(name, it, it_end, create);
2312
2313 } else {
2314 return nullptr;
2315 }
2316
2317 } else if (holds_alternative<std::monostate>(*this) and create) {
2318 *this = datum::make_map(name, std::monostate{});
2319 return find_one_name(name, it, it_end, create);
2320
2321 } else {
2322 return nullptr;
2323 }
2324 }
2325
2326 [[nodiscard]] datum *
2327 find_one_index(std::size_t index, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2328 {
2329 if (auto *vector = get_if<vector_type>(*this)) {
2330 if (index < vector->size()) {
2331 return (*vector)[index].find_one(it + 1, it_end, create);
2332 } else if (index == vector->size() and create) {
2333 vector->push_back(datum{std::monostate{}});
2334 return find_one_index(index, it, it_end, create);
2335 } else {
2336 return nullptr;
2337 }
2338
2339 } else if (holds_alternative<std::monostate>(*this) and index == 0 and create) {
2340 *this = datum::make_vector(std::monostate{});
2341 return find_one_index(index, it, it_end, create);
2342
2343 } else {
2344 return nullptr;
2345 }
2346 }
2347
2348 [[nodiscard]] datum *find_one(jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2349 {
2350 if (it == it_end) {
2351 return this;
2352
2353 } else if (std::holds_alternative<jsonpath::root>(*it)) {
2354 return find_one(it + 1, it_end, create);
2355
2356 } else if (std::holds_alternative<jsonpath::current>(*it)) {
2357 return find_one(it + 1, it_end, create);
2358
2359 } else if (hilet *indices = std::get_if<jsonpath::indices>(&*it)) {
2360 hi_axiom(indices->size() == 1);
2361 return find_one_index(indices->front(), it, it_end, create);
2362
2363 } else if (hilet *names = std::get_if<jsonpath::names>(&*it)) {
2364 hi_axiom(names->size() == 1);
2365 return find_one_name(datum{names->front()}, it, it_end, create);
2366
2367 } else {
2368 hi_no_default();
2369 }
2370 }
2371};
2372
2373}} // namespace hi::v1
2374
2375hi_export template<>
2376struct std::hash<hi::datum> {
2377 [[nodiscard]] inline std::size_t operator()(hi::datum const& rhs) const noexcept
2378 {
2379 return rhs.hash();
2380 }
2381};
2382
2383hi_export template<typename CharT>
2384struct std::formatter<hi::datum, CharT> : std::formatter<std::string, CharT> {
2385 auto format(hi::datum const& t, auto& fc) const
2386 {
2387 return std::formatter<std::string, CharT>{}.format(to_string(t), fc);
2388 }
2389};
2390
2391hi_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.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Promotion result.
Definition datum.hpp:43
Definition datum.hpp:183
A dynamic data type.
Definition datum.hpp:212
vector_type keys() const
Get the sorted list of keys of a map.
Definition datum.hpp:867
constexpr bool is_break() const noexcept
Check if the result of a expression was a break flow control statement.
Definition datum.hpp:686
friend constexpr T & get(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1787
friend constexpr bool promotable_to(datum const &rhs) noexcept
Check if the type held by the datum can be promoted.
Definition datum.hpp:1729
constexpr bool is_continue() const noexcept
Check if the result of a expression was a continue flow control statement.
Definition datum.hpp:694
bool remove(jsonpath const &path) noexcept
Remove the object by path.
Definition datum.hpp:989
friend constexpr auto promote_if(datum const &lhs, datum const &rhs) noexcept
Promote two datum-arguments to a common type.
Definition datum.hpp:226
friend std::string to_string(datum const &rhs) noexcept
Get the string representation of the value.
Definition datum.hpp:1672
friend constexpr T const * get_if(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1840
friend constexpr bool holds_alternative(datum const &rhs) noexcept
Check if the stored value is of a specific type.
Definition datum.hpp:1684
constexpr bool is_undefined() const noexcept
Check if the datum has an undefined value.
Definition datum.hpp:678
vector_type items() const
Get key value pairs of items of a map sorted by the key.
Definition datum.hpp:899
friend T * get_if(datum &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1859
datum const * find_one(jsonpath const &path) const noexcept
Find a object by path.
Definition datum.hpp:1021
friend T const * get_if(datum const &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1882
datum * find_one_or_create(jsonpath const &path) noexcept
Find a object by path potentially creating intermediate objects.
Definition datum.hpp:1010
friend constexpr T const & get(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1752
datum * find_one(jsonpath const &path) noexcept
Find a object by path.
Definition datum.hpp:999
friend constexpr T * get_if(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1822
vector_type values() const
Get the list of values of a map.
Definition datum.hpp:883
Definition datum.hpp:216
Definition datum.hpp:217
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)