mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Fixed object keys not being duplicated
This commit is contained in:
		| @@ -6,6 +6,8 @@ HEAD | ||||
|  | ||||
| * Added implicit conversion from `JsonArray` and `JsonObject` to `JsonVariant` | ||||
| * Allow mixed configuration in compilation units (issue #809) | ||||
| * Fixed object keys not being duplicated | ||||
| * `JsonPair::key()` now returns a `JsonKey` | ||||
|  | ||||
| v6.4.0-beta (2018-09-11) | ||||
| ----------- | ||||
|   | ||||
| @@ -31,7 +31,9 @@ using ARDUINOJSON_NAMESPACE::DynamicJsonDocument; | ||||
| using ARDUINOJSON_NAMESPACE::JsonArray; | ||||
| using ARDUINOJSON_NAMESPACE::JsonFloat; | ||||
| using ARDUINOJSON_NAMESPACE::JsonInteger; | ||||
| using ARDUINOJSON_NAMESPACE::JsonKey; | ||||
| using ARDUINOJSON_NAMESPACE::JsonObject; | ||||
| using ARDUINOJSON_NAMESPACE::JsonPair; | ||||
| using ARDUINOJSON_NAMESPACE::JsonUInt; | ||||
| using ARDUINOJSON_NAMESPACE::JsonVariant; | ||||
| using ARDUINOJSON_NAMESPACE::serialized; | ||||
|   | ||||
| @@ -1,42 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <stdlib.h>  // size_t | ||||
|  | ||||
| #include "JsonFloat.hpp" | ||||
| #include "JsonInteger.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
| struct JsonObjectData { | ||||
|   struct Slot* head; | ||||
|   struct Slot* tail; | ||||
| }; | ||||
|  | ||||
| struct JsonArrayData { | ||||
|   struct Slot* head; | ||||
|   struct Slot* tail; | ||||
| }; | ||||
|  | ||||
| struct RawData { | ||||
|   const char* data; | ||||
|   size_t size; | ||||
| }; | ||||
|  | ||||
| // A union that defines the actual content of a JsonVariantData. | ||||
| // The enum JsonVariantType determines which member is in use. | ||||
| union JsonVariantContent { | ||||
|   JsonFloat asFloat; | ||||
|   JsonUInt asInteger; | ||||
|   JsonArrayData asArray; | ||||
|   JsonObjectData asObject; | ||||
|   const char* asString; | ||||
|   struct { | ||||
|     const char* data; | ||||
|     size_t size; | ||||
|   } asRaw; | ||||
| }; | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -4,14 +4,60 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "JsonVariantContent.hpp" | ||||
| #include "JsonVariantType.hpp" | ||||
| #include <stdlib.h>  // size_t | ||||
|  | ||||
| #include "JsonFloat.hpp" | ||||
| #include "JsonInteger.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| enum JsonVariantType { | ||||
|   JSON_NULL, | ||||
|   JSON_LINKED_RAW, | ||||
|   JSON_OWNED_RAW, | ||||
|   JSON_LINKED_STRING, | ||||
|   JSON_OWNED_STRING, | ||||
|   JSON_BOOLEAN, | ||||
|   JSON_POSITIVE_INTEGER, | ||||
|   JSON_NEGATIVE_INTEGER, | ||||
|   JSON_ARRAY, | ||||
|   JSON_OBJECT, | ||||
|   JSON_FLOAT | ||||
| }; | ||||
|  | ||||
| struct JsonObjectData { | ||||
|   struct Slot *head; | ||||
|   struct Slot *tail; | ||||
| }; | ||||
|  | ||||
| struct JsonArrayData { | ||||
|   struct Slot *head; | ||||
|   struct Slot *tail; | ||||
| }; | ||||
|  | ||||
| struct RawData { | ||||
|   const char *data; | ||||
|   size_t size; | ||||
| }; | ||||
|  | ||||
| // A union that defines the actual content of a JsonVariantData. | ||||
| // The enum JsonVariantType determines which member is in use. | ||||
| union JsonVariantContent { | ||||
|   JsonFloat asFloat; | ||||
|   JsonUInt asInteger; | ||||
|   JsonArrayData asArray; | ||||
|   JsonObjectData asObject; | ||||
|   const char *asString; | ||||
|   struct { | ||||
|     const char *data; | ||||
|     size_t size; | ||||
|   } asRaw; | ||||
| }; | ||||
|  | ||||
| // this struct must be a POD type to prevent error calling offsetof on clang | ||||
| struct JsonVariantData { | ||||
|   JsonVariantType type; | ||||
|   bool keyIsStatic : 1; | ||||
|   JsonVariantType type : 7; | ||||
|   JsonVariantContent content; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,23 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
| // Enumerated type to know the current type of a JsonVariant. | ||||
| // The value determines which member of JsonVariantContent is used. | ||||
| enum JsonVariantType { | ||||
|   JSON_NULL, | ||||
|   JSON_LINKED_RAW, | ||||
|   JSON_OWNED_RAW, | ||||
|   JSON_LINKED_STRING, | ||||
|   JSON_OWNED_STRING, | ||||
|   JSON_BOOLEAN, | ||||
|   JSON_POSITIVE_INTEGER, | ||||
|   JSON_NEGATIVE_INTEGER, | ||||
|   JSON_ARRAY, | ||||
|   JSON_OBJECT, | ||||
|   JSON_FLOAT | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -16,6 +16,9 @@ namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <typename TReader, typename TStringStorage> | ||||
| class JsonDeserializer { | ||||
|   typedef typename remove_reference<TStringStorage>::type::StringBuilder | ||||
|       StringBuilder; | ||||
|  | ||||
|  public: | ||||
|   JsonDeserializer(MemoryPool &memoryPool, TReader reader, | ||||
|                    TStringStorage stringStorage, uint8_t nestingLimit) | ||||
| @@ -121,8 +124,8 @@ class JsonDeserializer { | ||||
|     // Read each key value pair | ||||
|     for (;;) { | ||||
|       // Parse key | ||||
|       const char *key; | ||||
|       err = parseKey(&key); | ||||
|       StringInMemoryPool key; | ||||
|       err = parseKey(key); | ||||
|       if (err) return err; | ||||
|  | ||||
|       // Skip spaces | ||||
| @@ -162,7 +165,7 @@ class JsonDeserializer { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   DeserializationError parseKey(const char **key) { | ||||
|   DeserializationError parseKey(StringInMemoryPool &key) { | ||||
|     if (isQuote(current())) { | ||||
|       return parseQuotedString(key); | ||||
|     } else { | ||||
| @@ -171,18 +174,16 @@ class JsonDeserializer { | ||||
|   } | ||||
|  | ||||
|   DeserializationError parseStringValue(JsonVariant variant) { | ||||
|     const char *value; | ||||
|     DeserializationError err = parseQuotedString(&value); | ||||
|     StringInMemoryPool value; | ||||
|     DeserializationError err = parseQuotedString(value); | ||||
|     if (err) return err; | ||||
|     variant.set(value); | ||||
|     return DeserializationError::Ok; | ||||
|   } | ||||
|  | ||||
|   DeserializationError parseQuotedString(const char **result) { | ||||
|     typename remove_reference<TStringStorage>::type::String str = | ||||
|         _stringStorage.startString(); | ||||
|  | ||||
|     char stopChar = current(); | ||||
|   DeserializationError parseQuotedString(StringInMemoryPool &result) { | ||||
|     StringBuilder str = _stringStorage.startString(); | ||||
|     const char stopChar = current(); | ||||
|  | ||||
|     move(); | ||||
|     for (;;) { | ||||
| @@ -205,14 +206,13 @@ class JsonDeserializer { | ||||
|       str.append(c); | ||||
|     } | ||||
|  | ||||
|     *result = str.c_str(); | ||||
|     if (*result == NULL) return DeserializationError::NoMemory; | ||||
|     result = str.complete(); | ||||
|     if (result.isNull()) return DeserializationError::NoMemory; | ||||
|     return DeserializationError::Ok; | ||||
|   } | ||||
|  | ||||
|   DeserializationError parseNonQuotedString(const char **result) { | ||||
|     typename remove_reference<TStringStorage>::type::String str = | ||||
|         _stringStorage.startString(); | ||||
|   DeserializationError parseNonQuotedString(StringInMemoryPool &result) { | ||||
|     StringBuilder str = _stringStorage.startString(); | ||||
|  | ||||
|     char c = current(); | ||||
|     if (c == '\0') return DeserializationError::IncompleteInput; | ||||
| @@ -227,8 +227,8 @@ class JsonDeserializer { | ||||
|       return DeserializationError::InvalidInput; | ||||
|     } | ||||
|  | ||||
|     *result = str.c_str(); | ||||
|     if (*result == NULL) return DeserializationError::NoMemory; | ||||
|     result = str.complete(); | ||||
|     if (result.isNull()) return DeserializationError::NoMemory; | ||||
|     return DeserializationError::Ok; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -57,7 +57,10 @@ class JsonObject { | ||||
|     bool ok = _data != 0; | ||||
|     clear(); | ||||
|     for (iterator it = src.begin(); it != src.end(); ++it) { | ||||
|       ok &= set(it->key(), it->value()); | ||||
|       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; | ||||
|   } | ||||
| @@ -103,7 +106,7 @@ class JsonObject { | ||||
|   template <typename TValue, typename TString> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type get( | ||||
|       const TString& key) const { | ||||
|     return get_impl<const TString&, TValue>(key); | ||||
|     return get_impl<TValue>(makeString(key)); | ||||
|   } | ||||
|   // | ||||
|   // TValue get<TValue>(TKey) const; | ||||
| @@ -112,7 +115,7 @@ class JsonObject { | ||||
|   //          std::string, String, JsonArray, JsonObject | ||||
|   template <typename TValue, typename TString> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type get(TString* key) const { | ||||
|     return get_impl<TString*, TValue>(key); | ||||
|     return get_impl<TValue>(makeString(key)); | ||||
|   } | ||||
|  | ||||
|   // Checks the type of the value associated with the specified key. | ||||
| @@ -199,14 +202,14 @@ class JsonObject { | ||||
|   // TKey = const std::string&, const String& | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE void remove(const TString& key) { | ||||
|     remove_impl<const TString&>(key); | ||||
|     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) { | ||||
|     remove_impl<TString*>(key); | ||||
|     remove_impl(makeString(key)); | ||||
|   } | ||||
|  | ||||
|   // Sets the specified key with the specified value. | ||||
| @@ -247,12 +250,16 @@ class JsonObject { | ||||
|  | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE JsonVariant set(TString* key) { | ||||
|     return set_impl<TString*>(key); | ||||
|     return set_impl(makeString(key)); | ||||
|   } | ||||
|  | ||||
|   template <typename TString> | ||||
|   FORCE_INLINE JsonVariant set(const TString& key) { | ||||
|     return set_impl<const TString&>(key); | ||||
|     return set_impl(makeString(key)); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE JsonVariant set(const StringInMemoryPool& key) { | ||||
|     return set_impl(key); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE size_t size() const { | ||||
| @@ -281,7 +288,7 @@ class JsonObject { | ||||
|  private: | ||||
|   template <typename TStringRef> | ||||
|   FORCE_INLINE bool containsKey_impl(TStringRef key) const { | ||||
|     return findSlot<TStringRef>(key) != 0; | ||||
|     return findSlot(makeString(key)) != 0; | ||||
|   } | ||||
|  | ||||
|   template <typename TStringRef> | ||||
| @@ -296,34 +303,34 @@ class JsonObject { | ||||
|     if (!_data) return 0; | ||||
|     Slot* slot = _data->head; | ||||
|     while (slot) { | ||||
|       if (makeString(key).equals(slot->key)) break; | ||||
|       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<TStringRef>(key); | ||||
|     return const_cast<JsonObject*>(this)->findSlot(key); | ||||
|   } | ||||
|  | ||||
|   template <typename TStringRef, typename TValue> | ||||
|   template <typename TValue, typename TStringRef> | ||||
|   FORCE_INLINE typename JsonVariantAs<TValue>::type get_impl( | ||||
|       TStringRef key) const { | ||||
|     Slot* slot = findSlot<TStringRef>(key); | ||||
|     Slot* slot = findSlot(key); | ||||
|     return slot ? JsonVariant(_memoryPool, &slot->value).as<TValue>() | ||||
|                 : TValue(); | ||||
|   } | ||||
|  | ||||
|   template <typename TStringRef, typename TValue> | ||||
|   FORCE_INLINE bool is_impl(TStringRef key) const { | ||||
|     Slot* slot = findSlot<TStringRef>(key); | ||||
|     Slot* slot = findSlot(makeString(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<TStringRef>(key); | ||||
|     Slot* slot = findSlot(key); | ||||
|     if (!slot) return; | ||||
|     if (slot->prev) | ||||
|       slot->prev->next = slot->next; | ||||
| @@ -340,10 +347,10 @@ class JsonObject { | ||||
|     if (!_data) return JsonVariant(); | ||||
|  | ||||
|     // ignore null key | ||||
|     if (makeString(key).is_null()) return JsonVariant(); | ||||
|     if (key.isNull()) return JsonVariant(); | ||||
|  | ||||
|     // search a matching key | ||||
|     Slot* slot = findSlot<TStringRef>(key); | ||||
|     Slot* slot = findSlot(key); | ||||
|     if (!slot) { | ||||
|       // add the key | ||||
|       slot = new (_memoryPool) Slot(); | ||||
| @@ -367,20 +374,28 @@ class JsonObject { | ||||
|     return JsonVariant(_memoryPool, &slot->value); | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE bool set_key(Slot* slot, const char* key) { | ||||
|     slot->key = key; | ||||
|   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; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set_key(Slot* slot, const T& key) { | ||||
|     const char* dup = makeString(key).save(_memoryPool); | ||||
|     if (!dup) return false; | ||||
|     slot->key = dup; | ||||
|   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; | ||||
| };  // namespace ARDUINOJSON_NAMESPACE | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -8,19 +8,45 @@ | ||||
|  | ||||
| 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: | ||||
|   JsonPair(MemoryPool* memoryPool, Slot* slot) { | ||||
|   JsonPair(MemoryPool* memoryPool, Slot* slot) : _key(slot) { | ||||
|     if (slot) { | ||||
|       _key = slot->key; | ||||
|       _value = JsonVariant(memoryPool, &slot->value); | ||||
|     } else { | ||||
|       _key = 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   const char* key() const { | ||||
|   JsonKey key() const { | ||||
|     return _key; | ||||
|   } | ||||
|  | ||||
| @@ -29,7 +55,7 @@ class JsonPair { | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const char* _key; | ||||
|   JsonKey _key; | ||||
|   JsonVariant _value; | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -125,32 +125,14 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set(const T &value, | ||||
|                         typename enable_if<IsString<T>::value>::type * = 0) { | ||||
|     if (!_data) return false; | ||||
|     const char *dup = makeString(value).save(_memoryPool); | ||||
|     if (dup) { | ||||
|       _data->type = JSON_OWNED_STRING; | ||||
|       _data->content.asString = dup; | ||||
|       return true; | ||||
|     } else { | ||||
|       _data->type = JSON_NULL; | ||||
|       return false; | ||||
|     } | ||||
|     return setString(makeString(value)); | ||||
|   } | ||||
|  | ||||
|   // set(char*) | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool set(T *value, | ||||
|                         typename enable_if<IsString<T *>::value>::type * = 0) { | ||||
|     if (!_data) return false; | ||||
|     const char *dup = makeString(value).save(_memoryPool); | ||||
|     if (dup) { | ||||
|       _data->type = JSON_OWNED_STRING; | ||||
|       _data->content.asString = dup; | ||||
|       return true; | ||||
|     } else { | ||||
|       _data->type = JSON_NULL; | ||||
|       return false; | ||||
|     } | ||||
|     return setString(makeString(value)); | ||||
|   } | ||||
|  | ||||
|   // set(const char*); | ||||
| @@ -161,6 +143,14 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|     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); | ||||
| @@ -367,6 +357,20 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|   typename enable_if<is_same<T, JsonVariant>::value, JsonVariant>::type to(); | ||||
|  | ||||
|  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; | ||||
|   JsonVariantData *_data; | ||||
| }; | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Strings/StringInMemoryPool.hpp" | ||||
| #include "MemoryPool.hpp" | ||||
|  | ||||
| #include <stdlib.h> | ||||
| @@ -77,9 +78,9 @@ class DynamicMemoryPoolBase : public MemoryPool { | ||||
|     _head = 0; | ||||
|   } | ||||
|  | ||||
|   class String { | ||||
|   class StringBuilder { | ||||
|    public: | ||||
|     String(DynamicMemoryPoolBase* parent) | ||||
|     explicit StringBuilder(DynamicMemoryPoolBase* parent) | ||||
|         : _parent(parent), _start(NULL), _length(0) {} | ||||
|  | ||||
|     void append(char c) { | ||||
| @@ -97,7 +98,7 @@ class DynamicMemoryPoolBase : public MemoryPool { | ||||
|       _length++; | ||||
|     } | ||||
|  | ||||
|     const char* c_str() { | ||||
|     StringInMemoryPool complete() { | ||||
|       append(0); | ||||
|       return _start; | ||||
|     } | ||||
| @@ -108,8 +109,8 @@ class DynamicMemoryPoolBase : public MemoryPool { | ||||
|     size_t _length; | ||||
|   }; | ||||
|  | ||||
|   String startString() { | ||||
|     return String(this); | ||||
|   StringBuilder startString() { | ||||
|     return StringBuilder(this); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   | ||||
| @@ -5,15 +5,16 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../Polyfills/mpl/max.hpp" | ||||
| #include "../Strings/StringInMemoryPool.hpp" | ||||
| #include "MemoryPool.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class StaticMemoryPoolBase : public MemoryPool { | ||||
|  public: | ||||
|   class String { | ||||
|   class StringBuilder { | ||||
|    public: | ||||
|     String(StaticMemoryPoolBase* parent) : _parent(parent) { | ||||
|     explicit StringBuilder(StaticMemoryPoolBase* parent) : _parent(parent) { | ||||
|       _start = parent->_buffer + parent->_size; | ||||
|     } | ||||
|  | ||||
| @@ -24,7 +25,7 @@ class StaticMemoryPoolBase : public MemoryPool { | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     const char* c_str() const { | ||||
|     StringInMemoryPool complete() const { | ||||
|       if (_parent->canAlloc(1)) { | ||||
|         char* last = static_cast<char*>(_parent->doAlloc(1)); | ||||
|         *last = '\0'; | ||||
| @@ -65,8 +66,8 @@ class StaticMemoryPoolBase : public MemoryPool { | ||||
|     _size = 0; | ||||
|   } | ||||
|  | ||||
|   String startString() { | ||||
|     return String(this); | ||||
|   StringBuilder startString() { | ||||
|     return StringBuilder(this); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   | ||||
| @@ -15,6 +15,9 @@ namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <typename TReader, typename TStringStorage> | ||||
| class MsgPackDeserializer { | ||||
|   typedef typename remove_reference<TStringStorage>::type::StringBuilder | ||||
|       StringBuilder; | ||||
|  | ||||
|  public: | ||||
|   MsgPackDeserializer(MemoryPool &memoryPool, TReader reader, | ||||
|                       TStringStorage stringStorage, uint8_t nestingLimit) | ||||
| @@ -218,15 +221,14 @@ class MsgPackDeserializer { | ||||
|   } | ||||
|  | ||||
|   DeserializationError readString(JsonVariant variant, size_t n) { | ||||
|     typename remove_reference<TStringStorage>::type::String str = | ||||
|         _stringStorage.startString(); | ||||
|     StringBuilder str = _stringStorage.startString(); | ||||
|     for (; n; --n) { | ||||
|       uint8_t c; | ||||
|       if (!readBytes(c)) return DeserializationError::IncompleteInput; | ||||
|       str.append(static_cast<char>(c)); | ||||
|     } | ||||
|     const char *s = str.c_str(); | ||||
|     if (s == NULL) return DeserializationError::NoMemory; | ||||
|     StringInMemoryPool s = str.complete(); | ||||
|     if (s.isNull()) return DeserializationError::NoMemory; | ||||
|     variant.set(s); | ||||
|     return DeserializationError::Ok; | ||||
|   } | ||||
| @@ -281,7 +283,7 @@ class MsgPackDeserializer { | ||||
|       if (err) return err; | ||||
|       if (!key.is<char *>()) return DeserializationError::NotSupported; | ||||
|  | ||||
|       JsonVariant value = object.set(key.as<char *>()); | ||||
|       JsonVariant value = object.set(StringInMemoryPool(key.as<char *>())); | ||||
|       if (value.isInvalid()) return DeserializationError::NoMemory; | ||||
|  | ||||
|       err = parse(value); | ||||
|   | ||||
| @@ -11,9 +11,9 @@ class StringCopier { | ||||
|  public: | ||||
|   StringCopier(TMemoryPool& memoryPool) : _memoryPool(&memoryPool) {} | ||||
|  | ||||
|   typedef typename TMemoryPool::String String; | ||||
|   typedef typename TMemoryPool::StringBuilder StringBuilder; | ||||
|  | ||||
|   String startString() { | ||||
|   StringBuilder startString() { | ||||
|     return _memoryPool->startString(); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -9,15 +9,15 @@ namespace ARDUINOJSON_NAMESPACE { | ||||
| template <typename TChar> | ||||
| class StringMover { | ||||
|  public: | ||||
|   class String { | ||||
|   class StringBuilder { | ||||
|    public: | ||||
|     String(TChar** ptr) : _writePtr(ptr), _startPtr(*ptr) {} | ||||
|     StringBuilder(TChar** ptr) : _writePtr(ptr), _startPtr(*ptr) {} | ||||
|  | ||||
|     void append(char c) { | ||||
|       *(*_writePtr)++ = TChar(c); | ||||
|     } | ||||
|  | ||||
|     const char* c_str() const { | ||||
|     StringInMemoryPool complete() const { | ||||
|       *(*_writePtr)++ = 0; | ||||
|       return reinterpret_cast<const char*>(_startPtr); | ||||
|     } | ||||
| @@ -29,8 +29,8 @@ class StringMover { | ||||
|  | ||||
|   StringMover(TChar* ptr) : _ptr(ptr) {} | ||||
|  | ||||
|   String startString() { | ||||
|     return String(&_ptr); | ||||
|   StringBuilder startString() { | ||||
|     return StringBuilder(&_ptr); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   | ||||
| @@ -12,16 +12,16 @@ class ArduinoString { | ||||
|  public: | ||||
|   ArduinoString(const ::String& str) : _str(&str) {} | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* memoryPool) const { | ||||
|     if (is_null()) return NULL; | ||||
|   template <typename TMemoryPool> | ||||
|   const char* save(TMemoryPool* memoryPool) const { | ||||
|     if (isNull()) return NULL; | ||||
|     size_t n = _str->length() + 1; | ||||
|     void* dup = memoryPool->alloc(n); | ||||
|     if (dup != NULL) memcpy(dup, _str->c_str(), n); | ||||
|     return static_cast<const char*>(dup); | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|   bool isNull() const { | ||||
|     // Arduino's String::c_str() can return NULL | ||||
|     return !_str->c_str(); | ||||
|   } | ||||
|   | ||||
| @@ -17,12 +17,12 @@ class FixedSizeFlashString { | ||||
|     return strncmp_P(expected, actual, _size) == 0; | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|   bool isNull() const { | ||||
|     return !_str; | ||||
|   } | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* memoryPool) const { | ||||
|   template <typename TMemoryPool> | ||||
|   const char* save(TMemoryPool* memoryPool) const { | ||||
|     if (!_str) return NULL; | ||||
|     void* dup = memoryPool->alloc(_size); | ||||
|     if (dup != NULL) memcpy_P(dup, (const char*)_str, _size); | ||||
|   | ||||
| @@ -18,12 +18,12 @@ class FixedSizeRamString { | ||||
|     return strcmp(actual, expected) == 0; | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|   bool isNull() const { | ||||
|     return !_str; | ||||
|   } | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* memoryPool) const { | ||||
|   template <typename TMemoryPool> | ||||
|   const char* save(TMemoryPool* memoryPool) const { | ||||
|     if (!_str) return NULL; | ||||
|     void* dup = memoryPool->alloc(_size); | ||||
|     if (!dup) return NULL; | ||||
|   | ||||
| @@ -12,15 +12,15 @@ class StlString { | ||||
|  public: | ||||
|   StlString(const std::string& str) : _str(&str) {} | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* memoryPool) const { | ||||
|   template <typename TMemoryPool> | ||||
|   const char* save(TMemoryPool* memoryPool) const { | ||||
|     size_t n = _str->length() + 1; | ||||
|     void* dup = memoryPool->alloc(n); | ||||
|     if (dup != NULL) memcpy(dup, _str->c_str(), n); | ||||
|     return static_cast<const char*>(dup); | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|   bool isNull() const { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   | ||||
							
								
								
									
										16
									
								
								src/ArduinoJson/Strings/StringInMemoryPool.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/ArduinoJson/Strings/StringInMemoryPool.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "ZeroTerminatedRamStringConst.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class StringInMemoryPool : public ZeroTerminatedRamStringConst { | ||||
|  public: | ||||
|   StringInMemoryPool(const char* str = 0) : ZeroTerminatedRamStringConst(str) {} | ||||
| }; | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -18,7 +18,9 @@ struct IsString<T&> : IsString<T> {}; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|  | ||||
| #include "FixedSizeRamString.hpp" | ||||
| #include "StringInMemoryPool.hpp" | ||||
| #include "ZeroTerminatedRamString.hpp" | ||||
| #include "ZeroTerminatedRamStringConst.hpp" | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STRING | ||||
| #include "StlString.hpp" | ||||
|   | ||||
| @@ -16,12 +16,12 @@ class ZeroTerminatedFlashString { | ||||
|     return strcmp_P(expected, actual) == 0; | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|   bool isNull() const { | ||||
|     return !_str; | ||||
|   } | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* memoryPool) const { | ||||
|   template <typename TMemoryPool> | ||||
|   const char* save(TMemoryPool* memoryPool) const { | ||||
|     if (!_str) return NULL; | ||||
|     size_t n = size() + 1;  // copy the terminator | ||||
|     void* dup = memoryPool->alloc(n); | ||||
|   | ||||
| @@ -4,24 +4,17 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "ZeroTerminatedRamStringConst.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class ZeroTerminatedRamString { | ||||
| class ZeroTerminatedRamString : public ZeroTerminatedRamStringConst { | ||||
|  public: | ||||
|   ZeroTerminatedRamString(const char* str) : _str(str) {} | ||||
|   ZeroTerminatedRamString(const char* str) | ||||
|       : ZeroTerminatedRamStringConst(str) {} | ||||
|  | ||||
|   bool equals(const char* expected) const { | ||||
|     const char* actual = reinterpret_cast<const char*>(_str); | ||||
|     if (!actual || !expected) return actual == expected; | ||||
|     return strcmp(actual, expected) == 0; | ||||
|   } | ||||
|  | ||||
|   bool is_null() const { | ||||
|     return !_str; | ||||
|   } | ||||
|  | ||||
|   template <typename Buffer> | ||||
|   const char* save(Buffer* memoryPool) const { | ||||
|   template <typename TMemoryPool> | ||||
|   const char* save(TMemoryPool* memoryPool) const { | ||||
|     if (!_str) return NULL; | ||||
|     size_t n = size() + 1; | ||||
|     void* dup = memoryPool->alloc(n); | ||||
| @@ -29,13 +22,6 @@ class ZeroTerminatedRamString { | ||||
|     memcpy(dup, _str, n); | ||||
|     return static_cast<const char*>(dup); | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return strlen(reinterpret_cast<const char*>(_str)); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const char* _str; | ||||
| }; | ||||
|  | ||||
| template <typename TChar> | ||||
| @@ -43,6 +29,10 @@ inline ZeroTerminatedRamString makeString(const TChar* str) { | ||||
|   return ZeroTerminatedRamString(reinterpret_cast<const char*>(str)); | ||||
| } | ||||
|  | ||||
| inline ZeroTerminatedRamString makeString(char* str) { | ||||
|   return ZeroTerminatedRamString(str); | ||||
| } | ||||
|  | ||||
| template <typename TChar> | ||||
| struct IsString<TChar*> { | ||||
|   static const bool value = sizeof(TChar) == 1; | ||||
|   | ||||
							
								
								
									
										43
									
								
								src/ArduinoJson/Strings/ZeroTerminatedRamStringConst.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/ArduinoJson/Strings/ZeroTerminatedRamStringConst.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <stdlib.h>  // size_t | ||||
| #include <string.h>  // strcmp | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class ZeroTerminatedRamStringConst { | ||||
|  public: | ||||
|   ZeroTerminatedRamStringConst(const char* str) : _str(str) {} | ||||
|  | ||||
|   bool equals(const char* expected) const { | ||||
|     const char* actual = _str; | ||||
|     if (!actual || !expected) return actual == expected; | ||||
|     return strcmp(actual, expected) == 0; | ||||
|   } | ||||
|  | ||||
|   bool isNull() const { | ||||
|     return !_str; | ||||
|   } | ||||
|  | ||||
|   template <typename TMemoryPool> | ||||
|   const char* save(TMemoryPool*) const { | ||||
|     return _str; | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     return strlen(_str); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   const char* _str; | ||||
| }; | ||||
|  | ||||
| inline ZeroTerminatedRamStringConst makeString(const char* str) { | ||||
|   return ZeroTerminatedRamStringConst(str); | ||||
| } | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -17,6 +17,8 @@ struct NoMemoryAllocator { | ||||
| TEST_CASE("DynamicMemoryPool no memory") { | ||||
|   DynamicMemoryPoolBase<NoMemoryAllocator> _memoryPool; | ||||
|  | ||||
|   typedef DynamicMemoryPoolBase<NoMemoryAllocator>::StringBuilder StringBuilder; | ||||
|  | ||||
|   SECTION("FixCodeCoverage") { | ||||
|     // call this function to fix code coverage | ||||
|     NoMemoryAllocator().deallocate(NULL); | ||||
| @@ -33,9 +35,8 @@ TEST_CASE("DynamicMemoryPool no memory") { | ||||
|   // } | ||||
|  | ||||
|   SECTION("startString()") { | ||||
|     DynamicMemoryPoolBase<NoMemoryAllocator>::String str = | ||||
|         _memoryPool.startString(); | ||||
|     StringBuilder str = _memoryPool.startString(); | ||||
|     str.append('!'); | ||||
|     REQUIRE(0 == str.c_str()); | ||||
|     REQUIRE(str.complete().isNull()); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -7,43 +7,45 @@ | ||||
|  | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| typedef DynamicMemoryPool::StringBuilder StringBuilder; | ||||
|  | ||||
| TEST_CASE("DynamicMemoryPool::startString()") { | ||||
|   SECTION("WorksWhenBufferIsBigEnough") { | ||||
|     DynamicMemoryPool memoryPool(6); | ||||
|  | ||||
|     DynamicMemoryPool::String str = memoryPool.startString(); | ||||
|     StringBuilder str = memoryPool.startString(); | ||||
|     str.append('h'); | ||||
|     str.append('e'); | ||||
|     str.append('l'); | ||||
|     str.append('l'); | ||||
|     str.append('o'); | ||||
|  | ||||
|     REQUIRE(std::string("hello") == str.c_str()); | ||||
|     REQUIRE(str.complete().equals("hello")); | ||||
|   } | ||||
|  | ||||
|   SECTION("GrowsWhenBufferIsTooSmall") { | ||||
|     DynamicMemoryPool memoryPool(5); | ||||
|  | ||||
|     DynamicMemoryPool::String str = memoryPool.startString(); | ||||
|     StringBuilder str = memoryPool.startString(); | ||||
|     str.append('h'); | ||||
|     str.append('e'); | ||||
|     str.append('l'); | ||||
|     str.append('l'); | ||||
|     str.append('o'); | ||||
|  | ||||
|     REQUIRE(std::string("hello") == str.c_str()); | ||||
|     REQUIRE(str.complete().equals("hello")); | ||||
|   } | ||||
|  | ||||
|   SECTION("SizeIncreases") { | ||||
|     DynamicMemoryPool memoryPool(5); | ||||
|  | ||||
|     DynamicMemoryPool::String str = memoryPool.startString(); | ||||
|     StringBuilder str = memoryPool.startString(); | ||||
|     REQUIRE(0 == memoryPool.size()); | ||||
|  | ||||
|     str.append('h'); | ||||
|     REQUIRE(1 == memoryPool.size()); | ||||
|  | ||||
|     str.c_str(); | ||||
|     str.complete(); | ||||
|     REQUIRE(2 == memoryPool.size()); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  | ||||
| add_executable(JsonObjectTests  | ||||
| 	containsKey.cpp | ||||
| 	copy.cpp | ||||
| 	createNestedArray.cpp | ||||
| 	createNestedObject.cpp | ||||
| 	get.cpp | ||||
|   | ||||
							
								
								
									
										59
									
								
								test/JsonObject/copy.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								test/JsonObject/copy.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("JsonObject::copyFrom()") { | ||||
|   DynamicJsonDocument doc1; | ||||
|   DynamicJsonDocument doc2; | ||||
|  | ||||
|   JsonObject obj1 = doc1.to<JsonObject>(); | ||||
|   JsonObject obj2 = doc2.to<JsonObject>(); | ||||
|  | ||||
|   SECTION("doesn't copy static string in key or value") { | ||||
|     obj1["hello"] = "world"; | ||||
|  | ||||
|     obj2.copyFrom(obj1); | ||||
|  | ||||
|     REQUIRE(doc1.memoryUsage() == doc2.memoryUsage()); | ||||
|     REQUIRE(obj2["hello"] == std::string("world")); | ||||
|   } | ||||
|  | ||||
|   SECTION("copy local string value") { | ||||
|     obj1["hello"] = std::string("world"); | ||||
|  | ||||
|     obj2.copyFrom(obj1); | ||||
|  | ||||
|     REQUIRE(doc1.memoryUsage() == doc2.memoryUsage()); | ||||
|     REQUIRE(obj2["hello"] == std::string("world")); | ||||
|   } | ||||
|  | ||||
|   SECTION("copy local key") { | ||||
|     obj1[std::string("hello")] = "world"; | ||||
|  | ||||
|     obj2.copyFrom(obj1); | ||||
|  | ||||
|     REQUIRE(doc1.memoryUsage() == doc2.memoryUsage()); | ||||
|     REQUIRE(obj2["hello"] == std::string("world")); | ||||
|   } | ||||
|  | ||||
|   SECTION("copy string from deserializeJson()") { | ||||
|     deserializeJson(doc1, "{'hello':'world'}"); | ||||
|  | ||||
|     obj2.copyFrom(obj1); | ||||
|  | ||||
|     REQUIRE(doc1.memoryUsage() == doc2.memoryUsage()); | ||||
|     REQUIRE(obj2["hello"] == std::string("world")); | ||||
|   } | ||||
|  | ||||
|   SECTION("copy string from deserializeMsgPack()") { | ||||
|     deserializeMsgPack(doc1, "\x81\xA5hello\xA5world"); | ||||
|  | ||||
|     obj2.copyFrom(obj1); | ||||
|  | ||||
|     REQUIRE(doc1.memoryUsage() == doc2.memoryUsage()); | ||||
|     REQUIRE(obj2["hello"] == std::string("world")); | ||||
|   } | ||||
| } | ||||
| @@ -16,11 +16,11 @@ TEST_CASE("JsonObject::begin()/end()") { | ||||
|   SECTION("NonConstIterator") { | ||||
|     JsonObject::iterator it = obj.begin(); | ||||
|     REQUIRE(obj.end() != it); | ||||
|     REQUIRE_THAT(it->key(), Equals("ab")); | ||||
|     REQUIRE(it->key() == "ab"); | ||||
|     REQUIRE(12 == it->value()); | ||||
|     ++it; | ||||
|     REQUIRE(obj.end() != it); | ||||
|     REQUIRE_THAT(it->key(), Equals("cd")); | ||||
|     REQUIRE(it->key() == "cd"); | ||||
|     REQUIRE(34 == it->value()); | ||||
|     ++it; | ||||
|     REQUIRE(obj.end() == it); | ||||
| @@ -42,7 +42,7 @@ TEST_CASE("JsonObject::begin()/end()") { | ||||
|   // } | ||||
|  | ||||
|   SECTION("Dereferencing end() is safe") { | ||||
|     REQUIRE(obj.end()->key() == 0); | ||||
|     REQUIRE(obj.end()->key().isNull()); | ||||
|     REQUIRE(obj.end()->value().isNull()); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -13,21 +13,21 @@ TEST_CASE("JsonVariant::set(JsonVariant)") { | ||||
|  | ||||
|   SECTION("stores JsonArray by copy") { | ||||
|     JsonArray arr = doc2.to<JsonArray>(); | ||||
|  | ||||
|     arr.add(42); | ||||
|     var1.set(doc2.as<JsonVariant>()); | ||||
|     arr[0] = 666; | ||||
|  | ||||
|     var1.set(arr); | ||||
|  | ||||
|     arr[0] = 666; | ||||
|     REQUIRE(var1.as<std::string>() == "[42]"); | ||||
|   } | ||||
|  | ||||
|   SECTION("stores JsonObject by copy") { | ||||
|     JsonObject obj = doc2.to<JsonObject>(); | ||||
|  | ||||
|     obj["value"] = 42; | ||||
|     var1.set(doc2.as<JsonVariant>()); | ||||
|     obj["value"] = 666; | ||||
|  | ||||
|     var1.set(obj); | ||||
|  | ||||
|     obj["value"] = 666; | ||||
|     REQUIRE(var1.as<std::string>() == "{\"value\":42}"); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -8,42 +8,44 @@ | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| TEST_CASE("StaticMemoryPool::startString()") { | ||||
|   typedef StaticMemoryPoolBase::StringBuilder StringBuilder; | ||||
|  | ||||
|   SECTION("WorksWhenBufferIsBigEnough") { | ||||
|     StaticMemoryPool<6> memoryPool; | ||||
|  | ||||
|     StaticMemoryPoolBase::String str = memoryPool.startString(); | ||||
|     StringBuilder str = memoryPool.startString(); | ||||
|     str.append('h'); | ||||
|     str.append('e'); | ||||
|     str.append('l'); | ||||
|     str.append('l'); | ||||
|     str.append('o'); | ||||
|  | ||||
|     REQUIRE(std::string("hello") == str.c_str()); | ||||
|     REQUIRE(str.complete().equals("hello")); | ||||
|   } | ||||
|  | ||||
|   SECTION("ReturnsNullWhenTooSmall") { | ||||
|     StaticMemoryPool<5> memoryPool; | ||||
|  | ||||
|     StaticMemoryPoolBase::String str = memoryPool.startString(); | ||||
|     StringBuilder str = memoryPool.startString(); | ||||
|     str.append('h'); | ||||
|     str.append('e'); | ||||
|     str.append('l'); | ||||
|     str.append('l'); | ||||
|     str.append('o'); | ||||
|  | ||||
|     REQUIRE(0 == str.c_str()); | ||||
|     REQUIRE(str.complete().isNull()); | ||||
|   } | ||||
|  | ||||
|   SECTION("SizeIncreases") { | ||||
|     StaticMemoryPool<5> memoryPool; | ||||
|  | ||||
|     StaticMemoryPoolBase::String str = memoryPool.startString(); | ||||
|     StringBuilder str = memoryPool.startString(); | ||||
|     REQUIRE(0 == memoryPool.size()); | ||||
|  | ||||
|     str.append('h'); | ||||
|     REQUIRE(1 == memoryPool.size()); | ||||
|  | ||||
|     str.c_str(); | ||||
|     str.complete(); | ||||
|     REQUIRE(2 == memoryPool.size()); | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user