240 template<
typename To>
244 if (holds_alternative<To>(lhs) and holds_alternative<To>(rhs)) {
245 r.set(get<To>(lhs), get<To>(rhs));
247 }
else if (holds_alternative<To>(lhs) and promotable_to<To>(rhs)) {
248 r.set(get<To>(lhs),
static_cast<To
>(rhs));
250 }
else if (promotable_to<To>(lhs) and holds_alternative<To>(rhs)) {
251 r.set(
static_cast<To
>(lhs), get<To>(rhs));
257 constexpr ~datum() noexcept
262 constexpr datum(datum
const& other) noexcept : _tag(other._tag), _value(other._value)
264 if (other.is_pointer()) {
269 constexpr datum(datum&& other) noexcept : _tag(other._tag), _value(other._value)
271 other._tag = tag_type::monostate;
272 other._value._long_long = 0;
275 constexpr datum() noexcept : _tag(tag_type::monostate), _value(0) {}
276 constexpr explicit datum(std::monostate) noexcept : _tag(tag_type::monostate), _value(0) {}
277 constexpr explicit datum(nullptr_t) noexcept : _tag(tag_type::null), _value(0) {}
278 constexpr explicit datum(continue_type) noexcept : _tag(tag_type::flow_continue), _value(0) {}
279 constexpr explicit datum(break_type) noexcept : _tag(tag_type::flow_break), _value(0) {}
280 constexpr explicit datum(
bool value) noexcept : _tag(tag_type::boolean), _value(value) {}
281 constexpr explicit datum(std::floating_point
auto value) noexcept :
282 _tag(tag_type::floating_point), _value(narrow_cast<double>(value))
286 constexpr explicit datum(numeric_integral
auto value) noexcept :
287 _tag(tag_type::integral), _value(narrow_cast<long long>(value))
291 constexpr explicit datum(decimal value) noexcept : _tag(tag_type::decimal), _value(value) {}
292 constexpr explicit datum(std::chrono::year_month_day value) noexcept : _tag(tag_type::year_month_day), _value(value) {}
294 explicit datum(std::string_view value) noexcept : _tag(tag_type::string), _value(
new std::string{value}) {}
295 explicit datum(
char const *value) noexcept : _tag(tag_type::string), _value(
new std::string{value}) {}
296 explicit datum(vector_type value) noexcept : _tag(tag_type::vector), _value(
new vector_type{
std::move(value)}) {}
297 explicit datum(map_type value) noexcept : _tag(tag_type::map), _value(
new map_type{
std::move(value)}) {}
298 explicit datum(URL value) noexcept : _tag(tag_type::url), _value(
new URL{
std::move(value)}) {}
299 explicit datum(bstring value) noexcept : _tag(tag_type::bstring), _value(
new bstring{
std::move(value)}) {}
301 template<
typename... Args>
302 [[nodiscard]]
static datum make_vector(Args
const&...args)
noexcept
304 return datum{vector_type{datum{args}...}};
307 template<
typename Key,
typename Value,
typename... Args>
308 static void populate_map(map_type& r, Key
const& key, Value
const& value, Args
const&...args)
noexcept
311 if constexpr (
sizeof...(Args) > 0) {
312 populate_map(r, args...);
316 template<
typename... Args>
317 [[nodiscard]]
static datum make_map(Args
const&...args)
noexcept
319 static_assert(
sizeof...(Args) % 2 == 0,
"Expect key value pairs for the arguments of make_map()");
322 if constexpr (
sizeof...(Args) > 0) {
323 populate_map(r, args...);
328 [[nodiscard]]
static datum make_break() noexcept
330 return datum{break_type{}};
333 [[nodiscard]]
static datum make_continue() noexcept
335 return datum{continue_type{}};
338 constexpr datum& operator=(datum
const& other)
noexcept
340 hi_return_on_self_assignment(other);
344 _value = other._value;
345 if (other.is_pointer()) {
351 constexpr datum& operator=(datum&& other)
noexcept
358 constexpr datum& operator=(std::floating_point
auto value)
noexcept(
sizeof(value) <= 4)
361 _tag = tag_type::floating_point;
362 _value =
static_cast<double>(value);
366 constexpr datum& operator=(numeric_integral
auto value)
noexcept(
sizeof(value) <= 4)
369 _tag = tag_type::integral;
370 _value =
static_cast<long long>(value);
374 constexpr datum& operator=(decimal value)
377 _tag = tag_type::decimal;
381 constexpr datum& operator=(
bool value)
noexcept
384 _tag = tag_type::boolean;
389 constexpr datum& operator=(std::chrono::year_month_day value)
noexcept
392 _tag = tag_type::year_month_day;
397 constexpr datum& operator=(std::monostate)
noexcept
400 _tag = tag_type::monostate;
405 constexpr datum& operator=(nullptr_t)
noexcept
408 _tag = tag_type::null;
416 _tag = tag_type::string;
421 datum& operator=(
char const *value)
noexcept
424 _tag = tag_type::string;
429 datum& operator=(std::string_view value)
noexcept
432 _tag = tag_type::string;
437 datum& operator=(vector_type value)
noexcept
440 _tag = tag_type::vector;
441 _value =
new vector_type{
std::move(value)};
445 datum& operator=(map_type value)
noexcept
448 _tag = tag_type::map;
453 datum& operator=(URL value)
noexcept
456 _tag = tag_type::url;
461 datum& operator=(bstring value)
noexcept
464 _tag = tag_type::bstring;
469 constexpr explicit operator bool() const noexcept
472 case tag_type::floating_point:
473 return to_bool(get<double>(*
this));
474 case tag_type::decimal:
475 return to_bool(get<decimal>(*
this));
476 case tag_type::boolean:
477 return get<bool>(*
this);
478 case tag_type::integral:
479 return to_bool(get<long long>(*
this));
480 case tag_type::year_month_day:
482 case tag_type::string:
483 return not get<std::string>(*this).empty();
484 case tag_type::vector:
485 return not get<vector_type>(*this).empty();
487 return not get<map_type>(*this).empty();
489 return not get<URL>(*this).empty();
490 case tag_type::bstring:
491 return not get<bstring>(*this).empty();
497 [[nodiscard]]
constexpr bool empty()
const
500 case tag_type::string:
501 return get<std::string>(*this).empty();
502 case tag_type::vector:
503 return get<vector_type>(*this).empty();
505 return get<map_type>(*this).empty();
507 return get<URL>(*this).empty();
508 case tag_type::bstring:
509 return get<bstring>(*this).empty();
511 throw std::domain_error(std::format(
"Type {} can not be checked for empty", *
this));
515 template<std::
floating_po
int T>
516 constexpr explicit operator T()
const
519 case tag_type::floating_point:
520 return static_cast<T
>(get<double>(*
this));
521 case tag_type::integral:
522 return static_cast<T
>(get<long long>(*
this));
523 case tag_type::decimal:
524 return static_cast<T
>(get<decimal>(*
this));
525 case tag_type::boolean:
526 return static_cast<T
>(get<bool>(*
this));
528 throw std::domain_error(std::format(
"Can't convert {} to floating point", *
this));
532 constexpr explicit operator decimal()
const
535 case tag_type::floating_point:
536 return decimal(get<double>(*
this));
537 case tag_type::integral:
538 return decimal(get<long long>(*
this));
539 case tag_type::decimal:
540 return get<decimal>(*
this);
541 case tag_type::boolean:
542 return decimal(get<bool>(*
this));
544 throw std::domain_error(std::format(
"Can't convert {} to floating point", *
this));
548 template<numeric_
integral T>
549 constexpr explicit operator T()
const
551 if (
auto f = get_if<double>(*
this)) {
558 return narrow_cast<T>(r);
560 }
else if (
auto i = get_if<long long>(*
this)) {
564 return narrow_cast<T>(*i);
566 }
else if (
auto d = get_if<decimal>(*
this)) {
567 hilet r =
static_cast<long long>(*d);
571 return narrow_cast<T>(r);
573 }
else if (
auto b = get_if<bool>(*
this)) {
574 return narrow_cast<T>(*b);
577 throw std::domain_error(std::format(
"Can't convert {} to an integral", repr(*
this)));
581 constexpr explicit operator std::chrono::year_month_day()
const
583 if (
auto ymd = get_if<std::chrono::year_month_day>(*
this)) {
586 throw std::domain_error(std::format(
"Can't convert {} to an std::chrono::year_month_day", repr(*
this)));
593 case tag_type::monostate:
595 case tag_type::floating_point:
596 return hi::to_string(_value._double);
597 case tag_type::decimal:
599 case tag_type::integral:
601 case tag_type::boolean:
602 return _value._bool ?
"true" :
"false";
603 case tag_type::year_month_day:
604 return std::format(
"{:%Y-%m-%d}", _value._year_month_day);
607 case tag_type::flow_break:
609 case tag_type::flow_continue:
611 case tag_type::string:
612 return *_value._string;
615 case tag_type::vector:
618 for (
hilet& item : *_value._vector) {
628 for (
hilet& item : *_value._map) {
629 r += repr(item.first);
631 r += repr(item.second);
637 case tag_type::bstring:
638 return base64::encode(*_value._bstring);
644 explicit operator std::string_view()
const
646 if (
auto s = get_if<std::string>(*
this)) {
647 return std::string_view{*s};
648 }
else if (
auto u = get_if<URL>(*
this)) {
651 throw std::domain_error(std::format(
"Can't convert {} to an std::string_view", repr(*
this)));
655 explicit operator vector_type()
const
657 if (
auto v = get_if<vector_type>(*
this)) {
660 throw std::domain_error(std::format(
"Can't convert {} to an vector", repr(*
this)));
664 explicit operator map_type()
const
666 if (
auto m = get_if<map_type>(*
this)) {
673 explicit operator URL()
const
675 if (
auto u = get_if<URL>(*
this)) {
677 }
else if (
auto s = get_if<std::string>(*
this)) {
684 explicit operator bstring()
const
687 if (_tag != tag_type::bstring) {
688 throw std::domain_error(std::format(
"Can't convert {} to an bstring", repr(*
this)));
690 return get<bstring>(*
this);
693 [[nodiscard]]
constexpr char const *type_name() const noexcept
696 case tag_type::floating_point:
698 case tag_type::decimal:
700 case tag_type::integral:
702 case tag_type::boolean:
704 case tag_type::year_month_day:
706 case tag_type::string:
710 case tag_type::vector:
714 case tag_type::bstring:
725 return _tag == tag_type::monostate;
731 [[nodiscard]]
constexpr bool is_break() const noexcept
733 return _tag == tag_type::flow_break;
741 return _tag == tag_type::flow_continue;
747 case tag_type::floating_point:
749 case tag_type::decimal:
751 case tag_type::integral:
753 case tag_type::boolean:
755 case tag_type::year_month_day:
758 r |= narrow_cast<uint32_t>(
static_cast<int>(_value._year_month_day.year())) << 16;
759 r |= narrow_cast<uint32_t>(
static_cast<unsigned>(_value._year_month_day.month())) << 8;
760 r |= narrow_cast<uint32_t>(
static_cast<unsigned>(_value._year_month_day.day()));
763 case tag_type::string:
765 case tag_type::vector:
768 for (
hilet& v : *_value._vector) {
769 r = hash_mix(r, v.hash());
776 for (
hilet& kv : *_value._map) {
777 r = hash_mix(r, kv.first.hash(), kv.second.hash());
783 case tag_type::bstring:
792 if (
hilet *s = get_if<std::string>(*
this)) {
794 }
else if (
hilet *v = get_if<vector_type>(*
this)) {
796 }
else if (
hilet *m = get_if<map_type>(*
this)) {
798 }
else if (
hilet *b = get_if<bstring>(*
this)) {
805 [[nodiscard]]
constexpr friend std::size_t size(datum
const& rhs)
810 [[nodiscard]]
constexpr datum
const& back()
const
812 if (
hilet *v = get_if<vector_type>(*
this)) {
822 [[nodiscard]]
constexpr datum& back()
824 if (
auto *v = get_if<vector_type>(*
this)) {
834 [[nodiscard]]
constexpr datum
const& front()
const
836 if (
hilet *v = get_if<vector_type>(*
this)) {
842 throw std::domain_error(std::format(
"Can not evaluate {}.front()", repr(*
this)));
846 [[nodiscard]]
constexpr datum& front()
848 if (
auto *v = get_if<vector_type>(*
this)) {
854 throw std::domain_error(std::format(
"Can not evaluate {}.front()", repr(*
this)));
858 [[nodiscard]]
constexpr auto cbegin()
const
860 if (
hilet *v = get_if<vector_type>(*
this)) {
863 throw std::domain_error(std::format(
"Can not evaluate {}.cbegin()", repr(*
this)));
867 [[nodiscard]]
constexpr auto begin()
const
869 if (
hilet *v = get_if<vector_type>(*
this)) {
872 throw std::domain_error(std::format(
"Can not evaluate {}.begin()", repr(*
this)));
876 [[nodiscard]]
constexpr auto begin()
878 if (
hilet *v = get_if<vector_type>(*
this)) {
881 throw std::domain_error(std::format(
"Can not evaluate {}.begin()", repr(*
this)));
885 [[nodiscard]]
constexpr auto cend()
const
887 if (
hilet *v = get_if<vector_type>(*
this)) {
894 [[nodiscard]]
constexpr auto end()
const
896 if (
hilet *v = get_if<vector_type>(*
this)) {
903 [[nodiscard]]
constexpr auto end()
905 if (
hilet *v = get_if<vector_type>(*
this)) {
916 if (
hilet *m = get_if<map_type>(*
this)) {
919 for (
hilet& kv : *m) {
920 r.push_back(kv.first);
932 if (
hilet *m = get_if<map_type>(*
this)) {
935 for (
hilet& kv : *m) {
936 r.push_back(kv.second);
940 throw std::domain_error(std::format(
"Can not evaluate {}.values()", repr(*
this)));
948 if (
hilet *m = get_if<map_type>(*
this)) {
952 for (
hilet& item : *m) {
953 r.push_back(make_vector(item.first, item.second));
957 throw std::domain_error(std::format(
"Can not evaluate {}.items()", repr(*
this)));
961 constexpr void push_back(
datum const& rhs)
963 if (
auto *v = get_if<vector_type>(*
this)) {
964 return v->push_back(rhs);
966 throw std::domain_error(std::format(
"Can not evaluate {}.push_back({})", repr(*
this), repr(rhs)));
970 constexpr void push_back(datum&& rhs)
972 if (
auto *v = get_if<vector_type>(*
this)) {
975 throw std::domain_error(std::format(
"Can not evaluate {}.push_back({})", repr(*
this), repr(rhs)));
979 template<
typename Arg>
980 constexpr void push_back(Arg&& arg)
982 push_back(datum{std::forward<Arg>(arg)});
985 constexpr void pop_back()
987 if (
auto *v = get_if<vector_type>(*
this)) {
991 return v->pop_back();
993 throw std::domain_error(std::format(
"Can not evaluate {}.pop_back()", repr(*
this)));
997 [[nodiscard]]
constexpr bool contains(datum
const& rhs)
const
999 if (
auto *m = get_if<map_type>(*
this)) {
1000 return m->contains(rhs);
1002 throw std::domain_error(std::format(
"Can not evaluate {}.contains({})", repr(*
this), repr(rhs)));
1006 template<
typename Arg>
1007 [[nodiscard]]
constexpr bool contains(Arg
const& arg)
const
1009 return contains(datum{arg});
1015 find(path.cbegin(), path.cend(), r);
1022 const_cast<datum *
>(
this)->
find(path.cbegin(), path.cend(), tmp);
1038 return to_bool(remove(path.cbegin(), path.cend()));
1048 hi_axiom(path.is_singular());
1049 return find_one(path.cbegin(), path.cend(),
false);
1059 hi_axiom(path.is_singular());
1060 return find_one(path.cbegin(), path.cend(),
true);
1070 hi_axiom(path.is_singular());
1071 return const_cast<datum *
>(
this)->find_one(path.cbegin(), path.cend(),
false);
1074 [[nodiscard]]
datum const& operator[](
datum const& rhs)
const
1076 if (holds_alternative<vector_type>(*
this) and holds_alternative<long long>(rhs)) {
1077 hilet& v = get<vector_type>(*
this);
1079 auto index = get<long long>(rhs);
1081 index = ssize(v) + index;
1083 if (index < 0 or index >= ssize(v)) {
1089 }
else if (holds_alternative<map_type>(*
this)) {
1090 hilet& m = get<map_type>(*
this);
1091 hilet it = m.find(rhs);
1092 if (it == m.end()) {
1099 throw std::domain_error(std::format(
"Can not evaluate {}[{}]", repr(*
this), repr(rhs)));
1103 [[nodiscard]]
constexpr datum& operator[](datum
const& rhs)
1105 if (holds_alternative<vector_type>(*
this) and holds_alternative<long long>(rhs)) {
1106 auto& v = get<vector_type>(*
this);
1108 auto index = get<long long>(rhs);
1110 index = ssize(v) + index;
1112 if (index < 0 or index >= ssize(v)) {
1118 }
else if (holds_alternative<map_type>(*
this)) {
1119 auto& m = get<map_type>(*
this);
1123 throw std::domain_error(std::format(
"Can not evaluate {}[{}]", repr(*
this), repr(rhs)));
1127 [[nodiscard]]
constexpr datum
const& operator[](
auto const& rhs)
const
1129 return (*
this)[datum{rhs}];
1132 [[nodiscard]]
constexpr datum& operator[](
auto const& rhs)
1134 return (*
this)[datum{rhs}];
1137 [[nodiscard]]
constexpr datum& operator++()
1139 if (holds_alternative<long long>(*
this)) {
1140 ++_value._long_long;
1147 [[nodiscard]]
constexpr datum& operator--()
1149 if (holds_alternative<long long>(*
this)) {
1150 --_value._long_long;
1157 [[nodiscard]]
constexpr datum operator++(
int)
1159 if (holds_alternative<long long>(*
this)) {
1161 _value._long_long++;
1167 [[nodiscard]]
constexpr datum operator--(
int)
1169 if (holds_alternative<long long>(*
this)) {
1171 _value._long_long--;
1178 constexpr datum& operator+=(
auto const& rhs)
1180 if (holds_alternative<vector_type>(*
this)) {
1184 return (*
this) = (*this) + rhs;
1188#define X(op, inner_op) \
1189 constexpr datum& operator op(auto const& rhs) \
1191 return (*this) = (*this)inner_op rhs; \
1205 [[nodiscard]]
friend constexpr bool operator==(datum
const& lhs, datum
const& rhs)
noexcept
1207 if (
hilet doubles = promote_if<double>(lhs, rhs)) {
1208 return doubles.lhs() == doubles.rhs();
1210 }
else if (
hilet decimals = promote_if<decimal>(lhs, rhs)) {
1211 return decimals.lhs() == decimals.rhs();
1213 }
else if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1214 return long_longs.lhs() == long_longs.rhs();
1216 }
else if (
hilet bools = promote_if<bool>(lhs, rhs)) {
1217 return bools.lhs() == bools.rhs();
1219 }
else if (
hilet ymds = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1220 return ymds.lhs() == ymds.rhs();
1222 }
else if (
hilet urls = promote_if<URL>(lhs, rhs)) {
1223 return urls.lhs() == urls.rhs();
1225 }
else if (
hilet strings = promote_if<std::string>(lhs, rhs)) {
1226 return strings.lhs() == strings.rhs();
1228 }
else if (
hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1229 return vectors.lhs() == vectors.rhs();
1231 }
else if (
hilet maps = promote_if<map_type>(lhs, rhs)) {
1232 return maps.lhs() == maps.rhs();
1235 return lhs._tag == rhs._tag;
1269 [[nodiscard]]
friend constexpr std::partial_ordering operator<=>(datum
const& lhs, datum
const& rhs)
noexcept
1271 if (
hilet doubles = promote_if<double>(lhs, rhs)) {
1272 return doubles.lhs() <=> doubles.rhs();
1274 }
else if (
hilet decimals = promote_if<decimal>(lhs, rhs)) {
1275 return decimals.lhs() <=> decimals.rhs();
1277 }
else if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1278 return long_longs.lhs() <=> long_longs.rhs();
1280 }
else if (
hilet bools = promote_if<bool>(lhs, rhs)) {
1281 return bools.lhs() <=> bools.rhs();
1283 }
else if (
hilet year_month_days = promote_if<std::chrono::year_month_day>(lhs, rhs)) {
1284 return year_month_days.lhs() <=> year_month_days.rhs();
1286 }
else if (
hilet urls = promote_if<URL>(lhs, rhs)) {
1287 return urls.lhs() <=> urls.rhs();
1289 }
else if (
hilet strings = promote_if<std::string>(lhs, rhs)) {
1290 return strings.lhs() <=> strings.rhs();
1292 }
else if (
hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1293 return vectors.lhs() <=> vectors.rhs();
1295 }
else if (
hilet maps = promote_if<map_type>(lhs, rhs)) {
1296 return maps.lhs() <=> maps.rhs();
1298 }
else if (
hilet bstrings = promote_if<bstring>(lhs, rhs)) {
1299 return bstrings.lhs() <=> bstrings.rhs();
1302 return lhs._tag <=> rhs._tag;
1316 [[nodiscard]]
friend constexpr datum operator-(datum
const& rhs)
1318 if (
hilet rhs_double = get_if<double>(rhs)) {
1319 return datum{-*rhs_double};
1321 }
else if (
hilet rhs_decimal = get_if<decimal>(rhs)) {
1322 return datum{-*rhs_decimal};
1324 }
else if (
hilet rhs_long_long = get_if<long long>(rhs)) {
1325 return datum{-*rhs_long_long};
1341 [[nodiscard]]
friend constexpr datum operator~(datum
const& rhs)
1343 if (
hilet rhs_long_long = get_if<long long>(rhs)) {
1344 return datum{~*rhs_long_long};
1365 [[nodiscard]]
friend constexpr datum operator+(datum
const& lhs, datum
const& rhs)
1367 if (
hilet doubles = promote_if<double>(lhs, rhs)) {
1368 return datum{doubles.lhs() + doubles.rhs()};
1370 }
else if (
hilet decimals = promote_if<decimal>(lhs, rhs)) {
1371 return datum{decimals.lhs() + decimals.rhs()};
1373 }
else if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1374 return datum{long_longs.lhs() + long_longs.rhs()};
1376 }
else if (
hilet strings = promote_if<std::string>(lhs, rhs)) {
1377 return datum{strings.lhs() + strings.rhs()};
1379 }
else if (
hilet vectors = promote_if<vector_type>(lhs, rhs)) {
1380 auto r = vectors.lhs();
1381 r.insert(r.end(), vectors.rhs().begin(), vectors.rhs().end());
1385 throw std::domain_error(std::format(
"Can not evaluate {} '+' {}", repr(lhs), repr(rhs)));
1400 [[nodiscard]]
friend constexpr datum operator-(datum
const& lhs, datum
const& rhs)
1402 if (
hilet doubles = promote_if<double>(lhs, rhs)) {
1403 return datum{doubles.lhs() - doubles.rhs()};
1405 }
else if (
hilet decimals = promote_if<decimal>(lhs, rhs)) {
1406 return datum{decimals.lhs() - decimals.rhs()};
1408 }
else if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1409 return datum{long_longs.lhs() - long_longs.rhs()};
1412 throw std::domain_error(std::format(
"Can not evaluate {} '-' {}", repr(lhs), repr(rhs)));
1427 [[nodiscard]]
friend constexpr datum operator*(datum
const& lhs, datum
const& rhs)
1429 if (
hilet doubles = promote_if<double>(lhs, rhs)) {
1430 return datum{doubles.lhs() * doubles.rhs()};
1432 }
else if (
hilet decimals = promote_if<decimal>(lhs, rhs)) {
1433 return datum{decimals.lhs() * decimals.rhs()};
1435 }
else if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1436 return datum{long_longs.lhs() * long_longs.rhs()};
1439 throw std::domain_error(std::format(
"Can not evaluate {} '*' {}", repr(lhs), repr(rhs)));
1456 [[nodiscard]]
friend constexpr datum operator/(datum
const& lhs, datum
const& rhs)
1458 if (
hilet doubles = promote_if<double>(lhs, rhs)) {
1459 if (doubles.rhs() == 0) {
1460 throw std::domain_error(std::format(
"Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1462 return datum{doubles.lhs() / doubles.rhs()};
1464 }
else if (
hilet decimals = promote_if<decimal>(lhs, rhs)) {
1465 if (decimals.rhs() == 0) {
1466 throw std::domain_error(std::format(
"Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1468 return datum{decimals.lhs() / decimals.rhs()};
1470 }
else if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1471 if (long_longs.rhs() == 0) {
1472 throw std::domain_error(std::format(
"Divide by zero {} '/' {}", repr(lhs), repr(rhs)));
1474 return datum{long_longs.lhs() / long_longs.rhs()};
1476 }
else if (
hilet urls = promote_if<URL>(lhs, rhs)) {
1477 return datum{urls.lhs() / urls.rhs()};
1480 throw std::domain_error(std::format(
"Can not evaluate {} '/' {}", repr(lhs), repr(rhs)));
1495 [[nodiscard]]
friend constexpr datum operator%(datum
const& lhs, datum
const& rhs)
1497 if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1498 if (long_longs.rhs() == 0) {
1499 throw std::domain_error(std::format(
"Divide by zero {} '%' {}", repr(lhs), repr(rhs)));
1501 return datum{long_longs.lhs() % long_longs.rhs()};
1504 throw std::domain_error(std::format(
"Can not evaluate {} '%' {}", repr(lhs), repr(rhs)));
1518 [[nodiscard]]
friend constexpr datum
pow(datum
const& lhs, datum
const& rhs)
1520 if (
hilet doubles = promote_if<double>(lhs, rhs)) {
1521 return datum{
pow(doubles.lhs(), doubles.rhs())};
1523 }
else if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1524 return datum{
pow(long_longs.lhs(), long_longs.rhs())};
1527 throw std::domain_error(std::format(
"Can not evaluate pow({}, {})", repr(lhs), repr(rhs)));
1541 [[nodiscard]]
friend constexpr datum operator&(datum
const& lhs, datum
const& rhs)
1543 if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1544 return datum{long_longs.lhs() & long_longs.rhs()};
1546 }
else if (
hilet bools = promote_if<bool>(lhs, rhs)) {
1547 return datum{bools.lhs() and bools.rhs()};
1550 throw std::domain_error(std::format(
"Can not evaluate {} '&' {}", repr(lhs), repr(rhs)));
1564 [[nodiscard]]
friend constexpr datum
operator|(datum
const& lhs, datum
const& rhs)
1566 if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1567 return datum{long_longs.lhs() | long_longs.rhs()};
1569 }
else if (
hilet bools = promote_if<bool>(lhs, rhs)) {
1570 return datum{bools.lhs() or bools.rhs()};
1573 throw std::domain_error(std::format(
"Can not evaluate {} '|' {}", repr(lhs), repr(rhs)));
1587 [[nodiscard]]
friend constexpr datum operator^(datum
const& lhs, datum
const& rhs)
1589 if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1590 return datum{long_longs.lhs() ^ long_longs.rhs()};
1592 }
else if (
hilet bools = promote_if<bool>(lhs, rhs)) {
1593 return datum{bools.lhs() != bools.rhs()};
1596 throw std::domain_error(std::format(
"Can not evaluate {} '^' {}", repr(lhs), repr(rhs)));
1612 [[nodiscard]]
friend constexpr datum operator<<(datum
const& lhs, datum
const& rhs)
1614 if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1615 if (long_longs.rhs() < 0 or long_longs.rhs() > (
sizeof(
long long) * CHAR_BIT - 1)) {
1616 throw std::domain_error(std::format(
"Invalid shift count {} '<<' {}", repr(lhs), repr(rhs)));
1618 return datum{long_longs.lhs() << long_longs.rhs()};
1621 throw std::domain_error(std::format(
"Can not evaluate {} '<<' {}", repr(lhs), repr(rhs)));
1636 [[nodiscard]]
friend constexpr datum operator>>(datum
const& lhs, datum
const& rhs)
1638 if (
hilet long_longs = promote_if<long long>(lhs, rhs)) {
1639 if (long_longs.rhs() < 0 or long_longs.rhs() > (
sizeof(
long long) * CHAR_BIT - 1)) {
1640 throw std::domain_error(std::format(
"Invalid shift count {} '>>' {}", repr(lhs), repr(rhs)));
1642 return datum{long_longs.lhs() >> long_longs.rhs()};
1645 throw std::domain_error(std::format(
"Can not evaluate {} '>>' {}", repr(lhs), repr(rhs)));
1655 [[nodiscard]] friend constexpr auto operator op(datum const& lhs, auto const& rhs) \
1657 return lhs op datum{rhs}; \
1659 [[nodiscard]] friend constexpr auto operator op(auto const& lhs, datum const& rhs) \
1661 return datum{lhs} op rhs; \
1678 [[nodiscard]]
friend std::string repr(datum
const& rhs)
noexcept
1681 case tag_type::monostate:
1683 case tag_type::floating_point:
1684 return std::format(
"{:.1f}", rhs._value._double);
1685 case tag_type::decimal:
1687 case tag_type::integral:
1688 return std::format(
"{}", rhs._value._long_long);
1689 case tag_type::boolean:
1690 return rhs._value._bool ?
"true" :
"false";
1691 case tag_type::year_month_day:
1692 return std::format(
"{:%Y-%m-%d}", rhs._value._year_month_day);
1693 case tag_type::null:
1695 case tag_type::flow_break:
1697 case tag_type::flow_continue:
1699 case tag_type::string:
1700 return std::format(
"\"{}\"", *rhs._value._string);
1703 case tag_type::vector:
1706 for (
hilet& item : *rhs._value._vector) {
1716 for (
hilet& item : *rhs._value._map) {
1717 r += repr(item.first);
1719 r += repr(item.second);
1725 case tag_type::bstring:
1726 return base64::encode(*rhs._value._bstring);
1745 template<
typename T>
1748 if constexpr (std::is_same_v<T, double>) {
1749 return rhs._tag == tag_type::floating_point;
1750 }
else if constexpr (std::is_same_v<T, decimal>) {
1751 return rhs._tag == tag_type::decimal;
1752 }
else if constexpr (std::is_same_v<T, long long>) {
1753 return rhs._tag == tag_type::integral;
1754 }
else if constexpr (std::is_same_v<T, bool>) {
1755 return rhs._tag == tag_type::boolean;
1756 }
else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1757 return rhs._tag == tag_type::year_month_day;
1758 }
else if constexpr (std::is_same_v<T, nullptr_t>) {
1759 return rhs._tag == tag_type::null;
1760 }
else if constexpr (std::is_same_v<T, std::monostate>) {
1761 return rhs._tag == tag_type::monostate;
1762 }
else if constexpr (std::is_same_v<T, break_type>) {
1763 return rhs._tag == tag_type::flow_break;
1764 }
else if constexpr (std::is_same_v<T, continue_type>) {
1765 return rhs._tag == tag_type::flow_continue;
1766 }
else if constexpr (std::is_same_v<T, std::string>) {
1767 return rhs._tag == tag_type::string;
1768 }
else if constexpr (std::is_same_v<T, vector_type>) {
1769 return rhs._tag == tag_type::vector;
1770 }
else if constexpr (std::is_same_v<T, map_type>) {
1771 return rhs._tag == tag_type::map;
1772 }
else if constexpr (std::is_same_v<T, URL>) {
1773 return rhs._tag == tag_type::url;
1774 }
else if constexpr (std::is_same_v<T, bstring>) {
1775 return rhs._tag == tag_type::bstring;
1777 hi_static_no_default();
1794 template<
typename To>
1797 if constexpr (std::is_same_v<To, double>) {
1798 return holds_alternative<double>(rhs) or holds_alternative<decimal>(rhs) or holds_alternative<long long>(rhs) or
1799 holds_alternative<bool>(rhs);
1800 }
else if constexpr (std::is_same_v<To, decimal>) {
1801 return holds_alternative<decimal>(rhs) or holds_alternative<long long>(rhs) or holds_alternative<bool>(rhs);
1802 }
else if constexpr (std::is_same_v<To, long long>) {
1803 return holds_alternative<long long>(rhs) or holds_alternative<bool>(rhs);
1804 }
else if constexpr (std::is_same_v<To, std::string>) {
1805 return holds_alternative<URL>(rhs) or holds_alternative<std::string>(rhs);
1806 }
else if constexpr (std::is_same_v<To, URL>) {
1807 return holds_alternative<URL>(rhs) or holds_alternative<std::string>(rhs);
1809 return holds_alternative<To>(rhs);
1821 template<
typename T>
1822 [[nodiscard]]
friend constexpr T
const&
get(
datum const& rhs)
noexcept
1824 hi_axiom(holds_alternative<T>(rhs));
1825 if constexpr (std::is_same_v<T, double>) {
1826 return rhs._value._double;
1827 }
else if constexpr (std::is_same_v<T, decimal>) {
1828 return rhs._value._decimal;
1829 }
else if constexpr (std::is_same_v<T, long long>) {
1830 return rhs._value._long_long;
1831 }
else if constexpr (std::is_same_v<T, bool>) {
1832 return rhs._value._bool;
1833 }
else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1834 return rhs._value._year_month_day;
1835 }
else if constexpr (std::is_same_v<T, std::string>) {
1836 return *rhs._value._string;
1837 }
else if constexpr (std::is_same_v<T, vector_type>) {
1838 return *rhs._value._vector;
1839 }
else if constexpr (std::is_same_v<T, map_type>) {
1840 return *rhs._value._map;
1841 }
else if constexpr (std::is_same_v<T, URL>) {
1842 return *rhs._value._url;
1843 }
else if constexpr (std::is_same_v<T, bstring>) {
1844 return *rhs._value._bstring;
1846 hi_static_no_default();
1858 template<
typename T>
1859 [[nodiscard]]
friend constexpr T&
get(
datum& rhs)
noexcept
1861 hi_axiom(holds_alternative<T>(rhs));
1862 if constexpr (std::is_same_v<T, double>) {
1863 return rhs._value._double;
1864 }
else if constexpr (std::is_same_v<T, decimal>) {
1865 return rhs._value._decimal;
1866 }
else if constexpr (std::is_same_v<T, long long>) {
1867 return rhs._value._long_long;
1868 }
else if constexpr (std::is_same_v<T, bool>) {
1869 return rhs._value._bool;
1870 }
else if constexpr (std::is_same_v<T, std::chrono::year_month_day>) {
1871 return rhs._value._year_month_day;
1872 }
else if constexpr (std::is_same_v<T, std::string>) {
1873 return *rhs._value._string;
1874 }
else if constexpr (std::is_same_v<T, vector_type>) {
1875 return *rhs._value._vector;
1876 }
else if constexpr (std::is_same_v<T, map_type>) {
1877 return *rhs._value._map;
1878 }
else if constexpr (std::is_same_v<T, URL>) {
1879 return *rhs._value._url;
1880 }
else if constexpr (std::is_same_v<T, bstring>) {
1881 return *rhs._value._bstring;
1883 hi_static_no_default();
1895 template<
typename T>
1898 if (holds_alternative<T>(rhs)) {
1899 return &get<T>(rhs);
1913 template<
typename T>
1914 [[nodiscard]]
friend constexpr T
const *
get_if(
datum const& rhs)
noexcept
1916 if (holds_alternative<T>(rhs)) {
1917 return &get<T>(rhs);
1932 template<
typename T>
1935 if (
auto *value = rhs.find_one(path)) {
1936 if (holds_alternative<T>(*value)) {
1937 return &get<T>(*value);
1955 template<
typename T>
1958 if (
auto *value =
const_cast<datum&
>(rhs).find_one(path)) {
1959 if (holds_alternative<T>(*value)) {
1960 return &get<T>(*value);
1970 enum class tag_type :
signed char {
1990 tag_type _tag = tag_type::monostate;
1993 long long _long_long;
1996 std::chrono::year_month_day _year_month_day;
1998 vector_type *_vector;
2003 constexpr value_type(numeric_integral
auto value) noexcept : _long_long(narrow_cast<long long>(value)) {}
2004 constexpr value_type(std::floating_point
auto value) noexcept : _double(narrow_cast<double>(value)) {}
2005 constexpr value_type(decimal value) noexcept : _decimal(value) {}
2006 constexpr value_type(
bool value) noexcept : _bool(value) {}
2007 constexpr value_type(std::chrono::year_month_day value) noexcept : _year_month_day(value) {}
2008 constexpr value_type(
std::string *value) noexcept : _string(value) {}
2009 constexpr value_type(vector_type *value) noexcept : _vector(value) {}
2010 constexpr value_type(map_type *value) noexcept : _map(value) {}
2011 constexpr value_type(URL *value) noexcept : _url(value) {}
2012 constexpr value_type(bstring *value) noexcept : _bstring(value) {}
2017 [[nodiscard]]
constexpr bool is_scalar() const noexcept
2019 return to_underlying(_tag) >= 0;
2022 [[nodiscard]]
constexpr bool is_pointer() const noexcept
2024 return to_underlying(_tag) < 0;
2027 hi_no_inline
void copy_pointer(datum
const& other)
noexcept
2029 hi_axiom(other.is_pointer());
2030 switch (other._tag) {
2031 case tag_type::string:
2032 _value._string =
new std::string{*other._value._string};
2034 case tag_type::vector:
2035 _value._vector =
new vector_type{*other._value._vector};
2038 _value._map =
new map_type{*other._value._map};
2041 _value._url =
new URL{*other._value._url};
2043 case tag_type::bstring:
2044 _value._bstring =
new bstring{*other._value._bstring};
2051 hi_no_inline
void _delete_pointer() noexcept
2053 hi_axiom(is_pointer());
2055 case tag_type::string:
2056 delete _value._string;
2058 case tag_type::vector:
2059 delete _value._vector;
2067 case tag_type::bstring:
2068 delete _value._bstring;
2075 constexpr void delete_pointer() noexcept
2082 void find_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end,
std::vector<datum *>& r)
noexcept
2084 if (
auto vector = get_if<datum::vector_type>(*
this)) {
2085 for (
auto& item : *vector) {
2086 item.find(it + 1, it_end, r);
2089 }
else if (
auto map = get_if<datum::map_type>(*
this)) {
2090 for (
auto& item : *map) {
2091 item.second.find(it + 1, it_end, r);
2096 void find_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end,
std::vector<datum *>& r)
noexcept
2098 this->
find(it + 1, it_end, r);
2100 if (
auto vector = get_if<datum::vector_type>(*
this)) {
2101 for (
auto& item : *vector) {
2102 item.find(it, it_end, r);
2105 }
else if (
auto map = get_if<datum::map_type>(*
this)) {
2106 for (
auto& item : *map) {
2107 item.second.find(it, it_end, r);
2113 jsonpath_indices
const& indices,
2114 jsonpath::const_iterator it,
2115 jsonpath::const_iterator it_end,
2118 if (
auto vector = get_if<datum::vector_type>(*
this)) {
2119 for (
hilet index : indices.filter(ssize(*vector))) {
2120 (*vector)[index].find(it + 1, it_end, r);
2126 jsonpath_names
const& names,
2127 jsonpath::const_iterator it,
2128 jsonpath::const_iterator it_end,
2131 if (
auto map = get_if<datum::map_type>(*
this)) {
2132 for (
hilet& name : names) {
2133 hilet name_ = datum{name};
2134 auto jt = map->find(name_);
2135 if (jt != map->cend()) {
2136 jt->second.find(it + 1, it_end, r);
2143 jsonpath_slice
const& slice,
2144 jsonpath::const_iterator it,
2145 jsonpath::const_iterator it_end,
2148 if (
auto vector = get_if<datum::vector_type>(*
this)) {
2149 hilet first = slice.begin(vector->size());
2150 hilet last = slice.end(vector->size());
2152 for (
auto index = first; index != last; index += slice.step) {
2153 if (index >= 0 and index < vector->size()) {
2154 (*this)[index].find(it + 1, it_end, r);
2165 }
else if (std::holds_alternative<jsonpath_root>(*it)) {
2166 find(it + 1, it_end, r);
2168 }
else if (std::holds_alternative<jsonpath_current>(*it)) {
2169 find(it + 1, it_end, r);
2171 }
else if (std::holds_alternative<jsonpath_wildcard>(*it)) {
2172 find_wildcard(it, it_end, r);
2174 }
else if (std::holds_alternative<jsonpath_descend>(*it)) {
2175 find_descend(it, it_end, r);
2177 }
else if (
auto indices = std::get_if<jsonpath_indices>(&*it)) {
2178 find_indices(*indices, it, it_end, r);
2180 }
else if (
auto names = std::get_if<jsonpath_names>(&*it)) {
2181 find_names(*names, it, it_end, r);
2183 }
else if (
auto slice = std::get_if<jsonpath_slice>(&*it)) {
2184 find_slice(*slice, it, it_end, r);
2191 [[nodiscard]]
int remove_wildcard(jsonpath::const_iterator it, jsonpath::const_iterator it_end)
noexcept
2195 if (
auto vector = get_if<datum::vector_type>(*
this)) {
2196 auto jt = vector->begin();
2197 while (jt != vector->end()) {
2198 hilet match = jt->remove(it + 1, it_end);
2202 jt = vector->erase(jt);
2207 return vector->empty() ? 2 : r;
2209 }
else if (
auto map = get_if<datum::map_type>(*
this)) {
2210 auto jt = map->begin();
2211 while (jt != map->end()) {
2212 hilet match = jt->second.remove(it + 1, it_end);
2216 jt = map->erase(jt);
2221 return map->empty() ? 2 : r;
2228 [[nodiscard]]
int remove_descend(jsonpath::const_iterator it, jsonpath::const_iterator it_end)
noexcept
2240 if (
auto vector = get_if<datum::vector_type>(*
this)) {
2241 auto jt = vector->begin();
2242 while (jt != vector->end()) {
2243 hilet match = jt->remove(it, it_end);
2247 jt = vector->erase(jt);
2252 return vector->empty() ? 2 : r;
2254 }
else if (
auto map = get_if<datum::map_type>(*
this)) {
2255 auto jt = map->begin();
2256 while (jt != map->end()) {
2257 hilet match = jt->second.remove(it, it_end);
2261 jt = map->erase(jt);
2266 return map->empty() ? 2 : r;
2274 remove_indices(jsonpath_indices
const& indices, jsonpath::const_iterator it, jsonpath::const_iterator it_end)
noexcept
2276 if (
auto vector = get_if<datum::vector_type>(*
this)) {
2280 for (
hilet index : indices.filter(ssize(*vector))) {
2281 hilet match = (*vector)[index - offset].remove(it + 1, it_end);
2284 vector->erase(vector->begin() + (index - offset));
2289 return vector->empty() ? 2 : r;
2297 remove_names(jsonpath_names
const& names, jsonpath::const_iterator it, jsonpath::const_iterator it_end)
noexcept
2299 if (
auto map = get_if<datum::map_type>(*
this)) {
2302 for (
hilet& name : names) {
2303 hilet name_ = datum{name};
2304 auto jt = map->find(name_);
2305 if (jt != map->cend()) {
2306 hilet match = jt->second.remove(it + 1, it_end);
2314 return map->empty() ? 2 : r;
2322 remove_slice(jsonpath_slice
const& slice, jsonpath::const_iterator it, jsonpath::const_iterator it_end)
noexcept
2324 if (
auto vector = get_if<datum::vector_type>(*
this)) {
2327 hilet first = slice.begin(vector->size());
2328 hilet last = slice.end(vector->size());
2331 for (
auto index = first; index != last; index += slice.step) {
2332 if (index >= 0 and index < vector->size()) {
2333 hilet match = (*this)[index - offset].remove(it + 1, it_end);
2337 vector->erase(vector->begin() + (index - offset));
2343 return vector->empty() ? 2 : r;
2350 [[nodiscard]]
int remove(jsonpath::const_iterator it, jsonpath::const_iterator it_end)
noexcept
2356 }
else if (std::holds_alternative<jsonpath_root>(*it)) {
2357 return remove(it + 1, it_end);
2359 }
else if (std::holds_alternative<jsonpath_current>(*it)) {
2360 return remove(it + 1, it_end);
2362 }
else if (std::holds_alternative<jsonpath_wildcard>(*it)) {
2363 return remove_wildcard(it, it_end);
2365 }
else if (std::holds_alternative<jsonpath_descend>(*it)) {
2366 return remove_descend(it, it_end);
2368 }
else if (
auto indices = std::get_if<jsonpath_indices>(&*it)) {
2369 return remove_indices(*indices, it, it_end);
2371 }
else if (
auto names = std::get_if<jsonpath_names>(&*it)) {
2372 return remove_names(*names, it, it_end);
2374 }
else if (
auto slice = std::get_if<jsonpath_slice>(&*it)) {
2375 return remove_slice(*slice, it, it_end);
2382 [[nodiscard]] datum *
2383 find_one_name(datum
const& name, jsonpath::const_iterator it, jsonpath::const_iterator it_end,
bool create)
noexcept
2385 hi_axiom(holds_alternative<std::string>(name));
2387 if (
auto *map = get_if<map_type>(*
this)) {
2388 auto i = map->find(name);
2389 if (i != map->end()) {
2390 return i->second.find_one(it + 1, it_end, create);
2392 }
else if (create) {
2393 (*map)[name] = datum{std::monostate{}};
2394 return find_one_name(name, it, it_end, create);
2400 }
else if (holds_alternative<std::monostate>(*
this) and create) {
2401 *
this = datum::make_map(name, std::monostate{});
2402 return find_one_name(name, it, it_end, create);
2409 [[nodiscard]] datum *
2410 find_one_index(
std::size_t index, jsonpath::const_iterator it, jsonpath::const_iterator it_end,
bool create)
noexcept
2412 if (
auto *vector = get_if<vector_type>(*
this)) {
2413 if (index < vector->size()) {
2414 return (*vector)[index].find_one(it + 1, it_end, create);
2415 }
else if (index == vector->size() and create) {
2416 vector->push_back(datum{std::monostate{}});
2417 return find_one_index(index, it, it_end, create);
2422 }
else if (holds_alternative<std::monostate>(*
this) and index == 0 and create) {
2423 *
this = datum::make_vector(std::monostate{});
2424 return find_one_index(index, it, it_end, create);
2431 [[nodiscard]] datum *find_one(jsonpath::const_iterator it, jsonpath::const_iterator it_end,
bool create)
noexcept
2436 }
else if (std::holds_alternative<jsonpath_root>(*it)) {
2437 return find_one(it + 1, it_end, create);
2439 }
else if (std::holds_alternative<jsonpath_current>(*it)) {
2440 return find_one(it + 1, it_end, create);
2442 }
else if (
hilet *indices = std::get_if<jsonpath_indices>(&*it)) {
2443 hi_axiom(indices->size() == 1);
2444 return find_one_index(indices->front(), it, it_end, create);
2446 }
else if (
hilet *names = std::get_if<jsonpath_names>(&*it)) {
2447 hi_axiom(names->size() == 1);
2448 return find_one_name(datum{names->front()}, it, it_end, create);