Minh Nguyen / ArduinoJson
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers VariantData.hpp Source File

VariantData.hpp

00001 // ArduinoJson - arduinojson.org
00002 // Copyright Benoit Blanchon 2014-2021
00003 // MIT License
00004 
00005 #pragma once
00006 
00007 #include <ArduinoJson/Memory/MemoryPool.hpp>
00008 #include <ArduinoJson/Misc/SerializedValue.hpp>
00009 #include <ArduinoJson/Numbers/convertNumber.hpp>
00010 #include <ArduinoJson/Strings/RamStringAdapter.hpp>
00011 #include <ArduinoJson/Variant/VariantContent.hpp>
00012 
00013 // VariantData can't have a constructor (to be a POD), so we have no way to fix
00014 // this warning
00015 #if defined(__GNUC__)
00016 #if __GNUC__ >= 7
00017 #pragma GCC diagnostic push
00018 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
00019 #pragma GCC diagnostic ignored "-Wuninitialized"
00020 #endif
00021 #endif
00022 
00023 namespace ARDUINOJSON_NAMESPACE {
00024 
00025 class VariantData {
00026   VariantContent _content;  // must be first to allow cast from array to variant
00027   uint8_t _flags;
00028 
00029  public:
00030   // Must be a POD!
00031   // - no constructor
00032   // - no destructor
00033   // - no virtual
00034   // - no inheritance
00035   void init() {
00036     _flags = 0;
00037   }
00038 
00039   template <typename TVisitor>
00040   typename TVisitor::result_type accept(TVisitor &visitor) const {
00041     switch (type()) {
00042       case VALUE_IS_FLOAT:
00043         return visitor.visitFloat(_content.asFloat);
00044 
00045       case VALUE_IS_ARRAY:
00046         return visitor.visitArray(_content.asCollection);
00047 
00048       case VALUE_IS_OBJECT:
00049         return visitor.visitObject(_content.asCollection);
00050 
00051       case VALUE_IS_LINKED_STRING:
00052       case VALUE_IS_OWNED_STRING:
00053         return visitor.visitString(_content.asString);
00054 
00055       case VALUE_IS_OWNED_RAW:
00056       case VALUE_IS_LINKED_RAW:
00057         return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size);
00058 
00059       case VALUE_IS_NEGATIVE_INTEGER:
00060         return visitor.visitNegativeInteger(_content.asInteger);
00061 
00062       case VALUE_IS_POSITIVE_INTEGER:
00063         return visitor.visitPositiveInteger(_content.asInteger);
00064 
00065       case VALUE_IS_BOOLEAN:
00066         return visitor.visitBoolean(_content.asInteger != 0);
00067 
00068       default:
00069         return visitor.visitNull();
00070     }
00071   }
00072 
00073   template <typename T>
00074   T asIntegral() const;
00075 
00076   template <typename T>
00077   T asFloat() const;
00078 
00079   const char *asString() const;
00080 
00081   bool asBoolean() const;
00082 
00083   CollectionData *asArray() {
00084     return isArray() ? &_content.asCollection : 0;
00085   }
00086 
00087   const CollectionData *asArray() const {
00088     return const_cast<VariantData *>(this)->asArray();
00089   }
00090 
00091   CollectionData *asObject() {
00092     return isObject() ? &_content.asCollection : 0;
00093   }
00094 
00095   const CollectionData *asObject() const {
00096     return const_cast<VariantData *>(this)->asObject();
00097   }
00098 
00099   bool copyFrom(const VariantData &src, MemoryPool *pool) {
00100     switch (src.type()) {
00101       case VALUE_IS_ARRAY:
00102         return toArray().copyFrom(src._content.asCollection, pool);
00103       case VALUE_IS_OBJECT:
00104         return toObject().copyFrom(src._content.asCollection, pool);
00105       case VALUE_IS_OWNED_STRING:
00106         return setString(RamStringAdapter(src._content.asString), pool);
00107       case VALUE_IS_OWNED_RAW:
00108         return setOwnedRaw(
00109             serialized(src._content.asRaw.data, src._content.asRaw.size), pool);
00110       default:
00111         setType(src.type());
00112         _content = src._content;
00113         return true;
00114     }
00115   }
00116 
00117   bool isArray() const {
00118     return (_flags & VALUE_IS_ARRAY) != 0;
00119   }
00120 
00121   bool isBoolean() const {
00122     return type() == VALUE_IS_BOOLEAN;
00123   }
00124 
00125   bool isCollection() const {
00126     return (_flags & COLLECTION_MASK) != 0;
00127   }
00128 
00129   template <typename T>
00130   bool isInteger() const {
00131     switch (type()) {
00132       case VALUE_IS_POSITIVE_INTEGER:
00133         return canStorePositiveInteger<T>(_content.asInteger);
00134 
00135       case VALUE_IS_NEGATIVE_INTEGER:
00136         return canStoreNegativeInteger<T>(_content.asInteger);
00137 
00138       default:
00139         return false;
00140     }
00141   }
00142 
00143   bool isFloat() const {
00144     return type() == VALUE_IS_FLOAT || type() == VALUE_IS_POSITIVE_INTEGER ||
00145            type() == VALUE_IS_NEGATIVE_INTEGER;
00146   }
00147 
00148   bool isString() const {
00149     return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
00150   }
00151 
00152   bool isObject() const {
00153     return (_flags & VALUE_IS_OBJECT) != 0;
00154   }
00155 
00156   bool isNull() const {
00157     return type() == VALUE_IS_NULL;
00158   }
00159 
00160   bool isEnclosed() const {
00161     return !isFloat();
00162   }
00163 
00164   void remove(size_t index) {
00165     if (isArray())
00166       _content.asCollection.removeElement(index);
00167   }
00168 
00169   template <typename TAdaptedString>
00170   void remove(TAdaptedString key) {
00171     if (isObject())
00172       _content.asCollection.removeMember(key);
00173   }
00174 
00175   void setBoolean(bool value) {
00176     setType(VALUE_IS_BOOLEAN);
00177     _content.asInteger = static_cast<UInt>(value);
00178   }
00179 
00180   void setFloat(Float value) {
00181     setType(VALUE_IS_FLOAT);
00182     _content.asFloat = value;
00183   }
00184 
00185   void setLinkedRaw(SerializedValue<const char *> value) {
00186     if (value.data()) {
00187       setType(VALUE_IS_LINKED_RAW);
00188       _content.asRaw.data = value.data();
00189       _content.asRaw.size = value.size();
00190     } else {
00191       setType(VALUE_IS_NULL);
00192     }
00193   }
00194 
00195   template <typename T>
00196   bool setOwnedRaw(SerializedValue<T> value, MemoryPool *pool) {
00197     const char *dup = pool->saveString(adaptString(value.data(), value.size()));
00198     if (dup) {
00199       setType(VALUE_IS_OWNED_RAW);
00200       _content.asRaw.data = dup;
00201       _content.asRaw.size = value.size();
00202       return true;
00203     } else {
00204       setType(VALUE_IS_NULL);
00205       return false;
00206     }
00207   }
00208 
00209   template <typename T>
00210   typename enable_if<is_unsigned<T>::value>::type setInteger(T value) {
00211     setUnsignedInteger(value);
00212   }
00213 
00214   template <typename T>
00215   typename enable_if<is_signed<T>::value>::type setInteger(T value) {
00216     setSignedInteger(value);
00217   }
00218 
00219   template <typename T>
00220   void setSignedInteger(T value) {
00221     if (value >= 0) {
00222       setPositiveInteger(static_cast<UInt>(value));
00223     } else {
00224       setNegativeInteger(~static_cast<UInt>(value) + 1);
00225     }
00226   }
00227 
00228   void setUnsignedInteger(UInt value) {
00229     setType(VALUE_IS_POSITIVE_INTEGER);
00230     _content.asInteger = static_cast<UInt>(value);
00231   }
00232 
00233   void setPositiveInteger(UInt value) {
00234     setType(VALUE_IS_POSITIVE_INTEGER);
00235     _content.asInteger = value;
00236   }
00237 
00238   void setNegativeInteger(UInt value) {
00239     setType(VALUE_IS_NEGATIVE_INTEGER);
00240     _content.asInteger = value;
00241   }
00242 
00243   void setNull() {
00244     setType(VALUE_IS_NULL);
00245   }
00246 
00247   void setStringPointer(const char *s, storage_policies::store_by_copy) {
00248     setType(VALUE_IS_OWNED_STRING);
00249     _content.asString = s;
00250   }
00251 
00252   void setStringPointer(const char *s, storage_policies::store_by_address) {
00253     setType(VALUE_IS_LINKED_STRING);
00254     _content.asString = s;
00255   }
00256 
00257   template <typename TAdaptedString>
00258   bool setString(TAdaptedString value, MemoryPool *pool) {
00259     return setString(value, pool, typename TAdaptedString::storage_policy());
00260   }
00261 
00262   template <typename TAdaptedString>
00263   inline bool setString(TAdaptedString value, MemoryPool *pool,
00264                         storage_policies::decide_at_runtime) {
00265     if (value.isStatic())
00266       return setString(value, pool, storage_policies::store_by_address());
00267     else
00268       return setString(value, pool, storage_policies::store_by_copy());
00269   }
00270 
00271   template <typename TAdaptedString>
00272   inline bool setString(TAdaptedString value, MemoryPool *,
00273                         storage_policies::store_by_address) {
00274     if (value.isNull())
00275       setNull();
00276     else
00277       setStringPointer(value.data(), storage_policies::store_by_address());
00278     return true;
00279   }
00280 
00281   template <typename TAdaptedString>
00282   inline bool setString(TAdaptedString value, MemoryPool *pool,
00283                         storage_policies::store_by_copy) {
00284     if (value.isNull()) {
00285       setNull();
00286       return true;
00287     }
00288     const char *copy = pool->saveString(value);
00289     if (!copy) {
00290       setNull();
00291       return false;
00292     }
00293     setStringPointer(copy, storage_policies::store_by_copy());
00294     return true;
00295   }
00296 
00297   CollectionData &toArray() {
00298     setType(VALUE_IS_ARRAY);
00299     _content.asCollection.clear();
00300     return _content.asCollection;
00301   }
00302 
00303   CollectionData &toObject() {
00304     setType(VALUE_IS_OBJECT);
00305     _content.asCollection.clear();
00306     return _content.asCollection;
00307   }
00308 
00309   size_t memoryUsage() const {
00310     switch (type()) {
00311       case VALUE_IS_OWNED_STRING:
00312         return strlen(_content.asString) + 1;
00313       case VALUE_IS_OWNED_RAW:
00314         return _content.asRaw.size;
00315       case VALUE_IS_OBJECT:
00316       case VALUE_IS_ARRAY:
00317         return _content.asCollection.memoryUsage();
00318       default:
00319         return 0;
00320     }
00321   }
00322 
00323   size_t nesting() const {
00324     return isCollection() ? _content.asCollection.nesting() : 0;
00325   }
00326 
00327   size_t size() const {
00328     return isCollection() ? _content.asCollection.size() : 0;
00329   }
00330 
00331   VariantData *addElement(MemoryPool *pool) {
00332     if (isNull())
00333       toArray();
00334     if (!isArray())
00335       return 0;
00336     return _content.asCollection.addElement(pool);
00337   }
00338 
00339   VariantData *getElement(size_t index) const {
00340     return isArray() ? _content.asCollection.getElement(index) : 0;
00341   }
00342 
00343   VariantData *getOrAddElement(size_t index, MemoryPool *pool) {
00344     if (isNull())
00345       toArray();
00346     if (!isArray())
00347       return 0;
00348     return _content.asCollection.getOrAddElement(index, pool);
00349   }
00350 
00351   template <typename TAdaptedString>
00352   VariantData *getMember(TAdaptedString key) const {
00353     return isObject() ? _content.asCollection.getMember(key) : 0;
00354   }
00355 
00356   template <typename TAdaptedString>
00357   VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) {
00358     if (isNull())
00359       toObject();
00360     if (!isObject())
00361       return 0;
00362     return _content.asCollection.getOrAddMember(key, pool);
00363   }
00364 
00365   void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) {
00366     if (_flags & VALUE_IS_OWNED)
00367       _content.asString += stringDistance;
00368     if (_flags & COLLECTION_MASK)
00369       _content.asCollection.movePointers(stringDistance, variantDistance);
00370   }
00371 
00372   uint8_t type() const {
00373     return _flags & VALUE_MASK;
00374   }
00375 
00376  private:
00377   void setType(uint8_t t) {
00378     _flags &= KEY_IS_OWNED;
00379     _flags |= t;
00380   }
00381 };
00382 
00383 }  // namespace ARDUINOJSON_NAMESPACE
00384 
00385 #if defined(__GNUC__)
00386 #if __GNUC__ >= 8
00387 #pragma GCC diagnostic pop
00388 #endif
00389 #endif