4#include "Stroika/Foundation/StroikaPreComp.h"
6#include "Stroika/Foundation/Characters/FloatConversion.h"
8#include "Stroika/Foundation/Characters/String2Int.h"
10#include "Stroika/Foundation/Containers/SortedMapping.h"
12#include "Stroika/Foundation/DataExchange/BadFormatException.h"
14#include "Stroika/Foundation/Math/Common.h"
16#include "VariantValue.h"
19using namespace Characters::Literals;
26static_assert (regular<VariantValue>);
30 using IntegerType_ =
long long int;
31 using UnsignedIntegerType_ =
unsigned long long int;
32 using FloatType_ =
long double;
42 struct TN_<Memory::
BLOB> {
46 struct TN_<IntegerType_> {
50 struct TN_<UnsignedIntegerType_> {
54 struct TN_<FloatType_> {
62 struct TN_<DateTime> {
81 template <
typename FWD>
82 inline TIRep_ (FWD&& v)
83 : fVal{forward<FWD> (v)}
86 virtual Type GetType ()
const override
88 return TN_<T>::kTYPEENUM;
98const shared_ptr<VariantValue::IRep_> VariantValue::kFalseRep_ = Memory::MakeSharedPtr<TIRep_<bool>> (
false);
99const shared_ptr<VariantValue::IRep_> VariantValue::kTrueRep_ = Memory::MakeSharedPtr<TIRep_<bool>> (
true);
102 : fVal_{val ? kTrueRep_ : kFalseRep_}
139 : fVal_{Memory::
MakeSharedPtr<TIRep_<UnsignedIntegerType_>> (val)}
144 : fVal_{Memory::
MakeSharedPtr<TIRep_<UnsignedIntegerType_>> (val)}
149 : fVal_{Memory::
MakeSharedPtr<TIRep_<UnsignedIntegerType_>> (val)}
154 : fVal_{Memory::
MakeSharedPtr<TIRep_<UnsignedIntegerType_>> (val)}
159 : fVal_{Memory::
MakeSharedPtr<TIRep_<UnsignedIntegerType_>> (val)}
221#if qStroika_HasComponent_boost
223 inline auto mk_ (
const boost::json::value& val) ->
VariantValue
225 using namespace boost;
226 switch (val.kind ()) {
227 case json::kind::null:
230 case json::kind::bool_:
231 return val.as_bool ();
233 case json::kind::double_:
234 return val.as_double ();
236 case json::kind::int64:
237 return val.as_int64 ();
239 case json::kind::uint64:
240 return val.as_uint64 ();
242 case json::kind::string: {
243 const json::string& bs = val.as_string ();
244 return String::FromUTF8 (span{bs});
246 case json::kind::array: {
247 const auto& a = val.as_array ();
248 std::vector<VariantValue> r;
249 r.reserve (a.size ());
250 for (
const boost::json::value& i : a) {
251 r.emplace_back (mk_ (i));
255 case json::kind::object: {
256 const auto& o = val.as_object ();
258 r.reserve (o.size ());
259 for (
const auto& i : o) {
260 r.
insert ({String::FromUTF8 (span{i.key ()}), mk_ (i.value ())});
278 if (fVal_ ==
nullptr) {
281 switch (fVal_->GetType ()) {
284 case Type::eUnsignedInteger: {
288 auto v = Debug::UncheckedDynamicCast<const TIRep_<Memory::BLOB>*> (fVal_.get ());
289 return v->fVal.
empty ();
292 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
294 return isnan (v->fVal);
299 case Type::eDateTime: {
302 case Type::eString: {
303 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
305 return v->fVal.empty ();
308 auto v = Debug::UncheckedDynamicCast<const TIRep_<Mapping<String, VariantValue>>*> (fVal_.get ());
310 return v->fVal.empty ();
313 auto v = Debug::UncheckedDynamicCast<const TIRep_<Sequence<VariantValue>>*> (fVal_.get ());
315 return v->fVal.empty ();
318 return As<String> ().empty ();
325 return As<String> ();
328bool VariantValue::AsBool_ ()
const
330 if (fVal_ ==
nullptr) {
333 switch (fVal_->GetType ()) {
334 case Type::eBoolean: {
335 auto v = Debug::UncheckedDynamicCast<const TIRep_<bool>*> (fVal_.get ());
339 case Type::eString: {
341 return As<String> () ==
"true"sv;
343 case Type::eInteger: {
344 return As<IntegerType_> () != 0;
346 case Type::eUnsignedInteger: {
347 return As<UnsignedIntegerType_> () != 0;
350#if USE_NOISY_TRACE_IN_THIS_MODULE_
351 DbgTrace (
"failed coerce-to-bool: type={}, value={}"_f, fVal_->GetType (), *
this);
360 if (GetType () == to) [[likely]] {
375 if (GetType () == to) [[likely]] {
384 return As<Memory::BLOB> ();
389 case Type::eUnsignedInteger:
390 return As<unsigned int> ();
392 return As<FloatType_> ();
394 return As<Time::Date> ();
395 case Type::eDateTime:
396 return As<Time::DateTime> ();
398 return As<String> ();
402 return VariantValue{As<Mapping<String, VariantValue>> ()};
411 switch (GetType ()) {
420 case Type::eUnsignedInteger:
425 FloatType_ f = As<FloatType_> ();
426 if (std::isnan (f) or std::isinf (f)) {
433 case Type::eDateTime:
444 [] (
const KVPT& kvp) {
return KVPT{kvp.fKey, kvp.fValue.Normalize ()}; })};
453 if (fVal_ ==
nullptr) {
456 switch (fVal_->GetType ()) {
458 auto v = Debug::UncheckedDynamicCast<const TIRep_<Memory::BLOB>*> (fVal_.get ());
463 return Cryptography::Encoding::Algorithm::Base64::Decode (As<String> ());
468VariantValue::IntegerType_ VariantValue::AsInteger_ ()
const
470 if (fVal_ ==
nullptr) {
473 switch (fVal_->GetType ()) {
474 case Type::eBoolean: {
475 auto v = Debug::UncheckedDynamicCast<const TIRep_<bool>*> (fVal_.get ());
480 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
482 return Math::Round<VariantValue::IntegerType_> (v->fVal);
484 case Type::eInteger: {
485 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
489 case Type::eUnsignedInteger: {
490 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
494 case Type::eString: {
495 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
497 return Characters::String2Int<IntegerType_> (v->fVal);
500#if USE_NOISY_TRACE_IN_THIS_MODULE_
501 DbgTrace (
"failed coerce-to-int: type={}, value={}"_f, fVal_->GetType (), *
this);
508VariantValue::UnsignedIntegerType_ VariantValue::AsUnsignedInteger_ ()
const
510 if (fVal_ ==
nullptr) {
513 switch (fVal_->GetType ()) {
515 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
517 return Math::Round<VariantValue::UnsignedIntegerType_> (v->fVal);
519 case Type::eInteger: {
520 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
524 case Type::eUnsignedInteger: {
525 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
529 case Type::eString: {
530 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
534 return Characters::String2Int<UnsignedIntegerType_> (v->fVal);
537#if USE_NOISY_TRACE_IN_THIS_MODULE_
538 DbgTrace (
"failed coerce-to-uint: type={}, value={}"_f, fVal_->GetType (), *
this);
545VariantValue::FloatType_ VariantValue::AsFloatType_ ()
const
547 if (fVal_ ==
nullptr) {
548 return Math::nan<FloatType_> ();
550 switch (fVal_->GetType ()) {
551 case Type::eInteger: {
552 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
554 return static_cast<FloatType_
> (v->fVal);
556 case Type::eUnsignedInteger: {
557 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
559 return static_cast<FloatType_
> (v->fVal);
562 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
566 case Type::eString: {
567 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
570 return Characters::FloatConversion::ToFloat<FloatType_> (v->fVal);
573#if USE_NOISY_TRACE_IN_THIS_MODULE_
574 DbgTrace (
"failed coerce-to-float: type={}, value={}"_f, fVal_->GetType (), *
this);
581Date VariantValue::AsDate_ ()
const
583 if (fVal_ ==
nullptr) {
586 switch (fVal_->GetType ()) {
588 auto v = Debug::UncheckedDynamicCast<const TIRep_<Date>*> (fVal_.get ());
592 case Type::eDateTime: {
593 auto v = Debug::UncheckedDynamicCast<const TIRep_<DateTime>*> (fVal_.get ());
595 return v->fVal.GetDate ();
597 case Type::eString: {
598 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
603#if USE_NOISY_TRACE_IN_THIS_MODULE_
604 DbgTrace (
"failed coerce-to-date: type={}, value={}"_f, fVal_->GetType (), *
this);
611DateTime VariantValue::AsDateTime_ ()
const
613 if (fVal_ ==
nullptr) {
616 switch (fVal_->GetType ()) {
618 auto v = Debug::UncheckedDynamicCast<const TIRep_<Date>*> (fVal_.get ());
620 return DateTime{v->fVal};
622 case Type::eDateTime: {
623 auto v = Debug::UncheckedDynamicCast<const TIRep_<DateTime>*> (fVal_.get ());
627 case Type::eString: {
628 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
630 return DateTime::Parse (v->fVal, DateTime::kISO8601Format);
633#if USE_NOISY_TRACE_IN_THIS_MODULE_
634 DbgTrace (
"failed coerce-to-datetime: type={}, value={}"_f, fVal_->GetType (), *
this);
641#if qStroika_HasComponent_boost
642boost::json::value VariantValue::AsBoostJSONValue_ ()
const
644 using namespace boost;
645 if (fVal_ ==
nullptr) {
646 return json::value{
nullptr};
648 switch (fVal_->GetType ()) {
650 return json::value{
nullptr};
652 case Type::eBoolean: {
655 case Type::eString: {
657 return As<String> ().AsUTF8<
string> ().c_str ();
659 case Type::eInteger: {
660 return As<IntegerType_> ();
662 case Type::eUnsignedInteger: {
663 return As<UnsignedIntegerType_> ();
666 return static_cast<double> (As<FloatType_> ());
670 case Type::eDateTime: {
672 return As<String> ().AsASCII ().c_str ();
678 result.reserve (srcArray.
size ());
679 for (
const auto& i : srcArray) {
688 for (
const auto& i : srcMap) {
689 result.
insert (json::key_value_pair{i.fKey.As<
String> ().AsUTF8<string> ().
c_str (), i.fValue.As<json::value> ()});
695 return json::value{
nullptr};
700String VariantValue::AsString_ ()
const
702 if (fVal_ ==
nullptr) [[unlikely]] {
705 switch (fVal_->GetType ()) {
710 case Type::eBoolean: {
711 auto v = Debug::UncheckedDynamicCast<const TIRep_<bool>*> (fVal_.get ());
713 return v->fVal ?
"true"sv :
"false"sv;
716 auto v = Debug::UncheckedDynamicCast<const TIRep_<Memory::BLOB>*> (fVal_.get ());
718 return String{Cryptography::Encoding::Algorithm::Base64::Encode (v->fVal)};
720 case Type::eInteger: {
721 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
723 return "{}"_f(v->fVal);
725 case Type::eUnsignedInteger: {
727 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
729 return "{}"_f(v->fVal);
732 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
734 using namespace Characters;
735 return FloatConversion::ToString (v->fVal, FloatConversion::Precision::kFull);
738 auto v = Debug::UncheckedDynamicCast<const TIRep_<Date>*> (fVal_.get ());
742 case Type::eDateTime: {
743 auto v = Debug::UncheckedDynamicCast<const TIRep_<DateTime>*> (fVal_.get ());
745 return v->fVal.Format (DateTime::kISO8601Format);
747 case Type::eString: {
748 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
753 auto v = Debug::UncheckedDynamicCast<const TIRep_<Sequence<VariantValue>>*> (fVal_.get ());
757 for (
auto i = v->fVal.begin (); i != v->fVal.end (); ++i) {
758 if (i != v->fVal.begin ()) {
767 auto v = Debug::UncheckedDynamicCast<const TIRep_<Mapping<String, VariantValue>>*> (fVal_.get ());
771 for (
auto i = v->fVal.begin (); i != v->fVal.end (); ++i) {
772 if (i != v->fVal.begin ()) {
775 tmp << i->fKey <<
" -> "sv << i->fValue.
As<
String> ();
789 if (fVal_ ==
nullptr) [[unlikely]] {
792 switch (fVal_->GetType ()) {
794 auto v = Debug::UncheckedDynamicCast<const TIRep_<Mapping<String, VariantValue>>*> (fVal_.get ());
806 if (fVal_ ==
nullptr) [[unlikely]] {
809 switch (fVal_->GetType ()) {
811 auto v = Debug::UncheckedDynamicCast<const TIRep_<Sequence<VariantValue>>*> (fVal_.get ());
826bool Stroika::Foundation::DataExchange::VariantValue::EqualsComparer::operator() (
const VariantValue& lhs,
const VariantValue& rhs)
const
836 case VariantValue::eNull:
838 case VariantValue::eBoolean:
839 return ln.
As<
bool> () == ln.
As<
bool> ();
840 case VariantValue::eFloat:
841 return Math::NearlyEquals (ln.
As<FloatType_> (), ln.
As<FloatType_> ());
842 case VariantValue::eString:
844 case VariantValue::eArray: {
848 case VariantValue::eMap: {
852 case VariantValue::eBLOB:
853 case VariantValue::eInteger:
854 case VariantValue::eUnsignedInteger:
855 case VariantValue::eDate:
856 case VariantValue::eDateTime:
879 case VariantValue::eNull:
880 return strong_ordering::equal;
881 case VariantValue::eBoolean:
882 return ln.
As<
bool> () <=> ln.
As<
bool> ();
883 case VariantValue::eFloat: {
885 FloatType_ l = ln.
As<FloatType_> ();
886 FloatType_ r = rn.
As<FloatType_> ();
887 if (Math::NearlyEquals (l, r)) {
888 return strong_ordering::equal;
891 return strong_ordering::less;
894 return strong_ordering::greater;
897 case VariantValue::eString:
899 case VariantValue::eArray: {
903 case VariantValue::eMap: {
920 case VariantValue::eBLOB:
921 case VariantValue::eInteger:
922 case VariantValue::eUnsignedInteger:
923 case VariantValue::eDate:
924 case VariantValue::eDateTime:
928 return strong_ordering::equal;
#define AssertNotReached()
auto MakeSharedPtr(ARGS_TYPE &&... args) -> shared_ptr< T >
same as make_shared, but if type T has block allocation, then use block allocation for the 'shared pa...
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper< T >, Common::Empty > UseBlockAllocationIfAppropriate
Use this to enable block allocation for a particular class. Beware of subclassing.
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
nonvirtual RESULT_T As() const
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual tuple< const wchar_t *, wstring_view > c_str(Memory::StackBuffer< wchar_t > *possibleBackingStore) const
Mapping_stdhashmap<KEY_TYPE, MAPPED_VALUE_TYPE, TRAITS> is an std::map-based concrete implementation ...
unordered_map< KEY_TYPE, MAPPED_VALUE_TYPE, HASH, KEY_EQUALS_COMPARER > STDHASHMAP
STDHASHMAP is std::map<> that can be used inside Mapping_stdhashmap.
Sequence_stdvector<T> is an std::vector-based concrete implementation of the Sequence<T> container pa...
nonvirtual void insert(ArgByValueType< value_type > kvp)
A generalization of a vector: a container whose elements are keyed by the natural numbers.
nonvirtual void push_back(ArgByValueType< value_type > item)
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
nonvirtual VariantValue ConvertTo(Type to) const
Return this VariantValue converted to the given type (as if by As<T> for the T appropriate to 'Type t...
VariantValue()=default
construct a VariantValue from most any 'basic type' you would expect to find in a weakly typed langua...
nonvirtual bool empty() const
nonvirtual String ToString() const
Type
Enumeration of variant types.
nonvirtual bool IsConvertibleTo(Type to) const
nonvirtual RETURNTYPE As() const
nonvirtual VariantValue Normalize() const
static constexpr string_view kISO8601Format
Y-M-D format - locale independent, and ISO-8601 date format standard.
static Date Parse(const String &rep, const locale &l=locale{})
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
nonvirtual size_t size() const
Returns the number of items contained.
STRING_TYPE ToString(FLOAT_TYPE f, const ToStringOptions &options={})
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...