HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
datum.hpp
1// Copyright Take Vos 2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "exception.hpp"
8#include "assert.hpp"
9#include "concepts.hpp"
10#include "required.hpp"
11#include "decimal.hpp"
12#include "URL.hpp"
13#include "byte_string.hpp"
14#include "hash.hpp"
15#include "charconv.hpp"
16#include "codec/base_n.hpp"
17#include "jsonpath.hpp"
18#include <cstdint>
19#include <concepts>
20#include <bit>
21#include <exception>
22#include <chrono>
23#include <limits>
24#include <vector>
25#include <map>
26
27namespace hi::inline v1 {
28class datum;
29}
30
31template<>
32struct std::hash<hi::datum> {
33 [[nodiscard]] constexpr std::size_t operator()(hi::datum const &rhs) const noexcept;
34};
35
36namespace hi::inline v1 {
37namespace detail {
38
43template<typename To>
45public:
46 using value_type = To;
47 static constexpr bool data_is_pointer = sizeof(value_type) > sizeof(void *);
48 static constexpr 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
71 constexpr datum_promotion_result(datum_promotion_result &&other) noexcept :
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
161 using data_type = std::conditional_t<data_is_pointer, value_type const *, value_type>;
162 data_type _lhs = data_type{};
163 data_type _rhs = data_type{};
164 bool _is_result = false;
165 bool _owns_lhs = false;
166 bool _owns_rhs = false;
167};
168
169} // namespace detail
170
171template<typename T>
173};
174
175template<>
176class is_datum_type<long long> : public std::true_type {
177};
178template<>
180};
181template<>
182class is_datum_type<double> : public std::true_type {
183};
184template<>
185class is_datum_type<bool> : public std::true_type {
186};
187template<>
188class is_datum_type<std::chrono::year_month_day> : public std::true_type {
189};
190template<>
191class is_datum_type<std::string> : public std::true_type {
192};
193template<>
195};
196
197template<typename T>
198constexpr bool is_datum_type_v = is_datum_type<T>::value;
199
209class datum {
210public:
213 struct break_type {
214 };
216 };
217
218 constexpr ~datum() noexcept
219 {
220 delete_pointer();
221 }
222
223 constexpr datum(datum const &other) noexcept : _tag(other._tag), _value(other._value)
224 {
225 if (other.is_pointer()) {
226 copy_pointer(other);
227 }
228 }
229
230 constexpr datum(datum &&other) noexcept : _tag(other._tag), _value(other._value)
231 {
232 other._tag = tag_type::monostate;
233 other._value._long_long = 0;
234 }
235
236 constexpr datum() noexcept : _tag(tag_type::monostate), _value(0) {}
237 constexpr explicit datum(std::monostate) noexcept : _tag(tag_type::monostate), _value(0) {}
238 constexpr explicit datum(nullptr_t) noexcept : _tag(tag_type::null), _value(0) {}
239 constexpr explicit datum(continue_type) noexcept : _tag(tag_type::flow_continue), _value(0) {}
240 constexpr explicit datum(break_type) noexcept : _tag(tag_type::flow_break), _value(0) {}
241 constexpr explicit datum(bool value) noexcept : _tag(tag_type::boolean), _value(value) {}
242 constexpr explicit datum(std::floating_point auto value) noexcept :
243 _tag(tag_type::floating_point), _value(static_cast<double>(value))
244 {
245 }
246
247 constexpr explicit datum(numeric_integral auto value) noexcept :
248 _tag(tag_type::integral), _value(static_cast<long long>(value))
249 {
250 }
251
252 constexpr explicit datum(decimal value) noexcept : _tag(tag_type::decimal), _value(value) {}
253 constexpr explicit datum(std::chrono::year_month_day value) noexcept : _tag(tag_type::year_month_day), _value(value) {}
254 explicit datum(std::string value) noexcept : _tag(tag_type::string), _value(new std::string{std::move(value)}) {}
255 explicit datum(std::string_view value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
256 explicit datum(char const *value) noexcept : _tag(tag_type::string), _value(new std::string{value}) {}
257 explicit datum(vector_type value) noexcept : _tag(tag_type::vector), _value(new vector_type{std::move(value)}) {}
258 explicit datum(map_type value) noexcept : _tag(tag_type::map), _value(new map_type{std::move(value)}) {}
259 explicit datum(URL value) noexcept : _tag(tag_type::url), _value(new URL{std::move(value)}) {}
260 explicit datum(bstring value) noexcept : _tag(tag_type::bstring), _value(new bstring{std::move(value)}) {}
261
262 template<typename... Args>
263 [[nodiscard]] static datum make_vector(Args const &...args) noexcept
264 {
265 return datum{vector_type{datum{args}...}};
266 }
267
268 template<typename Key, typename Value, typename... Args>
269 [[nodiscard]] static void populate_map(map_type &r, Key const &key, Value const &value, Args const &...args) noexcept
270 {
271 r.insert(std::pair<datum, datum>{datum{key}, datum{value}});
272 if constexpr (sizeof...(Args) > 0) {
273 populate_map(r, args...);
274 }
275 }
276
277 template<typename... Args>
278 [[nodiscard]] static datum make_map(Args const &...args) noexcept
279 {
280 static_assert(sizeof...(Args) % 2 == 0, "Expect key value pairs for the arguments of make_map()");
281
282 auto r = map_type{};
283 if constexpr (sizeof...(Args) > 0) {
284 populate_map(r, args...);
285 }
286 return datum{std::move(r)};
287 }
288
289 [[nodiscard]] static datum make_break() noexcept
290 {
291 return datum{break_type{}};
292 }
293
294 [[nodiscard]] static datum make_continue() noexcept
295 {
296 return datum{continue_type{}};
297 }
298
299 constexpr datum &operator=(datum const &other) noexcept
300 {
301 hi_return_on_self_assignment(other);
302
303 delete_pointer();
304 _tag = other._tag;
305 _value = other._value;
306 if (other.is_pointer()) {
307 copy_pointer(other);
308 }
309 return *this;
310 }
311
312 constexpr datum &operator=(datum &&other) noexcept
313 {
314 std::swap(_tag, other._tag);
315 std::swap(_value, other._value);
316 return *this;
317 }
318
319 constexpr datum &operator=(std::floating_point auto value) noexcept(sizeof(value) <= 4)
320 {
321 delete_pointer();
322 _tag = tag_type::floating_point;
323 _value = static_cast<double>(value);
324 return *this;
325 }
326
327 constexpr datum &operator=(numeric_integral auto value) noexcept(sizeof(value) <= 4)
328 {
329 delete_pointer();
330 _tag = tag_type::integral;
331 _value = static_cast<long long>(value);
332 return *this;
333 }
334
335 constexpr datum &operator=(decimal value)
336 {
337 delete_pointer();
338 _tag = tag_type::decimal;
339 _value = value;
340 return *this;
341 }
342 constexpr datum &operator=(bool value) noexcept
343 {
344 delete_pointer();
345 _tag = tag_type::boolean;
346 _value = value;
347 return *this;
348 }
349
350 constexpr datum &operator=(std::chrono::year_month_day value) noexcept
351 {
352 delete_pointer();
353 _tag = tag_type::year_month_day;
354 _value = value;
355 return *this;
356 }
357
358 constexpr datum &operator=(std::monostate) noexcept
359 {
360 delete_pointer();
361 _tag = tag_type::monostate;
362 _value = 0;
363 return *this;
364 }
365
366 constexpr datum &operator=(nullptr_t) noexcept
367 {
368 delete_pointer();
369 _tag = tag_type::null;
370 _value = 0;
371 return *this;
372 }
373
374 datum &operator=(std::string value) noexcept
375 {
376 delete_pointer();
377 _tag = tag_type::string;
378 _value = new std::string{std::move(value)};
379 return *this;
380 }
381
382 datum &operator=(char const *value) noexcept
383 {
384 delete_pointer();
385 _tag = tag_type::string;
386 _value = new std::string{value};
387 return *this;
388 }
389
390 datum &operator=(std::string_view value) noexcept
391 {
392 delete_pointer();
393 _tag = tag_type::string;
394 _value = new std::string{value};
395 return *this;
396 }
397
398 datum &operator=(vector_type value) noexcept
399 {
400 delete_pointer();
401 _tag = tag_type::vector;
402 _value = new vector_type{std::move(value)};
403 return *this;
404 }
405
406 datum &operator=(map_type value) noexcept
407 {
408 delete_pointer();
409 _tag = tag_type::map;
410 _value = new map_type{std::move(value)};
411 return *this;
412 }
413
414 datum &operator=(URL value) noexcept
415 {
416 delete_pointer();
417 _tag = tag_type::url;
418 _value = new URL{std::move(value)};
419 return *this;
420 }
421
422 datum &operator=(bstring value) noexcept
423 {
424 delete_pointer();
425 _tag = tag_type::bstring;
426 _value = new bstring{std::move(value)};
427 return *this;
428 }
429
430 constexpr explicit operator bool() const noexcept
431 {
432 switch (_tag) {
433 case tag_type::floating_point: return static_cast<bool>(get<double>(*this));
434 case tag_type::decimal: return static_cast<bool>(get<decimal>(*this));
435 case tag_type::boolean: return get<bool>(*this);
436 case tag_type::integral: return static_cast<bool>(get<long long>(*this));
437 case tag_type::year_month_day: return true;
438 case tag_type::string: return not get<std::string>(*this).empty();
439 case tag_type::vector: return not get<vector_type>(*this).empty();
440 case tag_type::map: return not get<map_type>(*this).empty();
441 case tag_type::url: return not get<URL>(*this).empty();
442 case tag_type::bstring: return not get<bstring>(*this).empty();
443 default: return false;
444 }
445 }
446
447 [[nodiscard]] constexpr bool empty() const
448 {
449 switch (_tag) {
450 case tag_type::string: return get<std::string>(*this).empty();
451 case tag_type::vector: return get<vector_type>(*this).empty();
452 case tag_type::map: return get<map_type>(*this).empty();
453 case tag_type::url: return get<URL>(*this).empty();
454 case tag_type::bstring: return get<bstring>(*this).empty();
455 default: throw std::domain_error(std::format("Type {} can not be checked for empty", *this));
456 }
457 }
458
459 template<std::floating_point T>
460 constexpr explicit operator T() const
461 {
462 switch (_tag) {
463 case tag_type::floating_point: return static_cast<T>(get<double>(*this));
464 case tag_type::integral: return static_cast<T>(get<long long>(*this));
465 case tag_type::decimal: return static_cast<T>(get<decimal>(*this));
466 case tag_type::boolean: return static_cast<T>(get<bool>(*this));
467 default: throw std::domain_error(std::format("Can't convert {} to floating point", *this));
468 }
469 }
470
471 constexpr explicit operator decimal() const
472 {
473 switch (_tag) {
474 case tag_type::floating_point: return decimal(get<double>(*this));
475 case tag_type::integral: return decimal(get<long long>(*this));
476 case tag_type::decimal: return get<decimal>(*this);
477 case tag_type::boolean: return decimal(get<bool>(*this));
478 default: throw std::domain_error(std::format("Can't convert {} to floating point", *this));
479 }
480 }
481
482 template<numeric_integral T>
483 constexpr explicit operator T() const
484 {
485 if (auto f = get_if<double>(*this)) {
486 errno = 0;
487 auto r = std::round(*f);
488 if (errno == EDOM or errno == ERANGE or r < std::numeric_limits<T>::min() or r > std::numeric_limits<T>::max()) {
489 throw std::overflow_error("double to integral");
490 }
491 return static_cast<T>(r);
492
493 } else if (auto i = get_if<long long>(*this)) {
495 throw std::overflow_error("long long to integral");
496 }
497 return static_cast<T>(*i);
498
499 } else if (auto d = get_if<decimal>(*this)) {
500 auto r = static_cast<long long>(*d);
502 throw std::overflow_error("decimal to integral");
503 }
504 return static_cast<T>(r);
505
506 } else if (auto b = get_if<bool>(*this)) {
507 return static_cast<T>(*b);
508
509 } else {
510 throw std::domain_error(std::format("Can't convert {} to an integral", repr(*this)));
511 }
512 }
513
514 constexpr explicit operator std::chrono::year_month_day() const
515 {
516 if (auto ymd = get_if<std::chrono::year_month_day>(*this)) {
517 return *ymd;
518 } else {
519 throw std::domain_error(std::format("Can't convert {} to an std::chrono::year_month_day", repr(*this)));
520 }
521 }
522
523 explicit operator std::string() const noexcept
524 {
525 switch (_tag) {
526 case tag_type::monostate: return "undefined";
527 case tag_type::floating_point: return hi::to_string(_value._double);
528 case tag_type::decimal: return to_string(_value._decimal);
529 case tag_type::integral: return to_string(_value._long_long);
530 case tag_type::boolean: return _value._bool ? "true" : "false";
531 case tag_type::year_month_day: return std::format("{:%Y-%m-%d}", _value._year_month_day);
532 case tag_type::null: return "null";
533 case tag_type::flow_break: return "break";
534 case tag_type::flow_continue: return "continue";
535 case tag_type::string: return *_value._string;
536 case tag_type::url: return to_string(*_value._url);
537 case tag_type::vector: {
538 auto r = std::string{"["};
539 for (hilet &item : *_value._vector) {
540 r += repr(item);
541 r += ',';
542 }
543 r += ']';
544 return r;
545 };
546 case tag_type::map: {
547 auto r = std::string{"{"};
548 for (hilet &item : *_value._map) {
549 r += repr(item.first);
550 r += ':';
551 r += repr(item.second);
552 r += ',';
553 }
554 r += '}';
555 return r;
556 };
557 case tag_type::bstring: return base64::encode(*_value._bstring);
558 default: hi_no_default();
559 }
560 }
561
562 explicit operator std::string_view() const
563 {
564 if (auto s = get_if<std::string>(*this)) {
565 return std::string_view{*s};
566 } else if (auto u = get_if<URL>(*this)) {
567 return std::string_view{to_string(*u)};
568 } else {
569 throw std::domain_error(std::format("Can't convert {} to an std::string_view", repr(*this)));
570 }
571 }
572
573 explicit operator vector_type() const
574 {
575 if (auto v = get_if<vector_type>(*this)) {
576 return *v;
577 } else {
578 throw std::domain_error(std::format("Can't convert {} to an vector", repr(*this)));
579 }
580 }
581
582 explicit operator map_type() const
583 {
584 if (auto m = get_if<map_type>(*this)) {
585 return *m;
586 } else {
587 throw std::domain_error(std::format("Can't convert {} to an map", repr(*this)));
588 }
589 }
590
591 explicit operator URL() const
592 {
593 if (auto u = get_if<URL>(*this)) {
594 return *u;
595 } else if (auto s = get_if<std::string>(*this)) {
596 return URL{*s};
597 } else {
598 throw std::domain_error(std::format("Can't convert {} to an URL", repr(*this)));
599 }
600 }
601
602 explicit operator bstring() const
603 {
604 // XXX should be able to base-64 decode a std::string.
605 if (_tag != tag_type::bstring) {
606 throw std::domain_error(std::format("Can't convert {} to an bstring", repr(*this)));
607 }
608 return get<bstring>(*this);
609 }
610
611 [[nodiscard]] constexpr char const *type_name() const noexcept
612 {
613 switch (_tag) {
614 case tag_type::floating_point: return "float";
615 case tag_type::decimal: return "decimal";
616 case tag_type::integral: return "int";
617 case tag_type::boolean: return "bool";
618 case tag_type::year_month_day: return "date";
619 case tag_type::string: return "string";
620 case tag_type::url: return "url";
621 case tag_type::vector: return "vector";
622 case tag_type::map: return "map";
623 case tag_type::bstring: return "bytes";
624 default: hi_no_default();
625 }
626 }
627
630 [[nodiscard]] constexpr bool is_undefined() const noexcept
631 {
632 return _tag == tag_type::monostate;
633 }
634
638 [[nodiscard]] constexpr bool is_break() const noexcept
639 {
640 return _tag == tag_type::flow_break;
641 }
642
646 [[nodiscard]] constexpr bool is_continue() const noexcept
647 {
648 return _tag == tag_type::flow_continue;
649 }
650
651 [[nodiscard]] constexpr std::size_t hash() const noexcept
652 {
653 switch (_tag) {
654 case tag_type::floating_point: return std::hash<double>{}(_value._double);
655 case tag_type::decimal: return std::hash<decimal>{}(_value._decimal);
656 case tag_type::integral: return std::hash<long long>{}(_value._long_long);
657 case tag_type::boolean: return std::hash<bool>{}(_value._bool);
658 case tag_type::year_month_day: {
659 uint32_t r = 0;
660 r |= static_cast<uint32_t>(static_cast<int>(_value._year_month_day.year())) << 16;
661 r |= static_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.month())) << 8;
662 r |= static_cast<uint32_t>(static_cast<unsigned>(_value._year_month_day.day()));
663 return std::hash<uint32_t>{}(r);
664 }
665 case tag_type::string: return std::hash<std::string>{}(*_value._string);
666 case tag_type::vector: {
667 std::size_t r = 0;
668 for (hilet &v : *_value._vector) {
669 r = hash_mix(r, v.hash());
670 }
671 return r;
672 }
673 case tag_type::map: {
674 std::size_t r = 0;
675 for (hilet &kv : *_value._map) {
676 r = hash_mix(r, kv.first.hash(), kv.second.hash());
677 }
678 return r;
679 }
680 case tag_type::url: return std::hash<URL>{}(*_value._url);
681 case tag_type::bstring: return std::hash<bstring>{}(*_value._bstring);
682 default: hi_no_default();
683 }
684 }
685
686 [[nodiscard]] constexpr std::size_t size() const
687 {
688 if (hilet *s = get_if<std::string>(*this)) {
689 return s->size();
690 } else if (hilet *v = get_if<vector_type>(*this)) {
691 return v->size();
692 } else if (hilet *m = get_if<map_type>(*this)) {
693 return m->size();
694 } else if (hilet *b = get_if<bstring>(*this)) {
695 return b->size();
696 } else {
697 throw std::domain_error(std::format("Can not evaluate {}.size()", repr(*this)));
698 }
699 }
700
701 [[nodiscard]] constexpr friend std::size_t size(datum const &rhs)
702 {
703 return rhs.size();
704 }
705
706 [[nodiscard]] constexpr datum const &back() const
707 {
708 if (hilet *v = get_if<vector_type>(*this)) {
709 if (v->empty()) {
710 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
711 }
712 return v->back();
713 } else {
714 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
715 }
716 }
717
718 [[nodiscard]] constexpr datum &back()
719 {
720 if (auto *v = get_if<vector_type>(*this)) {
721 if (v->empty()) {
722 throw std::domain_error(std::format("Empty vector {}.back()", repr(*this)));
723 }
724 return v->back();
725 } else {
726 throw std::domain_error(std::format("Can not evaluate {}.back()", repr(*this)));
727 }
728 }
729
730 [[nodiscard]] constexpr datum const &front() const
731 {
732 if (hilet *v = get_if<vector_type>(*this)) {
733 if (v->empty()) {
734 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
735 }
736 return v->front();
737 } else {
738 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
739 }
740 }
741
742 [[nodiscard]] constexpr datum &front()
743 {
744 if (auto *v = get_if<vector_type>(*this)) {
745 if (v->empty()) {
746 throw std::domain_error(std::format("Empty vector {}.front()", repr(*this)));
747 }
748 return v->front();
749 } else {
750 throw std::domain_error(std::format("Can not evaluate {}.front()", repr(*this)));
751 }
752 }
753
754 [[nodiscard]] constexpr auto cbegin() const
755 {
756 if (hilet *v = get_if<vector_type>(*this)) {
757 return v->cbegin();
758 } else {
759 throw std::domain_error(std::format("Can not evaluate {}.cbegin()", repr(*this)));
760 }
761 }
762
763 [[nodiscard]] constexpr auto begin() const
764 {
765 if (hilet *v = get_if<vector_type>(*this)) {
766 return v->begin();
767 } else {
768 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
769 }
770 }
771
772 [[nodiscard]] constexpr auto begin()
773 {
774 if (hilet *v = get_if<vector_type>(*this)) {
775 return v->begin();
776 } else {
777 throw std::domain_error(std::format("Can not evaluate {}.begin()", repr(*this)));
778 }
779 }
780
781 [[nodiscard]] constexpr auto cend() const
782 {
783 if (hilet *v = get_if<vector_type>(*this)) {
784 return v->cend();
785 } else {
786 throw std::domain_error(std::format("Can not evaluate {}.cend()", repr(*this)));
787 }
788 }
789
790 [[nodiscard]] constexpr auto end() const
791 {
792 if (hilet *v = get_if<vector_type>(*this)) {
793 return v->end();
794 } else {
795 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
796 }
797 }
798
799 [[nodiscard]] constexpr auto end()
800 {
801 if (hilet *v = get_if<vector_type>(*this)) {
802 return v->end();
803 } else {
804 throw std::domain_error(std::format("Can not evaluate {}.end()", repr(*this)));
805 }
806 }
807
810 [[nodiscard]] constexpr vector_type keys() const
811 {
812 if (hilet *m = get_if<map_type>(*this)) {
813 auto r = vector_type{};
814 r.reserve(m->size());
815 for (hilet &kv : *m) {
816 r.push_back(kv.first);
817 }
818 return r;
819 } else {
820 throw std::domain_error(std::format("Can not evaluate {}.keys()", repr(*this)));
821 }
822 }
823
826 [[nodiscard]] constexpr vector_type values() const
827 {
828 if (hilet *m = get_if<map_type>(*this)) {
829 auto r = vector_type{};
830 r.reserve(m->size());
831 for (hilet &kv : *m) {
832 r.push_back(kv.second);
833 }
834 return r;
835 } else {
836 throw std::domain_error(std::format("Can not evaluate {}.values()", repr(*this)));
837 }
838 }
839
842 [[nodiscard]] constexpr vector_type items() const
843 {
844 if (hilet *m = get_if<map_type>(*this)) {
845 auto r = vector_type{};
846 r.reserve(m->size());
847
848 for (hilet &item : *m) {
849 r.push_back(make_vector(item.first, item.second));
850 }
851 return r;
852 } else {
853 throw std::domain_error(std::format("Can not evaluate {}.items()", repr(*this)));
854 }
855 }
856
857 constexpr void push_back(datum const &rhs)
858 {
859 if (auto *v = get_if<vector_type>(*this)) {
860 return v->push_back(rhs);
861 } else {
862 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
863 }
864 }
865
866 constexpr void push_back(datum &&rhs)
867 {
868 if (auto *v = get_if<vector_type>(*this)) {
869 return v->push_back(std::move(rhs));
870 } else {
871 throw std::domain_error(std::format("Can not evaluate {}.push_back({})", repr(*this), repr(rhs)));
872 }
873 }
874
875 template<typename Arg>
876 constexpr void push_back(Arg &&arg)
877 {
878 push_back(datum{std::forward<Arg>(arg)});
879 }
880
881 constexpr void pop_back()
882 {
883 if (auto *v = get_if<vector_type>(*this)) {
884 if (v->empty()) {
885 throw std::domain_error(std::format("Empty vector {}.pop_back()", repr(*this)));
886 }
887 return v->pop_back();
888 } else {
889 throw std::domain_error(std::format("Can not evaluate {}.pop_back()", repr(*this)));
890 }
891 }
892
893 [[nodiscard]] constexpr bool contains(datum const &rhs) const
894 {
895 if (auto *m = get_if<map_type>(*this)) {
896 return m->contains(rhs);
897 } else {
898 throw std::domain_error(std::format("Can not evaluate {}.contains({})", repr(*this), repr(rhs)));
899 }
900 }
901
902 template<typename Arg>
903 [[nodiscard]] constexpr bool contains(Arg const &arg) const
904 {
905 return contains(datum{arg});
906 }
907
908 [[nodiscard]] std::vector<datum *> find(jsonpath const &path) noexcept
909 {
910 auto r = std::vector<datum *>{};
911 find(path.cbegin(), path.cend(), r);
912 return r;
913 }
914
915 [[nodiscard]] std::vector<datum const *> find(jsonpath const &path) const noexcept
916 {
917 auto tmp = std::vector<datum *>{};
918 const_cast<datum *>(this)->find(path.cbegin(), path.cend(), tmp);
920 std::copy(tmp.begin(), tmp.end(), std::back_inserter(r));
921 return r;
922 }
923
932 [[nodiscard]] bool remove(jsonpath const &path) noexcept
933 {
934 return static_cast<bool>(remove(path.cbegin(), path.cend()));
935 }
936
942 [[nodiscard]] datum *find_one(jsonpath const &path) noexcept
943 {
944 hi_axiom(path.is_singular());
945 return find_one(path.cbegin(), path.cend(), false);
946 }
947
953 [[nodiscard]] datum *find_one_or_create(jsonpath const &path) noexcept
954 {
955 hi_axiom(path.is_singular());
956 return find_one(path.cbegin(), path.cend(), true);
957 }
958
964 [[nodiscard]] datum const *find_one(jsonpath const &path) const noexcept
965 {
966 hi_axiom(path.is_singular());
967 return const_cast<datum *>(this)->find_one(path.cbegin(), path.cend(), false);
968 }
969
970 [[nodiscard]] constexpr datum const &operator[](datum const &rhs) const
971 {
972 if (holds_alternative<vector_type>(*this) and holds_alternative<long long>(rhs)) {
973 hilet &v = get<vector_type>(*this);
974
975 auto index = get<long long>(rhs);
976 if (index < 0) {
977 index = ssize(v) + index;
978 }
979 if (index < 0 or index >= ssize(v)) {
980 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
981 }
982
983 return v[index];
984
985 } else if (holds_alternative<map_type>(*this)) {
986 hilet &m = get<map_type>(*this);
987 hilet it = m.find(rhs);
988 if (it == m.end()) {
989 throw std::overflow_error(std::format("Key {} not found in map", repr(rhs)));
990 }
991
992 return it->second;
993
994 } else {
995 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
996 }
997 }
998
999 [[nodiscard]] constexpr datum &operator[](datum const &rhs)
1000 {
1001 if (holds_alternative<vector_type>(*this) and holds_alternative<long long>(rhs)) {
1002 auto &v = get<vector_type>(*this);
1003
1004 auto index = get<long long>(rhs);
1005 if (index < 0) {
1006 index = ssize(v) + index;
1007 }
1008 if (index < 0 or index >= ssize(v)) {
1009 throw std::overflow_error(std::format("Index {} beyond bounds of vector", repr(rhs)));
1010 }
1011
1012 return v[index];
1013
1014 } else if (holds_alternative<map_type>(*this)) {
1015 auto &m = get<map_type>(*this);
1016 return m[rhs];
1017
1018 } else {
1019 throw std::domain_error(std::format("Can not evaluate {}[{}]", repr(*this), repr(rhs)));
1020 }
1021 }
1022
1023 [[nodiscard]] constexpr datum const &operator[](auto const &rhs) const
1024 {
1025 return (*this)[datum{rhs}];
1026 }
1027
1028 [[nodiscard]] constexpr datum &operator[](auto const &rhs)
1029 {
1030 return (*this)[datum{rhs}];
1031 }
1032
1033 [[nodiscard]] constexpr datum &operator++()
1034 {
1035 if (holds_alternative<long long>(*this)) {
1036 ++_value._long_long;
1037 return *this;
1038 } else {
1039 throw std::domain_error(std::format("Can not evaluate ++{}", repr(*this)));
1040 }
1041 }
1042
1043 [[nodiscard]] constexpr datum &operator--()
1044 {
1045 if (holds_alternative<long long>(*this)) {
1046 --_value._long_long;
1047 return *this;
1048 } else {
1049 throw std::domain_error(std::format("Can not evaluate --{}", repr(*this)));
1050 }
1051 }
1052
1053 [[nodiscard]] constexpr datum operator++(int)
1054 {
1055 if (holds_alternative<long long>(*this)) {
1056 auto tmp = *this;
1057 _value._long_long++;
1058 return tmp;
1059 } else {
1060 throw std::domain_error(std::format("Can not evaluate {}++", repr(*this)));
1061 }
1062 }
1063 [[nodiscard]] constexpr datum operator--(int)
1064 {
1065 if (holds_alternative<long long>(*this)) {
1066 auto tmp = *this;
1067 _value._long_long--;
1068 return tmp;
1069 } else {
1070 throw std::domain_error(std::format("Can not evaluate {}--", repr(*this)));
1071 }
1072 }
1073
1074 constexpr datum &operator+=(auto const &rhs)
1075 {
1076 if (holds_alternative<vector_type>(*this)) {
1077 push_back(rhs);
1078 return *this;
1079 } else {
1080 return (*this) = (*this) + rhs;
1081 }
1082 }
1083
1084#define X(op, inner_op) \
1085 constexpr datum &operator op(auto const &rhs) \
1086 { \
1087 return (*this) = (*this)inner_op rhs; \
1088 }
1089
1090 X(-=, -)
1091 X(*=, *)
1092 X(/=, /)
1093 X(%=, %)
1094 X(&=, &)
1095 X(|=, |)
1096 X(^=, ^)
1097 X(<<=, <<)
1098 X(>>=, >>)
1099#undef X
1100
1101 [[nodiscard]] friend constexpr bool operator==(datum const &lhs, datum const &rhs) noexcept
1102 {
1103 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1104 return doubles.lhs() == doubles.rhs();
1105
1106 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1107 return decimals.lhs() == decimals.rhs();
1108
1109 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1110 return long_longs.lhs() == long_longs.rhs();
1111
1112 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1113 return bools.lhs() == bools.rhs();
1114
1115 } else if (hilet ymds = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1116 return ymds.lhs() == ymds.rhs();
1117
1118 } else if (hilet urls = promote_if<URL>(lhs, rhs)) {
1119 return urls.lhs() == urls.rhs();
1120
1121 } else if (hilet strings = promote_if<std::string>(lhs, rhs)) {
1122 return strings.lhs() == strings.rhs();
1123
1124 } else if (hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1125 return vectors.lhs() == vectors.rhs();
1126
1127 } else if (hilet maps = promote_if<map_type>(lhs, rhs)) {
1128 return maps.lhs() == maps.rhs();
1129
1130 } else {
1131 return lhs._tag == rhs._tag;
1132 }
1133 }
1134
1165 [[nodiscard]] friend constexpr std::partial_ordering operator<=>(datum const &lhs, datum const &rhs) noexcept
1166 {
1167 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1168 return doubles.lhs() <=> doubles.rhs();
1169
1170 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1171 return decimals.lhs() <=> decimals.rhs();
1172
1173 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1174 return long_longs.lhs() <=> long_longs.rhs();
1175
1176 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1177 return bools.lhs() <=> bools.rhs();
1178
1179 } else if (hilet year_month_days = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1180 return year_month_days.lhs() <=> year_month_days.rhs();
1181
1182 } else if (hilet urls = promote_if<URL>(lhs, rhs)) {
1183 return urls.lhs() <=> urls.rhs();
1184
1185 } else if (hilet strings = promote_if<std::string>(lhs, rhs)) {
1186 return strings.lhs() <=> strings.rhs();
1187
1188 } else if (hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1189 return vectors.lhs() <=> vectors.rhs();
1190
1191 } else if (hilet maps = promote_if<map_type>(lhs, rhs)) {
1192 return maps.lhs() <=> maps.rhs();
1193
1194 } else if (hilet bstrings = promote_if<bstring>(lhs, rhs)) {
1195 return bstrings.lhs() <=> bstrings.rhs();
1196
1197 } else {
1198 return lhs._tag <=> rhs._tag;
1199 }
1200 }
1201
1212 [[nodiscard]] friend constexpr datum operator-(datum const &rhs)
1213 {
1214 if (hilet rhs_double = get_if<double>(rhs)) {
1215 return datum{-*rhs_double};
1216
1217 } else if (hilet rhs_decimal = get_if<decimal>(rhs)) {
1218 return datum{-*rhs_decimal};
1219
1220 } else if (hilet rhs_long_long = get_if<long long>(rhs)) {
1221 return datum{-*rhs_long_long};
1222
1223 } else {
1224 throw std::domain_error(std::format("Can not evaluate -{}", repr(rhs)));
1225 }
1226 }
1227
1237 [[nodiscard]] friend constexpr datum operator~(datum const &rhs)
1238 {
1239 if (hilet rhs_long_long = get_if<long long>(rhs)) {
1240 return datum{~*rhs_long_long};
1241
1242 } else {
1243 throw std::domain_error(std::format("Can not evaluate ~{}", repr(rhs)));
1244 }
1245 }
1246
1261 [[nodiscard]] friend constexpr datum operator+(datum const &lhs, datum const &rhs)
1262 {
1263 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1264 return datum{doubles.lhs() + doubles.rhs()};
1265
1266 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1267 return datum{decimals.lhs() + decimals.rhs()};
1268
1269 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1270 return datum{long_longs.lhs() + long_longs.rhs()};
1271
1272 } else if (hilet strings = promote_if<std::string>(lhs, rhs)) {
1273 return datum{strings.lhs() + strings.rhs()};
1274
1275 } else if (hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1276 auto r = vectors.lhs();
1277 r.insert(r.end(), vectors.rhs().begin(), vectors.rhs().end());
1278 return datum{std::move(r)};
1279
1280 } else {
1281 throw std::domain_error(std::format("Can not evaluate {} '+' {}", repr(lhs), repr(rhs)));
1282 }
1283 }
1284
1296 [[nodiscard]] friend constexpr datum operator-(datum const &lhs, datum const &rhs)
1297 {
1298 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1299 return datum{doubles.lhs() - doubles.rhs()};
1300
1301 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1302 return datum{decimals.lhs() - decimals.rhs()};
1303
1304 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1305 return datum{long_longs.lhs() - long_longs.rhs()};
1306
1307 } else {
1308 throw std::domain_error(std::format("Can not evaluate {} '-' {}", repr(lhs), repr(rhs)));
1309 }
1310 }
1311
1323 [[nodiscard]] friend constexpr datum operator*(datum const &lhs, datum const &rhs)
1324 {
1325 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1326 return datum{doubles.lhs() * doubles.rhs()};
1327
1328 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1329 return datum{decimals.lhs() * decimals.rhs()};
1330
1331 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1332 return datum{long_longs.lhs() * long_longs.rhs()};
1333
1334 } else {
1335 throw std::domain_error(std::format("Can not evaluate {} '*' {}", repr(lhs), repr(rhs)));
1336 }
1337 }
1338
1352 [[nodiscard]] friend constexpr datum operator/(datum const &lhs, datum const &rhs)
1353 {
1354 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1355 if (doubles.rhs() == 0) {
1356 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1357 }
1358 return datum{doubles.lhs() / doubles.rhs()};
1359
1360 } else if (hilet decimals = promote_if<decimal>(lhs, rhs)) {
1361 if (decimals.rhs() == 0) {
1362 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1363 }
1364 return datum{decimals.lhs() / decimals.rhs()};
1365
1366 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1367 if (long_longs.rhs() == 0) {
1368 throw std::domain_error(std::format("Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1369 }
1370 return datum{long_longs.lhs() / long_longs.rhs()};
1371
1372 } else if (hilet urls = promote_if<URL>(lhs, rhs)) {
1373 return datum{urls.lhs() / urls.rhs()};
1374
1375 } else {
1376 throw std::domain_error(std::format("Can not evaluate {} '/' {}", repr(lhs), repr(rhs)));
1377 }
1378 }
1379
1391 [[nodiscard]] friend constexpr datum operator%(datum const &lhs, datum const &rhs)
1392 {
1393 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1394 if (long_longs.rhs() == 0) {
1395 throw std::domain_error(std::format("Divide by zero {} '%' {}", repr(lhs), repr(rhs)));
1396 }
1397 return datum{long_longs.lhs() % long_longs.rhs()};
1398
1399 } else {
1400 throw std::domain_error(std::format("Can not evaluate {} '%' {}", repr(lhs), repr(rhs)));
1401 }
1402 }
1403
1414 [[nodiscard]] friend constexpr datum pow(datum const &lhs, datum const &rhs)
1415 {
1416 if (hilet doubles = promote_if<double>(lhs, rhs)) {
1417 return datum{pow(doubles.lhs(), doubles.rhs())};
1418
1419 } else if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1420 return datum{pow(long_longs.lhs(), long_longs.rhs())};
1421
1422 } else {
1423 throw std::domain_error(std::format("Can not evaluate pow({}, {})", repr(lhs), repr(rhs)));
1424 }
1425 }
1426
1437 [[nodiscard]] friend constexpr datum operator&(datum const &lhs, datum const &rhs)
1438 {
1439 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1440 return datum{long_longs.lhs() & long_longs.rhs()};
1441
1442 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1443 return datum{bools.lhs() and bools.rhs()};
1444
1445 } else {
1446 throw std::domain_error(std::format("Can not evaluate {} '&' {}", repr(lhs), repr(rhs)));
1447 }
1448 }
1449
1460 [[nodiscard]] friend constexpr datum operator|(datum const &lhs, datum const &rhs)
1461 {
1462 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1463 return datum{long_longs.lhs() | long_longs.rhs()};
1464
1465 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1466 return datum{bools.lhs() or bools.rhs()};
1467
1468 } else {
1469 throw std::domain_error(std::format("Can not evaluate {} '|' {}", repr(lhs), repr(rhs)));
1470 }
1471 }
1472
1483 [[nodiscard]] friend constexpr datum operator^(datum const &lhs, datum const &rhs)
1484 {
1485 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1486 return datum{long_longs.lhs() ^ long_longs.rhs()};
1487
1488 } else if (hilet bools = promote_if<bool>(lhs, rhs)) {
1489 return datum{bools.lhs() != bools.rhs()};
1490
1491 } else {
1492 throw std::domain_error(std::format("Can not evaluate {} '^' {}", repr(lhs), repr(rhs)));
1493 }
1494 }
1495
1508 [[nodiscard]] friend constexpr datum operator<<(datum const &lhs, datum const &rhs)
1509 {
1510 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1511 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1512 throw std::domain_error(std::format("Invalid shift count {} '<<' {}", repr(lhs), repr(rhs)));
1513 }
1514 return datum{long_longs.lhs() << long_longs.rhs()};
1515
1516 } else {
1517 throw std::domain_error(std::format("Can not evaluate {} '<<' {}", repr(lhs), repr(rhs)));
1518 }
1519 }
1520
1532 [[nodiscard]] friend constexpr datum operator>>(datum const &lhs, datum const &rhs)
1533 {
1534 if (hilet long_longs = promote_if<long long>(lhs, rhs)) {
1535 if (long_longs.rhs() < 0 or long_longs.rhs() > (sizeof(long long) * CHAR_BIT - 1)) {
1536 throw std::domain_error(std::format("Invalid shift count {} '>>' {}", repr(lhs), repr(rhs)));
1537 }
1538 return datum{long_longs.lhs() >> long_longs.rhs()};
1539
1540 } else {
1541 throw std::domain_error(std::format("Can not evaluate {} '>>' {}", repr(lhs), repr(rhs)));
1542 }
1543 }
1544
1545 friend std::ostream &operator<<(std::ostream &lhs, datum const &rhs)
1546 {
1547 return lhs << to_string(rhs);
1548 }
1549
1550#define X(op) \
1551 [[nodiscard]] friend constexpr auto operator op(datum const &lhs, auto const &rhs) noexcept(noexcept(lhs op datum{rhs})) \
1552 { \
1553 return lhs op datum{rhs}; \
1554 } \
1555 [[nodiscard]] friend constexpr auto operator op(auto const &lhs, datum const &rhs) noexcept(noexcept(datum{lhs} op rhs)) \
1556 { \
1557 return datum{lhs} op rhs; \
1558 }
1559
1560 X(==)
1561 X(<=>)
1562 X(+)
1563 X(-)
1564 X(*)
1565 X(/)
1566 X(%)
1567 X(&)
1568 X(|)
1569 X(^) X(<<) X(>>)
1570#undef X
1571
1574 [[nodiscard]] friend std::string repr(datum const &rhs) noexcept
1575 {
1576 switch (rhs._tag) {
1577 case tag_type::monostate: return "undefined";
1578 case tag_type::floating_point: return std::format("{:.1f}", rhs._value._double);
1579 case tag_type::decimal: return to_string(rhs._value._decimal);
1580 case tag_type::integral: return std::format("{}", rhs._value._long_long);
1581 case tag_type::boolean: return rhs._value._bool ? "true" : "false";
1582 case tag_type::year_month_day: return std::format("{:%Y-%m-%d}", rhs._value._year_month_day);
1583 case tag_type::null: return "null";
1584 case tag_type::flow_break: return "break";
1585 case tag_type::flow_continue: return "continue";
1586 case tag_type::string: return std::format("\"{}\"", *rhs._value._string);
1587 case tag_type::url: return to_string(*rhs._value._url);
1588 case tag_type::vector: {
1589 auto r = std::string{"["};
1590 for (hilet &item : *rhs._value._vector) {
1591 r += repr(item);
1592 r += ',';
1593 }
1594 r += ']';
1595 return r;
1596 };
1597 case tag_type::map: {
1598 auto r = std::string{"{"};
1599 for (hilet &item : *rhs._value._map) {
1600 r += repr(item.first);
1601 r += ':';
1602 r += repr(item.second);
1603 r += ',';
1604 }
1605 r += '}';
1606 return r;
1607 };
1608 case tag_type::bstring: return base64::encode(*rhs._value._bstring);
1609 default: hi_no_default();
1610 }
1611 }
1612
1615 [[nodiscard]] friend std::string to_string(datum const &rhs) noexcept
1616 {
1617 return static_cast<std::string>(rhs);
1618 }
1619
1626 template<typename T>
1627 [[nodiscard]] friend constexpr bool holds_alternative(datum const &rhs) noexcept
1628 {
1629 if constexpr (std::is_same_v<T, double>) {
1630 return rhs._tag == tag_type::floating_point;
1631 } else if constexpr (std::is_same_v<T, decimal>) {
1632 return rhs._tag == tag_type::decimal;
1633 } else if constexpr (std::is_same_v<T, long long>) {
1634 return rhs._tag == tag_type::integral;
1635 } else if constexpr (std::is_same_v<T, bool>) {
1636 return rhs._tag == tag_type::boolean;
1637 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1638 return rhs._tag == tag_type::year_month_day;
1639 } else if constexpr (std::is_same_v<T, nullptr_t>) {
1640 return rhs._tag == tag_type::null;
1641 } else if constexpr (std::is_same_v<T, std::monostate>) {
1642 return rhs._tag == tag_type::monostate;
1643 } else if constexpr (std::is_same_v<T, break_type>) {
1644 return rhs._tag == tag_type::flow_break;
1645 } else if constexpr (std::is_same_v<T, continue_type>) {
1646 return rhs._tag == tag_type::flow_continue;
1647 } else if constexpr (std::is_same_v<T, std::string>) {
1648 return rhs._tag == tag_type::string;
1649 } else if constexpr (std::is_same_v<T, vector_type>) {
1650 return rhs._tag == tag_type::vector;
1651 } else if constexpr (std::is_same_v<T, map_type>) {
1652 return rhs._tag == tag_type::map;
1653 } else if constexpr (std::is_same_v<T, URL>) {
1654 return rhs._tag == tag_type::url;
1655 } else if constexpr (std::is_same_v<T, bstring>) {
1656 return rhs._tag == tag_type::bstring;
1657 } else {
1658 hi_static_no_default();
1659 }
1660 }
1661
1675 template<typename To>
1676 [[nodiscard]] friend constexpr bool promotable_to(datum const &rhs) noexcept
1677 {
1678 if constexpr (std::is_same_v<To, double>) {
1679 return holds_alternative<double>(rhs) or holds_alternative<decimal>(rhs) or holds_alternative<long long>(rhs) or
1680 holds_alternative<bool>(rhs);
1681 } else if constexpr (std::is_same_v<To, decimal>) {
1682 return holds_alternative<decimal>(rhs) or holds_alternative<long long>(rhs) or holds_alternative<bool>(rhs);
1683 } else if constexpr (std::is_same_v<To, long long>) {
1684 return holds_alternative<long long>(rhs) or holds_alternative<bool>(rhs);
1685 } else if constexpr (std::is_same_v<To, std::string>) {
1686 return holds_alternative<URL>(rhs) or holds_alternative<std::string>(rhs);
1687 } else if constexpr (std::is_same_v<To, URL>) {
1688 return holds_alternative<URL>(rhs) or holds_alternative<std::string>(rhs);
1689 } else {
1690 return holds_alternative<To>(rhs);
1691 }
1692 }
1693
1702 template<typename T>
1703 [[nodiscard]] friend constexpr T const &get(datum const &rhs) noexcept
1704 {
1705 hi_axiom(holds_alternative<T>(rhs));
1706 if constexpr (std::is_same_v<T, double>) {
1707 return rhs._value._double;
1708 } else if constexpr (std::is_same_v<T, decimal>) {
1709 return rhs._value._decimal;
1710 } else if constexpr (std::is_same_v<T, long long>) {
1711 return rhs._value._long_long;
1712 } else if constexpr (std::is_same_v<T, bool>) {
1713 return rhs._value._bool;
1714 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1715 return rhs._value._year_month_day;
1716 } else if constexpr (std::is_same_v<T, std::string>) {
1717 return *rhs._value._string;
1718 } else if constexpr (std::is_same_v<T, vector_type>) {
1719 return *rhs._value._vector;
1720 } else if constexpr (std::is_same_v<T, map_type>) {
1721 return *rhs._value._map;
1722 } else if constexpr (std::is_same_v<T, URL>) {
1723 return *rhs._value._url;
1724 } else if constexpr (std::is_same_v<T, bstring>) {
1725 return *rhs._value._bstring;
1726 } else {
1727 hi_static_no_default();
1728 }
1729 }
1730
1739 template<typename T>
1740 [[nodiscard]] friend constexpr T &get(datum &rhs) noexcept
1741 {
1742 hi_axiom(holds_alternative<T>(rhs));
1743 if constexpr (std::is_same_v<T, double>) {
1744 return rhs._value._double;
1745 } else if constexpr (std::is_same_v<T, decimal>) {
1746 return rhs._value._decimal;
1747 } else if constexpr (std::is_same_v<T, long long>) {
1748 return rhs._value._long_long;
1749 } else if constexpr (std::is_same_v<T, bool>) {
1750 return rhs._value._bool;
1751 } else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1752 return rhs._value._year_month_day;
1753 } else if constexpr (std::is_same_v<T, std::string>) {
1754 return *rhs._value._string;
1755 } else if constexpr (std::is_same_v<T, vector_type>) {
1756 return *rhs._value._vector;
1757 } else if constexpr (std::is_same_v<T, map_type>) {
1758 return *rhs._value._map;
1759 } else if constexpr (std::is_same_v<T, URL>) {
1760 return *rhs._value._url;
1761 } else if constexpr (std::is_same_v<T, bstring>) {
1762 return *rhs._value._bstring;
1763 } else {
1764 hi_static_no_default();
1765 }
1766 }
1767
1776 template<typename T>
1777 [[nodiscard]] friend constexpr T *get_if(datum &rhs) noexcept
1778 {
1779 if (holds_alternative<T>(rhs)) {
1780 return &get<T>(rhs);
1781 } else {
1782 return nullptr;
1783 }
1784 }
1785
1794 template<typename T>
1795 [[nodiscard]] friend constexpr T const *get_if(datum const &rhs) noexcept
1796 {
1797 if (holds_alternative<T>(rhs)) {
1798 return &get<T>(rhs);
1799 } else {
1800 return nullptr;
1801 }
1802 }
1803
1813 template<typename T>
1814 [[nodiscard]] friend T *get_if(datum &rhs, jsonpath const &path) noexcept
1815 {
1816 if (auto *value = rhs.find_one(path)) {
1817 if (holds_alternative<T>(*value)) {
1818 return &get<T>(*value);
1819 } else {
1820 return nullptr;
1821 }
1822 } else {
1823 return nullptr;
1824 }
1825 }
1826
1836 template<typename T>
1837 [[nodiscard]] friend T const *get_if(datum const &rhs, jsonpath const &path) noexcept
1838 {
1839 if (auto *value = const_cast<datum &>(rhs).find_one(path)) {
1840 if (holds_alternative<T>(*value)) {
1841 return &get<T>(*value);
1842 } else {
1843 return nullptr;
1844 }
1845 } else {
1846 return nullptr;
1847 }
1848 }
1849
1856 template<typename To>
1857 [[nodiscard]] friend constexpr auto promote_if(datum const &lhs, datum const &rhs) noexcept
1858 {
1860 if (holds_alternative<To>(lhs) and holds_alternative<To>(rhs)) {
1861 r.set(get<To>(lhs), get<To>(rhs));
1862
1863 } else if (holds_alternative<To>(lhs) and promotable_to<To>(rhs)) {
1864 r.set(get<To>(lhs), static_cast<To>(rhs));
1865
1866 } else if (promotable_to<To>(lhs) and holds_alternative<To>(rhs)) {
1867 r.set(static_cast<To>(lhs), get<To>(rhs));
1868 }
1869
1870 return r;
1871 }
1872
1873private:
1874 enum class tag_type : signed char {
1875 // scalars are detected by: `to_underlying(tag_type) >= 0`
1876 monostate = 0,
1877 floating_point = 1,
1878 integral = 2,
1879 decimal = 3,
1880 boolean = 4,
1881 null = 5,
1882 year_month_day = 6,
1883 flow_continue = 7,
1884 flow_break = 8,
1885
1886 // pointers are detected by: `to_underlying(tag_type) < 0`.
1887 string = -1,
1888 vector = -2,
1889 map = -3,
1890 url = -4,
1891 bstring = -5,
1892 };
1893
1894 tag_type _tag = tag_type::monostate;
1895 union value_type {
1896 double _double;
1897 long long _long_long;
1898 decimal _decimal;
1899 bool _bool;
1900 std::chrono::year_month_day _year_month_day;
1901 std::string *_string;
1902 vector_type *_vector;
1903 map_type *_map;
1904 URL *_url;
1905 bstring *_bstring;
1906
1907 constexpr value_type(numeric_integral auto value) noexcept : _long_long(static_cast<long long>(value)) {}
1908 constexpr value_type(std::floating_point auto value) noexcept : _double(static_cast<double>(value)) {}
1909 constexpr value_type(decimal value) noexcept : _decimal(value) {}
1910 constexpr value_type(bool value) noexcept : _bool(value) {}
1911 constexpr value_type(std::chrono::year_month_day value) noexcept : _year_month_day(value) {}
1912 constexpr value_type(std::string *value) noexcept : _string(value) {}
1913 constexpr value_type(vector_type *value) noexcept : _vector(value) {}
1914 constexpr value_type(map_type *value) noexcept : _map(value) {}
1915 constexpr value_type(URL *value) noexcept : _url(value) {}
1916 constexpr value_type(bstring *value) noexcept : _bstring(value) {}
1917 };
1918
1919 value_type _value;
1920
1921 [[nodiscard]] constexpr bool is_scalar() const noexcept
1922 {
1923 return to_underlying(_tag) >= 0;
1924 }
1925
1926 [[nodiscard]] constexpr bool is_pointer() const noexcept
1927 {
1928 return to_underlying(_tag) < 0;
1929 }
1930
1931 hi_no_inline void copy_pointer(datum const &other) noexcept
1932 {
1933 hi_axiom(other.is_pointer());
1934 switch (other._tag) {
1935 case tag_type::string: _value._string = new std::string{*other._value._string}; return;
1936 case tag_type::vector: _value._vector = new vector_type{*other._value._vector}; return;
1937 case tag_type::map: _value._map = new map_type{*other._value._map}; return;
1938 case tag_type::url: _value._url = new URL{*other._value._url}; return;
1939 case tag_type::bstring: _value._bstring = new bstring{*other._value._bstring}; return;
1940 default: hi_no_default();
1941 }
1942 }
1943
1944 hi_no_inline void _delete_pointer() noexcept
1945 {
1946 hi_axiom(is_pointer());
1947 switch (_tag) {
1948 case tag_type::string: delete _value._string; return;
1949 case tag_type::vector: delete _value._vector; return;
1950 case tag_type::map: delete _value._map; return;
1951 case tag_type::url: delete _value._url; return;
1952 case tag_type::bstring: delete _value._bstring; return;
1953 default: hi_no_default();
1954 }
1955 }
1956
1957 constexpr void delete_pointer() noexcept
1958 {
1959 if (is_pointer()) {
1960 _delete_pointer();
1961 }
1962 }
1963
1964 void find_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *> &r) noexcept
1965 {
1966 if (auto vector = get_if<datum::vector_type>(*this)) {
1967 for (auto &item : *vector) {
1968 item.find(it + 1, it_end, r);
1969 }
1970
1971 } else if (auto map = get_if<datum::map_type>(*this)) {
1972 for (auto &item : *map) {
1973 item.second.find(it + 1, it_end, r);
1974 }
1975 }
1976 }
1977
1978 void find_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *> &r) noexcept
1979 {
1980 this->find(it + 1, it_end, r);
1981
1982 if (auto vector = get_if<datum::vector_type>(*this)) {
1983 for (auto &item : *vector) {
1984 item.find(it, it_end, r);
1985 }
1986
1987 } else if (auto map = get_if<datum::map_type>(*this)) {
1988 for (auto &item : *map) {
1989 item.second.find(it, it_end, r);
1990 }
1991 }
1992 }
1993
1994 void find_indices(
1995 jsonpath_indices const &indices,
1996 jsonpath::const_iterator it,
1997 jsonpath::const_iterator it_end,
1998 std::vector<datum *> &r) noexcept
1999 {
2000 if (auto vector = get_if<datum::vector_type>(*this)) {
2001 for (hilet index : indices.filter(ssize(*vector))) {
2002 (*vector)[index].find(it + 1, it_end, r);
2003 }
2004 }
2005 }
2006
2007 void find_names(
2008 jsonpath_names const &names,
2009 jsonpath::const_iterator it,
2010 jsonpath::const_iterator it_end,
2011 std::vector<datum *> &r) noexcept
2012 {
2013 if (auto map = get_if<datum::map_type>(*this)) {
2014 for (hilet &name : names) {
2015 hilet name_ = datum{name};
2016 auto jt = map->find(name_);
2017 if (jt != map->cend()) {
2018 jt->second.find(it + 1, it_end, r);
2019 }
2020 }
2021 }
2022 }
2023
2024 void find_slice(
2025 jsonpath_slice const &slice,
2026 jsonpath::const_iterator it,
2027 jsonpath::const_iterator it_end,
2028 std::vector<datum *> &r) noexcept
2029 {
2030 if (auto vector = get_if<datum::vector_type>(*this)) {
2031 hilet first = slice.begin(vector->size());
2032 hilet last = slice.end(vector->size());
2033
2034 for (auto index = first; index != last; index += slice.step) {
2035 if (index >= 0 and index < vector->size()) {
2036 (*this)[index].find(it + 1, it_end, r);
2037 }
2038 }
2039 }
2040 }
2041
2042 void find(jsonpath::const_iterator it, jsonpath::const_iterator it_end, std::vector<datum *> &r) noexcept
2043 {
2044 if (it == it_end) {
2045 r.push_back(this);
2046
2047 } else if (std::holds_alternative<jsonpath_root>(*it)) {
2048 find(it + 1, it_end, r);
2049
2050 } else if (std::holds_alternative<jsonpath_current>(*it)) {
2051 find(it + 1, it_end, r);
2052
2053 } else if (std::holds_alternative<jsonpath_wildcard>(*it)) {
2054 find_wildcard(it, it_end, r);
2055
2056 } else if (std::holds_alternative<jsonpath_descend>(*it)) {
2057 find_descend(it, it_end, r);
2058
2059 } else if (auto indices = std::get_if<jsonpath_indices>(&*it)) {
2060 find_indices(*indices, it, it_end, r);
2061
2062 } else if (auto names = std::get_if<jsonpath_names>(&*it)) {
2063 find_names(*names, it, it_end, r);
2064
2065 } else if (auto slice = std::get_if<jsonpath_slice>(&*it)) {
2066 find_slice(*slice, it, it_end, r);
2067
2068 } else {
2069 hi_no_default();
2070 }
2071 }
2072
2073 [[nodiscard]] int remove_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2074 {
2075 int r = 0;
2076
2077 if (auto vector = get_if<datum::vector_type>(*this)) {
2078 auto jt = vector->begin();
2079 while (jt != vector->end()) {
2080 hilet match = jt->remove(it + 1, it_end);
2081 r |= match ? 1 : 0;
2082
2083 if (match == 2) {
2084 jt = vector->erase(jt);
2085 } else {
2086 ++jt;
2087 }
2088 }
2089 return vector->empty() ? 2 : r;
2090
2091 } else if (auto map = get_if<datum::map_type>(*this)) {
2092 auto jt = map->begin();
2093 while (jt != map->end()) {
2094 hilet match = jt->second.remove(it + 1, it_end);
2095 r |= match ? 1 : 0;
2096
2097 if (match == 2) {
2098 jt = map->erase(jt);
2099 } else {
2100 ++jt;
2101 }
2102 }
2103 return map->empty() ? 2 : r;
2104
2105 } else {
2106 return 0;
2107 }
2108 }
2109
2110 [[nodiscard]] int remove_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2111 {
2112 int r = 0;
2113
2114 {
2115 hilet match = this->remove(it + 1, it_end);
2116 if (match == 2) {
2117 return 2;
2118 }
2119 r |= match ? 1 : 0;
2120 }
2121
2122 if (auto vector = get_if<datum::vector_type>(*this)) {
2123 auto jt = vector->begin();
2124 while (jt != vector->end()) {
2125 hilet match = jt->remove(it, it_end);
2126 r |= match ? 1 : 0;
2127
2128 if (match == 2) {
2129 jt = vector->erase(jt);
2130 } else {
2131 ++jt;
2132 }
2133 }
2134 return vector->empty() ? 2 : r;
2135
2136 } else if (auto map = get_if<datum::map_type>(*this)) {
2137 auto jt = map->begin();
2138 while (jt != map->end()) {
2139 hilet match = jt->second.remove(it, it_end);
2140 r |= match ? 1 : 0;
2141
2142 if (match == 2) {
2143 jt = map->erase(jt);
2144 } else {
2145 ++jt;
2146 }
2147 }
2148 return map->empty() ? 2 : r;
2149
2150 } else {
2151 return 0;
2152 }
2153 }
2154
2155 [[nodiscard]] int
2156 remove_indices(jsonpath_indices const &indices, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2157 {
2158 if (auto vector = get_if<datum::vector_type>(*this)) {
2159 int r = 0;
2160 std::size_t offset = 0;
2161
2162 for (hilet index : indices.filter(ssize(*vector))) {
2163 hilet match = (*vector)[index - offset].remove(it + 1, it_end);
2164 r |= match ? 1 : 0;
2165 if (match == 2) {
2166 vector->erase(vector->begin() + (index - offset));
2167 ++offset;
2168 }
2169 }
2170
2171 return vector->empty() ? 2 : r;
2172
2173 } else {
2174 return 0;
2175 }
2176 }
2177
2178 [[nodiscard]] int
2179 remove_names(jsonpath_names const &names, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2180 {
2181 if (auto map = get_if<datum::map_type>(*this)) {
2182 int r = 0;
2183
2184 for (hilet &name : names) {
2185 hilet name_ = datum{name};
2186 auto jt = map->find(name_);
2187 if (jt != map->cend()) {
2188 hilet match = jt->second.remove(it + 1, it_end);
2189 r |= match ? 1 : 0;
2190 if (match == 2) {
2191 map->erase(jt);
2192 }
2193 }
2194 }
2195
2196 return map->empty() ? 2 : r;
2197
2198 } else {
2199 return 0;
2200 }
2201 }
2202
2203 [[nodiscard]] int
2204 remove_slice(jsonpath_slice const &slice, jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2205 {
2206 if (auto vector = get_if<datum::vector_type>(*this)) {
2207 int r = 0;
2208
2209 hilet first = slice.begin(vector->size());
2210 hilet last = slice.end(vector->size());
2211
2212 std::size_t offset = 0;
2213 for (auto index = first; index != last; index += slice.step) {
2214 if (index >= 0 and index < vector->size()) {
2215 hilet match = (*this)[index - offset].remove(it + 1, it_end);
2216 r |= match ? 1 : 0;
2217
2218 if (match == 2) {
2219 vector->erase(vector->begin() + (index - offset));
2220 ++offset;
2221 }
2222 }
2223 }
2224
2225 return vector->empty() ? 2 : r;
2226
2227 } else {
2228 return 0;
2229 }
2230 }
2231
2232 [[nodiscard]] int remove(jsonpath::const_iterator it, jsonpath::const_iterator it_end) noexcept
2233 {
2234 if (it == it_end) {
2235 // Reached end, remove matching name or index in parent.
2236 return 2;
2237
2238 } else if (std::holds_alternative<jsonpath_root>(*it)) {
2239 return remove(it + 1, it_end);
2240
2241 } else if (std::holds_alternative<jsonpath_current>(*it)) {
2242 return remove(it + 1, it_end);
2243
2244 } else if (std::holds_alternative<jsonpath_wildcard>(*it)) {
2245 return remove_wildcard(it, it_end);
2246
2247 } else if (std::holds_alternative<jsonpath_descend>(*it)) {
2248 return remove_descend(it, it_end);
2249
2250 } else if (auto indices = std::get_if<jsonpath_indices>(&*it)) {
2251 return remove_indices(*indices, it, it_end);
2252
2253 } else if (auto names = std::get_if<jsonpath_names>(&*it)) {
2254 return remove_names(*names, it, it_end);
2255
2256 } else if (auto slice = std::get_if<jsonpath_slice>(&*it)) {
2257 return remove_slice(*slice, it, it_end);
2258
2259 } else {
2260 hi_no_default();
2261 }
2262 }
2263
2264 [[nodiscard]] datum *
2265 find_one_name(datum const &name, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2266 {
2267 hi_axiom(holds_alternative<std::string>(name));
2268
2269 if (auto *map = get_if<map_type>(*this)) {
2270 auto i = map->find(name);
2271 if (i != map->end()) {
2272 return i->second.find_one(it + 1, it_end, create);
2273
2274 } else if (create) {
2275 (*map)[name] = datum{std::monostate{}};
2276 return find_one_name(name, it, it_end, create);
2277
2278 } else {
2279 return nullptr;
2280 }
2281
2282 } else if (holds_alternative<std::monostate>(*this) and create) {
2283 *this = datum::make_map(name, std::monostate{});
2284 return find_one_name(name, it, it_end, create);
2285
2286 } else {
2287 return nullptr;
2288 }
2289 }
2290
2291 [[nodiscard]] datum *
2292 find_one_index(std::size_t index, jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2293 {
2294 if (auto *vector = get_if<vector_type>(*this)) {
2295 if (index < vector->size()) {
2296 return (*vector)[index].find_one(it + 1, it_end, create);
2297 } else if (index == vector->size() and create) {
2298 vector->push_back(datum{std::monostate{}});
2299 return find_one_index(index, it, it_end, create);
2300 } else {
2301 return nullptr;
2302 }
2303
2304 } else if (holds_alternative<std::monostate>(*this) and index == 0 and create) {
2305 *this = datum::make_vector(std::monostate{});
2306 return find_one_index(index, it, it_end, create);
2307
2308 } else {
2309 return nullptr;
2310 }
2311 }
2312
2313 [[nodiscard]] datum *find_one(jsonpath::const_iterator it, jsonpath::const_iterator it_end, bool create) noexcept
2314 {
2315 if (it == it_end) {
2316 return this;
2317
2318 } else if (std::holds_alternative<jsonpath_root>(*it)) {
2319 return find_one(it + 1, it_end, create);
2320
2321 } else if (std::holds_alternative<jsonpath_current>(*it)) {
2322 return find_one(it + 1, it_end, create);
2323
2324 } else if (hilet *indices = std::get_if<jsonpath_indices>(&*it)) {
2325 hi_axiom(indices->size() == 1);
2326 return find_one_index(indices->front(), it, it_end, create);
2327
2328 } else if (hilet *names = std::get_if<jsonpath_names>(&*it)) {
2329 hi_axiom(names->size() == 1);
2330 return find_one_name(datum{names->front()}, it, it_end, create);
2331
2332 } else {
2333 hi_no_default();
2334 }
2335 }
2336};
2337
2338} // namespace hi::inline v1
2339
2340[[nodiscard]] constexpr std::size_t std::hash<hi::datum>::operator()(hi::datum const &rhs) const noexcept
2341{
2342 return rhs.hash();
2343}
2344
2345template<typename CharT>
2346struct std::formatter<hi::datum, CharT> : std::formatter<std::string_view, CharT> {
2347 auto format(hi::datum const &t, auto &fc)
2348 {
2349 return std::formatter<std::string_view, CharT>::format(to_string(t), fc);
2350 }
2351};
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
constexpr alignment operator|(horizontal_alignment lhs, vertical_alignment rhs) noexcept
Combine vertical and horizontal alignment.
Definition alignment.hpp:200
STL namespace.
Promotion result.
Definition datum.hpp:44
Definition datum.hpp:172
A dynamic data type.
Definition datum.hpp:209
friend constexpr T & get(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1740
friend constexpr bool promotable_to(datum const &rhs) noexcept
Check if the type held by the datum can be promoted.
Definition datum.hpp:1676
constexpr bool is_break() const noexcept
Check if the result of a expression was a break flow control statement.
Definition datum.hpp:638
friend constexpr auto promote_if(datum const &lhs, datum const &rhs) noexcept
Promote two datum-arguments to a common type.
Definition datum.hpp:1857
datum const * find_one(jsonpath const &path) const noexcept
Find a object by path.
Definition datum.hpp:964
friend std::string to_string(datum const &rhs) noexcept
Get the string representation of the value.
Definition datum.hpp:1615
friend constexpr T const * get_if(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1795
friend constexpr bool holds_alternative(datum const &rhs) noexcept
Check if the stored value is of a specific type.
Definition datum.hpp:1627
constexpr vector_type items() const
Get key value pairs of items of a map sorted by the key.
Definition datum.hpp:842
bool remove(jsonpath const &path) noexcept
Remove the object by path.
Definition datum.hpp:932
friend T * get_if(datum &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1814
friend T const * get_if(datum const &rhs, jsonpath const &path) noexcept
Get the value of a datum.
Definition datum.hpp:1837
friend constexpr T const & get(datum const &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1703
constexpr vector_type keys() const
Get the sorted list of keys of a map.
Definition datum.hpp:810
datum * find_one_or_create(jsonpath const &path) noexcept
Find a object by path potentially creating intermediate objects.
Definition datum.hpp:953
constexpr bool is_continue() const noexcept
Check if the result of a expression was a continue flow control statement.
Definition datum.hpp:646
constexpr vector_type values() const
Get the list of values of a map.
Definition datum.hpp:826
datum * find_one(jsonpath const &path) noexcept
Find a object by path.
Definition datum.hpp:942
constexpr bool is_undefined() const noexcept
Check if the datum has an undefined value.
Definition datum.hpp:630
friend constexpr T * get_if(datum &rhs) noexcept
Get the value of a datum.
Definition datum.hpp:1777
Definition datum.hpp:213
Definition datum.hpp:215
Definition decimal.hpp:18
Definition jsonpath.hpp:379
T back_inserter(T... args)
T begin(T... args)
T copy(T... args)
T end(T... args)
T find(T... args)
T max(T... args)
T move(T... args)
T operator()(T... args)
T pow(T... args)
T remove(T... args)
T reserve(T... args)
T round(T... args)
T swap(T... args)
T to_string(T... args)