CppWAMP
C++11 client library for the WAMP protocol
variant.hpp
Go to the documentation of this file.
1 /*------------------------------------------------------------------------------
2  Copyright Butterfly Energy Systems 2014-2016, 2018, 2022.
3  Distributed under the Boost Software License, Version 1.0.
4  http://www.boost.org/LICENSE_1_0.txt
5 ------------------------------------------------------------------------------*/
6 
7 #ifndef CPPWAMP_VARIANT_HPP
8 #define CPPWAMP_VARIANT_HPP
9 
10 //------------------------------------------------------------------------------
14 //------------------------------------------------------------------------------
15 
16 #include <algorithm>
17 #include <cstdint>
18 #include <map>
19 #include <ostream>
20 #include <sstream>
21 #include <stdexcept>
22 #include <string>
23 #include <type_traits>
24 #include <utility>
25 #include <vector>
26 #include "api.hpp"
27 #include "blob.hpp"
28 #include "conversionaccess.hpp"
29 #include "error.hpp"
30 #include "null.hpp"
31 #include "traits.hpp"
32 #include "variantdefs.hpp"
33 #include "visitor.hpp"
34 #include "internal/varianttraits.hpp"
35 #include "internal/variantvisitors.hpp"
36 
37 //------------------------------------------------------------------------------
56 //------------------------------------------------------------------------------
57 #define CPPWAMP_CONVERSION_SPLIT_FREE(Type) \
58 inline void convert(::wamp::FromVariantConverter& c, Type& obj) \
59 { \
60  convertFrom(c, obj); \
61 } \
62  \
63 inline void convert(::wamp::ToVariantConverter& c, Type& obj) \
64 { \
65  convertTo(c, const_cast<const Type&>(obj)); \
66 }
67 
68 //------------------------------------------------------------------------------
87 //------------------------------------------------------------------------------
88 #define CPPWAMP_CONVERSION_SPLIT_MEMBER(Type) \
89 inline void convert(::wamp::FromVariantConverter& c, Type& obj) \
90 { \
91  wamp::ConversionAccess::convertFrom(c, obj); \
92 } \
93  \
94 inline void convert(::wamp::ToVariantConverter& c, Type& obj) \
95 { \
96  const auto& constObj = obj; \
97  wamp::ConversionAccess::convertTo(c, constObj); \
98 }
99 
100 
101 namespace wamp
102 {
103 
104 //------------------------------------------------------------------------------
105 // Forward declaration
106 namespace internal {template <TypeId typeId> struct FieldTypeForId;}
107 
108 //------------------------------------------------------------------------------
133 //------------------------------------------------------------------------------
134 class CPPWAMP_API Variant
135 {
136 private:
137  template <typename TField, typename Enable = void>
138  using ArgTraits = internal::ArgTraits<TField>;
139 
140 public:
143 
144  template <TypeId typeId>
145  using BoundTypeForId = typename internal::FieldTypeForId<typeId>::Type;
146 
149  template <typename T>
150  static constexpr bool isValidArg() noexcept
151  {
152  return ArgTraits<ValueTypeOf<T>>::isValid;
153  }
154 
155  /* Indicates that the given argument type is not convertible
156  to a bound type. */
157  template <typename T>
158  static constexpr bool isInvalidArg() noexcept
159  {
160  return !ArgTraits<ValueTypeOf<T>>::isValid &&
161  !isSameType<T, Variant>();
162  }
163 
164  /* Indicates that the given argument type is a Variant. */
165  template <typename T>
166  static constexpr bool isVariantArg() noexcept
167  {
168  return isSameType<ValueTypeOf<T>, Variant>();
169  }
170 
172 
175  using Null = wamp::Null;
176  using Bool = wamp::Bool;
177  using Int = wamp::Int;
178  using UInt = wamp::UInt;
179  using Real = wamp::Real;
181  using Blob = wamp::Blob;
182  using Array = wamp::Array;
184 
187  using SizeType = Array::size_type;
188 
190  using CharType = String::value_type;
191 
194 
196  template <typename TValue>
197  static Variant from(TValue&& value);
198 
200  Variant() noexcept;
201 
203  Variant(const Variant& other);
204 
206  Variant(Variant&& other) noexcept;
207 
209  template <typename T, CPPWAMP_ENABLE_IF(Variant::isValidArg<T>()) = 0>
210  Variant(T value);
211 
213  Variant(Array array);
214 
217  template <typename T> Variant(std::vector<T> vec);
218 
220  Variant(Object object);
221 
223  template <typename T> Variant(std::map<String, T> map);
224 
226  ~Variant();
227 
229 
232 
234  TypeId typeId() const;
235 
237  explicit operator bool() const;
238 
241  template <typename TBound> bool is() const;
242 
245  template <TypeId id> bool is() const;
246 
248  template <typename T> T to() const;
249 
252  template <typename T> void to(T& value) const;
253 
256  template <typename T>
257  ValueTypeOf<T> valueOr(T&& fallback) const;
258 
260  SizeType size() const;
261 
263 
266 
268  template <typename TBound> TBound& as();
269 
271  template <typename TBound> const TBound& as() const;
272 
274  template <TypeId id> BoundTypeForId<id>& as();
275 
277  template <TypeId id> const BoundTypeForId<id>& as() const;
278 
280  Variant& operator[](SizeType index);
281 
283  const Variant& operator[](SizeType index) const;
284 
286  Variant& at(SizeType index);
287 
289  const Variant& at(SizeType index) const;
290 
292  Variant& operator[](const String& key);
293 
295  Variant& at(const String& key);
296 
298  const Variant& at(const String& key) const;
299 
301 
304 
306  bool operator==(const Variant& other) const;
307 
309  bool operator!=(const Variant& other) const;
310 
312  bool operator<(const Variant& other) const;
313 
315 
318 
320  Variant& operator=(const Variant& other);
321 
323  Variant& operator=(Variant&& other) noexcept;
324 
326  template <typename T> Variant& operator=(T value);
327 
329  Variant& operator=(Array array);
330 
332  template <typename T> Variant& operator=(std::vector<T> vec);
333 
335  Variant& operator=(Object object);
336 
338  template <typename T> Variant& operator=(std::map<String, T> map);
339 
341  void swap(Variant& other) noexcept;
342 
344 
345 private:
346  class CPPWAMP_HIDDEN Construct;
347  class CPPWAMP_HIDDEN MoveConstruct;
348  class CPPWAMP_HIDDEN MoveAssign;
349  class CPPWAMP_HIDDEN Destruct;
350  class CPPWAMP_HIDDEN Swap;
351  class CPPWAMP_HIDDEN ElementCount;
352  class CPPWAMP_HIDDEN LessThan;
353  class CPPWAMP_HIDDEN Output;
354 
355  template <typename TField>
356  using FieldTraits = internal::FieldTraits<TField>;
357 
358  template <typename TField>
359  using Access = internal::Access<TField>;
360 
361  template <typename... TFields> struct CPPWAMP_HIDDEN TypeMask;
362 
363  template <TypeId... typeIds> struct CPPWAMP_HIDDEN TypeIdMask;
364 
365  template <typename TValue, typename TArg>
366  CPPWAMP_HIDDEN void constructAs(TArg&& value);
367 
368  template <typename TField>
369  CPPWAMP_HIDDEN void destructAs();
370 
371  // Can't be hidden; invoked from inline operator=(T)
372  void destruct();
373 
374  template <typename T, EnableIf<Variant::isValidArg<T>()> = 0>
375  CPPWAMP_HIDDEN static Variant convertFrom(T&& value);
376 
377  template <typename T, EnableIf<Variant::isInvalidArg<T>()> = 0>
378  CPPWAMP_HIDDEN static Variant convertFrom(const T& value);
379 
380  template <typename T, EnableIf<Variant::isVariantArg<T>()> = 0>
381  CPPWAMP_HIDDEN static Variant convertFrom(const T& variant);
382 
383  template <typename T, EnableIf<Variant::isInvalidArg<T>()> = 0>
384  CPPWAMP_HIDDEN static Variant convertFrom(const std::vector<T>& vec);
385 
386  template <typename T, EnableIf<Variant::isInvalidArg<T>()> = 0>
387  CPPWAMP_HIDDEN static Variant convertFrom(const std::map<String, T>& map);
388 
389  template <typename T, EnableIf<Variant::isValidArg<T>()> = 0>
390  CPPWAMP_HIDDEN void convertTo(T& value) const;
391 
392  template <typename T, EnableIf<Variant::isInvalidArg<T>()> = 0>
393  CPPWAMP_HIDDEN void convertTo(T& value) const;
394 
395  template <typename T, EnableIf<Variant::isVariantArg<T>()> = 0>
396  CPPWAMP_HIDDEN void convertTo(T& variant) const;
397 
398  template <typename T, EnableIf<Variant::isInvalidArg<T>()> = 0>
399  CPPWAMP_HIDDEN void convertTo(std::vector<T>& vec) const;
400 
401  template <typename T, EnableIf<Variant::isInvalidArg<T>()> = 0>
402  CPPWAMP_HIDDEN void convertTo(std::map<String, T>& map) const;
403 
404  template <typename TField, typename V>
405  CPPWAMP_HIDDEN static TField& get(V&& variant);
406 
407  union Field
408  {
409  Field();
410  ~Field();
411  Null nullValue;
412  Bool boolean;
413  Int integer;
414  UInt uint;
415  Real real;
416  String string;
417  Blob* blob;
418  Array* array;
419  Object* object;
420  } field_;
421 
422  TypeId typeId_;
423 };
424 
425 
426 //------------------------------------------------------------------------------
428 //------------------------------------------------------------------------------
430 
434 CPPWAMP_API void swap(Variant& v, Variant& w) noexcept;
435 
437 
438 //------------------------------------------------------------------------------
440 //------------------------------------------------------------------------------
442 
450 CPPWAMP_API bool isNumber(const Variant& v);
451 
459 CPPWAMP_API bool isScalar(const Variant& v);
460 
467 CPPWAMP_API Variant::String typeNameOf(const Variant& v);
468 
474 template <typename TBound>
475 CPPWAMP_API Variant::String typeNameOf();
476 
478 
479 //------------------------------------------------------------------------------
481 //------------------------------------------------------------------------------
483 
484 CPPWAMP_API std::ostream& operator<<(std::ostream& out, const Array& a);
485 
487 CPPWAMP_API std::ostream& operator<<(std::ostream& out, const Object& o);
488 
490 CPPWAMP_API std::ostream& operator<<(std::ostream& out, const Variant& v);
491 
493 CPPWAMP_API std::string toString(const Array& a);
494 
496 CPPWAMP_API std::string toString(const Object& o);
497 
499 CPPWAMP_API std::string toString(const Variant& v);
501 
502 
503 //------------------------------------------------------------------------------
505 //------------------------------------------------------------------------------
507 
523 template <typename T>
524 CPPWAMP_API bool operator==(const Variant& variant, const T& value);
525 
529 template <typename T>
530 CPPWAMP_API bool operator==(const T& value, const Variant& variant);
531 
536 CPPWAMP_API bool operator==(const Variant& variant,
537  const Variant::CharType* str);
538 
543 CPPWAMP_API bool operator==(const Variant::CharType* str,
544  const Variant& variant);
545 
550 CPPWAMP_API bool operator==(const Variant& variant, Variant::CharType* str);
551 
556 CPPWAMP_API bool operator==(Variant::CharType* str, const Variant& variant);
557 
561 template <typename T>
562 bool operator!=(const Variant& variant, const T& value);
563 
567 template <typename T>
568 CPPWAMP_API bool operator!=(const T& value, const Variant& variant);
569 
574 CPPWAMP_API bool operator!=(const Variant& variant,
575  const Variant::CharType* str);
576 
581 CPPWAMP_API bool operator!=(const Variant::CharType* str,
582  const Variant& variant);
583 
588 CPPWAMP_API bool operator!=(const Variant& variant, Variant::CharType* str);
589 
594 CPPWAMP_API bool operator!=(Variant::CharType* str, const Variant& variant);
595 
597 
598 
599 //------------------------------------------------------------------------------
603 //------------------------------------------------------------------------------
604 class CPPWAMP_API ToVariantConverter
605 {
606 public:
608  using SizeType = size_t;
609 
611  using String = std::string;
612 
614  static constexpr bool convertingToVariant = true;
615 
617  explicit ToVariantConverter(Variant& var);
618 
620  ToVariantConverter& size(SizeType n);
621 
623  template <typename T>
624  ToVariantConverter& operator()(T&& value);
625 
627  template <typename T>
628  ToVariantConverter& operator[](T&& value);
629 
631  template <typename T>
632  ToVariantConverter& operator()(String key, T&& value);
633 
635  template <typename T, typename U>
636  ToVariantConverter& operator()(String key, T&& value, U&& ignored);
637 
639  Variant& variant();
640 
641 private:
642  Variant& var_;
643 };
644 
645 //------------------------------------------------------------------------------
649 //------------------------------------------------------------------------------
650 class CPPWAMP_API FromVariantConverter
651 {
652 public:
654  using SizeType = size_t;
655 
657  using String = std::string;
658 
660  static constexpr bool convertingToVariant = false;
661 
663  explicit FromVariantConverter(const Variant& var);
664 
666  SizeType size() const;
667 
669  FromVariantConverter& size(SizeType& n);
670 
672  template <typename T>
673  FromVariantConverter& operator()(T& value);
674 
676  template <typename T>
677  FromVariantConverter& operator[](T& value);
678 
680  template <typename T>
681  FromVariantConverter& operator()(const String& key, T& value);
682 
685  template <typename T, typename U>
686  FromVariantConverter& operator()(const String& key, T& value, U&& fallback);
687 
689  const Variant& variant() const;
690 
691 private:
692  const Variant& var_;
693  SizeType index_ = 0;
694 };
695 
696 
697 //------------------------------------------------------------------------------
706 //------------------------------------------------------------------------------
707 template <typename TConverter, typename TValue,
709 CPPWAMP_API inline void convert(TConverter& c, TValue& val)
710 {
711  // Fall back to intrusive conversion if 'convert' was not specialized
712  // for the given type.
713  ConversionAccess::convert(c, val);
714 }
715 
716 //------------------------------------------------------------------------------
718 //------------------------------------------------------------------------------
719 template <typename TEnum, EnableIf<std::is_enum<TEnum>::value> = 0>
720 CPPWAMP_API inline void convert(const FromVariantConverter& c, TEnum& e)
721 {
722  using U = typename std::underlying_type<TEnum>::type;
723  auto n = c.variant().to<U>();
724  e = static_cast<TEnum>(n);
725 }
726 
727 //------------------------------------------------------------------------------
729 //------------------------------------------------------------------------------
730 template <typename TEnum, EnableIf<std::is_enum<TEnum>::value> = 0>
731 CPPWAMP_API inline void convert(ToVariantConverter& c, const TEnum& e)
732 {
733  using U = typename std::underlying_type<TEnum>::type;
734  c.variant() = static_cast<U>(e);
735 }
736 
737 
738 //******************************************************************************
739 // Variant template member function implementations
740 //******************************************************************************
741 
742 //------------------------------------------------------------------------------
743 template <typename TValue>
744 Variant Variant::from(TValue&& value)
745 {
746  return convertFrom(std::forward<TValue>(value));
747 }
748 
749 //------------------------------------------------------------------------------
756 //------------------------------------------------------------------------------
757 template <typename T, CPPWAMP_ENABLE_IF(Variant::isValidArg<T>())>
759 {
760  static_assert(ArgTraits<T>::isValid, "Invalid argument type");
761  using FieldType = typename ArgTraits<T>::FieldType;
762  typeId_ = FieldTraits<FieldType>::typeId;
763  constructAs<FieldType>(std::move(value));
764 }
765 
766 //------------------------------------------------------------------------------
771 //------------------------------------------------------------------------------
772 template <typename T> Variant::Variant(std::vector<T> vec)
773  : typeId_(TypeId::array)
774 {
775  static_assert(ArgTraits<T>::isValid, "Invalid vector element type");
776  Array array;
777  array.reserve(vec.size());
778  std::move(vec.begin(), vec.end(), std::back_inserter(array));
779  constructAs<Array>(std::move(array));
780 }
781 
782 //------------------------------------------------------------------------------
787 //------------------------------------------------------------------------------
788 template <typename T> Variant::Variant(std::map<String, T> map)
789  : typeId_(TypeId::object)
790 {
791  static_assert(ArgTraits<T>::isValid, "Invalid map value type");
792  Object object;
793  std::move(map.begin(), map.end(), std::inserter(object, object.begin()));
794  constructAs<Object>(std::move(object));
795 }
796 
797 //------------------------------------------------------------------------------
798 template <typename TBound> bool Variant::is() const
799 {
800  static_assert(FieldTraits<TBound>::isValid, "Invalid field type");
801  return typeId_ == FieldTraits<TBound>::typeId;
802 }
803 
804 //------------------------------------------------------------------------------
805 template <TypeId id> bool Variant::is() const
806 {
807  return is<BoundTypeForId<id>>();
808 }
809 
810 //------------------------------------------------------------------------------
839 //------------------------------------------------------------------------------
840 template <typename T> T Variant::to() const
841 {
842  T result(std::move(ConversionAccess::defaultConstruct<T>()));
843  convertTo(result);
844  return result;
845 }
846 
847 //------------------------------------------------------------------------------
852 //------------------------------------------------------------------------------
853 template <typename T> void Variant::to(T& value) const
854 {
855  convertTo(value);
856 }
857 
858 //------------------------------------------------------------------------------
863 //------------------------------------------------------------------------------
864 template <typename T>
865 ValueTypeOf<T> Variant::valueOr(T&& fallback) const
866 {
867  if (!*this)
868  return std::forward<T>(fallback);
869  else
870  return this->to< ValueTypeOf<T> >();
871 }
872 
873 //------------------------------------------------------------------------------
878 //------------------------------------------------------------------------------
879 template <typename TBound> TBound& Variant::as()
880 {
881  return get<TBound>(*this);
882 }
883 
884 //------------------------------------------------------------------------------
889 //------------------------------------------------------------------------------
890 template <typename TBound> const TBound& Variant::as() const
891 {
892  return get<const TBound>(*this);
893 }
894 
895 //------------------------------------------------------------------------------
899 //------------------------------------------------------------------------------
900 template <TypeId id>
902 {
903  return as<BoundTypeForId<id>>();
904 }
905 
906 //------------------------------------------------------------------------------
910 //------------------------------------------------------------------------------
911 template <TypeId id>
913 {
914  return as<BoundTypeForId<id>>();
915 }
916 
917 //------------------------------------------------------------------------------
924 //------------------------------------------------------------------------------
925 template <typename T> Variant& Variant::operator=(T value)
926 {
927  static_assert(ArgTraits<T>::isValid, "Invalid argument type");
928 
929  using FieldType = typename ArgTraits<T>::FieldType;
930  if (is<FieldType>())
931  as<FieldType>() = std::move(value);
932  else
933  {
934  destruct();
935  constructAs<FieldType>(std::move(value));
936  typeId_ = FieldTraits<FieldType>::typeId;
937  }
938  return *this;
939 }
940 
941 //------------------------------------------------------------------------------
946 //------------------------------------------------------------------------------
947 template <typename T>
948 Variant& Variant::operator=(std::vector<T> vec)
949 {
950  static_assert(ArgTraits<T>::isValid, "Invalid vector element type");
951 
952  Array array;
953  array.reserve(vec.size());
954  std::move(vec.begin(), vec.end(), std::back_inserter(array));
955  return *this = std::move(array);
956 }
957 
958 //------------------------------------------------------------------------------
963 //------------------------------------------------------------------------------
964 template <typename T>
965 Variant& Variant::operator=(std::map<String,T> map)
966 {
967  static_assert(ArgTraits<T>::isValid, "Invalid map value type");
968  Object object(map.cbegin(), map.cend());
969  return *this = std::move(object);
970 }
971 
972 //------------------------------------------------------------------------------
973 template <typename TField, typename TArg>
974 void Variant::constructAs(TArg&& value)
975 {
976  Access<TField>::construct(std::forward<TArg>(value), &field_);
977 }
978 
979 //------------------------------------------------------------------------------
980 template <typename TField> void Variant::destructAs()
981 {
982  Access<TField>::destruct(&field_);
983 }
984 
985 //------------------------------------------------------------------------------
986 template <typename T, EnableIf<Variant::isValidArg<T>()>>
987 Variant Variant::convertFrom(T&& value)
988 {
989  return Variant(std::forward<T>(value));
990 }
991 
992 //------------------------------------------------------------------------------
993 template <typename T, EnableIf<Variant::isInvalidArg<T>()>>
994 Variant Variant::convertFrom(const T& value)
995 {
996  Variant v;
997  ToVariantConverter conv(v);
998  convert(conv, const_cast<T&>(value));
999  return v;
1000 }
1001 
1002 //------------------------------------------------------------------------------
1003 template <typename T, EnableIf<Variant::isVariantArg<T>()>>
1004 Variant Variant::convertFrom(const T& variant)
1005 {
1006  return variant;
1007 }
1008 
1009 //------------------------------------------------------------------------------
1010 template <typename T, EnableIf<Variant::isInvalidArg<T>()>>
1011 Variant Variant::convertFrom(const std::vector<T>& vec)
1012 {
1014  for (const auto& elem: vec)
1015  array.emplace_back(Variant::convertFrom(elem));
1016  return Variant(std::move(array));
1017 }
1018 
1019 //------------------------------------------------------------------------------
1020 template <typename T, EnableIf<Variant::isInvalidArg<T>()>>
1021 Variant Variant::convertFrom(const std::map<String, T>& map)
1022 {
1024  for (const auto& kv: map)
1025  object.emplace(kv.first, Variant::convertFrom(kv.second));
1026  return Variant(std::move(object));
1027 }
1028 
1029 //------------------------------------------------------------------------------
1030 template <typename T, EnableIf<Variant::isValidArg<T>()>>
1031 void Variant::convertTo(T& value) const
1032 {
1033  applyWithOperand(internal::VariantConvertTo<Variant>(), *this, value);
1034 }
1035 
1036 //------------------------------------------------------------------------------
1037 template <typename T, EnableIf<Variant::isInvalidArg<T>()>>
1038 void Variant::convertTo(T& value) const
1039 {
1040  FromVariantConverter conv(*this);
1041  convert(conv, value);
1042 }
1043 
1044 //------------------------------------------------------------------------------
1045 template <typename T, EnableIf<Variant::isVariantArg<T>()>>
1046 void Variant::convertTo(T& variant) const
1047 {
1048  variant = *this;
1049 }
1050 
1051 //------------------------------------------------------------------------------
1052 template <typename T, EnableIf<Variant::isInvalidArg<T>()>>
1053 void Variant::convertTo(std::vector<T>& vec) const
1054 {
1055  const auto& array = this->as<Array>();
1056  for (const auto& elem: array)
1057  {
1058  T value;
1059  elem.convertTo(value);
1060  vec.emplace_back(std::move(value));
1061  }
1062 }
1063 
1064 //------------------------------------------------------------------------------
1065 template <typename T, EnableIf<Variant::isInvalidArg<T>()>>
1066 void Variant::convertTo(std::map<String, T>& map) const
1067 {
1068  const auto& object = this->as<Object>();
1069  for (const auto& kv: object)
1070  {
1071  T value;
1072  kv.second.convertTo(value);
1073  map.emplace(std::move(kv.first), std::move(value));
1074  }
1075 }
1076 
1077 //------------------------------------------------------------------------------
1078 template <typename TField, typename V> TField& Variant::get(V&& variant)
1079 {
1080  using FieldType = typename std::remove_const<TField>::type;
1081  static_assert(FieldTraits<FieldType>::isValid, "Invalid field type");
1082  if (!variant.template is<FieldType>())
1083  throw error::Access(wamp::typeNameOf(variant),
1084  FieldTraits<FieldType>::typeName());
1085  return Access<FieldType>::get(&variant.field_);
1086 }
1087 
1088 //------------------------------------------------------------------------------
1089 template <typename TBound>
1090 Variant::String typeNameOf()
1091 {
1092  return internal::FieldTraits<TBound>::typeName();
1093 }
1094 
1095 //------------------------------------------------------------------------------
1096 template <typename T>
1097 bool operator==(const Variant& variant, const T& value)
1098 {
1099  static_assert(internal::ArgTraits<T>::isValid,
1100  "Invalid value type");
1101  return applyWithOperand(internal::VariantEquivalentTo<Variant>(), variant,
1102  value);
1103 }
1104 
1105 //------------------------------------------------------------------------------
1106 template <typename T>
1107 bool operator==(const T& value, const Variant& variant)
1108 {
1109  return variant == value;
1110 }
1111 
1112 //------------------------------------------------------------------------------
1113 template <typename T>
1114 bool operator!=(const Variant& variant, const T& value)
1115 {
1116  static_assert(internal::ArgTraits<T>::isValid,
1117  "Invalid value type");
1118  return applyWithOperand(internal::VariantNotEquivalentTo<Variant>(),
1119  variant, value);
1120 }
1121 
1122 //------------------------------------------------------------------------------
1123 template <typename T>
1124 bool operator!=(const T& value, const Variant& variant)
1125 {
1126  return variant != value;
1127 }
1128 
1129 
1130 //******************************************************************************
1131 // ToVariantConverter implementation
1132 //******************************************************************************
1133 
1134 //------------------------------------------------------------------------------
1136 
1137 //------------------------------------------------------------------------------
1142 //------------------------------------------------------------------------------
1144 {
1145  Array array;
1146  array.reserve(n);
1147  var_ = std::move(array);
1148  return *this;
1149 }
1150 
1151 //------------------------------------------------------------------------------
1155 //------------------------------------------------------------------------------
1156 template <typename T>
1158 {
1159  var_ = Variant::from(std::forward<T>(value));
1160  return *this;
1161 }
1162 
1163 //------------------------------------------------------------------------------
1168 //------------------------------------------------------------------------------
1169 template <typename T>
1171 {
1172  if (!var_.is<Array>())
1173  var_ = Array();
1174  auto& array = var_.as<Array>();
1175  array.emplace_back(Variant::from(std::forward<T>(value)));
1176  return *this;
1177 }
1178 
1179 //------------------------------------------------------------------------------
1184 //------------------------------------------------------------------------------
1185 template <typename T>
1187 {
1188  if (!var_.is<Object>())
1189  var_ = Object();
1190  auto& object = var_.as<Object>();
1191  object.emplace( std::move(key),
1192  Variant::from(std::forward<T>(value)) );
1193  return *this;
1194 }
1195 
1196 //------------------------------------------------------------------------------
1201 //------------------------------------------------------------------------------
1202 template <typename T, typename U>
1204 {
1205  return operator()(std::move(key), std::forward<T>(value));
1206 }
1207 
1208 inline Variant& ToVariantConverter::variant() {return var_;}
1209 
1210 
1211 //******************************************************************************
1212 // FromVariantConverter implementation
1213 //******************************************************************************
1214 
1215 //------------------------------------------------------------------------------
1217  : var_(var)
1218 {}
1219 
1220 //------------------------------------------------------------------------------
1224 //------------------------------------------------------------------------------
1226 {
1227  return var_.size();
1228 }
1229 
1230 //------------------------------------------------------------------------------
1234 //------------------------------------------------------------------------------
1236 {
1237  n = var_.size();
1238  return *this;
1239 }
1240 
1241 //------------------------------------------------------------------------------
1248 //------------------------------------------------------------------------------
1249 template <typename T>
1251 {
1252  var_.to(value);
1253  return *this;
1254 }
1255 
1256 //------------------------------------------------------------------------------
1267 //------------------------------------------------------------------------------
1268 template <typename T>
1270 {
1271  try
1272  {
1273  var_.at(index_).to(value);
1274  ++index_;
1275  }
1276  catch (const error::Conversion& e)
1277  {
1278  std::ostringstream oss;
1279  oss << e.what() << ", for array index " << index_;
1280  throw error::Conversion(oss.str());
1281  }
1282  catch (const error::Access&)
1283  {
1284  std::ostringstream oss;
1285  oss << "wamp::error::Conversion: Attemping to access field type "
1286  << typeNameOf(var_) << " as array";
1287  throw error::Conversion(oss.str());
1288  }
1289  catch (const std::out_of_range&)
1290  {
1291  std::ostringstream oss;
1292  oss << "wamp::error::Conversion: Cannot extract more than " << index_
1293  << " elements from the array";
1294  throw error::Conversion(oss.str());
1295  }
1296 
1297  return *this;
1298 }
1299 
1300 //------------------------------------------------------------------------------
1311 //------------------------------------------------------------------------------
1312 template <typename T>
1314  T& value)
1315 {
1316  try
1317  {
1318  var_.at(key).to(value);
1319  }
1320  catch (const error::Conversion& e)
1321  {
1322  std::ostringstream oss;
1323  oss << e.what() << ", for object member \"" << key << '"';
1324  throw error::Conversion(oss.str());
1325  }
1326  catch (const error::Access&)
1327  {
1328  std::ostringstream oss;
1329  oss << "wamp::error::Conversion: Attemping to access field type "
1330  << typeNameOf(var_) << " as object using key \"" << key << '"';
1331  throw error::Conversion(oss.str());
1332  }
1333  catch (const std::out_of_range&)
1334  {
1335  std::ostringstream oss;
1336  oss << "wamp::error::Conversion: Key \"" << key
1337  << "\" not found in object";
1338  throw error::Conversion(oss.str());
1339  }
1340 
1341  return *this;
1342 }
1343 
1344 //------------------------------------------------------------------------------
1352 //------------------------------------------------------------------------------
1353 template <typename T, typename U>
1355  T& value, U&& fallback)
1356 {
1357  try
1358  {
1359  auto& obj = var_.as<Object>();
1360  auto kv = obj.find(key);
1361  if (kv != obj.end())
1362  kv->second.to(value);
1363  else
1364  value = std::forward<U>(fallback);
1365  }
1366  catch (const error::Conversion& e)
1367  {
1368  std::ostringstream oss;
1369  oss << e.what() << ", for object member \"" << key << '"';
1370  throw error::Conversion(oss.str());
1371  }
1372  catch (const error::Access&)
1373  {
1374  std::ostringstream oss;
1375  oss << "wamp::error::Conversion: Attemping to access field type "
1376  << typeNameOf(var_) << " as object using key \"" << key << '"';
1377  throw error::Conversion(oss.str());
1378  }
1379 
1380  return *this;
1381 }
1382 
1383 //------------------------------------------------------------------------------
1384 inline const Variant& FromVariantConverter::variant() const {return var_;}
1385 
1386 } // namespace wamp
1387 
1388 #ifndef CPPWAMP_COMPILED_LIB
1389  #include "internal/variant.ipp"
1390 #endif
1391 
1392 #endif // CPPWAMP_VARIANT_HPP
wamp::Variant::isValidArg
static constexpr bool isValidArg() noexcept
Indicates that the given argument type is convertible to a bound type.
Definition: variant.hpp:150
wamp::DisableIf
typename std::enable_if<!B, T >::type DisableIf
Metafunction used to disable overloads based on a boolean condition.
Definition: traits.hpp:43
wamp::Variant::BoundTypeForId
typename internal::FieldTypeForId< typeId >::Type BoundTypeForId
Obtains the bound type associated with a particular TypeId.
Definition: variant.hpp:145
wamp::FromVariantConverter::operator()
FromVariantConverter & operator()(T &value)
Retrieves a non-composite value from the variant.
Definition: variant.hpp:1250
wamp::Blob
Contains binary data as an array of bytes.
Definition: blob.hpp:28
wamp::Null
Type used to represent a null or empty Variant value.
Definition: null.hpp:39
wamp::Variant::Variant
Variant() noexcept
Constructs a null variant.
Definition: variant.ipp:201
wamp::Variant::CharType
String::value_type CharType
Character type used by string variants.
Definition: variant.hpp:190
wamp::FromVariantConverter::variant
const Variant & variant() const
Returns a constant reference to the wrapped variant.
Definition: variant.hpp:1384
wamp::ToVariantConverter::size
ToVariantConverter & size(SizeType n)
Makes the variant become an Array variant.
Definition: variant.hpp:1143
wamp::TypeId
TypeId
Integer ID used to indicate the current dynamic type of a Variant.
Definition: variantdefs.hpp:26
wamp::UInt
std::uint64_t UInt
Variant bound type for unsigned integers.
Definition: variantdefs.hpp:48
wamp::Variant::Array
wamp::Array Array
Dynamic array of variants.
Definition: variant.hpp:182
wamp::Variant
Discriminated union container that represents a JSON value.
Definition: variant.hpp:134
null.hpp
Contains the declaration of Null, one of the bound types used by Variant.
wamp::FromVariantConverter::SizeType
size_t SizeType
Integer type used to represent the size of array variants.
Definition: variant.hpp:654
wamp::Variant::String
wamp::String String
String type.
Definition: variant.hpp:180
wamp::Variant::Real
wamp::Real Real
Floating-point number type.
Definition: variant.hpp:179
variantdefs.hpp
Contains fundamental type definitions related to Variant.
wamp::Variant::size
SizeType size() const
Returns the number of elements contained by the variant.
Definition: variant.ipp:254
api.hpp
Defines macros related to exporting/importing APIs.
wamp::TypeId::array
@ array
For Variant::Array.
wamp::FromVariantConverter::size
SizeType size() const
Obtains the current size of the variant.
Definition: variant.hpp:1225
visitor.hpp
Contains facilities for applying static visitors to Variant objects .
wamp::TypeId::string
@ string
For Variant::String.
wamp::Object
std::map< String, Variant > Object
Variant bound type for maps of variants.
Definition: variantdefs.hpp:52
wamp::FromVariantConverter::String
std::string String
String type used to represent an object variant key.
Definition: variant.hpp:657
wamp::ToVariantConverter::variant
Variant & variant()
Returns a reference to the wrapped variant.
Definition: variant.hpp:1208
wamp::ToVariantConverter::operator()
ToVariantConverter & operator()(T &&value)
Assigns a value to the variant.
Definition: variant.hpp:1157
wamp::FromVariantConverter::operator[]
FromVariantConverter & operator[](T &value)
Retrieves the next element from an Array variant.
Definition: variant.hpp:1269
wamp
Definition: anyhandler.hpp:36
wamp::ToVariantConverter
Wrapper around a destination Variant, used for conversions.
Definition: variant.hpp:604
wamp::ToVariantConverter::operator[]
ToVariantConverter & operator[](T &&value)
Appends an array element to the variant.
Definition: variant.hpp:1170
wamp::Variant::Object
wamp::Object Object
Dictionary of variants.
Definition: variant.hpp:183
wamp::Variant::SizeType
Array::size_type SizeType
Integer type used to access array elements.
Definition: variant.hpp:187
wamp::Variant::at
Variant & at(SizeType index)
Accesses an array element by index.
Definition: variant.ipp:287
wamp::Array
std::vector< Variant > Array
Variant bound type for arrays of variants.
Definition: variantdefs.hpp:51
conversionaccess.hpp
Contains the ConversionAccess class.
wamp::ToVariantConverter::ToVariantConverter
ToVariantConverter(Variant &var)
Constructor taking a variant reference.
Definition: variant.hpp:1135
wamp::Variant::operator=
Variant & operator=(const Variant &other)
Assigns a variant onto another variant.
Definition: variant.ipp:394
wamp::TypeId::uint
@ uint
For Variant::UInt.
wamp::ValueTypeOf
typename std::remove_cv< typename std::remove_reference< T >::type >::type ValueTypeOf
Metafunction used to obtain the plain value type of a parameter passed by universal reference.
Definition: traits.hpp:51
wamp::Variant::UInt
wamp::UInt UInt
Unsigned integer type.
Definition: variant.hpp:178
wamp::Int
std::int64_t Int
Variant bound type for signed integers.
Definition: variantdefs.hpp:47
wamp::Bool
bool Bool
Variant bound type for boolean values.
Definition: variantdefs.hpp:46
wamp::FromVariantConverter
Wrapper around a source Variant, used for conversions.
Definition: variant.hpp:650
blob.hpp
Contains the declaration of Variant and other closely related types/functions.
wamp::TypeId::boolean
@ boolean
For Variant::Bool.
wamp::Real
double Real
Variant bound type for floating-point numbers.
Definition: variantdefs.hpp:49
wamp::Variant::is
bool is() const
Returns true iff the variant's current dynamic type matches the given TBound type parameter.
Definition: variant.hpp:798
wamp::Variant::applyWithOperand
ResultTypeOf< V > applyWithOperand(V &&visitor, T &&variant, O &&operand)
Applies the given static visitor functor, with an operand value, to the given variant.
Definition: visitor.hpp:136
wamp::EnableIf
typename std::enable_if< B, T >::type EnableIf
Metafunction used to enable overloads based on a boolean condition.
Definition: traits.hpp:37
wamp::Variant::valueOr
ValueTypeOf< T > valueOr(T &&fallback) const
Obtains the variant's value converted to the given type, or the given fallback value if the variant i...
Definition: variant.hpp:865
wamp::Variant::as
TBound & as()
Returns a reference to the variant's bound value.
Definition: variant.hpp:879
wamp::convert
void convert(TConverter &c, TValue &val)
General function for converting custom types to/from Variant.
Definition: variant.hpp:709
wamp::error::Conversion
Exception type thrown when converting a Variant to an invalid type.
Definition: error.hpp:106
wamp::Variant::to
T to() const
Converts the variant's bound value to the given type.
Definition: variant.hpp:840
wamp::TypeId::real
@ real
For Variant::Real.
traits.hpp
Contains general-purpose type traits.
wamp::FromVariantConverter::FromVariantConverter
FromVariantConverter(const Variant &var)
Constructor taking a constant variant reference.
Definition: variant.hpp:1216
wamp::TypeId::object
@ object
For Variant::Object.
wamp::ToVariantConverter::SizeType
size_t SizeType
Integer type used to represent the size of array variants.
Definition: variant.hpp:608
wamp::Variant::Int
wamp::Int Int
Signed integer type.
Definition: variant.hpp:177
wamp::String
std::string String
Variant bound type for text strings.
Definition: variantdefs.hpp:50
wamp::ToVariantConverter::String
std::string String
String type used to represent an object variant key.
Definition: variant.hpp:611
wamp::Variant::from
static Variant from(TValue &&value)
Constructs a variant from a custom type.
Definition: variant.hpp:744
wamp::Variant::Bool
wamp::Bool Bool
Boolean type.
Definition: variant.hpp:176
wamp::isNumber
constexpr bool isNumber()
Determines if the given type is considered a number.
Definition: traits.hpp:77
wamp::error::Access
Exception type thrown when accessing a Variant as an invalid type.
Definition: error.hpp:97
wamp::TypeId::integer
@ integer
For Variant::Int.
error.hpp
Contains facilities for reporting and describing errors.
wamp::TypeId::blob
@ blob
For Variant::Blob.