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"
17#include "VariantValue.h"
20using namespace Characters::Literals;
23using Memory::MakeSharedPtr;
29static_assert (regular<VariantValue>);
33 using IntegerType_ =
long long int;
34 using UnsignedIntegerType_ =
unsigned long long int;
35 using FloatType_ =
long double;
45 struct TN_<Memory::
BLOB> {
49 struct TN_<IntegerType_> {
53 struct TN_<UnsignedIntegerType_> {
57 struct TN_<FloatType_> {
65 struct TN_<DateTime> {
84 template <
typename FWD>
85 inline TIRep_ (FWD&& v)
86 : fVal{forward<FWD> (v)}
89 virtual Type GetType ()
const override
91 return TN_<T>::kTYPEENUM;
101const shared_ptr<VariantValue::IRep_> VariantValue::kFalseRep_ = MakeSharedPtr<TIRep_<bool>> (
false);
102const shared_ptr<VariantValue::IRep_> VariantValue::kTrueRep_ = MakeSharedPtr<TIRep_<bool>> (
true);
105 : fVal_{val ? kTrueRep_ : kFalseRep_}
224#if qStroika_HasComponent_boost
226 inline auto mk_ (
const boost::json::value& val) ->
VariantValue
228 using namespace boost;
229 switch (val.kind ()) {
230 case json::kind::null:
233 case json::kind::bool_:
234 return val.as_bool ();
236 case json::kind::double_:
237 return val.as_double ();
239 case json::kind::int64:
240 return val.as_int64 ();
242 case json::kind::uint64:
243 return val.as_uint64 ();
245 case json::kind::string: {
246 const json::string& bs = val.as_string ();
247 return String::FromUTF8 (span{bs});
249 case json::kind::array: {
250 const auto& a = val.as_array ();
251 std::vector<VariantValue> r;
252 r.reserve (a.size ());
253 for (
const boost::json::value& i : a) {
254 r.emplace_back (mk_ (i));
258 case json::kind::object: {
259 const auto& o = val.as_object ();
261 for (
const auto& i : o) {
262 r.
insert ({String::FromUTF8 (span{i.key ()}), mk_ (i.value ())});
280 if (fVal_ ==
nullptr) {
283 switch (fVal_->GetType ()) {
286 case Type::eUnsignedInteger: {
290 auto v = Debug::UncheckedDynamicCast<const TIRep_<Memory::BLOB>*> (fVal_.get ());
291 return v->fVal.
empty ();
294 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
296 return isnan (v->fVal);
301 case Type::eDateTime: {
304 case Type::eString: {
305 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
307 return v->fVal.empty ();
310 auto v = Debug::UncheckedDynamicCast<const TIRep_<Mapping<String, VariantValue>>*> (fVal_.get ());
312 return v->fVal.empty ();
315 auto v = Debug::UncheckedDynamicCast<const TIRep_<Sequence<VariantValue>>*> (fVal_.get ());
317 return v->fVal.empty ();
320 return As<String> ().empty ();
327 return As<String> ();
330bool VariantValue::AsBool_ ()
const
332 if (fVal_ ==
nullptr) {
335 switch (fVal_->GetType ()) {
336 case Type::eBoolean: {
337 auto v = Debug::UncheckedDynamicCast<const TIRep_<bool>*> (fVal_.get ());
341 case Type::eString: {
343 return As<String> () ==
"true"sv;
345 case Type::eInteger: {
346 return As<IntegerType_> () != 0;
348 case Type::eUnsignedInteger: {
349 return As<UnsignedIntegerType_> () != 0;
352#if USE_NOISY_TRACE_IN_THIS_MODULE_
353 DbgTrace (
"failed coerce-to-bool: type={}, value={}"_f, fVal_->GetType (), *
this);
362 if (GetType () == to) [[likely]] {
377 if (GetType () == to) [[likely]] {
386 return As<Memory::BLOB> ();
391 case Type::eUnsignedInteger:
392 return As<unsigned int> ();
394 return As<FloatType_> ();
396 return As<Time::Date> ();
397 case Type::eDateTime:
398 return As<Time::DateTime> ();
400 return As<String> ();
404 return VariantValue{As<Mapping<String, VariantValue>> ()};
413 switch (GetType ()) {
422 case Type::eUnsignedInteger:
427 FloatType_ f = As<FloatType_> ();
428 if (std::isnan (f) or std::isinf (f)) {
435 case Type::eDateTime:
446 [] (
const KVPT& kvp) {
return KVPT{kvp.fKey, kvp.fValue.Normalize ()}; })};
455 if (fVal_ ==
nullptr) {
458 switch (fVal_->GetType ()) {
460 auto v = Debug::UncheckedDynamicCast<const TIRep_<Memory::BLOB>*> (fVal_.get ());
465 return Cryptography::Encoding::Algorithm::Base64::Decode (As<String> ());
470VariantValue::IntegerType_ VariantValue::AsInteger_ ()
const
472 if (fVal_ ==
nullptr) {
475 switch (fVal_->GetType ()) {
476 case Type::eBoolean: {
477 auto v = Debug::UncheckedDynamicCast<const TIRep_<bool>*> (fVal_.get ());
482 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
484 return Math::Round<VariantValue::IntegerType_> (v->fVal);
486 case Type::eInteger: {
487 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
491 case Type::eUnsignedInteger: {
492 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
496 case Type::eString: {
497 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
499 return Characters::String2Int<IntegerType_> (v->fVal);
502#if USE_NOISY_TRACE_IN_THIS_MODULE_
503 DbgTrace (
"failed coerce-to-int: type={}, value={}"_f, fVal_->GetType (), *
this);
510VariantValue::UnsignedIntegerType_ VariantValue::AsUnsignedInteger_ ()
const
512 if (fVal_ ==
nullptr) {
515 switch (fVal_->GetType ()) {
517 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
519 return Math::Round<VariantValue::UnsignedIntegerType_> (v->fVal);
521 case Type::eInteger: {
522 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
526 case Type::eUnsignedInteger: {
527 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
531 case Type::eString: {
532 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
536 return Characters::String2Int<UnsignedIntegerType_> (v->fVal);
539#if USE_NOISY_TRACE_IN_THIS_MODULE_
540 DbgTrace (
"failed coerce-to-uint: type={}, value={}"_f, fVal_->GetType (), *
this);
547VariantValue::FloatType_ VariantValue::AsFloatType_ ()
const
549 if (fVal_ ==
nullptr) {
550 return Math::nan<FloatType_> ();
552 switch (fVal_->GetType ()) {
553 case Type::eInteger: {
554 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
556 return static_cast<FloatType_
> (v->fVal);
558 case Type::eUnsignedInteger: {
559 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
561 return static_cast<FloatType_
> (v->fVal);
564 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
568 case Type::eString: {
569 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
572 return Characters::FloatConversion::ToFloat<FloatType_> (v->fVal);
575#if USE_NOISY_TRACE_IN_THIS_MODULE_
576 DbgTrace (
"failed coerce-to-float: type={}, value={}"_f, fVal_->GetType (), *
this);
583Date VariantValue::AsDate_ ()
const
585 if (fVal_ ==
nullptr) {
588 switch (fVal_->GetType ()) {
590 auto v = Debug::UncheckedDynamicCast<const TIRep_<Date>*> (fVal_.get ());
594 case Type::eDateTime: {
595 auto v = Debug::UncheckedDynamicCast<const TIRep_<DateTime>*> (fVal_.get ());
597 return v->fVal.GetDate ();
599 case Type::eString: {
600 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
605#if USE_NOISY_TRACE_IN_THIS_MODULE_
606 DbgTrace (
"failed coerce-to-date: type={}, value={}"_f, fVal_->GetType (), *
this);
613DateTime VariantValue::AsDateTime_ ()
const
615 if (fVal_ ==
nullptr) {
618 switch (fVal_->GetType ()) {
620 auto v = Debug::UncheckedDynamicCast<const TIRep_<Date>*> (fVal_.get ());
622 return DateTime{v->fVal};
624 case Type::eDateTime: {
625 auto v = Debug::UncheckedDynamicCast<const TIRep_<DateTime>*> (fVal_.get ());
629 case Type::eString: {
630 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
632 return DateTime::Parse (v->fVal, DateTime::kISO8601Format);
635#if USE_NOISY_TRACE_IN_THIS_MODULE_
636 DbgTrace (
"failed coerce-to-datetime: type={}, value={}"_f, fVal_->GetType (), *
this);
643#if qStroika_HasComponent_boost
644boost::json::value VariantValue::AsBoostJSONValue_ ()
const
646 using namespace boost;
647 if (fVal_ ==
nullptr) {
648 return json::value{
nullptr};
650 switch (fVal_->GetType ()) {
652 return json::value{
nullptr};
654 case Type::eBoolean: {
657 case Type::eString: {
659 return As<String> ().AsUTF8<
string> ().c_str ();
661 case Type::eInteger: {
662 return As<IntegerType_> ();
664 case Type::eUnsignedInteger: {
665 return As<UnsignedIntegerType_> ();
668 return static_cast<double> (As<FloatType_> ());
672 case Type::eDateTime: {
674 return As<String> ().AsASCII ().c_str ();
680 result.reserve (srcArray.
size ());
681 for (
const auto& i : srcArray) {
690 for (
const auto& i : srcMap) {
691 result.
insert (json::key_value_pair{i.fKey.As<
String> ().AsUTF8<string> ().
c_str (), i.fValue.As<json::value> ()});
697 return json::value{
nullptr};
702String VariantValue::AsString_ ()
const
704 if (fVal_ ==
nullptr) [[unlikely]] {
707 switch (fVal_->GetType ()) {
712 case Type::eBoolean: {
713 auto v = Debug::UncheckedDynamicCast<const TIRep_<bool>*> (fVal_.get ());
715 return v->fVal ?
"true"sv :
"false"sv;
718 auto v = Debug::UncheckedDynamicCast<const TIRep_<Memory::BLOB>*> (fVal_.get ());
720 return String{Cryptography::Encoding::Algorithm::Base64::Encode (v->fVal)};
722 case Type::eInteger: {
723 auto v = Debug::UncheckedDynamicCast<const TIRep_<IntegerType_>*> (fVal_.get ());
725 return "{}"_f(v->fVal);
727 case Type::eUnsignedInteger: {
729 auto v = Debug::UncheckedDynamicCast<const TIRep_<UnsignedIntegerType_>*> (fVal_.get ());
731 return "{}"_f(v->fVal);
734 auto v = Debug::UncheckedDynamicCast<const TIRep_<FloatType_>*> (fVal_.get ());
736 using namespace Characters;
737 return FloatConversion::ToString (v->fVal, FloatConversion::Precision::kFull);
740 auto v = Debug::UncheckedDynamicCast<const TIRep_<Date>*> (fVal_.get ());
744 case Type::eDateTime: {
745 auto v = Debug::UncheckedDynamicCast<const TIRep_<DateTime>*> (fVal_.get ());
747 return v->fVal.Format (DateTime::kISO8601Format);
749 case Type::eString: {
750 auto v = Debug::UncheckedDynamicCast<const TIRep_<String>*> (fVal_.get ());
755 auto v = Debug::UncheckedDynamicCast<const TIRep_<Sequence<VariantValue>>*> (fVal_.get ());
759 for (
auto i = v->fVal.begin (); i != v->fVal.end (); ++i) {
760 if (i != v->fVal.begin ()) {
769 auto v = Debug::UncheckedDynamicCast<const TIRep_<Mapping<String, VariantValue>>*> (fVal_.get ());
773 for (
auto i = v->fVal.begin (); i != v->fVal.end (); ++i) {
774 if (i != v->fVal.begin ()) {
777 tmp << i->fKey <<
" -> "sv << i->fValue.
As<
String> ();
791 if (fVal_ ==
nullptr) [[unlikely]] {
794 switch (fVal_->GetType ()) {
796 auto v = Debug::UncheckedDynamicCast<const TIRep_<Mapping<String, VariantValue>>*> (fVal_.get ());
808 if (fVal_ ==
nullptr) [[unlikely]] {
811 switch (fVal_->GetType ()) {
813 auto v = Debug::UncheckedDynamicCast<const TIRep_<Sequence<VariantValue>>*> (fVal_.get ());
828bool Stroika::Foundation::DataExchange::VariantValue::EqualsComparer::operator() (
const VariantValue& lhs,
const VariantValue& rhs)
const
838 case VariantValue::eNull:
840 case VariantValue::eBoolean:
841 return ln.
As<
bool> () == rn.
As<
bool> ();
842 case VariantValue::eFloat:
843 return Math::NearlyEquals (ln.
As<FloatType_> (), rn.
As<FloatType_> ());
844 case VariantValue::eString:
846 case VariantValue::eArray: {
850 case VariantValue::eMap: {
854 case VariantValue::eBLOB:
855 case VariantValue::eInteger:
856 case VariantValue::eUnsignedInteger:
857 case VariantValue::eDate:
858 case VariantValue::eDateTime:
881 case VariantValue::eNull:
882 return strong_ordering::equal;
883 case VariantValue::eBoolean:
884 return ln.
As<
bool> () <=> rn.
As<
bool> ();
885 case VariantValue::eFloat: {
887 FloatType_ l = ln.
As<FloatType_> ();
888 FloatType_ r = rn.
As<FloatType_> ();
889 if (Math::NearlyEquals (l, r)) {
890 return strong_ordering::equal;
893 return strong_ordering::less;
896 return strong_ordering::greater;
899 case VariantValue::eString:
901 case VariantValue::eArray: {
905 case VariantValue::eMap: {
922 case VariantValue::eBLOB:
923 case VariantValue::eInteger:
924 case VariantValue::eUnsignedInteger:
925 case VariantValue::eDate:
926 case VariantValue::eDateTime:
930 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...