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/Concrete/Mapping_HashTable.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 for (
const auto& i : o) {
259 r.
insert ({String::FromUTF8 (span{i.key ()}), mk_ (i.value ())});
277 if (fVal_ ==
nullptr) {
280 switch (fVal_->GetType ()) {
283 case Type::eUnsignedInteger: {
287 auto v = Debug::UncheckedDynamicCast<const TIRep_<Memory::BLOB>*> (fVal_.get ());
288 return v->fVal.
empty ();
291 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
293 return isnan (v->fVal);
298 case Type::eDateTime: {
301 case Type::eString: {
302 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
304 return v->fVal.empty ();
307 auto v = Debug::UncheckedDynamicCast<const TIRep_<Mapping<String, VariantValue>>*> (fVal_.get ());
309 return v->fVal.empty ();
312 auto v = Debug::UncheckedDynamicCast<const TIRep_<Sequence<VariantValue>>*> (fVal_.get ());
314 return v->fVal.empty ();
317 return As<String> ().empty ();
324 return As<String> ();
327bool VariantValue::AsBool_ ()
const
329 if (fVal_ ==
nullptr) {
332 switch (fVal_->GetType ()) {
333 case Type::eBoolean: {
334 auto v = Debug::UncheckedDynamicCast<const TIRep_<bool>*> (fVal_.get ());
338 case Type::eString: {
340 return As<String> () ==
"true"sv;
342 case Type::eInteger: {
343 return As<IntegerType_> () != 0;
345 case Type::eUnsignedInteger: {
346 return As<UnsignedIntegerType_> () != 0;
349#if USE_NOISY_TRACE_IN_THIS_MODULE_
350 DbgTrace (
"failed coerce-to-bool: type={}, value={}"_f, fVal_->GetType (), *
this);
359 if (GetType () == to) [[likely]] {
374 if (GetType () == to) [[likely]] {
383 return As<Memory::BLOB> ();
388 case Type::eUnsignedInteger:
389 return As<unsigned int> ();
391 return As<FloatType_> ();
393 return As<Time::Date> ();
394 case Type::eDateTime:
395 return As<Time::DateTime> ();
397 return As<String> ();
401 return VariantValue{As<Mapping<String, VariantValue>> ()};
410 switch (GetType ()) {
419 case Type::eUnsignedInteger:
424 FloatType_ f = As<FloatType_> ();
425 if (std::isnan (f) or std::isinf (f)) {
432 case Type::eDateTime:
443 [] (
const KVPT& kvp) {
return KVPT{kvp.fKey, kvp.fValue.Normalize ()}; })};
452 if (fVal_ ==
nullptr) {
455 switch (fVal_->GetType ()) {
457 auto v = Debug::UncheckedDynamicCast<const TIRep_<Memory::BLOB>*> (fVal_.get ());
462 return Cryptography::Encoding::Algorithm::Base64::Decode (As<String> ());
467VariantValue::IntegerType_ VariantValue::AsInteger_ ()
const
469 if (fVal_ ==
nullptr) {
472 switch (fVal_->GetType ()) {
473 case Type::eBoolean: {
474 auto v = Debug::UncheckedDynamicCast<const TIRep_<bool>*> (fVal_.get ());
479 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
481 return Math::Round<VariantValue::IntegerType_> (v->fVal);
483 case Type::eInteger: {
484 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
488 case Type::eUnsignedInteger: {
489 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
493 case Type::eString: {
494 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
496 return Characters::String2Int<IntegerType_> (v->fVal);
499#if USE_NOISY_TRACE_IN_THIS_MODULE_
500 DbgTrace (
"failed coerce-to-int: type={}, value={}"_f, fVal_->GetType (), *
this);
507VariantValue::UnsignedIntegerType_ VariantValue::AsUnsignedInteger_ ()
const
509 if (fVal_ ==
nullptr) {
512 switch (fVal_->GetType ()) {
514 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
516 return Math::Round<VariantValue::UnsignedIntegerType_> (v->fVal);
518 case Type::eInteger: {
519 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
523 case Type::eUnsignedInteger: {
524 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
528 case Type::eString: {
529 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
533 return Characters::String2Int<UnsignedIntegerType_> (v->fVal);
536#if USE_NOISY_TRACE_IN_THIS_MODULE_
537 DbgTrace (
"failed coerce-to-uint: type={}, value={}"_f, fVal_->GetType (), *
this);
544VariantValue::FloatType_ VariantValue::AsFloatType_ ()
const
546 if (fVal_ ==
nullptr) {
547 return Math::nan<FloatType_> ();
549 switch (fVal_->GetType ()) {
550 case Type::eInteger: {
551 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
553 return static_cast<FloatType_
> (v->fVal);
555 case Type::eUnsignedInteger: {
556 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
558 return static_cast<FloatType_
> (v->fVal);
561 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
565 case Type::eString: {
566 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
569 return Characters::FloatConversion::ToFloat<FloatType_> (v->fVal);
572#if USE_NOISY_TRACE_IN_THIS_MODULE_
573 DbgTrace (
"failed coerce-to-float: type={}, value={}"_f, fVal_->GetType (), *
this);
580Date VariantValue::AsDate_ ()
const
582 if (fVal_ ==
nullptr) {
585 switch (fVal_->GetType ()) {
587 auto v = Debug::UncheckedDynamicCast<const TIRep_<Date>*> (fVal_.get ());
591 case Type::eDateTime: {
592 auto v = Debug::UncheckedDynamicCast<const TIRep_<DateTime>*> (fVal_.get ());
594 return v->fVal.GetDate ();
596 case Type::eString: {
597 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
602#if USE_NOISY_TRACE_IN_THIS_MODULE_
603 DbgTrace (
"failed coerce-to-date: type={}, value={}"_f, fVal_->GetType (), *
this);
610DateTime VariantValue::AsDateTime_ ()
const
612 if (fVal_ ==
nullptr) {
615 switch (fVal_->GetType ()) {
617 auto v = Debug::UncheckedDynamicCast<const TIRep_<Date>*> (fVal_.get ());
619 return DateTime{v->fVal};
621 case Type::eDateTime: {
622 auto v = Debug::UncheckedDynamicCast<const TIRep_<DateTime>*> (fVal_.get ());
626 case Type::eString: {
627 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
629 return DateTime::Parse (v->fVal, DateTime::kISO8601Format);
632#if USE_NOISY_TRACE_IN_THIS_MODULE_
633 DbgTrace (
"failed coerce-to-datetime: type={}, value={}"_f, fVal_->GetType (), *
this);
640#if qStroika_HasComponent_boost
641boost::json::value VariantValue::AsBoostJSONValue_ ()
const
643 using namespace boost;
644 if (fVal_ ==
nullptr) {
645 return json::value{
nullptr};
647 switch (fVal_->GetType ()) {
649 return json::value{
nullptr};
651 case Type::eBoolean: {
654 case Type::eString: {
656 return As<String> ().AsUTF8<
string> ().c_str ();
658 case Type::eInteger: {
659 return As<IntegerType_> ();
661 case Type::eUnsignedInteger: {
662 return As<UnsignedIntegerType_> ();
665 return static_cast<double> (As<FloatType_> ());
669 case Type::eDateTime: {
671 return As<String> ().AsASCII ().c_str ();
677 result.reserve (srcArray.
size ());
678 for (
const auto& i : srcArray) {
687 for (
const auto& i : srcMap) {
688 result.
insert (json::key_value_pair{i.fKey.As<
String> ().AsUTF8<string> ().
c_str (), i.fValue.As<json::value> ()});
694 return json::value{
nullptr};
699String VariantValue::AsString_ ()
const
701 if (fVal_ ==
nullptr) [[unlikely]] {
704 switch (fVal_->GetType ()) {
709 case Type::eBoolean: {
710 auto v = Debug::UncheckedDynamicCast<const TIRep_<bool>*> (fVal_.get ());
712 return v->fVal ?
"true"sv :
"false"sv;
715 auto v = Debug::UncheckedDynamicCast<const TIRep_<Memory::BLOB>*> (fVal_.get ());
717 return String{Cryptography::Encoding::Algorithm::Base64::Encode (v->fVal)};
719 case Type::eInteger: {
720 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
722 return "{}"_f(v->fVal);
724 case Type::eUnsignedInteger: {
726 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
728 return "{}"_f(v->fVal);
731 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
733 using namespace Characters;
734 return FloatConversion::ToString (v->fVal, FloatConversion::Precision::kFull);
737 auto v = Debug::UncheckedDynamicCast<const TIRep_<Date>*> (fVal_.get ());
741 case Type::eDateTime: {
742 auto v = Debug::UncheckedDynamicCast<const TIRep_<DateTime>*> (fVal_.get ());
744 return v->fVal.Format (DateTime::kISO8601Format);
746 case Type::eString: {
747 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
752 auto v = Debug::UncheckedDynamicCast<const TIRep_<Sequence<VariantValue>>*> (fVal_.get ());
756 for (
auto i = v->fVal.begin (); i != v->fVal.end (); ++i) {
757 if (i != v->fVal.begin ()) {
766 auto v = Debug::UncheckedDynamicCast<const TIRep_<Mapping<String, VariantValue>>*> (fVal_.get ());
770 for (
auto i = v->fVal.begin (); i != v->fVal.end (); ++i) {
771 if (i != v->fVal.begin ()) {
774 tmp << i->fKey <<
" -> "sv << i->fValue.
As<
String> ();
788 if (fVal_ ==
nullptr) [[unlikely]] {
791 switch (fVal_->GetType ()) {
793 auto v = Debug::UncheckedDynamicCast<const TIRep_<Mapping<String, VariantValue>>*> (fVal_.get ());
805 if (fVal_ ==
nullptr) [[unlikely]] {
808 switch (fVal_->GetType ()) {
810 auto v = Debug::UncheckedDynamicCast<const TIRep_<Sequence<VariantValue>>*> (fVal_.get ());
825bool Stroika::Foundation::DataExchange::VariantValue::EqualsComparer::operator() (
const VariantValue& lhs,
const VariantValue& rhs)
const
835 case VariantValue::eNull:
837 case VariantValue::eBoolean:
838 return ln.
As<
bool> () == ln.
As<
bool> ();
839 case VariantValue::eFloat:
840 return Math::NearlyEquals (ln.
As<FloatType_> (), ln.
As<FloatType_> ());
841 case VariantValue::eString:
843 case VariantValue::eArray: {
847 case VariantValue::eMap: {
851 case VariantValue::eBLOB:
852 case VariantValue::eInteger:
853 case VariantValue::eUnsignedInteger:
854 case VariantValue::eDate:
855 case VariantValue::eDateTime:
878 case VariantValue::eNull:
879 return strong_ordering::equal;
880 case VariantValue::eBoolean:
881 return ln.
As<
bool> () <=> ln.
As<
bool> ();
882 case VariantValue::eFloat: {
884 FloatType_ l = ln.
As<FloatType_> ();
885 FloatType_ r = rn.
As<FloatType_> ();
886 if (Math::NearlyEquals (l, r)) {
887 return strong_ordering::equal;
890 return strong_ordering::less;
893 return strong_ordering::greater;
896 case VariantValue::eString:
898 case VariantValue::eArray: {
902 case VariantValue::eMap: {
919 case VariantValue::eBLOB:
920 case VariantValue::eInteger:
921 case VariantValue::eUnsignedInteger:
922 case VariantValue::eDate:
923 case VariantValue::eDateTime:
927 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_HashTable<KEY_TYPE, MAPPED_VALUE_TYPE, TRAITS> is a HashTable based concrete implementation o...
Sequence_stdvector<T> is an std::vector-based concrete implementation of the Sequence<T> container pa...
implement hash table support in a lightweight standard template library style. Use traits to describe...
nonvirtual void insert(const pair< KEY_TYPE, MAPPED_TYPE > &p)
somewhat stdlib-like names - that will do what is expected of someone from stdc++,...
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...