mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Added JsonArrayConst, JsonObjectConst, and JsonVariantConst
				
					
				
			This commit is contained in:
		| @@ -10,6 +10,7 @@ HEAD | ||||
| * `JsonPair::key()` now returns a `JsonKey` | ||||
| * Increased the default capacity of `DynamicJsonDocument` | ||||
| * Fixed `JsonVariant::is<String>()` (closes #763) | ||||
| * Added `JsonArrayConst`, `JsonObjectConst`, and `JsonVariantConst` | ||||
|  | ||||
| v6.4.0-beta (2018-09-11) | ||||
| ----------- | ||||
|   | ||||
| @@ -9,7 +9,9 @@ | ||||
| #include "ArduinoJson/JsonArray.hpp" | ||||
| #include "ArduinoJson/JsonDocument.hpp" | ||||
| #include "ArduinoJson/JsonObject.hpp" | ||||
| #include "ArduinoJson/JsonVariant.hpp" | ||||
|  | ||||
| #include "ArduinoJson/Data/VariantAsImpl.hpp" | ||||
| #include "ArduinoJson/JsonArrayImpl.hpp" | ||||
| #include "ArduinoJson/JsonArraySubscript.hpp" | ||||
| #include "ArduinoJson/JsonObjectImpl.hpp" | ||||
| @@ -26,13 +28,16 @@ namespace ArduinoJson { | ||||
| using ARDUINOJSON_NAMESPACE::DeserializationError; | ||||
| using ARDUINOJSON_NAMESPACE::DynamicJsonDocument; | ||||
| using ARDUINOJSON_NAMESPACE::JsonArray; | ||||
| using ARDUINOJSON_NAMESPACE::JsonArrayConst; | ||||
| using ARDUINOJSON_NAMESPACE::JsonFloat; | ||||
| using ARDUINOJSON_NAMESPACE::JsonInteger; | ||||
| using ARDUINOJSON_NAMESPACE::JsonKey; | ||||
| using ARDUINOJSON_NAMESPACE::JsonObject; | ||||
| using ARDUINOJSON_NAMESPACE::JsonObjectConst; | ||||
| using ARDUINOJSON_NAMESPACE::JsonPair; | ||||
| using ARDUINOJSON_NAMESPACE::JsonUInt; | ||||
| using ARDUINOJSON_NAMESPACE::JsonVariant; | ||||
| using ARDUINOJSON_NAMESPACE::JsonVariantConst; | ||||
| using ARDUINOJSON_NAMESPACE::serialized; | ||||
| using ARDUINOJSON_NAMESPACE::StaticJsonDocument; | ||||
| }  // namespace ArduinoJson | ||||
|   | ||||
							
								
								
									
										99
									
								
								src/ArduinoJson/Data/ArrayFunctions.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/ArduinoJson/Data/ArrayFunctions.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "JsonVariantData.hpp" | ||||
| #include "Slot.hpp" | ||||
| #include "SlotFunctions.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| inline JsonVariantData* arrayAdd(JsonArrayData* arr, MemoryPool* pool) { | ||||
|   if (!arr) return 0; | ||||
|  | ||||
|   Slot* slot = new (pool) Slot(); | ||||
|   if (!slot) return 0; | ||||
|  | ||||
|   slot->next = 0; | ||||
|  | ||||
|   if (arr->tail) { | ||||
|     slot->prev = arr->tail; | ||||
|     arr->tail->next = slot; | ||||
|     arr->tail = slot; | ||||
|   } else { | ||||
|     slot->prev = 0; | ||||
|     arr->head = slot; | ||||
|     arr->tail = slot; | ||||
|   } | ||||
|  | ||||
|   return &slot->value; | ||||
| } | ||||
|  | ||||
| inline Slot* arrayGetSlot(const JsonArrayData* arr, size_t index) { | ||||
|   if (!arr) return 0; | ||||
|   return slotAdvance(arr->head, index); | ||||
| } | ||||
|  | ||||
| inline JsonVariantData* arrayGet(const JsonArrayData* arr, size_t index) { | ||||
|   Slot* slot = arrayGetSlot(arr, index); | ||||
|   return slot ? &slot->value : 0; | ||||
| } | ||||
|  | ||||
| inline void arrayRemove(JsonArrayData* arr, Slot* slot) { | ||||
|   if (!arr || !slot) return; | ||||
|  | ||||
|   if (slot->prev) | ||||
|     slot->prev->next = slot->next; | ||||
|   else | ||||
|     arr->head = slot->next; | ||||
|   if (slot->next) | ||||
|     slot->next->prev = slot->prev; | ||||
|   else | ||||
|     arr->tail = slot->prev; | ||||
| } | ||||
|  | ||||
| inline void arrayRemove(JsonArrayData* arr, size_t index) { | ||||
|   arrayRemove(arr, arrayGetSlot(arr, index)); | ||||
| } | ||||
|  | ||||
| inline void arrayClear(JsonArrayData* arr) { | ||||
|   if (!arr) return; | ||||
|   arr->head = 0; | ||||
|   arr->tail = 0; | ||||
| } | ||||
|  | ||||
| bool variantCopy(JsonVariantData*, const JsonVariantData*, MemoryPool*); | ||||
|  | ||||
| inline bool arrayCopy(JsonArrayData* dst, const JsonArrayData* src, | ||||
|                       MemoryPool* pool) { | ||||
|   if (!dst || !src) return false; | ||||
|   arrayClear(dst); | ||||
|   for (Slot* s = src->head; s; s = s->next) { | ||||
|     if (!variantCopy(arrayAdd(dst, pool), &s->value, pool)) return false; | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool variantEquals(const JsonVariantData*, const JsonVariantData*); | ||||
|  | ||||
| inline bool arrayEquals(const JsonArrayData* a1, const JsonArrayData* a2) { | ||||
|   if (a1 == a2) return true; | ||||
|   if (!a1 || !a2) return false; | ||||
|   Slot* s1 = a1->head; | ||||
|   Slot* s2 = a2->head; | ||||
|   for (;;) { | ||||
|     if (s1 == s2) return true; | ||||
|     if (!s1 || !s2) return false; | ||||
|     if (!variantEquals(&s1->value, &s2->value)) return false; | ||||
|     s1 = s1->next; | ||||
|     s2 = s2->next; | ||||
|   } | ||||
| } | ||||
|  | ||||
| inline size_t arraySize(const JsonArrayData* arr) { | ||||
|   if (!arr) return 0; | ||||
|   return slotSize(arr->head); | ||||
| } | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -1,15 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Polyfills/type_traits.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class JsonVariantTag {}; | ||||
|  | ||||
| template <typename T> | ||||
| struct IsVariant : is_base_of<JsonVariantTag, T> {}; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -6,6 +6,13 @@ | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class JsonArray; | ||||
| class JsonArrayConst; | ||||
| class JsonObject; | ||||
| class JsonObjectConst; | ||||
| class JsonVariant; | ||||
| class JsonVariantConst; | ||||
|  | ||||
| // A metafunction that returns the type of the value returned by | ||||
| // JsonVariant::as<T>() | ||||
| template <typename T> | ||||
| @@ -18,4 +25,25 @@ struct JsonVariantAs<char*> { | ||||
|   typedef const char* type; | ||||
| }; | ||||
|  | ||||
| // A metafunction that returns the type of the value returned by | ||||
| // JsonVariant::as<T>() | ||||
| template <typename T> | ||||
| struct JsonVariantConstAs { | ||||
|   typedef typename JsonVariantAs<T>::type type; | ||||
| }; | ||||
|  | ||||
| template <> | ||||
| struct JsonVariantConstAs<JsonVariant> { | ||||
|   typedef JsonVariantConst type; | ||||
| }; | ||||
|  | ||||
| template <> | ||||
| struct JsonVariantConstAs<JsonObject> { | ||||
|   typedef JsonObjectConst type; | ||||
| }; | ||||
|  | ||||
| template <> | ||||
| struct JsonVariantConstAs<JsonArray> { | ||||
|   typedef JsonArrayConst type; | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
							
								
								
									
										123
									
								
								src/ArduinoJson/Data/ObjectFunctions.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/ArduinoJson/Data/ObjectFunctions.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "JsonVariantData.hpp" | ||||
| #include "SlotFunctions.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <typename TKey> | ||||
| inline Slot* objectFindSlot(const JsonObjectData* obj, TKey key) { | ||||
|   if (!obj) return 0; | ||||
|   Slot* slot = obj->head; | ||||
|   while (slot) { | ||||
|     if (key.equals(slot->key)) break; | ||||
|     slot = slot->next; | ||||
|   } | ||||
|   return slot; | ||||
| } | ||||
|  | ||||
| template <typename TKey> | ||||
| inline bool objectContainsKey(const JsonObjectData* obj, const TKey& key) { | ||||
|   return objectFindSlot(obj, key) != 0; | ||||
| } | ||||
|  | ||||
| template <typename TKey> | ||||
| inline JsonVariantData* objectAdd(JsonObjectData* obj, TKey key, | ||||
|                                   MemoryPool* pool) { | ||||
|   Slot* slot = new (pool) Slot(); | ||||
|   if (!slot) return 0; | ||||
|  | ||||
|   slot->next = 0; | ||||
|  | ||||
|   if (obj->tail) { | ||||
|     slot->prev = obj->tail; | ||||
|     obj->tail->next = slot; | ||||
|     obj->tail = slot; | ||||
|   } else { | ||||
|     slot->prev = 0; | ||||
|     obj->head = slot; | ||||
|     obj->tail = slot; | ||||
|   } | ||||
|  | ||||
|   if (!slotSetKey(slot, key, pool)) return 0; | ||||
|   return &slot->value; | ||||
| } | ||||
|  | ||||
| template <typename TKey> | ||||
| inline JsonVariantData* objectSet(JsonObjectData* obj, TKey key, | ||||
|                                   MemoryPool* pool) { | ||||
|   if (!obj) return 0; | ||||
|  | ||||
|   // ignore null key | ||||
|   if (key.isNull()) return 0; | ||||
|  | ||||
|   // search a matching key | ||||
|   Slot* slot = objectFindSlot(obj, key); | ||||
|   if (slot) return &slot->value; | ||||
|  | ||||
|   return objectAdd(obj, key, pool); | ||||
| } | ||||
|  | ||||
| template <typename TKey> | ||||
| inline JsonVariantData* objectGet(const JsonObjectData* obj, TKey key) { | ||||
|   Slot* slot = objectFindSlot(obj, key); | ||||
|   return slot ? &slot->value : 0; | ||||
| } | ||||
|  | ||||
| inline void objectClear(JsonObjectData* obj) { | ||||
|   if (!obj) return; | ||||
|   obj->head = 0; | ||||
|   obj->tail = 0; | ||||
| } | ||||
|  | ||||
| inline void objectRemove(JsonObjectData* obj, Slot* slot) { | ||||
|   if (!obj) return; | ||||
|   if (!slot) return; | ||||
|   if (slot->prev) | ||||
|     slot->prev->next = slot->next; | ||||
|   else | ||||
|     obj->head = slot->next; | ||||
|   if (slot->next) | ||||
|     slot->next->prev = slot->prev; | ||||
|   else | ||||
|     obj->tail = slot->prev; | ||||
| } | ||||
|  | ||||
| inline size_t objectSize(const JsonObjectData* obj) { | ||||
|   if (!obj) return 0; | ||||
|   return slotSize(obj->head); | ||||
| } | ||||
|  | ||||
| // bool variantCopy(JsonVariantData*, const JsonVariantData*, MemoryPool*); | ||||
|  | ||||
| inline bool objectCopy(JsonObjectData* dst, const JsonObjectData* src, | ||||
|                        MemoryPool* pool) { | ||||
|   if (!dst || !src) return false; | ||||
|   objectClear(dst); | ||||
|   for (Slot* s = src->head; s; s = s->next) { | ||||
|     JsonVariantData* var; | ||||
|     if (s->value.keyIsStatic) | ||||
|       var = objectAdd(dst, ZeroTerminatedRamStringConst(s->key), pool); | ||||
|     else | ||||
|       var = objectAdd(dst, ZeroTerminatedRamString(s->key), pool); | ||||
|     if (!variantCopy(var, &s->value, pool)) return false; | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool objectEquals(const JsonObjectData* o1, const JsonObjectData* o2) { | ||||
|   if (o1 == o2) return true; | ||||
|   if (!o1 || !o2) return false; | ||||
|  | ||||
|   for (Slot* s = o1->head; s; s = s->next) { | ||||
|     JsonVariantData* v1 = &s->value; | ||||
|     JsonVariantData* v2 = objectGet(o2, makeString(s->key)); | ||||
|     if (!variantEquals(v1, v2)) return false; | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
							
								
								
									
										59
									
								
								src/ArduinoJson/Data/SlotFunctions.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/ArduinoJson/Data/SlotFunctions.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Strings/StringTypes.hpp" | ||||
| #include "JsonVariantData.hpp" | ||||
| #include "Slot.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <typename TKey> | ||||
| inline bool slotSetKey(Slot* slot, TKey key, MemoryPool* pool) { | ||||
|   const char* dup = key.save(pool); | ||||
|   if (!dup) return false; | ||||
|   slot->key = dup; | ||||
|   slot->value.keyIsStatic = false; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool slotSetKey(Slot* slot, ZeroTerminatedRamStringConst key, | ||||
|                        MemoryPool* pool) { | ||||
|   slot->key = key.save(pool); | ||||
|   slot->value.keyIsStatic = true; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool slotSetKey(Slot* slot, StringInMemoryPool key, MemoryPool* pool) { | ||||
|   slot->key = key.save(pool); | ||||
|   slot->value.keyIsStatic = false; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline const Slot* slotAdvance(const Slot* slot, size_t distance) { | ||||
|   while (distance && slot) { | ||||
|     slot = slot->next; | ||||
|     distance--; | ||||
|   } | ||||
|   return slot; | ||||
| } | ||||
|  | ||||
| inline Slot* slotAdvance(Slot* slot, size_t distance) { | ||||
|   while (distance && slot) { | ||||
|     slot = slot->next; | ||||
|     distance--; | ||||
|   } | ||||
|   return slot; | ||||
| } | ||||
|  | ||||
| inline size_t slotSize(const Slot* slot) { | ||||
|   size_t n = 0; | ||||
|   while (slot) { | ||||
|     n++; | ||||
|     slot = slot->next; | ||||
|   } | ||||
|   return n; | ||||
| } | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
							
								
								
									
										48
									
								
								src/ArduinoJson/Data/VariantAs.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/ArduinoJson/Data/VariantAs.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Serialization/DynamicStringWriter.hpp" | ||||
| #include "VariantFunctions.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class JsonVariantConst; | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if<is_integral<T>::value, T>::type variantAs( | ||||
|     const JsonVariantData* _data) { | ||||
|   return variantAsIntegral<T>(_data); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if<is_same<T, bool>::value, T>::type variantAs( | ||||
|     const JsonVariantData* _data) { | ||||
|   return variantAsBoolean(_data); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if<is_floating_point<T>::value, T>::type variantAs( | ||||
|     const JsonVariantData* _data) { | ||||
|   return variantAsFloat<T>(_data); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if<is_same<T, const char*>::value || | ||||
|                               is_same<T, char*>::value, | ||||
|                           const char*>::type | ||||
| variantAs(const JsonVariantData* _data) { | ||||
|   return variantAsString(_data); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if<is_same<JsonVariantConst, T>::value, T>::type | ||||
| variantAs(const JsonVariantData* _data); | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if<IsWriteableString<T>::value, T>::type variantAs( | ||||
|     const JsonVariantData* _data); | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
							
								
								
									
										29
									
								
								src/ArduinoJson/Data/VariantAsImpl.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/ArduinoJson/Data/VariantAsImpl.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../JsonVariant.hpp" | ||||
| #include "../Serialization/DynamicStringWriter.hpp" | ||||
| #include "VariantFunctions.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if<is_same<JsonVariantConst, T>::value, T>::type | ||||
| variantAs(const JsonVariantData* _data) { | ||||
|   return JsonVariantConst(_data); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if<IsWriteableString<T>::value, T>::type variantAs( | ||||
|     const JsonVariantData* _data) { | ||||
|   const char* cstr = variantAsString(_data); | ||||
|   if (cstr) return T(cstr); | ||||
|   T s; | ||||
|   serializeJson(JsonVariantConst(_data), s); | ||||
|   return s; | ||||
| } | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
							
								
								
									
										287
									
								
								src/ArduinoJson/Data/VariantFunctions.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								src/ArduinoJson/Data/VariantFunctions.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,287 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Numbers/parseFloat.hpp" | ||||
| #include "../Numbers/parseInteger.hpp" | ||||
| #include "../SerializedValue.hpp" | ||||
| #include "ArrayFunctions.hpp" | ||||
| #include "JsonVariantData.hpp" | ||||
| #include "ObjectFunctions.hpp" | ||||
| #include "Slot.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <typename T> | ||||
| inline T variantAsIntegral(const JsonVariantData* var) { | ||||
|   if (!var) return 0; | ||||
|   switch (var->type) { | ||||
|     case JSON_POSITIVE_INTEGER: | ||||
|     case JSON_BOOLEAN: | ||||
|       return T(var->content.asInteger); | ||||
|     case JSON_NEGATIVE_INTEGER: | ||||
|       return T(~var->content.asInteger + 1); | ||||
|     case JSON_LINKED_STRING: | ||||
|     case JSON_OWNED_STRING: | ||||
|       return parseInteger<T>(var->content.asString); | ||||
|     case JSON_FLOAT: | ||||
|       return T(var->content.asFloat); | ||||
|     default: | ||||
|       return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
| inline bool variantAsBoolean(const JsonVariantData* var) { | ||||
|   return variantAsIntegral<int>(var) != 0; | ||||
| } | ||||
|  | ||||
| // T = float/double | ||||
| template <typename T> | ||||
| inline T variantAsFloat(const JsonVariantData* var) { | ||||
|   if (!var) return 0; | ||||
|   switch (var->type) { | ||||
|     case JSON_POSITIVE_INTEGER: | ||||
|     case JSON_BOOLEAN: | ||||
|       return static_cast<T>(var->content.asInteger); | ||||
|     case JSON_NEGATIVE_INTEGER: | ||||
|       return -static_cast<T>(var->content.asInteger); | ||||
|     case JSON_LINKED_STRING: | ||||
|     case JSON_OWNED_STRING: | ||||
|       return parseFloat<T>(var->content.asString); | ||||
|     case JSON_FLOAT: | ||||
|       return static_cast<T>(var->content.asFloat); | ||||
|     default: | ||||
|       return 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
| inline const char* variantAsString(const JsonVariantData* var) { | ||||
|   if (!var) return 0; | ||||
|   if (var && | ||||
|       (var->type == JSON_LINKED_STRING || var->type == JSON_OWNED_STRING)) | ||||
|     return var->content.asString; | ||||
|   else | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| inline JsonArrayData* variantAsArray(JsonVariantData* var) { | ||||
|   if (var && var->type == JSON_ARRAY) | ||||
|     return &var->content.asArray; | ||||
|   else | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| inline const JsonArrayData* variantAsArray(const JsonVariantData* var) { | ||||
|   if (var && var->type == JSON_ARRAY) | ||||
|     return &var->content.asArray; | ||||
|   else | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| inline JsonObjectData* variantAsObject(JsonVariantData* var) { | ||||
|   if (var && var->type == JSON_OBJECT) | ||||
|     return &var->content.asObject; | ||||
|   else | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| inline const JsonObjectData* variantAsObject(const JsonVariantData* var) { | ||||
|   if (var && var->type == JSON_OBJECT) | ||||
|     return &var->content.asObject; | ||||
|   else | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| inline bool variantSetBoolean(JsonVariantData* var, bool value) { | ||||
|   if (!var) return false; | ||||
|   var->type = JSON_BOOLEAN; | ||||
|   var->content.asInteger = static_cast<JsonUInt>(value); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool variantSetFloat(JsonVariantData* var, JsonFloat value) { | ||||
|   if (!var) return false; | ||||
|   var->type = JSON_FLOAT; | ||||
|   var->content.asFloat = value; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline bool variantSetSignedInteger(JsonVariantData* var, T value) { | ||||
|   if (!var) return false; | ||||
|   if (value >= 0) { | ||||
|     var->type = JSON_POSITIVE_INTEGER; | ||||
|     var->content.asInteger = static_cast<JsonUInt>(value); | ||||
|   } else { | ||||
|     var->type = JSON_NEGATIVE_INTEGER; | ||||
|     var->content.asInteger = ~static_cast<JsonUInt>(value) + 1; | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool variantSetSignedInteger(JsonVariantData* var, JsonUInt value) { | ||||
|   if (!var) return false; | ||||
|   var->type = JSON_POSITIVE_INTEGER; | ||||
|   var->content.asInteger = static_cast<JsonUInt>(value); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool variantSetLinkedRaw(JsonVariantData* var, | ||||
|                                 SerializedValue<const char*> value) { | ||||
|   if (!var) return false; | ||||
|   var->type = JSON_LINKED_RAW; | ||||
|   var->content.asRaw.data = value.data(); | ||||
|   var->content.asRaw.size = value.size(); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline bool variantSetOwnedRaw(JsonVariantData* var, SerializedValue<T> value, | ||||
|                                MemoryPool* pool) { | ||||
|   if (!var) return false; | ||||
|   const char* dup = makeString(value.data(), value.size()).save(pool); | ||||
|   if (dup) { | ||||
|     var->type = JSON_OWNED_RAW; | ||||
|     var->content.asRaw.data = dup; | ||||
|     var->content.asRaw.size = value.size(); | ||||
|     return true; | ||||
|   } else { | ||||
|     var->type = JSON_NULL; | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline bool variantSetString(JsonVariantData* var, T value, MemoryPool* pool) { | ||||
|   if (!var) return false; | ||||
|   const char* dup = value.save(pool); | ||||
|   if (dup) { | ||||
|     var->type = JSON_OWNED_STRING; | ||||
|     var->content.asString = dup; | ||||
|     return true; | ||||
|   } else { | ||||
|     var->type = JSON_NULL; | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
|  | ||||
| inline bool variantSetString(JsonVariantData* var, const char* value) { | ||||
|   if (!var) return false; | ||||
|   var->type = JSON_LINKED_STRING; | ||||
|   var->content.asString = value; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool variantSetString(JsonVariantData* var, const char* value, | ||||
|                              MemoryPool* pool) { | ||||
|   return variantSetString(var, makeString(const_cast<char*>(value)), pool); | ||||
| } | ||||
|  | ||||
| inline void variantSetNull(JsonVariantData* var) { | ||||
|   if (var) var->type = JSON_NULL; | ||||
| } | ||||
|  | ||||
| inline JsonArrayData* variantToArray(JsonVariantData* var) { | ||||
|   if (!var) return 0; | ||||
|   var->type = JSON_ARRAY; | ||||
|   var->content.asArray.head = 0; | ||||
|   var->content.asArray.tail = 0; | ||||
|   return &var->content.asArray; | ||||
| } | ||||
|  | ||||
| inline JsonObjectData* variantToObject(JsonVariantData* var) { | ||||
|   if (!var) return 0; | ||||
|   var->type = JSON_OBJECT; | ||||
|   var->content.asObject.head = 0; | ||||
|   var->content.asObject.tail = 0; | ||||
|   return &var->content.asObject; | ||||
| } | ||||
|  | ||||
| inline bool variantCopy(JsonVariantData* dst, const JsonVariantData* src, | ||||
|                         MemoryPool* pool) { | ||||
|   if (!dst) return false; | ||||
|   if (!src) { | ||||
|     dst->type = JSON_NULL; | ||||
|     return true; | ||||
|   } | ||||
|   switch (src->type) { | ||||
|     case JSON_ARRAY: | ||||
|       return arrayCopy(variantToArray(dst), &src->content.asArray, pool); | ||||
|     case JSON_OBJECT: | ||||
|       return objectCopy(variantToObject(dst), &src->content.asObject, pool); | ||||
|     case JSON_OWNED_STRING: | ||||
|       return variantSetString(dst, src->content.asString, pool); | ||||
|     case JSON_OWNED_RAW: | ||||
|       return variantSetOwnedRaw( | ||||
|           dst, | ||||
|           serialized(const_cast<char*>(src->content.asRaw.data), | ||||
|                      src->content.asRaw.size), | ||||
|           pool); | ||||
|     default: | ||||
|       *dst = *src; | ||||
|       return true; | ||||
|   } | ||||
| } | ||||
|  | ||||
| inline bool variantIsInteger(const JsonVariantData* var) { | ||||
|   return var && (var->type == JSON_POSITIVE_INTEGER || | ||||
|                  var->type == JSON_NEGATIVE_INTEGER); | ||||
| } | ||||
|  | ||||
| inline bool variantIsFloat(const JsonVariantData* var) { | ||||
|   return var && | ||||
|          (var->type == JSON_FLOAT || var->type == JSON_POSITIVE_INTEGER || | ||||
|           var->type == JSON_NEGATIVE_INTEGER); | ||||
| } | ||||
|  | ||||
| inline bool variantIsString(const JsonVariantData* var) { | ||||
|   return var && | ||||
|          (var->type == JSON_LINKED_STRING || var->type == JSON_OWNED_STRING); | ||||
| } | ||||
|  | ||||
| inline bool variantIsArray(const JsonVariantData* var) { | ||||
|   return var && var->type == JSON_ARRAY; | ||||
| } | ||||
|  | ||||
| inline bool variantIsObject(const JsonVariantData* var) { | ||||
|   return var && var->type == JSON_OBJECT; | ||||
| } | ||||
|  | ||||
| inline bool variantIsNull(const JsonVariantData* var) { | ||||
|   return var == 0 || var->type == JSON_NULL; | ||||
| } | ||||
|  | ||||
| inline bool variantEquals(const JsonVariantData* a, const JsonVariantData* b) { | ||||
|   if (a == b) return true; | ||||
|   if (!a || !b) return false; | ||||
|   if (a->type != b->type) return false; | ||||
|  | ||||
|   switch (a->type) { | ||||
|     case JSON_LINKED_RAW: | ||||
|     case JSON_OWNED_RAW: | ||||
|     case JSON_LINKED_STRING: | ||||
|     case JSON_OWNED_STRING: | ||||
|       return !strcmp(a->content.asString, b->content.asString); | ||||
|  | ||||
|     case JSON_BOOLEAN: | ||||
|     case JSON_POSITIVE_INTEGER: | ||||
|     case JSON_NEGATIVE_INTEGER: | ||||
|       return a->content.asInteger == b->content.asInteger; | ||||
|  | ||||
|     case JSON_ARRAY: | ||||
|       return arrayEquals(&a->content.asArray, &b->content.asArray); | ||||
|  | ||||
|     case JSON_OBJECT: | ||||
|       return objectEquals(&a->content.asObject, &b->content.asObject); | ||||
|  | ||||
|     case JSON_FLOAT: | ||||
|       return a->content.asFloat == b->content.asFloat; | ||||
|  | ||||
|     case JSON_NULL: | ||||
|     default: | ||||
|       return true; | ||||
|   } | ||||
| } | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -19,10 +19,10 @@ class JsonSerializer { | ||||
|     _writer.writeFloat(value); | ||||
|   } | ||||
|  | ||||
|   void visitArray(JsonArray array) { | ||||
|   void visitArray(JsonArrayConst array) { | ||||
|     _writer.beginArray(); | ||||
|  | ||||
|     JsonArray::iterator it = array.begin(); | ||||
|     JsonArrayConst::iterator it = array.begin(); | ||||
|     while (it != array.end()) { | ||||
|       it->accept(*this); | ||||
|  | ||||
| @@ -35,10 +35,10 @@ class JsonSerializer { | ||||
|     _writer.endArray(); | ||||
|   } | ||||
|  | ||||
|   void visitObject(JsonObject object) { | ||||
|   void visitObject(JsonObjectConst object) { | ||||
|     _writer.beginObject(); | ||||
|  | ||||
|     JsonObject::iterator it = object.begin(); | ||||
|     JsonObjectConst::iterator it = object.begin(); | ||||
|     while (it != object.end()) { | ||||
|       _writer.writeString(it->key()); | ||||
|       _writer.writeColon(); | ||||
| @@ -115,6 +115,10 @@ inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) { | ||||
|   serializeJson(source, os); | ||||
|   return os; | ||||
| } | ||||
| inline std::ostream &operator<<(std::ostream &os, JsonVariantConst source) { | ||||
|   os << serializeJson(source, os); | ||||
|   return os; | ||||
| } | ||||
|  | ||||
| inline std::ostream &operator<<(std::ostream &os, | ||||
|                                 const JsonArraySubscript &source) { | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "Data/ArrayFunctions.hpp" | ||||
| #include "Data/JsonVariantData.hpp" | ||||
| #include "JsonArrayIterator.hpp" | ||||
|  | ||||
| @@ -17,60 +18,91 @@ namespace ARDUINOJSON_NAMESPACE { | ||||
| class JsonObject; | ||||
| class JsonArraySubscript; | ||||
|  | ||||
| class JsonArray { | ||||
|   friend class JsonVariant; | ||||
| template <typename TData> | ||||
| class JsonArrayProxy { | ||||
|  public: | ||||
|   FORCE_INLINE bool isNull() const { | ||||
|     return _data == 0; | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE JsonVariantConst operator[](size_t index) const { | ||||
|     return JsonVariantConst(arrayGet(_data, index)); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE size_t size() const { | ||||
|     return arraySize(_data); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   JsonArrayProxy(TData* data) : _data(data) {} | ||||
|   TData* _data; | ||||
| }; | ||||
|  | ||||
| class JsonArrayConst : public JsonArrayProxy<const JsonArrayData> { | ||||
|   friend class JsonArray; | ||||
|   typedef JsonArrayProxy<const JsonArrayData> proxy_type; | ||||
|  | ||||
|  public: | ||||
|   typedef JsonArrayConstIterator iterator; | ||||
|  | ||||
|   FORCE_INLINE iterator begin() const { | ||||
|     if (!_data) return iterator(); | ||||
|     return iterator(_data->head); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE iterator end() const { | ||||
|     return iterator(); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE JsonArrayConst() : proxy_type(0) {} | ||||
|   FORCE_INLINE JsonArrayConst(const JsonArrayData* data) : proxy_type(data) {} | ||||
|  | ||||
|   FORCE_INLINE bool operator==(JsonArrayConst rhs) const { | ||||
|     return arrayEquals(_data, rhs._data); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class JsonArray : public JsonArrayProxy<JsonArrayData> { | ||||
|   typedef JsonArrayProxy<JsonArrayData> proxy_type; | ||||
|  | ||||
|  public: | ||||
|   typedef JsonArrayIterator iterator; | ||||
|  | ||||
|   FORCE_INLINE JsonArray() : _memoryPool(0), _data(0) {} | ||||
|   FORCE_INLINE JsonArray(MemoryPool* pool, JsonArrayData* arr) | ||||
|       : _memoryPool(pool), _data(arr) {} | ||||
|   FORCE_INLINE JsonArray() : proxy_type(0), _memoryPool(0) {} | ||||
|   FORCE_INLINE JsonArray(MemoryPool* pool, JsonArrayData* data) | ||||
|       : proxy_type(data), _memoryPool(pool) {} | ||||
|  | ||||
|   operator JsonVariant() { | ||||
|     return JsonVariant(_memoryPool, getVariantData(_data)); | ||||
|   } | ||||
|  | ||||
|   operator JsonArrayConst() const { | ||||
|     return JsonArrayConst(_data); | ||||
|   } | ||||
|  | ||||
|   // Adds the specified value at the end of the array. | ||||
|   // | ||||
|   // bool add(TValue); | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonObject | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool add(const T& value) { | ||||
|   FORCE_INLINE bool add(const T& value) const { | ||||
|     return add().set(value); | ||||
|   } | ||||
|   // Adds the specified value at the end of the array. | ||||
|   FORCE_INLINE bool add(JsonArray value) { | ||||
|   FORCE_INLINE bool add(JsonArray value) const { | ||||
|     return add().set(value); | ||||
|   } | ||||
|   // | ||||
|   // bool add(TValue); | ||||
|   // TValue = char*, const char*, const FlashStringHelper* | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool add(T* value) { | ||||
|   FORCE_INLINE bool add(T* value) const { | ||||
|     return add().set(value); | ||||
|   } | ||||
|  | ||||
|   JsonVariant add() { | ||||
|     if (!_data) return JsonVariant(); | ||||
|  | ||||
|     Slot* slot = new (_memoryPool) Slot(); | ||||
|     if (!slot) return JsonVariant(); | ||||
|  | ||||
|     slot->next = 0; | ||||
|  | ||||
|     if (_data->tail) { | ||||
|       slot->prev = _data->tail; | ||||
|       _data->tail->next = slot; | ||||
|       _data->tail = slot; | ||||
|     } else { | ||||
|       slot->prev = 0; | ||||
|       _data->head = slot; | ||||
|       _data->tail = slot; | ||||
|     } | ||||
|  | ||||
|     return JsonVariant(_memoryPool, &slot->value); | ||||
|   JsonVariant add() const { | ||||
|     return JsonVariant(_memoryPool, arrayAdd(_data, _memoryPool)); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE iterator begin() const { | ||||
| @@ -84,13 +116,13 @@ class JsonArray { | ||||
|  | ||||
|   // Imports a 1D array | ||||
|   template <typename T, size_t N> | ||||
|   FORCE_INLINE bool copyFrom(T (&array)[N]) { | ||||
|   FORCE_INLINE bool copyFrom(T (&array)[N]) const { | ||||
|     return copyFrom(array, N); | ||||
|   } | ||||
|  | ||||
|   // Imports a 1D array | ||||
|   template <typename T> | ||||
|   bool copyFrom(T* array, size_t len) { | ||||
|   bool copyFrom(T* array, size_t len) const { | ||||
|     bool ok = true; | ||||
|     for (size_t i = 0; i < len; i++) { | ||||
|       ok &= add(array[i]); | ||||
| @@ -100,7 +132,7 @@ class JsonArray { | ||||
|  | ||||
|   // Imports a 2D array | ||||
|   template <typename T, size_t N1, size_t N2> | ||||
|   bool copyFrom(T (&array)[N1][N2]) { | ||||
|   bool copyFrom(T (&array)[N1][N2]) const { | ||||
|     bool ok = true; | ||||
|     for (size_t i = 0; i < N1; i++) { | ||||
|       JsonArray nestedArray = createNestedArray(); | ||||
| @@ -112,12 +144,8 @@ class JsonArray { | ||||
|   } | ||||
|  | ||||
|   // Copy a JsonArray | ||||
|   bool copyFrom(JsonArray src) { | ||||
|     bool ok = _data != 0; | ||||
|     for (iterator it = src.begin(); it != src.end(); ++it) { | ||||
|       ok &= add(*it); | ||||
|     } | ||||
|     return ok; | ||||
|   FORCE_INLINE bool copyFrom(JsonArray src) const { | ||||
|     return arrayCopy(_data, src._data, _memoryPool); | ||||
|   } | ||||
|  | ||||
|   // Exports a 1D array | ||||
| @@ -144,102 +172,54 @@ class JsonArray { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE JsonArray createNestedArray(); | ||||
|   FORCE_INLINE JsonObject createNestedObject(); | ||||
|   FORCE_INLINE JsonArray createNestedArray() const; | ||||
|   FORCE_INLINE JsonObject createNestedObject() const; | ||||
|  | ||||
|   FORCE_INLINE JsonArraySubscript operator[](size_t index); | ||||
|  | ||||
|   FORCE_INLINE const JsonArraySubscript operator[](size_t index) const; | ||||
|   FORCE_INLINE JsonArraySubscript operator[](size_t index) const; | ||||
|  | ||||
|   FORCE_INLINE bool operator==(JsonArray rhs) const { | ||||
|     iterator it1 = begin(); | ||||
|     iterator it2 = rhs.begin(); | ||||
|     for (;;) { | ||||
|       if (it1 == end() && it2 == rhs.end()) return true; | ||||
|       if (it1 == end()) return false; | ||||
|       if (it2 == end()) return false; | ||||
|       if (*it1 != *it2) return false; | ||||
|       ++it1; | ||||
|       ++it2; | ||||
|     } | ||||
|     return arrayEquals(_data, rhs._data); | ||||
|   } | ||||
|  | ||||
|   // Gets the value at the specified index. | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename JsonVariantAs<T>::type get(size_t index) const { | ||||
|     iterator it = begin() += index; | ||||
|     return it != end() ? it->as<T>() : T(); | ||||
|     return get_impl(index).as<T>(); | ||||
|   } | ||||
|  | ||||
|   // Check the type of the value at specified index. | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool is(size_t index) const { | ||||
|     iterator it = begin() += index; | ||||
|     return it != end() ? it->is<T>() : false; | ||||
|     return get_impl(index).is<T>(); | ||||
|   } | ||||
|  | ||||
|   // Removes element at specified position. | ||||
|   FORCE_INLINE void remove(iterator it) { | ||||
|     if (!_data) return; | ||||
|  | ||||
|     Slot* slot = it.internal(); | ||||
|     if (!slot) return; | ||||
|  | ||||
|     if (slot->prev) | ||||
|       slot->prev->next = slot->next; | ||||
|     else | ||||
|       _data->head = slot->next; | ||||
|     if (slot->next) | ||||
|       slot->next->prev = slot->prev; | ||||
|     else | ||||
|       _data->tail = slot->prev; | ||||
|   FORCE_INLINE void remove(iterator it) const { | ||||
|     arrayRemove(_data, it.internal()); | ||||
|   } | ||||
|  | ||||
|   // Removes element at specified index. | ||||
|   FORCE_INLINE void remove(size_t index) { | ||||
|     remove(begin() += index); | ||||
|   FORCE_INLINE void remove(size_t index) const { | ||||
|     arrayRemove(_data, index); | ||||
|   } | ||||
|  | ||||
|   // Sets the value at specified index. | ||||
|   // | ||||
|   // bool add(size_t index, const TValue&); | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonArrayData, JsonObject | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set(size_t index, const T& value) { | ||||
|   FORCE_INLINE bool set(size_t index, const T& value) const { | ||||
|     if (!_data) return false; | ||||
|     return set_impl<const T&>(index, value); | ||||
|     return get_impl(index).set(value); | ||||
|   } | ||||
|   // | ||||
|   // bool add(size_t index, TValue); | ||||
|   // TValue = char*, const char*, const FlashStringHelper* | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set(size_t index, T* value) { | ||||
|   FORCE_INLINE bool set(size_t index, T* value) const { | ||||
|     if (!_data) return false; | ||||
|     return set_impl<T*>(index, value); | ||||
|   } | ||||
|   // Sets the value at specified index. | ||||
|   // | ||||
|   // bool add(size_t index, JsonArray); | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set(size_t index, JsonArray value) { | ||||
|     if (!_data) return false; | ||||
|     return get<JsonVariant>(index).set(value); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE size_t size() const { | ||||
|     if (!_data) return 0; | ||||
|     Slot* slot = _data->head; | ||||
|     size_t n = 0; | ||||
|     while (slot) { | ||||
|       slot = slot->next; | ||||
|       n++; | ||||
|     } | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool isNull() const { | ||||
|     return _data == 0; | ||||
|     return get_impl(index).set(value); | ||||
|   } | ||||
|  | ||||
|   template <typename Visitor> | ||||
| @@ -252,18 +232,14 @@ class JsonArray { | ||||
|  | ||||
|  private: | ||||
|   template <typename TValueRef> | ||||
|   FORCE_INLINE bool set_impl(size_t index, TValueRef value) { | ||||
|     iterator it = begin() += index; | ||||
|     if (it == end()) return false; | ||||
|     return it->set(value); | ||||
|   } | ||||
|  | ||||
|   template <typename TValueRef> | ||||
|   FORCE_INLINE bool add_impl(TValueRef value) { | ||||
|   FORCE_INLINE bool add_impl(TValueRef value) const { | ||||
|     return add().set(value); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE JsonVariant get_impl(size_t index) const { | ||||
|     return JsonVariant(_memoryPool, arrayGet(_data, index)); | ||||
|   } | ||||
|  | ||||
|   MemoryPool* _memoryPool; | ||||
|   JsonArrayData* _data; | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -9,11 +9,11 @@ | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| inline JsonArray JsonArray::createNestedArray() { | ||||
| inline JsonArray JsonArray::createNestedArray() const { | ||||
|   return add().to<JsonArray>(); | ||||
| } | ||||
|  | ||||
| inline JsonObject JsonArray::createNestedObject() { | ||||
| inline JsonObject JsonArray::createNestedObject() const { | ||||
|   return add().to<JsonObject>(); | ||||
| } | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "Data/Slot.hpp" | ||||
| #include "Data/SlotFunctions.hpp" | ||||
| #include "JsonVariant.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
| @@ -29,8 +30,8 @@ class JsonVariantPtr { | ||||
| class JsonArrayIterator { | ||||
|  public: | ||||
|   JsonArrayIterator() : _slot(0) {} | ||||
|   explicit JsonArrayIterator(MemoryPool *memoryPool, Slot *iterator) | ||||
|       : _memoryPool(memoryPool), _slot(iterator) {} | ||||
|   explicit JsonArrayIterator(MemoryPool *memoryPool, Slot *slot) | ||||
|       : _memoryPool(memoryPool), _slot(slot) {} | ||||
|  | ||||
|   JsonVariant operator*() const { | ||||
|     return JsonVariant(_memoryPool, &_slot->value); | ||||
| @@ -53,10 +54,7 @@ class JsonArrayIterator { | ||||
|   } | ||||
|  | ||||
|   JsonArrayIterator &operator+=(size_t distance) { | ||||
|     while (distance && _slot) { | ||||
|       _slot = _slot->next; | ||||
|       distance--; | ||||
|     } | ||||
|     _slot = slotAdvance(_slot, distance); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
| @@ -68,4 +66,58 @@ class JsonArrayIterator { | ||||
|   MemoryPool *_memoryPool; | ||||
|   Slot *_slot; | ||||
| }; | ||||
|  | ||||
| class JsonVariantConstPtr { | ||||
|  public: | ||||
|   JsonVariantConstPtr(const JsonVariantData *data) : _variant(data) {} | ||||
|  | ||||
|   JsonVariantConst *operator->() { | ||||
|     return &_variant; | ||||
|   } | ||||
|  | ||||
|   JsonVariantConst &operator*() { | ||||
|     return _variant; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonVariantConst _variant; | ||||
| }; | ||||
|  | ||||
| class JsonArrayConstIterator { | ||||
|  public: | ||||
|   JsonArrayConstIterator() : _slot(0) {} | ||||
|   explicit JsonArrayConstIterator(const Slot *slot) : _slot(slot) {} | ||||
|  | ||||
|   JsonVariantConst operator*() const { | ||||
|     return JsonVariantConst(&_slot->value); | ||||
|   } | ||||
|   JsonVariantConstPtr operator->() { | ||||
|     return JsonVariantConstPtr(&_slot->value); | ||||
|   } | ||||
|  | ||||
|   bool operator==(const JsonArrayConstIterator &other) const { | ||||
|     return _slot == other._slot; | ||||
|   } | ||||
|  | ||||
|   bool operator!=(const JsonArrayConstIterator &other) const { | ||||
|     return _slot != other._slot; | ||||
|   } | ||||
|  | ||||
|   JsonArrayConstIterator &operator++() { | ||||
|     _slot = _slot->next; | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   JsonArrayConstIterator &operator+=(size_t distance) { | ||||
|     _slot = slotAdvance(_slot, distance); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   const Slot *internal() { | ||||
|     return _slot; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const Slot *_slot; | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -19,7 +19,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { | ||||
|       : _array(array), _index(index) {} | ||||
|  | ||||
|   FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) { | ||||
|     _array.set(_index, src.as<JsonVariant>()); | ||||
|     get_impl().set(src.as<JsonVariant>()); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
| @@ -30,7 +30,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename T> | ||||
|   FORCE_INLINE JsonArraySubscript& operator=(const T& src) { | ||||
|     _array.set(_index, src); | ||||
|     get_impl().set(src); | ||||
|     return *this; | ||||
|   } | ||||
|   // | ||||
| @@ -38,7 +38,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { | ||||
|   // TValue = char*, const char*, const FlashStringHelper* | ||||
|   template <typename T> | ||||
|   FORCE_INLINE JsonArraySubscript& operator=(T* src) { | ||||
|     _array.set(_index, src); | ||||
|     get_impl().set(src); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
| @@ -57,7 +57,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename JsonVariantTo<T>::type to() { | ||||
|   FORCE_INLINE typename JsonVariantTo<T>::type to() const { | ||||
|     return _array.get<JsonVariant>(_index).to<T>(); | ||||
|   } | ||||
|  | ||||
| @@ -67,44 +67,42 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> { | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE bool set(const TValue& value) { | ||||
|     return _array.set(_index, value); | ||||
|   FORCE_INLINE bool set(const TValue& value) const { | ||||
|     return get_impl().set(value); | ||||
|   } | ||||
|   // | ||||
|   // bool set(TValue) | ||||
|   // TValue = char*, const char*, const FlashStringHelper* | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE bool set(TValue* value) { | ||||
|     return _array.set(_index, value); | ||||
|   FORCE_INLINE bool set(TValue* value) const { | ||||
|     return get_impl().set(value); | ||||
|   } | ||||
|  | ||||
|   template <typename Visitor> | ||||
|   void accept(Visitor& visitor) const { | ||||
|     return _array.get<JsonVariant>(_index).accept(visitor); | ||||
|     return get_impl().accept(visitor); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE size_t size() const { | ||||
|     return get_impl().size(); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonVariant get_impl() const { | ||||
|     return _array.get<JsonVariant>(_index); | ||||
|   } | ||||
|  | ||||
|   JsonArray _array; | ||||
|   const size_t _index; | ||||
| }; | ||||
|  | ||||
| template <typename TImpl> | ||||
| inline JsonArraySubscript JsonVariantSubscripts<TImpl>::operator[]( | ||||
|     size_t index) { | ||||
|   return impl()->template as<JsonArray>()[index]; | ||||
| } | ||||
|  | ||||
| template <typename TImpl> | ||||
| inline const JsonArraySubscript JsonVariantSubscripts<TImpl>::operator[]( | ||||
|     size_t index) const { | ||||
|   return impl()->template as<JsonArray>()[index]; | ||||
| } | ||||
|  | ||||
| inline JsonArraySubscript JsonArray::operator[](size_t index) { | ||||
|   return JsonArraySubscript(*this, index); | ||||
| } | ||||
|  | ||||
| inline const JsonArraySubscript JsonArray::operator[](size_t index) const { | ||||
| inline JsonArraySubscript JsonArray::operator[](size_t index) const { | ||||
|   return JsonArraySubscript(*this, index); | ||||
| } | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -24,7 +24,12 @@ class JsonDocument { | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   typename JsonVariantAs<T>::type as() const { | ||||
|   typename JsonVariantAs<T>::type as() { | ||||
|     return getVariant().template as<T>(); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   typename JsonVariantConstAs<T>::type as() const { | ||||
|     return getVariant().template as<T>(); | ||||
|   } | ||||
|  | ||||
| @@ -53,12 +58,16 @@ class JsonDocument { | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonVariant getVariant() const { | ||||
|   JsonVariant getVariant() { | ||||
|     return JsonVariant(&_memoryPool, &_rootData); | ||||
|   } | ||||
|  | ||||
|   mutable TMemoryPool _memoryPool; | ||||
|   mutable JsonVariantData _rootData; | ||||
|   JsonVariantConst getVariant() const { | ||||
|     return JsonVariantConst(&_rootData); | ||||
|   } | ||||
|  | ||||
|   TMemoryPool _memoryPool; | ||||
|   JsonVariantData _rootData; | ||||
| }; | ||||
|  | ||||
| class DynamicJsonDocument : public JsonDocument<DynamicMemoryPool> { | ||||
|   | ||||
							
								
								
									
										37
									
								
								src/ArduinoJson/JsonKey.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/ArduinoJson/JsonKey.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class JsonKey { | ||||
|  public: | ||||
|   JsonKey(const Slot* slot) : _slot(slot) {} | ||||
|  | ||||
|   operator const char*() const { | ||||
|     return c_str(); | ||||
|   } | ||||
|  | ||||
|   const char* c_str() const { | ||||
|     return _slot ? _slot->key : 0; | ||||
|   } | ||||
|  | ||||
|   bool isNull() const { | ||||
|     return _slot == 0 || _slot->key == 0; | ||||
|   } | ||||
|  | ||||
|   bool isStatic() const { | ||||
|     return _slot ? _slot->value.keyIsStatic : true; | ||||
|   } | ||||
|  | ||||
|   friend bool operator==(JsonKey lhs, const char* rhs) { | ||||
|     if (lhs.isNull()) return rhs == 0; | ||||
|     return rhs ? !strcmp(lhs, rhs) : false; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const Slot* _slot; | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -4,7 +4,8 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "./JsonObjectIterator.hpp" | ||||
| #include "Data/ObjectFunctions.hpp" | ||||
| #include "JsonObjectIterator.hpp" | ||||
|  | ||||
| // Returns the size (in bytes) of an object with n elements. | ||||
| // Can be very handy to determine the size of a StaticMemoryPool. | ||||
| @@ -13,88 +14,162 @@ | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class JsonObject { | ||||
|   friend class JsonVariant; | ||||
| template <typename TData> | ||||
| class JsonObjectProxy { | ||||
|  public: | ||||
|   // Tells weither the specified key is present and associated with a value. | ||||
|   // | ||||
|   // bool containsKey(TKey); | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE bool containsKey(const TKey& key) const { | ||||
|     return objectContainsKey(_data, makeString(key)); | ||||
|   } | ||||
|   // | ||||
|   // bool containsKey(TKey); | ||||
|   // TKey = char*, const char*, char[], const char[], const FlashStringHelper* | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE bool containsKey(TKey* key) const { | ||||
|     return objectContainsKey(_data, makeString(key)); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE size_t size() const { | ||||
|     return objectSize(_data); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   JsonObjectProxy(TData* data) : _data(data) {} | ||||
|   TData* _data; | ||||
| }; | ||||
|  | ||||
| class JsonObjectConst : public JsonObjectProxy<const JsonObjectData> { | ||||
|   friend class JsonObject; | ||||
|   typedef JsonObjectProxy<const JsonObjectData> proxy_type; | ||||
|  | ||||
|  public: | ||||
|   typedef JsonObjectConstIterator iterator; | ||||
|  | ||||
|   JsonObjectConst() : proxy_type(0) {} | ||||
|   JsonObjectConst(const JsonObjectData* data) : proxy_type(data) {} | ||||
|  | ||||
|   FORCE_INLINE iterator begin() const { | ||||
|     if (!_data) return iterator(); | ||||
|     return iterator(_data->head); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE iterator end() const { | ||||
|     return iterator(); | ||||
|   } | ||||
|  | ||||
|   // Gets the value associated with the specified key. | ||||
|   // | ||||
|   // TValue get<TValue>(TKey) const; | ||||
|   // TKey = const std::string&, const String& | ||||
|   // TValue = bool, char, long, int, short, float, double, | ||||
|   //          std::string, String, JsonArrayConst, JsonObjectConst | ||||
|   template <typename TValue, typename TKey> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type get(const TKey& key) const { | ||||
|     return get_impl(makeString(key)).template as<TValue>(); | ||||
|   } | ||||
|   // | ||||
|   // TValue get<TValue>(TKey) const; | ||||
|   // TKey = char*, const char*, const FlashStringHelper* | ||||
|   // TValue = bool, char, long, int, short, float, double, | ||||
|   //          std::string, String, JsonArrayConst, JsonObjectConst | ||||
|   template <typename TValue, typename TKey> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type get(TKey* key) const { | ||||
|     return get_impl(makeString(key)).template as<TValue>(); | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   // JsonVariantConst operator[](TKey) const; | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE typename enable_if<IsString<TKey>::value, JsonVariantConst>::type | ||||
|   operator[](const TKey& key) const { | ||||
|     return get_impl(makeString(key)); | ||||
|   } | ||||
|   // | ||||
|   // JsonVariantConst operator[](TKey) const; | ||||
|   // TKey = const char*, const char[N], const FlashStringHelper* | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE | ||||
|       typename enable_if<IsString<TKey*>::value, JsonVariantConst>::type | ||||
|       operator[](TKey* key) const { | ||||
|     return get_impl(makeString(key)); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool operator==(JsonObjectConst rhs) const { | ||||
|     return objectEquals(_data, rhs._data); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE JsonVariantConst get_impl(TKey key) const { | ||||
|     return JsonVariantConst(objectGet(_data, key)); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class JsonObject : public JsonObjectProxy<JsonObjectData> { | ||||
|   typedef JsonObjectProxy<JsonObjectData> proxy_type; | ||||
|  | ||||
|  public: | ||||
|   typedef JsonObjectIterator iterator; | ||||
|  | ||||
|   FORCE_INLINE JsonObject() : _memoryPool(0), _data(0) {} | ||||
|   FORCE_INLINE JsonObject(MemoryPool* buf, JsonObjectData* object) | ||||
|       : _memoryPool(buf), _data(object) {} | ||||
|   FORCE_INLINE JsonObject() : proxy_type(0), _memoryPool(0) {} | ||||
|   FORCE_INLINE JsonObject(MemoryPool* buf, JsonObjectData* data) | ||||
|       : proxy_type(data), _memoryPool(buf) {} | ||||
|  | ||||
|   operator JsonVariant() { | ||||
|   operator JsonVariant() const { | ||||
|     return JsonVariant(_memoryPool, getVariantData(_data)); | ||||
|   } | ||||
|  | ||||
|   operator JsonObjectConst() const { | ||||
|     return JsonObjectConst(_data); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE iterator begin() const { | ||||
|     if (!_data) return iterator(); | ||||
|     return iterator(_memoryPool, _data->head); | ||||
|   } | ||||
|  | ||||
|   void clear() { | ||||
|     _data->head = 0; | ||||
|     _data->tail = 0; | ||||
|   } | ||||
|  | ||||
|   // Tells weither the specified key is present and associated with a value. | ||||
|   // | ||||
|   // bool containsKey(TKey); | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE bool containsKey(const TString& key) const { | ||||
|     return containsKey_impl(makeString(key)); | ||||
|   } | ||||
|   // | ||||
|   // bool containsKey(TKey); | ||||
|   // TKey = char*, const char*, char[], const char[], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE bool containsKey(TString* key) const { | ||||
|     return containsKey_impl(makeString(key)); | ||||
|   } | ||||
|  | ||||
|   bool copyFrom(JsonObject src) { | ||||
|     bool ok = _data != 0; | ||||
|     clear(); | ||||
|     for (iterator it = src.begin(); it != src.end(); ++it) { | ||||
|       if (it->key().isStatic()) | ||||
|         ok &= set(it->key().c_str(), it->value()); | ||||
|       else | ||||
|         ok &= set(const_cast<char*>(it->key().c_str()), it->value()); | ||||
|     } | ||||
|     return ok; | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE iterator end() const { | ||||
|     return iterator(); | ||||
|   } | ||||
|  | ||||
|   void clear() const { | ||||
|     objectClear(_data); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool copyFrom(JsonObjectConst src) { | ||||
|     return objectCopy(_data, src._data, _memoryPool); | ||||
|   } | ||||
|  | ||||
|   // Creates and adds a JsonArray. | ||||
|   // | ||||
|   // JsonArray createNestedArray(TKey); | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE JsonArray createNestedArray(const TString& key); | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE JsonArray createNestedArray(const TKey& key) const; | ||||
|   // JsonArray createNestedArray(TKey); | ||||
|   // TKey = char*, const char*, char[], const char[], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE JsonArray createNestedArray(TString* key); | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE JsonArray createNestedArray(TKey* key) const; | ||||
|  | ||||
|   // Creates and adds a JsonObject. | ||||
|   // | ||||
|   // JsonObject createNestedObject(TKey); | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE JsonObject createNestedObject(const TString& key) { | ||||
|     if (!_data) return JsonObject(); | ||||
|     return createNestedObject_impl(makeString(key)); | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE JsonObject createNestedObject(const TKey& key) const { | ||||
|     return set(key).template to<JsonObject>(); | ||||
|   } | ||||
|   // | ||||
|   // JsonObject createNestedObject(TKey); | ||||
|   // TKey = char*, const char*, char[], const char[], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE JsonObject createNestedObject(TString* key) { | ||||
|     return createNestedObject_impl(makeString(key)); | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE JsonObject createNestedObject(TKey* key) const { | ||||
|     return set(key).template to<JsonObject>(); | ||||
|   } | ||||
|  | ||||
|   // Gets the value associated with the specified key. | ||||
| @@ -103,19 +178,18 @@ class JsonObject { | ||||
|   // TKey = const std::string&, const String& | ||||
|   // TValue = bool, char, long, int, short, float, double, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue, typename TString> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type get( | ||||
|       const TString& key) const { | ||||
|     return get_impl<TValue>(makeString(key)); | ||||
|   template <typename TValue, typename TKey> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type get(const TKey& key) const { | ||||
|     return get_impl(makeString(key)).template as<TValue>(); | ||||
|   } | ||||
|   // | ||||
|   // TValue get<TValue>(TKey) const; | ||||
|   // TKey = char*, const char*, const FlashStringHelper* | ||||
|   // TValue = bool, char, long, int, short, float, double, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue, typename TString> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type get(TString* key) const { | ||||
|     return get_impl<TValue>(makeString(key)); | ||||
|   template <typename TValue, typename TKey> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type get(TKey* key) const { | ||||
|     return get_impl(makeString(key)).template as<TValue>(); | ||||
|   } | ||||
|  | ||||
|   // Checks the type of the value associated with the specified key. | ||||
| @@ -125,90 +199,58 @@ class JsonObject { | ||||
|   // TKey = const std::string&, const String& | ||||
|   // TValue = bool, char, long, int, short, float, double, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue, typename TString> | ||||
|   FORCE_INLINE bool is(const TString& key) const { | ||||
|     return is_impl<TValue>(makeString(key)); | ||||
|   template <typename TValue, typename TKey> | ||||
|   FORCE_INLINE bool is(const TKey& key) const { | ||||
|     return get_impl(makeString(key)).template is<TValue>(); | ||||
|   } | ||||
|   // | ||||
|   // bool is<TValue>(TKey) const; | ||||
|   // TKey = char*, const char*, const FlashStringHelper* | ||||
|   // TValue = bool, char, long, int, short, float, double, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue, typename TString> | ||||
|   FORCE_INLINE bool is(TString* key) const { | ||||
|     return is_impl<TValue>(makeString(key)); | ||||
|   template <typename TValue, typename TKey> | ||||
|   FORCE_INLINE bool is(TKey* key) const { | ||||
|     return get_impl(makeString(key)).template is<TValue>(); | ||||
|   } | ||||
|  | ||||
|   // Gets or sets the value associated with the specified key. | ||||
|   // | ||||
|   // JsonObjectSubscript operator[](TKey) | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE JsonObjectSubscript<const TString&> operator[]( | ||||
|       const TString& key) { | ||||
|     return JsonObjectSubscript<const TString&>(*this, key); | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE JsonObjectSubscript<const TKey&> operator[]( | ||||
|       const TKey& key) const { | ||||
|     return JsonObjectSubscript<const TKey&>(*this, key); | ||||
|   } | ||||
|   // | ||||
|   // JsonObjectSubscript operator[](TKey) | ||||
|   // TKey = char*, const char*, char[], const char[N], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE JsonObjectSubscript<TString*> operator[](TString* key) { | ||||
|     return JsonObjectSubscript<TString*>(*this, key); | ||||
|   } | ||||
|  | ||||
|   // Gets the value associated with the specified key. | ||||
|   // | ||||
|   // const JsonObjectSubscript operator[](TKey) const; | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE const JsonObjectSubscript<const TString&> operator[]( | ||||
|       const TString& key) const { | ||||
|     return JsonObjectSubscript<const TString&>(*this, key); | ||||
|   } | ||||
|   // | ||||
|   // const JsonObjectSubscript operator[](TKey) const; | ||||
|   // TKey = const char*, const char[N], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE const JsonObjectSubscript<TString*> operator[]( | ||||
|       TString* key) const { | ||||
|     return JsonObjectSubscript<TString*>(*this, key); | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE JsonObjectSubscript<TKey*> operator[](TKey* key) const { | ||||
|     return JsonObjectSubscript<TKey*>(*this, key); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool operator==(JsonObject rhs) const { | ||||
|     if (size() != rhs.size()) return false; | ||||
|     for (iterator it = begin(); it != end(); ++it) { | ||||
|       if (rhs.get<JsonVariant>(it->key()) != it->value()) return false; | ||||
|     } | ||||
|     return true; | ||||
|     return objectEquals(_data, rhs._data); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE void remove(iterator it) { | ||||
|     if (!_data) return; | ||||
|     Slot* slot = it.internal(); | ||||
|     if (!slot) return; | ||||
|     if (slot->prev) | ||||
|       slot->prev->next = slot->next; | ||||
|     else | ||||
|       _data->head = slot->next; | ||||
|     if (slot->next) | ||||
|       slot->next->prev = slot->prev; | ||||
|     else | ||||
|       _data->tail = slot->prev; | ||||
|   FORCE_INLINE void remove(iterator it) const { | ||||
|     objectRemove(_data, it.internal()); | ||||
|   } | ||||
|  | ||||
|   // Removes the specified key and the associated value. | ||||
|   // | ||||
|   // void remove(TKey); | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE void remove(const TString& key) { | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE void remove(const TKey& key) const { | ||||
|     remove_impl(makeString(key)); | ||||
|   } | ||||
|   // | ||||
|   // void remove(TKey); | ||||
|   // TKey = char*, const char*, char[], const char[], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE void remove(TString* key) { | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE void remove(TKey* key) const { | ||||
|     remove_impl(makeString(key)); | ||||
|   } | ||||
|  | ||||
| @@ -218,16 +260,16 @@ class JsonObject { | ||||
|   // TKey = const std::string&, const String& | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue, typename TString> | ||||
|   FORCE_INLINE bool set(const TString& key, const TValue& value) { | ||||
|   template <typename TValue, typename TKey> | ||||
|   FORCE_INLINE bool set(const TKey& key, const TValue& value) const { | ||||
|     return set(key).set(value); | ||||
|   } | ||||
|   // | ||||
|   // bool set(TKey, TValue); | ||||
|   // TKey = const std::string&, const String& | ||||
|   // TValue = char*, const char*, const FlashStringHelper* | ||||
|   template <typename TValue, typename TString> | ||||
|   FORCE_INLINE bool set(const TString& key, TValue* value) { | ||||
|   template <typename TValue, typename TKey> | ||||
|   FORCE_INLINE bool set(const TKey& key, TValue* value) const { | ||||
|     return set(key).set(value); | ||||
|   } | ||||
|   // | ||||
| @@ -235,44 +277,33 @@ class JsonObject { | ||||
|   // TKey = char*, const char*, const FlashStringHelper* | ||||
|   // TValue = bool, long, int, short, float, double, serialized, JsonVariant, | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue, typename TString> | ||||
|   FORCE_INLINE bool set(TString* key, const TValue& value) { | ||||
|   template <typename TValue, typename TKey> | ||||
|   FORCE_INLINE bool set(TKey* key, const TValue& value) const { | ||||
|     return set(key).set(value); | ||||
|   } | ||||
|   // | ||||
|   // bool set(TKey, TValue); | ||||
|   // TKey = char*, const char*, const FlashStringHelper* | ||||
|   // TValue = char*, const char*, const FlashStringHelper* | ||||
|   template <typename TValue, typename TString> | ||||
|   FORCE_INLINE bool set(TString* key, TValue* value) { | ||||
|   template <typename TValue, typename TKey> | ||||
|   FORCE_INLINE bool set(TKey* key, TValue* value) const { | ||||
|     return set(key).set(value); | ||||
|   } | ||||
|  | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE JsonVariant set(TString* key) { | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE JsonVariant set(TKey* key) const { | ||||
|     return set_impl(makeString(key)); | ||||
|   } | ||||
|  | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE JsonVariant set(const TString& key) { | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE JsonVariant set(const TKey& key) const { | ||||
|     return set_impl(makeString(key)); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE JsonVariant set(const StringInMemoryPool& key) { | ||||
|   FORCE_INLINE JsonVariant set(const StringInMemoryPool& key) const { | ||||
|     return set_impl(key); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE size_t size() const { | ||||
|     if (!_data) return 0; | ||||
|     size_t n = 0; | ||||
|     Slot* slot = _data->head; | ||||
|     while (slot) { | ||||
|       n++; | ||||
|       slot = slot->next; | ||||
|     } | ||||
|     return n; | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool isNull() const { | ||||
|     return _data == 0; | ||||
|   } | ||||
| @@ -280,122 +311,27 @@ class JsonObject { | ||||
|   template <typename Visitor> | ||||
|   FORCE_INLINE void accept(Visitor& visitor) const { | ||||
|     if (_data) | ||||
|       visitor.visitObject(*this); | ||||
|       visitor.visitObject(JsonObjectConst(_data)); | ||||
|     else | ||||
|       visitor.visitNull(); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   template <typename TStringRef> | ||||
|   FORCE_INLINE bool containsKey_impl(TStringRef key) const { | ||||
|     return findSlot(key) != 0; | ||||
|   FORCE_INLINE JsonVariant get_impl(TStringRef key) const { | ||||
|     return JsonVariant(_memoryPool, objectGet(_data, key)); | ||||
|   } | ||||
|  | ||||
|   template <typename TKey> | ||||
|   FORCE_INLINE JsonVariant set_impl(TKey key) const { | ||||
|     return JsonVariant(_memoryPool, objectSet(_data, key, _memoryPool)); | ||||
|   } | ||||
|  | ||||
|   template <typename TStringRef> | ||||
|   FORCE_INLINE JsonArray createNestedArray_impl(TStringRef key); | ||||
|  | ||||
|   template <typename TStringRef> | ||||
|   FORCE_INLINE JsonObject createNestedObject_impl(TStringRef key); | ||||
|  | ||||
|   // Returns the list node that matches the specified key. | ||||
|   template <typename TStringRef> | ||||
|   Slot* findSlot(TStringRef key) { | ||||
|     if (!_data) return 0; | ||||
|     Slot* slot = _data->head; | ||||
|     while (slot) { | ||||
|       if (key.equals(slot->key)) break; | ||||
|       slot = slot->next; | ||||
|     } | ||||
|     return slot; | ||||
|   } | ||||
|   template <typename TStringRef> | ||||
|   FORCE_INLINE Slot* findSlot(TStringRef key) const { | ||||
|     return const_cast<JsonObject*>(this)->findSlot(key); | ||||
|   FORCE_INLINE void remove_impl(TStringRef key) const { | ||||
|     objectRemove(_data, objectFindSlot(_data, key)); | ||||
|   } | ||||
|  | ||||
|   template <typename TValue, typename TStringRef> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type get_impl( | ||||
|       TStringRef key) const { | ||||
|     Slot* slot = findSlot(key); | ||||
|     return slot ? JsonVariant(_memoryPool, &slot->value).as<TValue>() | ||||
|                 : TValue(); | ||||
|   } | ||||
|  | ||||
|   template <typename TValue, typename TStringRef> | ||||
|   FORCE_INLINE bool is_impl(TStringRef key) const { | ||||
|     Slot* slot = findSlot(key); | ||||
|     return slot ? JsonVariant(_memoryPool, &slot->value).is<TValue>() : false; | ||||
|   } | ||||
|  | ||||
|   template <typename TStringRef> | ||||
|   FORCE_INLINE void remove_impl(TStringRef key) { | ||||
|     if (!_data) return; | ||||
|     Slot* slot = findSlot(key); | ||||
|     if (!slot) return; | ||||
|     if (slot->prev) | ||||
|       slot->prev->next = slot->next; | ||||
|     else | ||||
|       _data->head = slot->next; | ||||
|     if (slot->next) | ||||
|       slot->next->prev = slot->prev; | ||||
|     else | ||||
|       _data->tail = slot->prev; | ||||
|   } | ||||
|  | ||||
|   template <typename TStringRef> | ||||
|   FORCE_INLINE JsonVariant set_impl(TStringRef key) { | ||||
|     if (!_data) return JsonVariant(); | ||||
|  | ||||
|     // ignore null key | ||||
|     if (key.isNull()) return JsonVariant(); | ||||
|  | ||||
|     // search a matching key | ||||
|     Slot* slot = findSlot(key); | ||||
|     if (!slot) { | ||||
|       // add the key | ||||
|       slot = new (_memoryPool) Slot(); | ||||
|       if (!slot) return JsonVariant(); | ||||
|  | ||||
|       slot->next = 0; | ||||
|  | ||||
|       if (_data->tail) { | ||||
|         slot->prev = _data->tail; | ||||
|         _data->tail->next = slot; | ||||
|         _data->tail = slot; | ||||
|       } else { | ||||
|         slot->prev = 0; | ||||
|         _data->head = slot; | ||||
|         _data->tail = slot; | ||||
|       } | ||||
|  | ||||
|       if (!set_key(slot, key)) return JsonVariant(); | ||||
|     } | ||||
|  | ||||
|     return JsonVariant(_memoryPool, &slot->value); | ||||
|   } | ||||
|  | ||||
|   template <typename TStringRef> | ||||
|   FORCE_INLINE bool set_key(Slot* slot, TStringRef key) { | ||||
|     const char* dup = key.save(_memoryPool); | ||||
|     if (!dup) return false; | ||||
|     slot->key = dup; | ||||
|     slot->value.keyIsStatic = false; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool set_key(Slot* slot, ZeroTerminatedRamStringConst key) { | ||||
|     slot->key = key.save(_memoryPool); | ||||
|     slot->value.keyIsStatic = true; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool set_key(Slot* slot, StringInMemoryPool key) { | ||||
|     slot->key = key.save(_memoryPool); | ||||
|     slot->value.keyIsStatic = false; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   mutable MemoryPool* _memoryPool; | ||||
|   mutable JsonObjectData* _data; | ||||
|   MemoryPool* _memoryPool; | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -10,22 +10,12 @@ | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <typename TString> | ||||
| inline JsonArray JsonObject::createNestedArray(const TString& key) { | ||||
|   return createNestedArray_impl(makeString(key)); | ||||
| inline JsonArray JsonObject::createNestedArray(const TString& key) const { | ||||
|   return set(key).template to<JsonArray>(); | ||||
| } | ||||
|  | ||||
| template <typename TString> | ||||
| inline JsonArray JsonObject::createNestedArray(TString* key) { | ||||
|   return createNestedArray_impl(makeString(key)); | ||||
| } | ||||
|  | ||||
| template <typename TStringRef> | ||||
| inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) { | ||||
|   return set_impl(key).template to<JsonArray>(); | ||||
| } | ||||
|  | ||||
| template <typename TStringRef> | ||||
| inline JsonObject JsonObject::createNestedObject_impl(TStringRef key) { | ||||
|   return set_impl(key).template to<JsonObject>(); | ||||
| inline JsonArray JsonObject::createNestedArray(TString* key) const { | ||||
|   return set(key).template to<JsonArray>(); | ||||
| } | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "Data/SlotFunctions.hpp" | ||||
| #include "JsonPair.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
| @@ -52,10 +53,7 @@ class JsonObjectIterator { | ||||
|   } | ||||
|  | ||||
|   JsonObjectIterator &operator+=(size_t distance) { | ||||
|     while (_slot && distance > 0) { | ||||
|       _slot = _slot->next; | ||||
|       distance--; | ||||
|     } | ||||
|     _slot = slotAdvance(_slot, distance); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
| @@ -67,4 +65,59 @@ class JsonObjectIterator { | ||||
|   MemoryPool *_memoryPool; | ||||
|   Slot *_slot; | ||||
| }; | ||||
|  | ||||
| class JsonPairConstPtr { | ||||
|  public: | ||||
|   JsonPairConstPtr(const Slot *slot) : _pair(slot) {} | ||||
|  | ||||
|   const JsonPairConst *operator->() const { | ||||
|     return &_pair; | ||||
|   } | ||||
|  | ||||
|   const JsonPairConst &operator*() const { | ||||
|     return _pair; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonPairConst _pair; | ||||
| }; | ||||
|  | ||||
| class JsonObjectConstIterator { | ||||
|  public: | ||||
|   JsonObjectConstIterator() : _slot(0) {} | ||||
|  | ||||
|   explicit JsonObjectConstIterator(const Slot *slot) : _slot(slot) {} | ||||
|  | ||||
|   JsonPairConst operator*() const { | ||||
|     return JsonPairConst(_slot); | ||||
|   } | ||||
|   JsonPairConstPtr operator->() { | ||||
|     return JsonPairConstPtr(_slot); | ||||
|   } | ||||
|  | ||||
|   bool operator==(const JsonObjectConstIterator &other) const { | ||||
|     return _slot == other._slot; | ||||
|   } | ||||
|  | ||||
|   bool operator!=(const JsonObjectConstIterator &other) const { | ||||
|     return _slot != other._slot; | ||||
|   } | ||||
|  | ||||
|   JsonObjectConstIterator &operator++() { | ||||
|     if (_slot) _slot = _slot->next; | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   JsonObjectConstIterator &operator+=(size_t distance) { | ||||
|     _slot = slotAdvance(_slot, distance); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   const Slot *internal() { | ||||
|     return _slot; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const Slot *_slot; | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -24,8 +24,12 @@ class JsonObjectSubscript | ||||
|   FORCE_INLINE JsonObjectSubscript(JsonObject object, TStringRef key) | ||||
|       : _object(object), _key(key) {} | ||||
|  | ||||
|   operator JsonVariantConst() const { | ||||
|     return get_impl(); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE this_type &operator=(const this_type &src) { | ||||
|     _object.set(_key, src); | ||||
|     set_impl().set(src); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
| @@ -37,7 +41,7 @@ class JsonObjectSubscript | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE typename enable_if<!is_array<TValue>::value, this_type &>::type | ||||
|   operator=(const TValue &src) { | ||||
|     _object.set(_key, src); | ||||
|     set_impl().set(src); | ||||
|     return *this; | ||||
|   } | ||||
|   // | ||||
| @@ -45,27 +49,27 @@ class JsonObjectSubscript | ||||
|   // TValue = char*, const char*, const FlashStringHelper* | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE this_type &operator=(TValue *src) { | ||||
|     _object.set(_key, src); | ||||
|     set_impl().set(src); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool isNull() const { | ||||
|     return !_object.containsKey(_key); | ||||
|     return get_impl().isNull(); | ||||
|   } | ||||
|  | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type as() const { | ||||
|     return _object.get<TValue>(_key); | ||||
|     return get_impl().template as<TValue>(); | ||||
|   } | ||||
|  | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE bool is() const { | ||||
|     return _object.is<TValue>(_key); | ||||
|     return get_impl().template is<TValue>(); | ||||
|   } | ||||
|  | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE typename JsonVariantTo<TValue>::type to() { | ||||
|     return _object.set(_key).template to<TValue>(); | ||||
|     return set_impl().template to<TValue>(); | ||||
|   } | ||||
|  | ||||
|   // Sets the specified value. | ||||
| @@ -77,39 +81,39 @@ class JsonObjectSubscript | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE typename enable_if<!is_array<TValue>::value, bool>::type set( | ||||
|       const TValue &value) { | ||||
|     return _object.set(_key, value); | ||||
|     return set_impl().set(value); | ||||
|   } | ||||
|   // | ||||
|   // bool set(TValue); | ||||
|   // TValue = char*, const char, const FlashStringHelper* | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE bool set(const TValue *value) { | ||||
|     return _object.set(_key, value); | ||||
|     return set_impl().set(value); | ||||
|   } | ||||
|  | ||||
|   template <typename Visitor> | ||||
|   void accept(Visitor &visitor) const { | ||||
|     return _object.get<JsonVariant>(_key).accept(visitor); | ||||
|     return get_impl().accept(visitor); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonVariant get_impl() const { | ||||
|     return _object.get<JsonVariant>(_key); | ||||
|   } | ||||
|  | ||||
|   JsonVariant set_impl() const { | ||||
|     return _object.set(_key); | ||||
|   } | ||||
|  | ||||
|   JsonObject _object; | ||||
|   TStringRef _key; | ||||
| }; | ||||
|  | ||||
| template <typename TImpl> | ||||
| template <typename TString> | ||||
| inline typename enable_if<IsString<TString>::value, | ||||
|                           const JsonObjectSubscript<const TString &> >::type | ||||
|     JsonVariantSubscripts<TImpl>::operator[](const TString &key) const { | ||||
|   return impl()->template as<JsonObject>()[key]; | ||||
| } | ||||
|  | ||||
| template <typename TImpl> | ||||
| template <typename TString> | ||||
| inline typename enable_if<IsString<TString>::value, | ||||
|                           JsonObjectSubscript<const TString &> >::type | ||||
|     JsonVariantSubscripts<TImpl>::operator[](const TString &key) { | ||||
|     JsonVariantSubscripts<TImpl>::operator[](const TString &key) const { | ||||
|   return impl()->template as<JsonObject>()[key]; | ||||
| } | ||||
|  | ||||
| @@ -117,14 +121,6 @@ template <typename TImpl> | ||||
| template <typename TString> | ||||
| inline typename enable_if<IsString<TString *>::value, | ||||
|                           JsonObjectSubscript<TString *> >::type | ||||
|     JsonVariantSubscripts<TImpl>::operator[](TString *key) { | ||||
|   return impl()->template as<JsonObject>()[key]; | ||||
| } | ||||
|  | ||||
| template <typename TImpl> | ||||
| template <typename TString> | ||||
| inline typename enable_if<IsString<TString *>::value, | ||||
|                           const JsonObjectSubscript<TString *> >::type | ||||
|     JsonVariantSubscripts<TImpl>::operator[](TString *key) const { | ||||
|   return impl()->template as<JsonObject>()[key]; | ||||
| } | ||||
|   | ||||
| @@ -4,39 +4,10 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "JsonKey.hpp" | ||||
| #include "JsonVariant.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class JsonKey { | ||||
|  public: | ||||
|   JsonKey(Slot* slot) : _slot(slot) {} | ||||
|  | ||||
|   operator const char*() const { | ||||
|     return c_str(); | ||||
|   } | ||||
|  | ||||
|   const char* c_str() const { | ||||
|     return _slot ? _slot->key : 0; | ||||
|   } | ||||
|  | ||||
|   bool isNull() const { | ||||
|     return _slot == 0 || _slot->key == 0; | ||||
|   } | ||||
|  | ||||
|   bool isStatic() const { | ||||
|     return _slot ? _slot->value.keyIsStatic : true; | ||||
|   } | ||||
|  | ||||
|   friend bool operator==(JsonKey lhs, const char* rhs) { | ||||
|     if (lhs.isNull()) return rhs == 0; | ||||
|     return rhs ? !strcmp(lhs, rhs) : false; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   Slot* _slot; | ||||
| }; | ||||
|  | ||||
| // A key value pair for JsonObjectData. | ||||
| class JsonPair { | ||||
|  public: | ||||
| @@ -58,4 +29,25 @@ class JsonPair { | ||||
|   JsonKey _key; | ||||
|   JsonVariant _value; | ||||
| }; | ||||
|  | ||||
| class JsonPairConst { | ||||
|  public: | ||||
|   JsonPairConst(const Slot* slot) : _key(slot) { | ||||
|     if (slot) { | ||||
|       _value = JsonVariantConst(&slot->value); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   JsonKey key() const { | ||||
|     return _key; | ||||
|   } | ||||
|  | ||||
|   JsonVariantConst value() const { | ||||
|     return _value; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonKey _key; | ||||
|   JsonVariantConst _value; | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -8,14 +8,14 @@ | ||||
| #include <stdint.h>  // for uint8_t | ||||
|  | ||||
| #include "Data/JsonVariantData.hpp" | ||||
| #include "Data/VariantAs.hpp" | ||||
| #include "Data/VariantFunctions.hpp" | ||||
| #include "JsonVariant.hpp" | ||||
| #include "JsonVariantBase.hpp" | ||||
| #include "Memory/MemoryPool.hpp" | ||||
| #include "Numbers/parseFloat.hpp" | ||||
| #include "Numbers/parseInteger.hpp" | ||||
| #include "Polyfills/type_traits.hpp" | ||||
| #include "Serialization/DynamicStringWriter.hpp" | ||||
| #include "SerializedValue.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| @@ -23,251 +23,11 @@ namespace ARDUINOJSON_NAMESPACE { | ||||
| class JsonArray; | ||||
| class JsonObject; | ||||
|  | ||||
| // A variant that can be a any value serializable to a JSON value. | ||||
| // | ||||
| // It can be set to: | ||||
| // - a boolean | ||||
| // - a char, short, int or a long (signed or unsigned) | ||||
| // - a string (const char*) | ||||
| // - a reference to a JsonArray or JsonObject | ||||
| class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
| // Contains the methods shared by JsonVariant and JsonVariantConst | ||||
| template <typename TData> | ||||
| class JsonVariantProxy { | ||||
|  public: | ||||
|   // Intenal use only | ||||
|   FORCE_INLINE JsonVariant(MemoryPool *memoryPool, JsonVariantData *data) | ||||
|       : _memoryPool(memoryPool), _data(data) {} | ||||
|  | ||||
|   // Creates an uninitialized JsonVariant | ||||
|   FORCE_INLINE JsonVariant() : _memoryPool(0), _data(0) {} | ||||
|  | ||||
|   // set(bool value) | ||||
|   FORCE_INLINE bool set(bool value) { | ||||
|     if (!_data) return false; | ||||
|     _data->type = JSON_BOOLEAN; | ||||
|     _data->content.asInteger = static_cast<JsonUInt>(value); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // set(double value); | ||||
|   // set(float value); | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set( | ||||
|       T value, typename enable_if<is_floating_point<T>::value>::type * = 0) { | ||||
|     if (!_data) return false; | ||||
|     _data->type = JSON_FLOAT; | ||||
|     _data->content.asFloat = static_cast<JsonFloat>(value); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // set(char) | ||||
|   // set(signed short) | ||||
|   // set(signed int) | ||||
|   // set(signed long) | ||||
|   // set(signed char) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set(T value, | ||||
|                         typename enable_if<is_integral<T>::value && | ||||
|                                            is_signed<T>::value>::type * = 0) { | ||||
|     if (!_data) return false; | ||||
|     if (value >= 0) { | ||||
|       _data->type = JSON_POSITIVE_INTEGER; | ||||
|       _data->content.asInteger = static_cast<JsonUInt>(value); | ||||
|     } else { | ||||
|       _data->type = JSON_NEGATIVE_INTEGER; | ||||
|       _data->content.asInteger = ~static_cast<JsonUInt>(value) + 1; | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // set(unsigned short) | ||||
|   // set(unsigned int) | ||||
|   // set(unsigned long) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set(T value, | ||||
|                         typename enable_if<is_integral<T>::value && | ||||
|                                            is_unsigned<T>::value>::type * = 0) { | ||||
|     if (!_data) return false; | ||||
|     _data->type = JSON_POSITIVE_INTEGER; | ||||
|     _data->content.asInteger = static_cast<JsonUInt>(value); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // set(SerializedValue<const char *>) | ||||
|   FORCE_INLINE bool set(SerializedValue<const char *> value) { | ||||
|     if (!_data) return false; | ||||
|     _data->type = JSON_LINKED_RAW; | ||||
|     _data->content.asRaw.data = value.data(); | ||||
|     _data->content.asRaw.size = value.size(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // set(SerializedValue<std::string>) | ||||
|   // set(SerializedValue<String>) | ||||
|   // set(SerializedValue<const __FlashStringHelper*>) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set( | ||||
|       SerializedValue<T> value, | ||||
|       typename enable_if<!is_same<const char *, T>::value>::type * = 0) { | ||||
|     if (!_data) return false; | ||||
|     const char *dup = makeString(value.data(), value.size()).save(_memoryPool); | ||||
|     if (dup) { | ||||
|       _data->type = JSON_OWNED_RAW; | ||||
|       _data->content.asRaw.data = dup; | ||||
|       _data->content.asRaw.size = value.size(); | ||||
|       return true; | ||||
|     } else { | ||||
|       _data->type = JSON_NULL; | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // set(const std::string&) | ||||
|   // set(const String&) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set(const T &value, | ||||
|                         typename enable_if<IsString<T>::value>::type * = 0) { | ||||
|     return setString(makeString(value)); | ||||
|   } | ||||
|  | ||||
|   // set(char*) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set(T *value, | ||||
|                         typename enable_if<IsString<T *>::value>::type * = 0) { | ||||
|     return setString(makeString(value)); | ||||
|   } | ||||
|  | ||||
|   // set(const char*); | ||||
|   FORCE_INLINE bool set(const char *value) { | ||||
|     if (!_data) return false; | ||||
|     _data->type = JSON_LINKED_STRING; | ||||
|     _data->content.asString = value; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // set(const char*); | ||||
|   FORCE_INLINE bool set(StringInMemoryPool value) { | ||||
|     if (!_data) return false; | ||||
|     _data->type = JSON_OWNED_STRING; | ||||
|     _data->content.asString = value.save(_memoryPool); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool set(const JsonVariant &value); | ||||
|  | ||||
|   FORCE_INLINE bool set(JsonArray array); | ||||
|   FORCE_INLINE bool set(const JsonArraySubscript &); | ||||
|   FORCE_INLINE bool set(JsonObject object); | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE bool set(const JsonObjectSubscript<TString> &); | ||||
|  | ||||
|   // Get the variant as the specified type. | ||||
|   // | ||||
|   // char as<char>() const; | ||||
|   // signed char as<signed char>() const; | ||||
|   // signed short as<signed short>() const; | ||||
|   // signed int as<signed int>() const; | ||||
|   // signed long as<signed long>() const; | ||||
|   // unsigned char as<unsigned char>() const; | ||||
|   // unsigned short as<unsigned short>() const; | ||||
|   // unsigned int as<unsigned int>() const; | ||||
|   // unsigned long as<unsigned long>() const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE const typename enable_if<is_integral<T>::value, T>::type as() | ||||
|       const { | ||||
|     if (!_data) return 0; | ||||
|     switch (_data->type) { | ||||
|       case JSON_POSITIVE_INTEGER: | ||||
|       case JSON_BOOLEAN: | ||||
|         return T(_data->content.asInteger); | ||||
|       case JSON_NEGATIVE_INTEGER: | ||||
|         return T(~_data->content.asInteger + 1); | ||||
|       case JSON_LINKED_STRING: | ||||
|       case JSON_OWNED_STRING: | ||||
|         return parseInteger<T>(_data->content.asString); | ||||
|       case JSON_FLOAT: | ||||
|         return T(_data->content.asFloat); | ||||
|       default: | ||||
|         return 0; | ||||
|     } | ||||
|   } | ||||
|   // bool as<bool>() const | ||||
|   template <typename T> | ||||
|   FORCE_INLINE const typename enable_if<is_same<T, bool>::value, T>::type as() | ||||
|       const { | ||||
|     return as<int>() != 0; | ||||
|   } | ||||
|   // | ||||
|   // double as<double>() const; | ||||
|   // float as<float>() const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE const typename enable_if<is_floating_point<T>::value, T>::type | ||||
|   as() const { | ||||
|     if (!_data) return 0; | ||||
|     switch (_data->type) { | ||||
|       case JSON_POSITIVE_INTEGER: | ||||
|       case JSON_BOOLEAN: | ||||
|         return static_cast<T>(_data->content.asInteger); | ||||
|       case JSON_NEGATIVE_INTEGER: | ||||
|         return -static_cast<T>(_data->content.asInteger); | ||||
|       case JSON_LINKED_STRING: | ||||
|       case JSON_OWNED_STRING: | ||||
|         return parseFloat<T>(_data->content.asString); | ||||
|       case JSON_FLOAT: | ||||
|         return static_cast<T>(_data->content.asFloat); | ||||
|       default: | ||||
|         return 0; | ||||
|     } | ||||
|   } | ||||
|   // | ||||
|   // const char* as<const char*>() const; | ||||
|   // const char* as<char*>() const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if<is_same<T, const char *>::value || | ||||
|                                       is_same<T, char *>::value, | ||||
|                                   const char *>::type | ||||
|   as() const { | ||||
|     if (!_data) return 0; | ||||
|     if (_data && | ||||
|         (_data->type == JSON_LINKED_STRING || _data->type == JSON_OWNED_STRING)) | ||||
|       return _data->content.asString; | ||||
|     else | ||||
|       return 0; | ||||
|   } | ||||
|   // | ||||
|   // std::string as<std::string>() const; | ||||
|   // String as<String>() const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if<IsWriteableString<T>::value, T>::type as() | ||||
|       const { | ||||
|     const char *cstr = as<const char *>(); | ||||
|     if (cstr) return T(cstr); | ||||
|     T s; | ||||
|     serializeJson(*this, s); | ||||
|     return s; | ||||
|   } | ||||
|   // | ||||
|   // JsonArray as<JsonArray>() const; | ||||
|   // const JsonArray as<const JsonArray>() const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if< | ||||
|       is_same<typename remove_const<T>::type, JsonArray>::value, | ||||
|       JsonArray>::type | ||||
|   as() const; | ||||
|   // | ||||
|   // JsonObject as<JsonObject>() const; | ||||
|   // const JsonObject as<const JsonObject>() const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if< | ||||
|       is_same<typename remove_const<T>::type, JsonObject>::value, T>::type | ||||
|   as() const; | ||||
|   // | ||||
|   // JsonVariant as<JsonVariant> const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if<is_same<T, JsonVariant>::value, T>::type as() | ||||
|       const { | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   // Tells weither the variant has the specified type. | ||||
|   // Tells wether the variant has the specified type. | ||||
|   // Returns true if the variant has type type T, false otherwise. | ||||
|   // | ||||
|   // bool is<char>() const; | ||||
| @@ -282,8 +42,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if<is_integral<T>::value, bool>::type is() | ||||
|       const { | ||||
|     return _data && (_data->type == JSON_POSITIVE_INTEGER || | ||||
|                      _data->type == JSON_NEGATIVE_INTEGER); | ||||
|     return variantIsInteger(_data); | ||||
|   } | ||||
|   // | ||||
|   // bool is<double>() const; | ||||
| @@ -291,9 +50,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if<is_floating_point<T>::value, bool>::type is() | ||||
|       const { | ||||
|     return _data && | ||||
|            (_data->type == JSON_FLOAT || _data->type == JSON_POSITIVE_INTEGER || | ||||
|             _data->type == JSON_NEGATIVE_INTEGER); | ||||
|     return variantIsFloat(_data); | ||||
|   } | ||||
|   // | ||||
|   // bool is<bool>() const | ||||
| @@ -313,8 +70,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|                                       IsWriteableString<T>::value, | ||||
|                                   bool>::type | ||||
|   is() const { | ||||
|     return _data && (_data->type == JSON_LINKED_STRING || | ||||
|                      _data->type == JSON_OWNED_STRING); | ||||
|     return variantIsString(_data); | ||||
|   } | ||||
|   // | ||||
|   // bool is<JsonArray> const; | ||||
| @@ -323,7 +79,7 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|   FORCE_INLINE typename enable_if< | ||||
|       is_same<typename remove_const<T>::type, JsonArray>::value, bool>::type | ||||
|   is() const { | ||||
|     return _data && _data->type == JSON_ARRAY; | ||||
|     return variantIsArray(_data); | ||||
|   } | ||||
|   // | ||||
|   // bool is<JsonObject> const; | ||||
| @@ -332,51 +88,235 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|   FORCE_INLINE typename enable_if< | ||||
|       is_same<typename remove_const<T>::type, JsonObject>::value, bool>::type | ||||
|   is() const { | ||||
|     return _data && _data->type == JSON_OBJECT; | ||||
|     return variantIsObject(_data); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool isNull() const { | ||||
|     return _data == 0 || _data->type == JSON_NULL; | ||||
|     return variantIsNull(_data); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool isInvalid() const { | ||||
|     return _data == 0; | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return objectSize(variantAsObject(_data)) + | ||||
|            arraySize(variantAsArray(_data)); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   JsonVariantProxy(TData *data) : _data(data) {} | ||||
|   TData *_data; | ||||
| }; | ||||
|  | ||||
| // A variant that can be a any value serializable to a JSON value. | ||||
| // | ||||
| // It can be set to: | ||||
| // - a boolean | ||||
| // - a char, short, int or a long (signed or unsigned) | ||||
| // - a string (const char*) | ||||
| // - a reference to a JsonArray or JsonObject | ||||
| class JsonVariant : public JsonVariantProxy<JsonVariantData>, | ||||
|                     public JsonVariantBase<JsonVariant> { | ||||
|   typedef JsonVariantProxy<JsonVariantData> proxy_type; | ||||
|   friend class JsonVariantConst; | ||||
|  | ||||
|  public: | ||||
|   // Intenal use only | ||||
|   FORCE_INLINE JsonVariant(MemoryPool *memoryPool, JsonVariantData *data) | ||||
|       : proxy_type(data), _memoryPool(memoryPool) {} | ||||
|  | ||||
|   // Creates an uninitialized JsonVariant | ||||
|   FORCE_INLINE JsonVariant() : proxy_type(0), _memoryPool(0) {} | ||||
|  | ||||
|   // set(bool value) | ||||
|   FORCE_INLINE bool set(bool value) const { | ||||
|     return variantSetBoolean(_data, value); | ||||
|   } | ||||
|  | ||||
|   // set(double value); | ||||
|   // set(float value); | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set( | ||||
|       T value, | ||||
|       typename enable_if<is_floating_point<T>::value>::type * = 0) const { | ||||
|     return variantSetFloat(_data, static_cast<JsonFloat>(value)); | ||||
|   } | ||||
|  | ||||
|   // set(char) | ||||
|   // set(signed short) | ||||
|   // set(signed int) | ||||
|   // set(signed long) | ||||
|   // set(signed char) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set( | ||||
|       T value, | ||||
|       typename enable_if<is_integral<T>::value && is_signed<T>::value>::type * = | ||||
|           0) const { | ||||
|     return variantSetSignedInteger(_data, value); | ||||
|   } | ||||
|  | ||||
|   // set(unsigned short) | ||||
|   // set(unsigned int) | ||||
|   // set(unsigned long) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set( | ||||
|       T value, typename enable_if<is_integral<T>::value && | ||||
|                                   is_unsigned<T>::value>::type * = 0) const { | ||||
|     return variantSetSignedInteger(_data, static_cast<JsonUInt>(value)); | ||||
|   } | ||||
|  | ||||
|   // set(SerializedValue<const char *>) | ||||
|   FORCE_INLINE bool set(SerializedValue<const char *> value) const { | ||||
|     return variantSetLinkedRaw(_data, value); | ||||
|   } | ||||
|  | ||||
|   // set(SerializedValue<std::string>) | ||||
|   // set(SerializedValue<String>) | ||||
|   // set(SerializedValue<const __FlashStringHelper*>) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set( | ||||
|       SerializedValue<T> value, | ||||
|       typename enable_if<!is_same<const char *, T>::value>::type * = 0) const { | ||||
|     return variantSetOwnedRaw(_data, value, _memoryPool); | ||||
|   } | ||||
|  | ||||
|   // set(const std::string&) | ||||
|   // set(const String&) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set( | ||||
|       const T &value, | ||||
|       typename enable_if<IsString<T>::value>::type * = 0) const { | ||||
|     return variantSetString(_data, makeString(value), _memoryPool); | ||||
|   } | ||||
|  | ||||
|   // set(char*) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set( | ||||
|       T *value, typename enable_if<IsString<T *>::value>::type * = 0) const { | ||||
|     return variantSetString(_data, makeString(value), _memoryPool); | ||||
|   } | ||||
|  | ||||
|   // set(const char*); | ||||
|   FORCE_INLINE bool set(const char *value) const { | ||||
|     return variantSetString(_data, value); | ||||
|   } | ||||
|  | ||||
|   // set(const char*); | ||||
|   FORCE_INLINE bool set(StringInMemoryPool value) const { | ||||
|     return variantSetString(_data, value, _memoryPool); | ||||
|   } | ||||
|  | ||||
|   bool set(const JsonVariant &value) const; | ||||
|  | ||||
|   FORCE_INLINE bool set(JsonArray array) const; | ||||
|   FORCE_INLINE bool set(const JsonArraySubscript &) const; | ||||
|   FORCE_INLINE bool set(JsonObject object) const; | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE bool set(const JsonObjectSubscript<TString> &) const; | ||||
|  | ||||
|   // Get the variant as the specified type. | ||||
|   // | ||||
|   // std::string as<std::string>() const; | ||||
|   // String as<String>() const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if<!is_same<T, JsonArray>::value && | ||||
|                                       !is_same<T, JsonObject>::value && | ||||
|                                       !is_same<T, JsonVariant>::value, | ||||
|                                   typename JsonVariantAs<T>::type>::type | ||||
|   as() const { | ||||
|     return variantAs<T>(_data); | ||||
|   } | ||||
|   // | ||||
|   // JsonArray as<JsonArray>() const; | ||||
|   // const JsonArray as<const JsonArray>() const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if<is_same<T, JsonArray>::value, T>::type as() | ||||
|       const; | ||||
|   // | ||||
|   // JsonObject as<JsonObject>() const; | ||||
|   // const JsonObject as<const JsonObject>() const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if<is_same<T, JsonObject>::value, T>::type as() | ||||
|       const; | ||||
|   // | ||||
|   // JsonVariant as<JsonVariant> const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if<is_same<T, JsonVariant>::value, T>::type as() | ||||
|       const { | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   template <typename Visitor> | ||||
|   void accept(Visitor &visitor) const; | ||||
|  | ||||
|   FORCE_INLINE bool operator==(JsonVariant lhs) const { | ||||
|     return variantEquals(_data, lhs._data); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool operator!=(JsonVariant lhs) const { | ||||
|     return !variantEquals(_data, lhs._data); | ||||
|   } | ||||
|  | ||||
|   // Change the type of the variant | ||||
|   // | ||||
|   // JsonArray to<JsonArray>() | ||||
|   template <typename T> | ||||
|   typename enable_if<is_same<T, JsonArray>::value, JsonArray>::type to(); | ||||
|   typename enable_if<is_same<T, JsonArray>::value, JsonArray>::type to() const; | ||||
|   // | ||||
|   // JsonObject to<JsonObject>() | ||||
|   template <typename T> | ||||
|   typename enable_if<is_same<T, JsonObject>::value, JsonObject>::type to(); | ||||
|   typename enable_if<is_same<T, JsonObject>::value, JsonObject>::type to() | ||||
|       const; | ||||
|   // | ||||
|   // JsonObject to<JsonVariant>() | ||||
|   template <typename T> | ||||
|   typename enable_if<is_same<T, JsonVariant>::value, JsonVariant>::type to(); | ||||
|   typename enable_if<is_same<T, JsonVariant>::value, JsonVariant>::type to() | ||||
|       const; | ||||
|  | ||||
|  private: | ||||
|   template <typename TStringRef> | ||||
|   bool setString(TStringRef value) { | ||||
|     if (!_data) return false; | ||||
|     const char *dup = value.save(_memoryPool); | ||||
|     if (dup) { | ||||
|       _data->type = JSON_OWNED_STRING; | ||||
|       _data->content.asString = dup; | ||||
|       return true; | ||||
|     } else { | ||||
|       _data->type = JSON_NULL; | ||||
|       return false; | ||||
|     } | ||||
|   MemoryPool *_memoryPool; | ||||
| }; | ||||
|  | ||||
| class JsonVariantConst : public JsonVariantProxy<const JsonVariantData>, | ||||
|                          public JsonVariantBase<JsonVariantConst> { | ||||
|   typedef JsonVariantProxy<const JsonVariantData> proxy_type; | ||||
|  | ||||
|  public: | ||||
|   JsonVariantConst() : proxy_type(0) {} | ||||
|   JsonVariantConst(const JsonVariantData *data) : proxy_type(data) {} | ||||
|   JsonVariantConst(JsonVariant var) : proxy_type(var._data) {} | ||||
|  | ||||
|   template <typename Visitor> | ||||
|   void accept(Visitor &visitor) const; | ||||
|  | ||||
|   // Get the variant as the specified type. | ||||
|   // | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename JsonVariantConstAs<T>::type as() const { | ||||
|     return variantAs<typename JsonVariantConstAs<T>::type>(_data); | ||||
|   } | ||||
|  | ||||
|   MemoryPool *_memoryPool; | ||||
|   JsonVariantData *_data; | ||||
|   FORCE_INLINE JsonVariantConst operator[](size_t index) const; | ||||
|  | ||||
|   // | ||||
|   // const JsonVariantConst operator[](TKey) const; | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE | ||||
|       typename enable_if<IsString<TString>::value, JsonVariantConst>::type | ||||
|       operator[](const TString &key) const { | ||||
|     return JsonVariantConst(objectGet(variantAsObject(_data), makeString(key))); | ||||
|   } | ||||
|   // | ||||
|   // JsonVariantConst operator[](TKey); | ||||
|   // TKey = const char*, const char[N], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE | ||||
|       typename enable_if<IsString<TString *>::value, JsonVariantConst>::type | ||||
|       operator[](TString *key) const { | ||||
|     return JsonVariantConst(objectGet(variantAsObject(_data), makeString(key))); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class JsonVariantLocal : public JsonVariant { | ||||
|   | ||||
| @@ -15,6 +15,5 @@ template <typename TImpl> | ||||
| class JsonVariantBase : public JsonVariantCasts<TImpl>, | ||||
|                         public JsonVariantComparisons<TImpl>, | ||||
|                         public JsonVariantOr<TImpl>, | ||||
|                         public JsonVariantSubscripts<TImpl>, | ||||
|                         public JsonVariantTag {}; | ||||
|                         public JsonVariantSubscripts<TImpl> {}; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -4,134 +4,158 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "Data/IsVariant.hpp" | ||||
| #include "Data/JsonFloat.hpp" | ||||
| #include "Data/JsonInteger.hpp" | ||||
| #include "Polyfills/type_traits.hpp" | ||||
| #include "Strings/StringTypes.hpp" | ||||
| #include "JsonVariant.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
| class JsonArray; | ||||
| class JsonObject; | ||||
| template <typename T> | ||||
| struct is_simple_value { | ||||
|   static const bool value = is_integral<T>::value || | ||||
|                             is_floating_point<T>::value || | ||||
|                             is_same<T, bool>::value; | ||||
| }; | ||||
|  | ||||
| template <typename TImpl> | ||||
| template <typename TVariant> | ||||
| class JsonVariantComparisons { | ||||
|  public: | ||||
|   template <typename TComparand> | ||||
|   friend bool operator==(const JsonVariantComparisons &variant, | ||||
|                          TComparand comparand) { | ||||
|     return variant.equals(comparand); | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend typename enable_if<!IsVariant<TComparand>::value, bool>::type | ||||
|   operator==(TComparand comparand, const JsonVariantComparisons &variant) { | ||||
|     return variant.equals(comparand); | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend bool operator!=(const JsonVariantComparisons &variant, | ||||
|                          TComparand comparand) { | ||||
|     return !variant.equals(comparand); | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend typename enable_if<!IsVariant<TComparand>::value, bool>::type | ||||
|   operator!=(TComparand comparand, const JsonVariantComparisons &variant) { | ||||
|     return !variant.equals(comparand); | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend bool operator<=(const JsonVariantComparisons &left, TComparand right) { | ||||
|     return left.as<TComparand>() <= right; | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend bool operator<=(TComparand comparand, | ||||
|                          const JsonVariantComparisons &variant) { | ||||
|     return comparand <= variant.as<TComparand>(); | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend bool operator>=(const JsonVariantComparisons &variant, | ||||
|                          TComparand comparand) { | ||||
|     return variant.as<TComparand>() >= comparand; | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend bool operator>=(TComparand comparand, | ||||
|                          const JsonVariantComparisons &variant) { | ||||
|     return comparand >= variant.as<TComparand>(); | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend bool operator<(const JsonVariantComparisons &varian, | ||||
|                         TComparand comparand) { | ||||
|     return varian.as<TComparand>() < comparand; | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend bool operator<(TComparand comparand, | ||||
|                         const JsonVariantComparisons &variant) { | ||||
|     return comparand < variant.as<TComparand>(); | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend bool operator>(const JsonVariantComparisons &variant, | ||||
|                         TComparand comparand) { | ||||
|     return variant.as<TComparand>() > comparand; | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   friend bool operator>(TComparand comparand, | ||||
|                         const JsonVariantComparisons &variant) { | ||||
|     return comparand > variant.as<TComparand>(); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const TImpl *impl() const { | ||||
|     return static_cast<const TImpl *>(this); | ||||
|   } | ||||
|  | ||||
|   // const char* == TVariant | ||||
|   template <typename T> | ||||
|   const typename JsonVariantAs<T>::type as() const { | ||||
|     return impl()->template as<T>(); | ||||
|   friend typename enable_if<IsString<T *>::value, bool>::type operator==( | ||||
|       T *lhs, TVariant rhs) { | ||||
|     return makeString(lhs).equals(rhs.template as<const char *>()); | ||||
|   } | ||||
|  | ||||
|   // std::string == TVariant | ||||
|   template <typename T> | ||||
|   bool is() const { | ||||
|     return impl()->template is<T>(); | ||||
|   friend typename enable_if<IsString<T>::value, bool>::type operator==( | ||||
|       const T &lhs, TVariant rhs) { | ||||
|     return makeString(lhs).equals(rhs.template as<const char *>()); | ||||
|   } | ||||
|  | ||||
|   template <typename TString> | ||||
|   typename enable_if<IsString<TString>::value, bool>::type equals( | ||||
|       const TString &comparand) const { | ||||
|     return makeString(comparand).equals(as<const char *>()); | ||||
|   // TVariant == const char* | ||||
|   template <typename T> | ||||
|   friend typename enable_if<IsString<T *>::value, bool>::type operator==( | ||||
|       TVariant lhs, T *rhs) { | ||||
|     return makeString(rhs).equals(lhs.template as<const char *>()); | ||||
|   } | ||||
|  | ||||
|   template <typename TComparand> | ||||
|   typename enable_if< | ||||
|       !IsVariant<TComparand>::value && !IsString<TComparand>::value, bool>::type | ||||
|   equals(const TComparand &comparand) const { | ||||
|     return as<TComparand>() == comparand; | ||||
|   // TVariant == std::string | ||||
|   template <typename T> | ||||
|   friend typename enable_if<IsString<T>::value, bool>::type operator==( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return makeString(rhs).equals(lhs.template as<const char *>()); | ||||
|   } | ||||
|  | ||||
|   template <typename TVariant2> | ||||
|   bool equals(const JsonVariantComparisons<TVariant2> &right) const { | ||||
|     if (is<bool>() && right.template is<bool>()) | ||||
|       return as<bool>() == right.template as<bool>(); | ||||
|     if (is<JsonInteger>() && right.template is<JsonInteger>()) | ||||
|       return as<JsonInteger>() == right.template as<JsonInteger>(); | ||||
|     if (is<JsonFloat>() && right.template is<JsonFloat>()) | ||||
|       return as<JsonFloat>() == right.template as<JsonFloat>(); | ||||
|     if (is<JsonArray>() && right.template is<JsonArray>()) | ||||
|       return as<JsonArray>() == right.template as<JsonArray>(); | ||||
|     if (is<JsonObject>() && right.template is<JsonObject>()) | ||||
|       return as<JsonObject>() == right.template as<JsonObject>(); | ||||
|     if (is<char *>() && right.template is<char *>()) | ||||
|       return makeString(as<char *>()).equals(right.template as<char *>()); | ||||
|   // bool/int/float == TVariant | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator==( | ||||
|       const T &lhs, TVariant rhs) { | ||||
|     return lhs == rhs.template as<T>(); | ||||
|   } | ||||
|  | ||||
|     return false; | ||||
|   // TVariant == bool/int/float | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator==( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return lhs.template as<T>() == rhs; | ||||
|   } | ||||
|  | ||||
|   // const char* != TVariant | ||||
|   template <typename T> | ||||
|   friend typename enable_if<IsString<T *>::value, bool>::type operator!=( | ||||
|       T *lhs, TVariant rhs) { | ||||
|     return !makeString(lhs).equals(rhs.template as<const char *>()); | ||||
|   } | ||||
|  | ||||
|   // std::string != TVariant | ||||
|   template <typename T> | ||||
|   friend typename enable_if<IsString<T>::value, bool>::type operator!=( | ||||
|       const T &lhs, TVariant rhs) { | ||||
|     return !makeString(lhs).equals(rhs.template as<const char *>()); | ||||
|   } | ||||
|  | ||||
|   // TVariant != const char* | ||||
|   template <typename T> | ||||
|   friend typename enable_if<IsString<T *>::value, bool>::type operator!=( | ||||
|       TVariant lhs, T *rhs) { | ||||
|     return !makeString(rhs).equals(lhs.template as<const char *>()); | ||||
|   } | ||||
|  | ||||
|   // TVariant != std::string | ||||
|   template <typename T> | ||||
|   friend typename enable_if<IsString<T>::value, bool>::type operator!=( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return !makeString(rhs).equals(lhs.template as<const char *>()); | ||||
|   } | ||||
|  | ||||
|   // bool/int/float != TVariant | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator!=( | ||||
|       const T &lhs, TVariant rhs) { | ||||
|     return lhs != rhs.template as<T>(); | ||||
|   } | ||||
|  | ||||
|   // TVariant != bool/int/float | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator!=( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return lhs.template as<T>() != rhs; | ||||
|   } | ||||
|  | ||||
|   // bool/int/float < TVariant | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator<( | ||||
|       const T &lhs, TVariant rhs) { | ||||
|     return lhs < rhs.template as<T>(); | ||||
|   } | ||||
|  | ||||
|   // TVariant < bool/int/float | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator<( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return lhs.template as<T>() < rhs; | ||||
|   } | ||||
|  | ||||
|   // bool/int/float <= TVariant | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator<=( | ||||
|       const T &lhs, TVariant rhs) { | ||||
|     return lhs <= rhs.template as<T>(); | ||||
|   } | ||||
|  | ||||
|   // TVariant <= bool/int/float | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator<=( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return lhs.template as<T>() <= rhs; | ||||
|   } | ||||
|  | ||||
|   // bool/int/float > TVariant | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator>( | ||||
|       const T &lhs, TVariant rhs) { | ||||
|     return lhs > rhs.template as<T>(); | ||||
|   } | ||||
|  | ||||
|   // TVariant > bool/int/float | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator>( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return lhs.template as<T>() > rhs; | ||||
|   } | ||||
|  | ||||
|   // bool/int/float >= TVariant | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator>=( | ||||
|       const T &lhs, TVariant rhs) { | ||||
|     return lhs >= rhs.template as<T>(); | ||||
|   } | ||||
|  | ||||
|   // TVariant >= bool/int/float | ||||
|   template <typename T> | ||||
|   friend typename enable_if<is_simple_value<T>::value, bool>::type operator>=( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return lhs.template as<T>() >= rhs; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -13,95 +13,65 @@ | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| inline bool JsonVariant::set(JsonArray array) { | ||||
| inline bool JsonVariant::set(JsonArray array) const { | ||||
|   return to<JsonArray>().copyFrom(array); | ||||
| } | ||||
|  | ||||
| inline bool JsonVariant::set(const JsonArraySubscript& value) { | ||||
| inline bool JsonVariant::set(const JsonArraySubscript& value) const { | ||||
|   return set(value.as<JsonVariant>()); | ||||
| } | ||||
|  | ||||
| inline bool JsonVariant::set(JsonObject object) { | ||||
| inline bool JsonVariant::set(JsonObject object) const { | ||||
|   return to<JsonObject>().copyFrom(object); | ||||
| } | ||||
|  | ||||
| template <typename TString> | ||||
| inline bool JsonVariant::set(const JsonObjectSubscript<TString>& value) { | ||||
| inline bool JsonVariant::set(const JsonObjectSubscript<TString>& value) const { | ||||
|   return set(value.template as<JsonVariant>()); | ||||
| } | ||||
|  | ||||
| inline bool JsonVariant::set(const JsonVariant& value) { | ||||
|   if (!_data) return false; | ||||
|   if (!value._data) { | ||||
|     _data->type = JSON_NULL; | ||||
|     return true; | ||||
|   } | ||||
|   switch (value._data->type) { | ||||
|     case JSON_ARRAY: | ||||
|       return set(value.as<JsonArray>()); | ||||
|     case JSON_OBJECT: | ||||
|       return set(value.as<JsonObject>()); | ||||
|     case JSON_OWNED_STRING: | ||||
|       return set(const_cast<char*>(value._data->content.asString)); | ||||
|     case JSON_OWNED_RAW: | ||||
|       return set(serialized(const_cast<char*>(value._data->content.asRaw.data), | ||||
|                             value._data->content.asRaw.size)); | ||||
|     default: | ||||
|       *_data = *value._data; | ||||
|       return true; | ||||
|   } | ||||
| inline bool JsonVariant::set(const JsonVariant& value) const { | ||||
|   return variantCopy(_data, value._data, _memoryPool); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if< | ||||
|     is_same<typename remove_const<T>::type, JsonArray>::value, JsonArray>::type | ||||
| inline typename enable_if<is_same<T, JsonArray>::value, T>::type | ||||
| JsonVariant::as() const { | ||||
|   if (_data && _data->type == JSON_ARRAY) | ||||
|     return JsonArray(_memoryPool, &_data->content.asArray); | ||||
|   else | ||||
|     return JsonArray(); | ||||
|   return JsonArray(_memoryPool, variantAsArray(_data)); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if< | ||||
|     is_same<typename remove_const<T>::type, JsonObject>::value, T>::type | ||||
| inline typename enable_if<is_same<T, JsonObject>::value, T>::type | ||||
| JsonVariant::as() const { | ||||
|   if (_data && _data->type == JSON_OBJECT) | ||||
|     return JsonObject(_memoryPool, &_data->content.asObject); | ||||
|   else | ||||
|     return JsonObject(); | ||||
|   return JsonObject(_memoryPool, variantAsObject(_data)); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if<is_same<T, JsonArray>::value, JsonArray>::type | ||||
| JsonVariant::to() { | ||||
|   if (!_data) return JsonArray(); | ||||
|   _data->type = JSON_ARRAY; | ||||
|   _data->content.asArray.head = 0; | ||||
|   _data->content.asArray.tail = 0; | ||||
|   return JsonArray(_memoryPool, &_data->content.asArray); | ||||
| JsonVariant::to() const { | ||||
|   return JsonArray(_memoryPool, variantToArray(_data)); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| typename enable_if<is_same<T, JsonObject>::value, JsonObject>::type | ||||
| JsonVariant::to() { | ||||
|   if (!_data) return JsonObject(); | ||||
|   _data->type = JSON_OBJECT; | ||||
|   _data->content.asObject.head = 0; | ||||
|   _data->content.asObject.tail = 0; | ||||
|   return JsonObject(_memoryPool, &_data->content.asObject); | ||||
| JsonVariant::to() const { | ||||
|   return JsonObject(_memoryPool, variantToObject(_data)); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| typename enable_if<is_same<T, JsonVariant>::value, JsonVariant>::type | ||||
| JsonVariant::to() { | ||||
|   if (!_data) return JsonVariant(); | ||||
|   _data->type = JSON_NULL; | ||||
| JsonVariant::to() const { | ||||
|   variantSetNull(_data); | ||||
|   return *this; | ||||
| } | ||||
|  | ||||
| template <typename Visitor> | ||||
| inline void JsonVariant::accept(Visitor& visitor) const { | ||||
|   return JsonVariantConst(_data).accept(visitor); | ||||
| } | ||||
|  | ||||
| template <typename Visitor> | ||||
| inline void JsonVariantConst::accept(Visitor& visitor) const { | ||||
|   if (!_data) return visitor.visitNull(); | ||||
|  | ||||
|   switch (_data->type) { | ||||
| @@ -109,12 +79,10 @@ inline void JsonVariant::accept(Visitor& visitor) const { | ||||
|       return visitor.visitFloat(_data->content.asFloat); | ||||
|  | ||||
|     case JSON_ARRAY: | ||||
|       return visitor.visitArray( | ||||
|           JsonArray(_memoryPool, &_data->content.asArray)); | ||||
|       return visitor.visitArray(JsonArrayConst(&_data->content.asArray)); | ||||
|  | ||||
|     case JSON_OBJECT: | ||||
|       return visitor.visitObject( | ||||
|           JsonObject(_memoryPool, &_data->content.asObject)); | ||||
|       return visitor.visitObject(JsonObjectConst(&_data->content.asObject)); | ||||
|  | ||||
|     case JSON_LINKED_STRING: | ||||
|     case JSON_OWNED_STRING: | ||||
| @@ -138,4 +106,9 @@ inline void JsonVariant::accept(Visitor& visitor) const { | ||||
|       return visitor.visitNull(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| inline JsonVariantConst JsonVariantConst::operator[](size_t index) const { | ||||
|   return JsonArrayConst(variantAsArray(_data))[index]; | ||||
| } | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -21,50 +21,26 @@ class JsonObjectSubscript; | ||||
| template <typename TImpl> | ||||
| class JsonVariantSubscripts { | ||||
|  public: | ||||
|   // Mimics an array or an object. | ||||
|   // Returns the size of the array or object if the variant has that type. | ||||
|   // Returns 0 if the variant is neither an array nor an object | ||||
|   size_t size() const { | ||||
|     return impl()->template as<JsonArray>().size() + | ||||
|            impl()->template as<JsonObject>().size(); | ||||
|   } | ||||
|  | ||||
|   // Mimics an array. | ||||
|   // Returns the element at specified index if the variant is an array. | ||||
|   FORCE_INLINE const JsonArraySubscript operator[](size_t index) const; | ||||
|   FORCE_INLINE JsonArraySubscript operator[](size_t index); | ||||
|   FORCE_INLINE JsonArraySubscript operator[](size_t index) const; | ||||
|  | ||||
|   // Mimics an object. | ||||
|   // Returns the value associated with the specified key if the variant is | ||||
|   // an object. | ||||
|   // | ||||
|   // const JsonObjectSubscript operator[](TKey) const; | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE | ||||
|       typename enable_if<IsString<TString>::value, | ||||
|                          const JsonObjectSubscript<const TString &> >::type | ||||
|       operator[](const TString &key) const; | ||||
|   // | ||||
|   // const JsonObjectSubscript operator[](TKey) const; | ||||
|   // JsonObjectSubscript operator[](TKey) const; | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE typename enable_if<IsString<TString>::value, | ||||
|                                   JsonObjectSubscript<const TString &> >::type | ||||
|   operator[](const TString &key); | ||||
|   operator[](const TString &key) const; | ||||
|   // | ||||
|   // JsonObjectSubscript operator[](TKey); | ||||
|   // JsonObjectSubscript operator[](TKey) const; | ||||
|   // TKey = const char*, const char[N], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE typename enable_if<IsString<TString *>::value, | ||||
|                                   JsonObjectSubscript<TString *> >::type | ||||
|   operator[](TString *key); | ||||
|   // | ||||
|   // JsonObjectSubscript operator[](TKey); | ||||
|   // TKey = const char*, const char[N], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE typename enable_if<IsString<TString *>::value, | ||||
|                                   const JsonObjectSubscript<TString *> >::type | ||||
|   operator[](TString *key) const; | ||||
|  | ||||
|  private: | ||||
|   | ||||
| @@ -35,7 +35,7 @@ class MsgPackSerializer { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void visitArray(JsonArray array) { | ||||
|   void visitArray(JsonArrayConst array) { | ||||
|     size_t n = array.size(); | ||||
|     if (n < 0x10) { | ||||
|       writeByte(uint8_t(0x90 + array.size())); | ||||
| @@ -46,12 +46,12 @@ class MsgPackSerializer { | ||||
|       writeByte(0xDD); | ||||
|       writeInteger(uint32_t(n)); | ||||
|     } | ||||
|     for (JsonArray::iterator it = array.begin(); it != array.end(); ++it) { | ||||
|     for (JsonArrayConst::iterator it = array.begin(); it != array.end(); ++it) { | ||||
|       it->accept(*this); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void visitObject(JsonObject object) { | ||||
|   void visitObject(JsonObjectConst object) { | ||||
|     size_t n = object.size(); | ||||
|     if (n < 0x10) { | ||||
|       writeByte(uint8_t(0x80 + n)); | ||||
| @@ -62,7 +62,8 @@ class MsgPackSerializer { | ||||
|       writeByte(0xDF); | ||||
|       writeInteger(uint32_t(n)); | ||||
|     } | ||||
|     for (JsonObject::iterator it = object.begin(); it != object.end(); ++it) { | ||||
|     for (JsonObjectConst::iterator it = object.begin(); it != object.end(); | ||||
|          ++it) { | ||||
|       visitString(it->key()); | ||||
|       it->value().accept(*this); | ||||
|     } | ||||
|   | ||||
| @@ -38,4 +38,9 @@ struct IsString<TChar*> { | ||||
|   static const bool value = sizeof(TChar) == 1; | ||||
| }; | ||||
|  | ||||
| template <> | ||||
| struct IsString<void*> { | ||||
|   static const bool value = false; | ||||
| }; | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -7,6 +7,7 @@ add_executable(JsonArrayTests | ||||
| 	copyFrom.cpp | ||||
| 	copyTo.cpp | ||||
| 	createNested.cpp | ||||
| 	equals.cpp | ||||
| 	isNull.cpp | ||||
| 	iterator.cpp | ||||
| 	remove.cpp | ||||
|   | ||||
							
								
								
									
										32
									
								
								test/JsonArray/equals.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								test/JsonArray/equals.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("JsonArray::operator==()") { | ||||
|   DynamicJsonDocument doc1; | ||||
|   JsonArray array1 = doc1.to<JsonArray>(); | ||||
|   JsonArrayConst array1c = array1; | ||||
|  | ||||
|   DynamicJsonDocument doc2; | ||||
|   JsonArray array2 = doc2.to<JsonArray>(); | ||||
|   JsonArrayConst array2c = array2; | ||||
|  | ||||
|   SECTION("should return false when arrays differ") { | ||||
|     array1.add("coucou"); | ||||
|     array2.add(1); | ||||
|  | ||||
|     REQUIRE_FALSE(array1 == array2); | ||||
|     REQUIRE_FALSE(array1c == array2c); | ||||
|   } | ||||
|  | ||||
|   SECTION("should return false when arrays differ") { | ||||
|     array1.add("coucou"); | ||||
|     array2.add("coucou"); | ||||
|  | ||||
|     REQUIRE(array1 == array2); | ||||
|     REQUIRE(array1c == array2c); | ||||
|   } | ||||
| } | ||||
| @@ -23,3 +23,22 @@ TEST_CASE("JsonArray::isNull()") { | ||||
|       REQUIRE(array.isNull() == true); | ||||
|     }*/ | ||||
| } | ||||
|  | ||||
| TEST_CASE("JsonArrayConst::isNull()") { | ||||
|   SECTION("returns true for undefined JsonArray") { | ||||
|     JsonArrayConst array; | ||||
|     REQUIRE(array.isNull() == true); | ||||
|   } | ||||
|  | ||||
|   SECTION("returns false when allocation succeeds") { | ||||
|     StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc; | ||||
|     JsonArrayConst array = doc.to<JsonArray>(); | ||||
|     REQUIRE(array.isNull() == false); | ||||
|   } | ||||
|  | ||||
|   /*  SECTION("returns true when allocation fails") { | ||||
|       StaticJsonDocument<1> doc; | ||||
|       JsonArray array = doc.to<JsonArray>(); | ||||
|       REQUIRE(array.isNull() == true); | ||||
|     }*/ | ||||
| } | ||||
|   | ||||
| @@ -5,15 +5,16 @@ | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| template <typename TIterator> | ||||
| template <typename TArray> | ||||
| static void run_iterator_test() { | ||||
|   StaticJsonDocument<JSON_ARRAY_SIZE(2)> doc; | ||||
|   JsonArray array = doc.to<JsonArray>(); | ||||
|   array.add(12); | ||||
|   array.add(34); | ||||
|   JsonArray tmp = doc.to<JsonArray>(); | ||||
|   tmp.add(12); | ||||
|   tmp.add(34); | ||||
|  | ||||
|   TIterator it = array.begin(); | ||||
|   TIterator end = array.end(); | ||||
|   TArray array = tmp; | ||||
|   typename TArray::iterator it = array.begin(); | ||||
|   typename TArray::iterator end = array.end(); | ||||
|  | ||||
|   REQUIRE(end != it); | ||||
|   REQUIRE(12 == it->template as<int>()); | ||||
| @@ -27,7 +28,9 @@ static void run_iterator_test() { | ||||
| } | ||||
|  | ||||
| TEST_CASE("JsonArray::begin()/end()") { | ||||
|   SECTION("Mutable") { | ||||
|     run_iterator_test<JsonArray::iterator>(); | ||||
|   } | ||||
|   run_iterator_test<JsonArray>(); | ||||
| } | ||||
|  | ||||
| TEST_CASE("JsonArrayConst::begin()/end()") { | ||||
|   run_iterator_test<JsonArrayConst>(); | ||||
| } | ||||
|   | ||||
| @@ -58,9 +58,6 @@ TEST_CASE("JsonArray::operator[]") { | ||||
|     array[0] = arr2; | ||||
|  | ||||
|     REQUIRE(arr2 == array[0].as<JsonArray>()); | ||||
|     REQUIRE(arr2 == array[0].as<JsonArray>());  // <- short hand | ||||
|     // REQUIRE(arr2 == array[0].as<const JsonArray>()); | ||||
|     // REQUIRE(arr2 == array[0].as<const JsonArray>());  // <- short hand | ||||
|     REQUIRE(true == array[0].is<JsonArray>()); | ||||
|     REQUIRE(false == array[0].is<int>()); | ||||
|   } | ||||
| @@ -72,7 +69,6 @@ TEST_CASE("JsonArray::operator[]") { | ||||
|     array[0] = obj; | ||||
|  | ||||
|     REQUIRE(obj == array[0].as<JsonObject>()); | ||||
|     REQUIRE(obj == array[0].as<const JsonObject>());  // <- short hand | ||||
|     REQUIRE(true == array[0].is<JsonObject>()); | ||||
|     REQUIRE(false == array[0].is<int>()); | ||||
|   } | ||||
| @@ -148,3 +144,18 @@ TEST_CASE("JsonArray::operator[]") { | ||||
|   } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| TEST_CASE("JsonArrayConst::operator[]") { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonArray array = doc.to<JsonArray>(); | ||||
|   array.add(0); | ||||
|  | ||||
|   SECTION("int") { | ||||
|     array[0] = 123; | ||||
|     JsonArrayConst carr = array; | ||||
|  | ||||
|     REQUIRE(123 == carr[0].as<int>()); | ||||
|     REQUIRE(true == carr[0].is<int>()); | ||||
|     REQUIRE(false == carr[0].is<bool>()); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -7,6 +7,7 @@ add_executable(JsonObjectTests | ||||
| 	copy.cpp | ||||
| 	createNestedArray.cpp | ||||
| 	createNestedObject.cpp | ||||
| 	equals.cpp | ||||
| 	get.cpp | ||||
| 	invalid.cpp | ||||
| 	is.cpp | ||||
|   | ||||
| @@ -10,12 +10,15 @@ TEST_CASE("JsonObject::containsKey()") { | ||||
|   JsonObject obj = doc.to<JsonObject>(); | ||||
|   obj.set("hello", 42); | ||||
|  | ||||
|   SECTION("returns false if key not present") { | ||||
|   SECTION("returns true only if key is present") { | ||||
|     REQUIRE(false == obj.containsKey("world")); | ||||
|     REQUIRE(true == obj.containsKey("hello")); | ||||
|   } | ||||
|  | ||||
|   SECTION("returns true if key present") { | ||||
|     REQUIRE(true == obj.containsKey("hello")); | ||||
|   SECTION("works with JsonObjectConst") { | ||||
|     JsonObjectConst cobj = obj; | ||||
|     REQUIRE(false == cobj.containsKey("world")); | ||||
|     REQUIRE(true == cobj.containsKey("hello")); | ||||
|   } | ||||
|  | ||||
|   SECTION("returns false after remove()") { | ||||
|   | ||||
| @@ -56,4 +56,13 @@ TEST_CASE("JsonObject::copyFrom()") { | ||||
|     REQUIRE(doc1.memoryUsage() == doc2.memoryUsage()); | ||||
|     REQUIRE(obj2["hello"] == std::string("world")); | ||||
|   } | ||||
|  | ||||
|   SECTION("should work with JsonObjectConst") { | ||||
|     obj1["hello"] = "world"; | ||||
|  | ||||
|     obj2.copyFrom(static_cast<JsonObjectConst>(obj1)); | ||||
|  | ||||
|     REQUIRE(doc1.memoryUsage() == doc2.memoryUsage()); | ||||
|     REQUIRE(obj2["hello"] == std::string("world")); | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										35
									
								
								test/JsonObject/equals.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								test/JsonObject/equals.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("JsonObject::operator==()") { | ||||
|   DynamicJsonDocument doc1; | ||||
|   JsonObject obj1 = doc1.to<JsonObject>(); | ||||
|   JsonObjectConst obj1c = obj1; | ||||
|  | ||||
|   DynamicJsonDocument doc2; | ||||
|   JsonObject obj2 = doc2.to<JsonObject>(); | ||||
|   JsonObjectConst obj2c = obj2; | ||||
|  | ||||
|   SECTION("should return false when objs differ") { | ||||
|     obj1["hello"] = "coucou"; | ||||
|     obj2["world"] = 1; | ||||
|  | ||||
|     REQUIRE_FALSE(obj1 == obj2); | ||||
|     REQUIRE_FALSE(obj1c == obj2c); | ||||
|   } | ||||
|  | ||||
|   SECTION("should return false when objs differ") { | ||||
|     obj1["hello"] = "world"; | ||||
|     obj1["anwser"] = 42; | ||||
|     // insert in different order | ||||
|     obj2["anwser"] = 42; | ||||
|     obj2["hello"] = "world"; | ||||
|  | ||||
|     REQUIRE(obj1 == obj2); | ||||
|     REQUIRE(obj1c == obj2c); | ||||
|   } | ||||
| } | ||||
| @@ -27,4 +27,11 @@ TEST_CASE("JsonObject::get()") { | ||||
|     REQUIRE(std::string("world") == obj.get<char*>(vla)); | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   SECTION("works on JsonObjectConst") { | ||||
|     obj.set("hello", "world"); | ||||
|     const char* value = | ||||
|         static_cast<JsonObjectConst>(obj).get<const char*>("hello"); | ||||
|     REQUIRE_THAT(value, Equals("world")); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -26,23 +26,35 @@ TEST_CASE("JsonObject::begin()/end()") { | ||||
|     REQUIRE(obj.end() == it); | ||||
|   } | ||||
|  | ||||
|   // SECTION("ConstIterator") { | ||||
|   //   const JsonObject const_object = obj; | ||||
|   //   JsonObject::iterator it = const_object.begin(); | ||||
|  | ||||
|   //   REQUIRE(const_object.end() != it); | ||||
|   //   REQUIRE_THAT(it->key(), Equals("ab")); | ||||
|   //   REQUIRE(12 == it->value()); | ||||
|   //   ++it; | ||||
|   //   REQUIRE(const_object.end() != it); | ||||
|   //   REQUIRE_THAT(it->key(), Equals("cd")); | ||||
|   //   REQUIRE(34 == it->value()); | ||||
|   //   ++it; | ||||
|   //   REQUIRE(const_object.end() == it); | ||||
|   // } | ||||
|  | ||||
|   SECTION("Dereferencing end() is safe") { | ||||
|     REQUIRE(obj.end()->key().isNull()); | ||||
|     REQUIRE(obj.end()->value().isNull()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| TEST_CASE("JsonObjectConst::begin()/end()") { | ||||
|   StaticJsonDocument<JSON_OBJECT_SIZE(2)> doc; | ||||
|   JsonObject obj = doc.to<JsonObject>(); | ||||
|   obj["ab"] = 12; | ||||
|   obj["cd"] = 34; | ||||
|  | ||||
|   JsonObjectConst cobj = obj; | ||||
|  | ||||
|   SECTION("NonConstIterator") { | ||||
|     JsonObjectConst::iterator it = cobj.begin(); | ||||
|     REQUIRE(cobj.end() != it); | ||||
|     REQUIRE(it->key() == "ab"); | ||||
|     REQUIRE(12 == it->value()); | ||||
|     ++it; | ||||
|     REQUIRE(cobj.end() != it); | ||||
|     REQUIRE(it->key() == "cd"); | ||||
|     REQUIRE(34 == it->value()); | ||||
|     ++it; | ||||
|     REQUIRE(cobj.end() == it); | ||||
|   } | ||||
|  | ||||
|   SECTION("Dereferencing end() is safe") { | ||||
|     REQUIRE(cobj.end()->key().isNull()); | ||||
|     REQUIRE(cobj.end()->value().isNull()); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -58,13 +58,7 @@ TEST_CASE("JsonObject::operator[]") { | ||||
|     obj["hello"] = arr; | ||||
|  | ||||
|     REQUIRE(arr == obj["hello"].as<JsonArray>()); | ||||
|     REQUIRE(arr == obj["hello"].as<JsonArray>());  // <- short hand | ||||
|     // REQUIRE(arr == obj["hello"].as<const JsonArray>()); | ||||
|     // REQUIRE(arr == obj["hello"].as<const JsonArray>());  // <- short hand | ||||
|     REQUIRE(true == obj["hello"].is<JsonArray>()); | ||||
|     REQUIRE(true == obj["hello"].is<JsonArray>()); | ||||
|     REQUIRE(true == obj["hello"].is<const JsonArray>()); | ||||
|     REQUIRE(true == obj["hello"].is<const JsonArray>()); | ||||
|     REQUIRE(false == obj["hello"].is<JsonObject>()); | ||||
|   } | ||||
|  | ||||
| @@ -75,9 +69,7 @@ TEST_CASE("JsonObject::operator[]") { | ||||
|     obj["hello"] = obj2; | ||||
|  | ||||
|     REQUIRE(obj2 == obj["hello"].as<JsonObject>()); | ||||
|     REQUIRE(obj2 == obj["hello"].as<const JsonObject>()); | ||||
|     REQUIRE(true == obj["hello"].is<JsonObject>()); | ||||
|     REQUIRE(true == obj["hello"].is<const JsonObject>()); | ||||
|     REQUIRE(false == obj["hello"].is<JsonArray>()); | ||||
|   } | ||||
|  | ||||
| @@ -219,4 +211,12 @@ TEST_CASE("JsonObject::operator[]") { | ||||
|     REQUIRE(std::string("world") == obj[vla]); | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   SECTION("chain") { | ||||
|     obj.createNestedObject("hello")["world"] = 123; | ||||
|  | ||||
|     REQUIRE(123 == obj["hello"]["world"].as<int>()); | ||||
|     REQUIRE(true == obj["hello"]["world"].is<int>()); | ||||
|     REQUIRE(false == obj["hello"]["world"].is<bool>()); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -158,4 +158,16 @@ TEST_CASE("JsonVariant::as()") { | ||||
|     REQUIRE(variant.as<long long>() == 9223372036854775807); | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   SECTION("should work on JsonVariantConst") { | ||||
|     variant.set("hello"); | ||||
|  | ||||
|     JsonVariantConst cvar = variant; | ||||
|  | ||||
|     REQUIRE(cvar.as<bool>() == false); | ||||
|     REQUIRE(cvar.as<long>() == 0L); | ||||
|     REQUIRE(cvar.as<const char*>() == std::string("hello")); | ||||
|     REQUIRE(cvar.as<char*>() == std::string("hello")); | ||||
|     // REQUIRE(cvar.as<std::string>() == std::string("hello")); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -5,116 +5,146 @@ | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| void checkIsArray(JsonArray value) { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonVariant var = doc.to<JsonVariant>(); | ||||
|   var.set(value); | ||||
| template <typename TVariant> | ||||
| void checkIsArray(TVariant var) { | ||||
|   REQUIRE(var.template is<JsonArray>()); | ||||
|  | ||||
|   REQUIRE(var.is<JsonArray>()); | ||||
|   REQUIRE(var.is<JsonArray>()); | ||||
|   REQUIRE(var.is<const JsonArray>()); | ||||
|   REQUIRE(var.is<const JsonArray>()); | ||||
|  | ||||
|   REQUIRE_FALSE(var.is<bool>()); | ||||
|   REQUIRE_FALSE(var.is<double>()); | ||||
|   REQUIRE_FALSE(var.is<float>()); | ||||
|   REQUIRE_FALSE(var.is<int>()); | ||||
|   REQUIRE_FALSE(var.is<long>()); | ||||
|   REQUIRE_FALSE(var.is<const char *>()); | ||||
|   REQUIRE_FALSE(var.is<JsonObject>()); | ||||
|   REQUIRE_FALSE(var.template is<bool>()); | ||||
|   REQUIRE_FALSE(var.template is<double>()); | ||||
|   REQUIRE_FALSE(var.template is<float>()); | ||||
|   REQUIRE_FALSE(var.template is<int>()); | ||||
|   REQUIRE_FALSE(var.template is<long>()); | ||||
|   REQUIRE_FALSE(var.template is<const char *>()); | ||||
|   REQUIRE_FALSE(var.template is<JsonObject>()); | ||||
| } | ||||
|  | ||||
| void checkIsBool(bool value) { | ||||
| void testArray(JsonArray value) { | ||||
|   DynamicJsonDocument doc; | ||||
|  | ||||
|   JsonVariant var = doc.to<JsonVariant>(); | ||||
|   var.set(value); | ||||
|  | ||||
|   REQUIRE(var.is<bool>()); | ||||
|   checkIsArray(var); | ||||
|  | ||||
|   REQUIRE_FALSE(var.is<double>()); | ||||
|   REQUIRE_FALSE(var.is<float>()); | ||||
|   REQUIRE_FALSE(var.is<int>()); | ||||
|   REQUIRE_FALSE(var.is<long>()); | ||||
|   REQUIRE_FALSE(var.is<const char *>()); | ||||
|   REQUIRE_FALSE(var.is<JsonArray>()); | ||||
|   REQUIRE_FALSE(var.is<JsonObject>()); | ||||
|   JsonVariantConst cvar = var; | ||||
|   checkIsArray(cvar); | ||||
| } | ||||
|  | ||||
| void checkIsFloat(double value) { | ||||
| template <typename TVariant> | ||||
| void checkIsBool(TVariant var) { | ||||
|   REQUIRE(var.template is<bool>()); | ||||
|  | ||||
|   REQUIRE_FALSE(var.template is<double>()); | ||||
|   REQUIRE_FALSE(var.template is<float>()); | ||||
|   REQUIRE_FALSE(var.template is<int>()); | ||||
|   REQUIRE_FALSE(var.template is<long>()); | ||||
|   REQUIRE_FALSE(var.template is<const char *>()); | ||||
|   REQUIRE_FALSE(var.template is<JsonArray>()); | ||||
|   REQUIRE_FALSE(var.template is<JsonObject>()); | ||||
| } | ||||
|  | ||||
| void testBool(bool value) { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonVariant var = doc.to<JsonVariant>(); | ||||
|   var.set(value); | ||||
|  | ||||
|   REQUIRE(var.is<double>()); | ||||
|   REQUIRE(var.is<float>()); | ||||
|   checkIsBool(var); | ||||
|   checkIsBool(JsonVariantConst(var)); | ||||
| } | ||||
|  | ||||
|   REQUIRE_FALSE(var.is<bool>()); | ||||
|   REQUIRE_FALSE(var.is<int>()); | ||||
|   REQUIRE_FALSE(var.is<long>()); | ||||
|   REQUIRE_FALSE(var.is<const char *>()); | ||||
|   REQUIRE_FALSE(var.is<JsonArray>()); | ||||
|   REQUIRE_FALSE(var.is<JsonObject>()); | ||||
| template <typename TVariant> | ||||
| void checkIsFloat(TVariant var) { | ||||
|   REQUIRE(var.template is<double>()); | ||||
|   REQUIRE(var.template is<float>()); | ||||
|  | ||||
|   REQUIRE_FALSE(var.template is<bool>()); | ||||
|   REQUIRE_FALSE(var.template is<int>()); | ||||
|   REQUIRE_FALSE(var.template is<long>()); | ||||
|   REQUIRE_FALSE(var.template is<const char *>()); | ||||
|   REQUIRE_FALSE(var.template is<JsonArray>()); | ||||
|   REQUIRE_FALSE(var.template is<JsonObject>()); | ||||
| } | ||||
|  | ||||
| void testFloat(double value) { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonVariant var = doc.to<JsonVariant>(); | ||||
|   var.set(value); | ||||
|  | ||||
|   checkIsFloat(var); | ||||
|   checkIsFloat(JsonVariantConst(var)); | ||||
| } | ||||
|  | ||||
| template <typename TVariant> | ||||
| void checkIsInteger(TVariant var) { | ||||
|   REQUIRE(var.template is<long>()); | ||||
|   REQUIRE(var.template is<int>()); | ||||
|   REQUIRE(var.template is<float>()); | ||||
|   REQUIRE(var.template is<double>()); | ||||
|  | ||||
|   REQUIRE_FALSE(var.template is<bool>()); | ||||
|   REQUIRE_FALSE(var.template is<const char *>()); | ||||
|   REQUIRE_FALSE(var.template is<JsonArray>()); | ||||
|   REQUIRE_FALSE(var.template is<JsonObject>()); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| void checkIsInteger(T value) { | ||||
| void testInteger(T value) { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonVariant var = doc.to<JsonVariant>(); | ||||
|   var.set(value); | ||||
|  | ||||
|   REQUIRE(var.is<long>()); | ||||
|   REQUIRE(var.is<int>()); | ||||
|   REQUIRE(var.is<float>()); | ||||
|   REQUIRE(var.is<double>()); | ||||
|  | ||||
|   REQUIRE_FALSE(var.is<bool>()); | ||||
|   REQUIRE_FALSE(var.is<const char *>()); | ||||
|   REQUIRE_FALSE(var.is<JsonArray>()); | ||||
|   REQUIRE_FALSE(var.is<JsonObject>()); | ||||
|   checkIsInteger(var); | ||||
|   checkIsInteger(JsonVariantConst(var)); | ||||
| } | ||||
|  | ||||
| void checkIsString(const char *value) { | ||||
| template <typename TVariant> | ||||
| void checkIsString(TVariant var) { | ||||
|   REQUIRE(var.template is<const char *>()); | ||||
|   REQUIRE(var.template is<std::string>()); | ||||
|  | ||||
|   REQUIRE_FALSE(var.template is<bool>()); | ||||
|   REQUIRE_FALSE(var.template is<int>()); | ||||
|   REQUIRE_FALSE(var.template is<double>()); | ||||
|   REQUIRE_FALSE(var.template is<float>()); | ||||
|   REQUIRE_FALSE(var.template is<long>()); | ||||
|   REQUIRE_FALSE(var.template is<JsonArray>()); | ||||
|   REQUIRE_FALSE(var.template is<JsonObject>()); | ||||
| } | ||||
|  | ||||
| void testString(const char *value) { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonVariant var = doc.to<JsonVariant>(); | ||||
|   var.set(value); | ||||
|  | ||||
|   REQUIRE(var.is<const char *>()); | ||||
|   REQUIRE(var.is<std::string>()); | ||||
|  | ||||
|   REQUIRE_FALSE(var.is<bool>()); | ||||
|   REQUIRE_FALSE(var.is<int>()); | ||||
|   REQUIRE_FALSE(var.is<double>()); | ||||
|   REQUIRE_FALSE(var.is<float>()); | ||||
|   REQUIRE_FALSE(var.is<long>()); | ||||
|   REQUIRE_FALSE(var.is<JsonArray>()); | ||||
|   REQUIRE_FALSE(var.is<JsonObject>()); | ||||
|   checkIsString(var); | ||||
|   checkIsString(JsonVariantConst(var)); | ||||
| } | ||||
|  | ||||
| TEST_CASE("JsonVariant::is()") { | ||||
|   SECTION("JsonArray") { | ||||
|     DynamicJsonDocument doc; | ||||
|     JsonArray array = doc.to<JsonArray>(); | ||||
|     checkIsArray(array); | ||||
|     testArray(array); | ||||
|   } | ||||
|  | ||||
|   SECTION("bool") { | ||||
|     checkIsBool(true); | ||||
|     checkIsBool(false); | ||||
|     testBool(true); | ||||
|     testBool(false); | ||||
|   } | ||||
|  | ||||
|   SECTION("double") { | ||||
|     checkIsFloat(4.2); | ||||
|     testFloat(4.2); | ||||
|   } | ||||
|  | ||||
|   SECTION("int") { | ||||
|     checkIsInteger(42); | ||||
|     testInteger(42); | ||||
|   } | ||||
|  | ||||
|   SECTION("long") { | ||||
|     checkIsInteger(42L); | ||||
|     testInteger(42L); | ||||
|   } | ||||
|  | ||||
|   SECTION("string") { | ||||
|     checkIsString("42"); | ||||
|     testString("42"); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -44,4 +44,12 @@ TEST_CASE("JsonVariant::isNull()") { | ||||
|       variant.set(JsonObject()); | ||||
|       REQUIRE(variant.isNull() == true); | ||||
|     }*/ | ||||
|  | ||||
|   SECTION("works with JsonVariantConst") { | ||||
|     variant.set(42); | ||||
|  | ||||
|     JsonVariantConst cvar = variant; | ||||
|  | ||||
|     REQUIRE(cvar.isNull() == false); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -120,3 +120,55 @@ TEST_CASE("JsonVariant::operator[]") { | ||||
|   } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| TEST_CASE("JsonVariantConst::operator[]") { | ||||
|   DynamicJsonDocument doc; | ||||
|   JsonVariant var = doc.to<JsonVariant>(); | ||||
|   JsonVariantConst cvar = var; | ||||
|  | ||||
|   SECTION("The JsonVariant is undefined") { | ||||
|     REQUIRE(0 == cvar.size()); | ||||
|     REQUIRE(cvar["0"].isNull()); | ||||
|     REQUIRE(cvar[0].isNull()); | ||||
|   } | ||||
|  | ||||
|   SECTION("The JsonVariant is a string") { | ||||
|     var.set("hello world"); | ||||
|     REQUIRE(0 == cvar.size()); | ||||
|     REQUIRE(cvar["0"].isNull()); | ||||
|     REQUIRE(cvar[0].isNull()); | ||||
|   } | ||||
|  | ||||
|   SECTION("The JsonVariant is a JsonArray") { | ||||
|     JsonArray array = var.to<JsonArray>(); | ||||
|  | ||||
|     SECTION("get value") { | ||||
|       array.add("element at index 0"); | ||||
|       array.add("element at index 1"); | ||||
|  | ||||
|       REQUIRE(2 == cvar.size()); | ||||
|       REQUIRE(std::string("element at index 0") == cvar[0]); | ||||
|       REQUIRE(std::string("element at index 1") == cvar[1]); | ||||
|       REQUIRE(std::string("element at index 0") == | ||||
|               var[static_cast<unsigned char>(0)]);  // issue #381 | ||||
|       REQUIRE(cvar[666].isNull()); | ||||
|       REQUIRE(cvar[3].isNull()); | ||||
|       REQUIRE(cvar["0"].isNull()); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("The JsonVariant is a JsonObject") { | ||||
|     JsonObject object = var.to<JsonObject>(); | ||||
|  | ||||
|     SECTION("get value") { | ||||
|       object["a"] = "element at key \"a\""; | ||||
|       object["b"] = "element at key \"b\""; | ||||
|  | ||||
|       REQUIRE(2 == cvar.size()); | ||||
|       REQUIRE(std::string("element at key \"a\"") == cvar["a"]); | ||||
|       REQUIRE(std::string("element at key \"b\"") == cvar["b"]); | ||||
|       REQUIRE(cvar["c"].isNull()); | ||||
|       REQUIRE(cvar[0].isNull()); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -32,15 +32,7 @@ TEST_CASE("JsonVariant undefined") { | ||||
|     REQUIRE(variant.as<JsonArray>().isNull()); | ||||
|   } | ||||
|  | ||||
|   SECTION("as<const JsonArray>()") { | ||||
|     REQUIRE(variant.as<const JsonArray>().isNull()); | ||||
|   } | ||||
|  | ||||
|   SECTION("as<JsonObject>()") { | ||||
|     REQUIRE(variant.as<JsonObject>().isNull()); | ||||
|   } | ||||
|  | ||||
|   SECTION("as<const JsonObject>()") { | ||||
|     REQUIRE(variant.as<const JsonObject>().isNull()); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -24,12 +24,6 @@ TEST_CASE("Polyfills/type_traits") { | ||||
|     REQUIRE((is_array<const char[10]>::value)); | ||||
|   } | ||||
|  | ||||
|   SECTION("IsVariant") { | ||||
|     REQUIRE( | ||||
|         static_cast<bool>(IsVariant<JsonObjectSubscript<const char*> >::value)); | ||||
|     REQUIRE(static_cast<bool>(IsVariant<JsonVariant>::value)); | ||||
|   } | ||||
|  | ||||
|   SECTION("is_const") { | ||||
|     CHECK(is_const<char>::value == false); | ||||
|     CHECK(is_const<const char>::value == true); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user