mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Reduced memory consumption by not duplicating spaces and comments
This commit is contained in:
		| @@ -5,6 +5,7 @@ HEAD | ||||
| ---- | ||||
|  | ||||
| * Added operator `==` to compare `JsonVariant` and strings (issue #402) | ||||
| * Reduced memory consumption by not duplicating spaces and comments | ||||
|  | ||||
| v5.7.3 | ||||
| ------ | ||||
|   | ||||
| @@ -1,115 +0,0 @@ | ||||
| // Copyright Benoit Blanchon 2014-2016 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../JsonBuffer.hpp" | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic push | ||||
| #pragma clang diagnostic ignored "-Wnon-virtual-dtor" | ||||
| #elif defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic push | ||||
| #endif | ||||
| #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" | ||||
| #endif | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| class DefaultAllocator { | ||||
|  public: | ||||
|   void* allocate(size_t size) { | ||||
|     return malloc(size); | ||||
|   } | ||||
|   void deallocate(void* pointer) { | ||||
|     free(pointer); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TAllocator> | ||||
| class BlockJsonBuffer : public JsonBuffer { | ||||
|   struct Block; | ||||
|   struct EmptyBlock { | ||||
|     Block* next; | ||||
|     size_t capacity; | ||||
|     size_t size; | ||||
|   }; | ||||
|   struct Block : EmptyBlock { | ||||
|     uint8_t data[1]; | ||||
|   }; | ||||
|  | ||||
|  public: | ||||
|   BlockJsonBuffer(size_t initialSize = 256) | ||||
|       : _head(NULL), _nextBlockSize(initialSize) {} | ||||
|  | ||||
|   ~BlockJsonBuffer() { | ||||
|     Block* currentBlock = _head; | ||||
|  | ||||
|     while (currentBlock != NULL) { | ||||
|       Block* nextBlock = currentBlock->next; | ||||
|       _allocator.deallocate(currentBlock); | ||||
|       currentBlock = nextBlock; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     size_t total = 0; | ||||
|     for (const Block* b = _head; b; b = b->next) total += b->size; | ||||
|     return total; | ||||
|   } | ||||
|  | ||||
|   virtual void* alloc(size_t bytes) { | ||||
|     return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   bool canAllocInHead(size_t bytes) const { | ||||
|     return _head != NULL && _head->size + bytes <= _head->capacity; | ||||
|   } | ||||
|  | ||||
|   void* allocInHead(size_t bytes) { | ||||
|     void* p = _head->data + _head->size; | ||||
|     _head->size += round_size_up(bytes); | ||||
|     return p; | ||||
|   } | ||||
|  | ||||
|   void* allocInNewBlock(size_t bytes) { | ||||
|     size_t capacity = _nextBlockSize; | ||||
|     if (bytes > capacity) capacity = bytes; | ||||
|     if (!addNewBlock(capacity)) return NULL; | ||||
|     _nextBlockSize *= 2; | ||||
|     return allocInHead(bytes); | ||||
|   } | ||||
|  | ||||
|   bool addNewBlock(size_t capacity) { | ||||
|     size_t bytes = sizeof(EmptyBlock) + capacity; | ||||
|     Block* block = static_cast<Block*>(_allocator.allocate(bytes)); | ||||
|     if (block == NULL) return false; | ||||
|     block->capacity = capacity; | ||||
|     block->size = 0; | ||||
|     block->next = _head; | ||||
|     _head = block; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   TAllocator _allocator; | ||||
|   Block* _head; | ||||
|   size_t _nextBlockSize; | ||||
| }; | ||||
| } | ||||
| } | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic pop | ||||
| #elif defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic pop | ||||
| #endif | ||||
| #endif | ||||
| @@ -30,6 +30,17 @@ template <typename TString> | ||||
| struct StringFuncs<TString&> : StringFuncs<TString> {}; | ||||
|  | ||||
| struct CharPtrFuncs { | ||||
|   class Iterator { | ||||
|     const char* _ptr; | ||||
|  | ||||
|    public: | ||||
|     Iterator(const char* ptr) : _ptr(ptr ? ptr : "") {} | ||||
|  | ||||
|     char next() { | ||||
|       return *_ptr++; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   static bool equals(const char* str, const char* expected) { | ||||
|     return strcmp(str, expected) == 0; | ||||
|   } | ||||
| @@ -71,6 +82,10 @@ struct StdStringFuncs { | ||||
|     return static_cast<char*>(dup); | ||||
|   } | ||||
|  | ||||
|   struct Iterator : CharPtrFuncs::Iterator { | ||||
|     Iterator(const TString& str) : CharPtrFuncs::Iterator(str.c_str()) {} | ||||
|   }; | ||||
|  | ||||
|   static bool equals(const TString& str, const char* expected) { | ||||
|     return str == expected; | ||||
|   } | ||||
| @@ -99,6 +114,18 @@ struct StringFuncs<std::string> : StdStringFuncs<std::string> {}; | ||||
| #if ARDUINOJSON_ENABLE_PROGMEM | ||||
| template <> | ||||
| struct StringFuncs<const __FlashStringHelper*> { | ||||
|   class Iterator { | ||||
|     const char* _ptr; | ||||
|  | ||||
|    public: | ||||
|     Iterator(const __FlashStringHelper* ptr) | ||||
|         : _ptr(reinterpret_cast<const char*>(ptr)) {} | ||||
|  | ||||
|     char next() { | ||||
|       return pgm_read_byte_near(_ptr++); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   static bool equals(const __FlashStringHelper* str, const char* expected) { | ||||
|     return strcmp_P(expected, (PGM_P)str) == 0; | ||||
|   } | ||||
|   | ||||
| @@ -12,51 +12,51 @@ namespace Internals { | ||||
| template <typename TInput> | ||||
| void skipSpacesAndComments(TInput& input) { | ||||
|   for (;;) { | ||||
|     switch (input.peek()) { | ||||
|     switch (input.current()) { | ||||
|       // spaces | ||||
|       case ' ': | ||||
|       case '\t': | ||||
|       case '\r': | ||||
|       case '\n': | ||||
|         input.skip(); | ||||
|         input.move(); | ||||
|         continue; | ||||
|  | ||||
|       // comments | ||||
|       case '/': | ||||
|         switch (input.peekNext()) { | ||||
|         switch (input.next()) { | ||||
|           // C-style block comment | ||||
|           case '*': | ||||
|             input.skip();  // skip '/' | ||||
|             input.skip();  // skip '*' | ||||
|             input.move();  // skip '/' | ||||
|             input.move();  // skip '*' | ||||
|             for (;;) { | ||||
|               switch (input.peek()) { | ||||
|               switch (input.current()) { | ||||
|                 case '\0': | ||||
|                   return; | ||||
|                 case '*': | ||||
|                   input.skip();  // skip '*' | ||||
|                   if (input.peek() == '/') { | ||||
|                     input.skip();  // skip '/' | ||||
|                   input.move();  // skip '*' | ||||
|                   if (input.current() == '/') { | ||||
|                     input.move();  // skip '/' | ||||
|                     return; | ||||
|                   } | ||||
|                   break; | ||||
|                 default: | ||||
|                   input.skip(); | ||||
|                   input.move(); | ||||
|               } | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|           // C++-style line comment | ||||
|           case '/': | ||||
|             input.skip();  // skip '/' | ||||
|             input.move();  // skip '/' | ||||
|             for (;;) { | ||||
|               switch (input.peek()) { | ||||
|               switch (input.current()) { | ||||
|                 case '\0': | ||||
|                   return; | ||||
|                 case '\n': | ||||
|                   input.skip(); | ||||
|                   input.move(); | ||||
|                   return; | ||||
|                 default: | ||||
|                   input.skip(); | ||||
|                   input.move(); | ||||
|               } | ||||
|             } | ||||
|             return; | ||||
|   | ||||
| @@ -18,12 +18,14 @@ namespace Internals { | ||||
| // Parse JSON string to create JsonArrays and JsonObjects | ||||
| // This internal class is not indended to be used directly. | ||||
| // Instead, use JsonBuffer.parseArray() or .parseObject() | ||||
| template <typename TReader, typename TWriter> | ||||
| class JsonParser { | ||||
|  public: | ||||
|   JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit) | ||||
|   JsonParser(JsonBuffer *buffer, TReader reader, TWriter writer, | ||||
|              uint8_t nestingLimit) | ||||
|       : _buffer(buffer), | ||||
|         _reader(json), | ||||
|         _writer(json), | ||||
|         _reader(reader), | ||||
|         _writer(writer), | ||||
|         _nestingLimit(nestingLimit) {} | ||||
|  | ||||
|   JsonArray &parseArray(); | ||||
| @@ -36,7 +38,9 @@ class JsonParser { | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   static bool eat(StringReader &, char charToSkip); | ||||
|   JsonParser &operator=(const JsonParser &);  // non-copiable | ||||
|  | ||||
|   static bool eat(TReader &, char charToSkip); | ||||
|   FORCE_INLINE bool eat(char charToSkip) { | ||||
|     return eat(_reader, charToSkip); | ||||
|   } | ||||
| @@ -63,9 +67,42 @@ class JsonParser { | ||||
|   } | ||||
|  | ||||
|   JsonBuffer *_buffer; | ||||
|   StringReader _reader; | ||||
|   StringWriter _writer; | ||||
|   TReader _reader; | ||||
|   TWriter _writer; | ||||
|   uint8_t _nestingLimit; | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TString> | ||||
| struct JsonParserBuilder { | ||||
|   typedef typename Internals::StringFuncs<TString>::Iterator InputIterator; | ||||
|   typedef JsonParser<StringReader<InputIterator>, TJsonBuffer &> TParser; | ||||
|  | ||||
|   static TParser makeParser(TJsonBuffer *buffer, const TString &json, | ||||
|                             uint8_t nestingLimit) { | ||||
|     return TParser(buffer, InputIterator(json), *buffer, nestingLimit); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer> | ||||
| struct JsonParserBuilder<TJsonBuffer, char *> { | ||||
|   typedef typename Internals::StringFuncs<char *>::Iterator InputIterator; | ||||
|   typedef JsonParser<StringReader<InputIterator>, StringWriter> TParser; | ||||
|  | ||||
|   static TParser makeParser(TJsonBuffer *buffer, char *json, | ||||
|                             uint8_t nestingLimit) { | ||||
|     return TParser(buffer, InputIterator(json), json, nestingLimit); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TChar, size_t N> | ||||
| struct JsonParserBuilder<TJsonBuffer, TChar[N]> | ||||
|     : JsonParserBuilder<TJsonBuffer, TChar *> {}; | ||||
|  | ||||
| template <typename TJsonBuffer, typename TString> | ||||
| inline typename JsonParserBuilder<TJsonBuffer, TString>::TParser makeParser( | ||||
|     TJsonBuffer *buffer, TString &json, uint8_t nestingLimit) { | ||||
|   return JsonParserBuilder<TJsonBuffer, TString>::makeParser(buffer, json, | ||||
|                                                              nestingLimit); | ||||
| } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -10,16 +10,19 @@ | ||||
| #include "Comments.hpp" | ||||
| #include "JsonParser.hpp" | ||||
|  | ||||
| inline bool ArduinoJson::Internals::JsonParser::eat(StringReader &reader, | ||||
|                                                     char charToSkip) { | ||||
| template <typename TReader, typename TWriter> | ||||
| inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::eat( | ||||
|     TReader &reader, char charToSkip) { | ||||
|   skipSpacesAndComments(reader); | ||||
|   if (reader.peek() != charToSkip) return false; | ||||
|   reader.skip(); | ||||
|   if (reader.current() != charToSkip) return false; | ||||
|   reader.move(); | ||||
|   skipSpacesAndComments(reader); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool ArduinoJson::Internals::JsonParser::parseAnythingTo( | ||||
| template <typename TReader, typename TWriter> | ||||
| inline bool | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo( | ||||
|     JsonVariant *destination) { | ||||
|   if (_nestingLimit == 0) return false; | ||||
|   _nestingLimit--; | ||||
| @@ -28,11 +31,13 @@ inline bool ArduinoJson::Internals::JsonParser::parseAnythingTo( | ||||
|   return success; | ||||
| } | ||||
|  | ||||
| inline bool ArduinoJson::Internals::JsonParser::parseAnythingToUnsafe( | ||||
| template <typename TReader, typename TWriter> | ||||
| inline bool | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingToUnsafe( | ||||
|     JsonVariant *destination) { | ||||
|   skipSpacesAndComments(_reader); | ||||
|  | ||||
|   switch (_reader.peek()) { | ||||
|   switch (_reader.current()) { | ||||
|     case '[': | ||||
|       return parseArrayTo(destination); | ||||
|  | ||||
| @@ -44,8 +49,9 @@ inline bool ArduinoJson::Internals::JsonParser::parseAnythingToUnsafe( | ||||
|   } | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonArray & | ||||
| ArduinoJson::Internals::JsonParser::parseArray() { | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray() { | ||||
|   // Create an empty array | ||||
|   JsonArray &array = _buffer->createArray(); | ||||
|  | ||||
| @@ -76,7 +82,8 @@ ERROR_NO_MEMORY: | ||||
|   return JsonArray::invalid(); | ||||
| } | ||||
|  | ||||
| inline bool ArduinoJson::Internals::JsonParser::parseArrayTo( | ||||
| template <typename TReader, typename TWriter> | ||||
| inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArrayTo( | ||||
|     JsonVariant *destination) { | ||||
|   JsonArray &array = parseArray(); | ||||
|   if (!array.success()) return false; | ||||
| @@ -85,8 +92,9 @@ inline bool ArduinoJson::Internals::JsonParser::parseArrayTo( | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonObject & | ||||
| ArduinoJson::Internals::JsonParser::parseObject() { | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject() { | ||||
|   // Create an empty object | ||||
|   JsonObject &object = _buffer->createObject(); | ||||
|  | ||||
| @@ -124,7 +132,8 @@ ERROR_NO_MEMORY: | ||||
|   return JsonObject::invalid(); | ||||
| } | ||||
|  | ||||
| inline bool ArduinoJson::Internals::JsonParser::parseObjectTo( | ||||
| template <typename TReader, typename TWriter> | ||||
| inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObjectTo( | ||||
|     JsonVariant *destination) { | ||||
|   JsonObject &object = parseObject(); | ||||
|   if (!object.success()) return false; | ||||
| @@ -133,46 +142,49 @@ inline bool ArduinoJson::Internals::JsonParser::parseObjectTo( | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline const char *ArduinoJson::Internals::JsonParser::parseString() { | ||||
|   const char *str = _writer.startString(); | ||||
| template <typename TReader, typename TWriter> | ||||
| inline const char * | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseString() { | ||||
|   typename TypeTraits::RemoveReference<TWriter>::type::String str = | ||||
|       _writer.startString(); | ||||
|  | ||||
|   char c = _reader.peek(); | ||||
|   char c = _reader.current(); | ||||
|  | ||||
|   if (isQuote(c)) {  // quotes | ||||
|     _reader.skip(); | ||||
|     _reader.move(); | ||||
|     char stopChar = c; | ||||
|     for (;;) { | ||||
|       c = _reader.peek(); | ||||
|       c = _reader.current(); | ||||
|       if (c == '\0') break; | ||||
|       _reader.skip(); | ||||
|       _reader.move(); | ||||
|  | ||||
|       if (c == stopChar) break; | ||||
|  | ||||
|       if (c == '\\') { | ||||
|         // replace char | ||||
|         c = Encoding::unescapeChar(_reader.peek()); | ||||
|         c = Encoding::unescapeChar(_reader.current()); | ||||
|         if (c == '\0') break; | ||||
|         _reader.skip(); | ||||
|         _reader.move(); | ||||
|       } | ||||
|  | ||||
|       _writer.append(c); | ||||
|       str.append(c); | ||||
|     } | ||||
|   } else {  // no quotes | ||||
|     for (;;) { | ||||
|       if (!isLetterOrNumber(c)) break; | ||||
|       _reader.skip(); | ||||
|       _writer.append(c); | ||||
|       c = _reader.peek(); | ||||
|       _reader.move(); | ||||
|       str.append(c); | ||||
|       c = _reader.current(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   _writer.stopString(); | ||||
|   return str; | ||||
|   return str.c_str(); | ||||
| } | ||||
|  | ||||
| inline bool ArduinoJson::Internals::JsonParser::parseStringTo( | ||||
| template <typename TReader, typename TWriter> | ||||
| inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseStringTo( | ||||
|     JsonVariant *destination) { | ||||
|   bool hasQuotes = isQuote(_reader.peek()); | ||||
|   bool hasQuotes = isQuote(_reader.current()); | ||||
|   const char *value = parseString(); | ||||
|   if (value == NULL) return false; | ||||
|   if (hasQuotes) { | ||||
|   | ||||
| @@ -13,24 +13,29 @@ namespace Internals { | ||||
| // Parse JSON string to create JsonArrays and JsonObjects | ||||
| // This internal class is not indended to be used directly. | ||||
| // Instead, use JsonBuffer.parseArray() or .parseObject() | ||||
| template <typename TIterator> | ||||
| class StringReader { | ||||
|   TIterator _input; | ||||
|   char _current, _next; | ||||
|  | ||||
|  public: | ||||
|   StringReader(const char *input) : _ptr(input ? input : "") {} | ||||
|  | ||||
|   void skip() { | ||||
|     _ptr++; | ||||
|   StringReader(const TIterator& input) : _input(input) { | ||||
|     _current = _input.next(); | ||||
|     _next = _input.next(); | ||||
|   } | ||||
|  | ||||
|   char peek() const { | ||||
|     return _ptr[0]; | ||||
|   void move() { | ||||
|     _current = _next; | ||||
|     _next = _input.next(); | ||||
|   } | ||||
|  | ||||
|   char peekNext() const { | ||||
|     return _ptr[1]; | ||||
|   char current() const { | ||||
|     return _current; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const char *_ptr; | ||||
|   char next() const { | ||||
|     return _next; | ||||
|   } | ||||
| }; | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -10,27 +10,34 @@ | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| // Parse JSON string to create JsonArrays and JsonObjects | ||||
| // This internal class is not indended to be used directly. | ||||
| // Instead, use JsonBuffer.parseArray() or .parseObject() | ||||
| class StringWriter { | ||||
|  public: | ||||
|   StringWriter(char *buffer) : _ptr(buffer) {} | ||||
|   class String { | ||||
|    public: | ||||
|     String(char** ptr) : _writePtr(ptr), _startPtr(*ptr) {} | ||||
|  | ||||
|   const char *startString() { | ||||
|     return _ptr; | ||||
|   } | ||||
|     void append(char c) { | ||||
|       *(*_writePtr)++ = c; | ||||
|     } | ||||
|  | ||||
|   void stopString() { | ||||
|     *_ptr++ = 0; | ||||
|   } | ||||
|     const char* c_str() const { | ||||
|       *(*_writePtr)++ = 0; | ||||
|       return _startPtr; | ||||
|     } | ||||
|  | ||||
|   void append(char c) { | ||||
|     *_ptr++ = c; | ||||
|    private: | ||||
|     char** _writePtr; | ||||
|     char* _startPtr; | ||||
|   }; | ||||
|  | ||||
|   StringWriter(char* buffer) : _ptr(buffer) {} | ||||
|  | ||||
|   String startString() { | ||||
|     return String(&_ptr); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   char *_ptr; | ||||
|   char* _ptr; | ||||
| }; | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -7,12 +7,153 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "Data/BlockJsonBuffer.hpp" | ||||
| #include "JsonBufferBase.hpp" | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic push | ||||
| #pragma clang diagnostic ignored "-Wnon-virtual-dtor" | ||||
| #elif defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic push | ||||
| #endif | ||||
| #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" | ||||
| #endif | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| class DefaultAllocator { | ||||
|  public: | ||||
|   void* allocate(size_t size) { | ||||
|     return malloc(size); | ||||
|   } | ||||
|   void deallocate(void* pointer) { | ||||
|     free(pointer); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TAllocator> | ||||
| class DynamicJsonBufferBase | ||||
|     : public JsonBufferBase<DynamicJsonBufferBase<TAllocator> > { | ||||
|   struct Block; | ||||
|   struct EmptyBlock { | ||||
|     Block* next; | ||||
|     size_t capacity; | ||||
|     size_t size; | ||||
|   }; | ||||
|   struct Block : EmptyBlock { | ||||
|     uint8_t data[1]; | ||||
|   }; | ||||
|  | ||||
|  public: | ||||
|   DynamicJsonBufferBase(size_t initialSize = 256) | ||||
|       : _head(NULL), _nextBlockCapacity(initialSize) {} | ||||
|  | ||||
|   ~DynamicJsonBufferBase() { | ||||
|     Block* currentBlock = _head; | ||||
|  | ||||
|     while (currentBlock != NULL) { | ||||
|       Block* nextBlock = currentBlock->next; | ||||
|       _allocator.deallocate(currentBlock); | ||||
|       currentBlock = nextBlock; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     size_t total = 0; | ||||
|     for (const Block* b = _head; b; b = b->next) total += b->size; | ||||
|     return total; | ||||
|   } | ||||
|  | ||||
|   virtual void* alloc(size_t bytes) { | ||||
|     alignNextAlloc(); | ||||
|     return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes); | ||||
|   } | ||||
|  | ||||
|   class String { | ||||
|    public: | ||||
|     String(DynamicJsonBufferBase* parent) | ||||
|         : _parent(parent), _start(NULL), _length(0) {} | ||||
|  | ||||
|     void append(char c) { | ||||
|       if (_parent->canAllocInHead(1)) { | ||||
|         char* end = static_cast<char*>(_parent->allocInHead(1)); | ||||
|         *end = c; | ||||
|         if (_length == 0) _start = end; | ||||
|       } else { | ||||
|         char* newStart = | ||||
|             static_cast<char*>(_parent->allocInNewBlock(_length + 1)); | ||||
|         if (_start && newStart) memcpy(newStart, _start, _length); | ||||
|         newStart[_length] = c; | ||||
|         _start = newStart; | ||||
|       } | ||||
|       _length++; | ||||
|     } | ||||
|  | ||||
|     const char* c_str() { | ||||
|       append(0); | ||||
|       return _start; | ||||
|     } | ||||
|  | ||||
|    private: | ||||
|     DynamicJsonBufferBase* _parent; | ||||
|     char* _start; | ||||
|     int _length; | ||||
|   }; | ||||
|  | ||||
|   String startString() { | ||||
|     return String(this); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   void alignNextAlloc() { | ||||
|     if (_head) _head->size = this->round_size_up(_head->size); | ||||
|   } | ||||
|  | ||||
|   bool canAllocInHead(size_t bytes) const { | ||||
|     return _head != NULL && _head->size + bytes <= _head->capacity; | ||||
|   } | ||||
|  | ||||
|   void* allocInHead(size_t bytes) { | ||||
|     void* p = _head->data + _head->size; | ||||
|     _head->size += bytes; | ||||
|     return p; | ||||
|   } | ||||
|  | ||||
|   void* allocInNewBlock(size_t bytes) { | ||||
|     size_t capacity = _nextBlockCapacity; | ||||
|     if (bytes > capacity) capacity = bytes; | ||||
|     if (!addNewBlock(capacity)) return NULL; | ||||
|     _nextBlockCapacity *= 2; | ||||
|     return allocInHead(bytes); | ||||
|   } | ||||
|  | ||||
|   bool addNewBlock(size_t capacity) { | ||||
|     size_t bytes = sizeof(EmptyBlock) + capacity; | ||||
|     Block* block = static_cast<Block*>(_allocator.allocate(bytes)); | ||||
|     if (block == NULL) return false; | ||||
|     block->capacity = capacity; | ||||
|     block->size = 0; | ||||
|     block->next = _head; | ||||
|     _head = block; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   TAllocator _allocator; | ||||
|   Block* _head; | ||||
|   size_t _nextBlockCapacity; | ||||
| }; | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic pop | ||||
| #elif defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic pop | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| // Implements a JsonBuffer with dynamic memory allocation. | ||||
| // You are strongly encouraged to consider using StaticJsonBuffer which is much | ||||
| // more suitable for embedded systems. | ||||
| typedef Internals::BlockJsonBuffer<Internals::DefaultAllocator> | ||||
|     DynamicJsonBuffer; | ||||
| typedef DynamicJsonBufferBase<DefaultAllocator> DynamicJsonBuffer; | ||||
| } | ||||
|   | ||||
| @@ -51,58 +51,6 @@ class JsonBuffer { | ||||
|   // allocation fails. | ||||
|   JsonObject &createObject(); | ||||
|  | ||||
|   // Allocates and populate a JsonArray from a JSON string. | ||||
|   // | ||||
|   // The First argument is a pointer to the JSON string, the memory must be | ||||
|   // writable | ||||
|   // because the parser will insert null-terminators and replace escaped chars. | ||||
|   // | ||||
|   // The second argument set the nesting limit | ||||
|   // | ||||
|   // Returns a reference to the new JsonObject or JsonObject::invalid() if the | ||||
|   // allocation fails. | ||||
|   JsonArray &parseArray( | ||||
|       char *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT); | ||||
|  | ||||
|   // With this overload, the JsonBuffer will make a copy of the string | ||||
|   template <typename TString> | ||||
|   JsonArray &parseArray(const TString &json, | ||||
|                         uint8_t nesting = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { | ||||
|     return parseArray(strdup(json), nesting); | ||||
|   } | ||||
|  | ||||
|   // Allocates and populate a JsonObject from a JSON string. | ||||
|   // | ||||
|   // The First argument is a pointer to the JSON string, the memory must be | ||||
|   // writable | ||||
|   // because the parser will insert null-terminators and replace escaped chars. | ||||
|   // | ||||
|   // The second argument set the nesting limit | ||||
|   // | ||||
|   // Returns a reference to the new JsonObject or JsonObject::invalid() if the | ||||
|   // allocation fails. | ||||
|   JsonObject &parseObject( | ||||
|       char *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT); | ||||
|  | ||||
|   // With this overload, the JsonBuffer will make a copy of the string | ||||
|   template <typename TString> | ||||
|   JsonObject &parseObject(const TString &json, | ||||
|                           uint8_t nesting = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { | ||||
|     return parseObject(strdup(json), nesting); | ||||
|   } | ||||
|  | ||||
|   // Generalized version of parseArray() and parseObject(), also works for | ||||
|   // integral types. | ||||
|   JsonVariant parse(char *json, | ||||
|                     uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT); | ||||
|  | ||||
|   // With this overload, the JsonBuffer will make a copy of the string | ||||
|   template <typename TString> | ||||
|   JsonVariant parse(const TString &json, | ||||
|                     uint8_t nesting = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { | ||||
|     return parse(strdup(json), nesting); | ||||
|   } | ||||
|  | ||||
|   // Duplicate a string | ||||
|   template <typename TString> | ||||
|   char *strdup(const TString &src) { | ||||
| @@ -114,7 +62,7 @@ class JsonBuffer { | ||||
|   virtual void *alloc(size_t size) = 0; | ||||
|  | ||||
|  protected: | ||||
|   // Preserve aligment if nessary | ||||
|   // Preserve aligment if necessary | ||||
|   static FORCE_INLINE size_t round_size_up(size_t bytes) { | ||||
| #if ARDUINOJSON_ENABLE_ALIGNMENT | ||||
|     const size_t x = sizeof(void *) - 1; | ||||
|   | ||||
							
								
								
									
										97
									
								
								include/ArduinoJson/JsonBufferBase.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								include/ArduinoJson/JsonBufferBase.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| // Copyright Benoit Blanchon 2014-2016 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "Deserialization/JsonParser.hpp" | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic push | ||||
| #pragma clang diagnostic ignored "-Wnon-virtual-dtor" | ||||
| #elif defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic push | ||||
| #endif | ||||
| #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" | ||||
| #endif | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| template <typename TDerived> | ||||
| class JsonBufferBase : public JsonBuffer { | ||||
|  public: | ||||
|   // Allocates and populate a JsonArray from a JSON string. | ||||
|   // | ||||
|   // The First argument is a pointer to the JSON string, the memory must be | ||||
|   // writable | ||||
|   // because the parser will insert null-terminators and replace escaped chars. | ||||
|   // | ||||
|   // The second argument set the nesting limit | ||||
|   // | ||||
|   // Returns a reference to the new JsonObject or JsonObject::invalid() if the | ||||
|   // allocation fails. | ||||
|   // With this overload, the JsonBuffer will make a copy of the string | ||||
|   template <typename TString> | ||||
|   JsonArray &parseArray( | ||||
|       const TString &json, | ||||
|       uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { | ||||
|     return Internals::makeParser(that(), json, nestingLimit).parseArray(); | ||||
|   } | ||||
|   template <typename TString> | ||||
|   JsonArray &parseArray( | ||||
|       TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { | ||||
|     return Internals::makeParser(that(), json, nestingLimit).parseArray(); | ||||
|   } | ||||
|  | ||||
|   // Allocates and populate a JsonObject from a JSON string. | ||||
|   // | ||||
|   // The First argument is a pointer to the JSON string, the memory must be | ||||
|   // writable | ||||
|   // because the parser will insert null-terminators and replace escaped chars. | ||||
|   // | ||||
|   // The second argument set the nesting limit | ||||
|   // | ||||
|   // Returns a reference to the new JsonObject or JsonObject::invalid() if the | ||||
|   // allocation fails. | ||||
|   template <typename TString> | ||||
|   JsonObject &parseObject( | ||||
|       const TString &json, | ||||
|       uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { | ||||
|     return Internals::makeParser(that(), json, nestingLimit).parseObject(); | ||||
|   } | ||||
|   template <typename TString> | ||||
|   JsonObject &parseObject( | ||||
|       TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { | ||||
|     return Internals::makeParser(that(), json, nestingLimit).parseObject(); | ||||
|   } | ||||
|  | ||||
|   // Generalized version of parseArray() and parseObject(), also works for | ||||
|   // integral types. | ||||
|   template <typename TString> | ||||
|   JsonVariant parse(const TString &json, | ||||
|                     uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { | ||||
|     return Internals::makeParser(that(), json, nestingLimit).parseVariant(); | ||||
|   } | ||||
|   template <typename TString> | ||||
|   JsonVariant parse(TString &json, | ||||
|                     uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { | ||||
|     return Internals::makeParser(that(), json, nestingLimit).parseVariant(); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   TDerived *that() { | ||||
|     return static_cast<TDerived *>(this); | ||||
|   } | ||||
| }; | ||||
| } | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic pop | ||||
| #elif defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic pop | ||||
| #endif | ||||
| #endif | ||||
| @@ -18,21 +18,3 @@ inline ArduinoJson::JsonObject &ArduinoJson::JsonBuffer::createObject() { | ||||
|   JsonObject *ptr = new (this) JsonObject(this); | ||||
|   return ptr ? *ptr : JsonObject::invalid(); | ||||
| } | ||||
|  | ||||
| inline ArduinoJson::JsonArray &ArduinoJson::JsonBuffer::parseArray( | ||||
|     char *json, uint8_t nestingLimit) { | ||||
|   Internals::JsonParser parser(this, json, nestingLimit); | ||||
|   return parser.parseArray(); | ||||
| } | ||||
|  | ||||
| inline ArduinoJson::JsonObject &ArduinoJson::JsonBuffer::parseObject( | ||||
|     char *json, uint8_t nestingLimit) { | ||||
|   Internals::JsonParser parser(this, json, nestingLimit); | ||||
|   return parser.parseObject(); | ||||
| } | ||||
|  | ||||
| inline ArduinoJson::JsonVariant ArduinoJson::JsonBuffer::parse( | ||||
|     char *json, uint8_t nestingLimit) { | ||||
|   Internals::JsonParser parser(this, json, nestingLimit); | ||||
|   return parser.parseVariant(); | ||||
| } | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "Internals/StringFuncs.hpp" | ||||
| #include "Data/StringFuncs.hpp" | ||||
| #include "JsonVariantBase.hpp" | ||||
| #include "TypeTraits/EnableIf.hpp" | ||||
|  | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "JsonBuffer.hpp" | ||||
| #include "JsonBufferBase.hpp" | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic push | ||||
| @@ -21,32 +21,87 @@ | ||||
|  | ||||
| namespace ArduinoJson { | ||||
|  | ||||
| // Implements a JsonBuffer with fixed memory allocation. | ||||
| // The template paramenter CAPACITY specifies the capacity of the buffer in | ||||
| // bytes. | ||||
| template <size_t CAPACITY> | ||||
| class StaticJsonBuffer : public JsonBuffer { | ||||
| class StaticJsonBufferBase : public JsonBufferBase<StaticJsonBufferBase> { | ||||
|  public: | ||||
|   explicit StaticJsonBuffer() : _size(0) {} | ||||
|   class String { | ||||
|    public: | ||||
|     String(StaticJsonBufferBase* parent) : _parent(parent) { | ||||
|       _start = parent->_buffer + parent->_size; | ||||
|     } | ||||
|  | ||||
|     void append(char c) { | ||||
|       if (_parent->canAlloc(1)) { | ||||
|         char* last = static_cast<char*>(_parent->doAlloc(1)); | ||||
|         *last = c; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     const char* c_str() const { | ||||
|       if (_parent->canAlloc(1)) { | ||||
|         char* last = static_cast<char*>(_parent->doAlloc(1)); | ||||
|         *last = '\0'; | ||||
|         return _start; | ||||
|       } else { | ||||
|         return NULL; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|    private: | ||||
|     StaticJsonBufferBase* _parent; | ||||
|     char* _start; | ||||
|   }; | ||||
|  | ||||
|   StaticJsonBufferBase(char* buffer, size_t capa) | ||||
|       : _buffer(buffer), _capacity(capa), _size(0) {} | ||||
|  | ||||
|   size_t capacity() const { | ||||
|     return CAPACITY; | ||||
|     return _capacity; | ||||
|   } | ||||
|   size_t size() const { | ||||
|     return _size; | ||||
|   } | ||||
|  | ||||
|   virtual void* alloc(size_t bytes) { | ||||
|     if (_size + bytes > CAPACITY) return NULL; | ||||
|     void* p = &_buffer[_size]; | ||||
|     _size += round_size_up(bytes); | ||||
|     return p; | ||||
|     alignNextAlloc(); | ||||
|     if (!canAlloc(bytes)) return NULL; | ||||
|     return doAlloc(bytes); | ||||
|   } | ||||
|  | ||||
|   String startString() { | ||||
|     return String(this); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   uint8_t _buffer[CAPACITY]; | ||||
|   void alignNextAlloc() { | ||||
|     _size = round_size_up(_size); | ||||
|   } | ||||
|  | ||||
|   bool canAlloc(size_t bytes) const { | ||||
|     return _size + bytes <= _capacity; | ||||
|   } | ||||
|  | ||||
|   void* doAlloc(size_t bytes) { | ||||
|     void* p = &_buffer[_size]; | ||||
|     _size += bytes; | ||||
|     return p; | ||||
|   } | ||||
|  | ||||
|   char* _buffer; | ||||
|   size_t _capacity; | ||||
|   size_t _size; | ||||
| }; | ||||
|  | ||||
| // Implements a JsonBuffer with fixed memory allocation. | ||||
| // The template paramenter CAPACITY specifies the capacity of the buffer in | ||||
| // bytes. | ||||
| template <size_t CAPACITY> | ||||
| class StaticJsonBuffer : public StaticJsonBufferBase { | ||||
|  public: | ||||
|   explicit StaticJsonBuffer() : StaticJsonBufferBase(_buffer, CAPACITY) {} | ||||
|  | ||||
|  private: | ||||
|   char _buffer[CAPACITY]; | ||||
| }; | ||||
| } | ||||
|  | ||||
| #if defined(__clang__) | ||||
|   | ||||
| @@ -30,13 +30,19 @@ TEST_F(DynamicJsonBuffer_Basic_Tests, ReturnDifferentPointer) { | ||||
|   ASSERT_NE(p1, p2); | ||||
| } | ||||
|  | ||||
| TEST_F(DynamicJsonBuffer_Basic_Tests, Alignment) { | ||||
|   size_t mask = sizeof(void*) - 1; | ||||
| static bool isAligned(void* ptr) { | ||||
|   const size_t mask = sizeof(void*) - 1; | ||||
|   size_t addr = reinterpret_cast<size_t>(ptr); | ||||
|   return (addr & mask) == 0; | ||||
| } | ||||
|  | ||||
|   for (size_t size = 1; size <= sizeof(void*); size++) { | ||||
|     size_t addr = reinterpret_cast<size_t>(buffer.alloc(1)); | ||||
|     ASSERT_EQ(0, addr & mask); | ||||
|   } | ||||
| TEST_F(DynamicJsonBuffer_Basic_Tests, Alignment) { | ||||
|   // make room for tow but not three | ||||
|   buffer = DynamicJsonBuffer(2 * sizeof(void*) + 1); | ||||
|  | ||||
|   ASSERT_TRUE(isAligned(buffer.alloc(1)));  // this on is aligned by design | ||||
|   ASSERT_TRUE(isAligned(buffer.alloc(1)));  // this one fits in the first block | ||||
|   ASSERT_TRUE(isAligned(buffer.alloc(1)));  // this one requires a new block | ||||
| } | ||||
|  | ||||
| TEST_F(DynamicJsonBuffer_Basic_Tests, strdup) { | ||||
|   | ||||
| @@ -5,18 +5,20 @@ | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <gtest/gtest.h> | ||||
|  | ||||
| class NoMemoryAllocator { | ||||
|  public: | ||||
|   void* allocate(size_t) { return NULL; } | ||||
|   void* allocate(size_t) { | ||||
|     return NULL; | ||||
|   } | ||||
|   void deallocate(void*) {} | ||||
| }; | ||||
|  | ||||
| class DynamicJsonBuffer_NoMemory_Tests : public ::testing::Test { | ||||
|  protected: | ||||
|   Internals::BlockJsonBuffer<NoMemoryAllocator> _jsonBuffer; | ||||
|   DynamicJsonBufferBase<NoMemoryAllocator> _jsonBuffer; | ||||
| }; | ||||
|  | ||||
| TEST_F(DynamicJsonBuffer_NoMemory_Tests, FixCodeCoverage) { | ||||
|   | ||||
							
								
								
									
										48
									
								
								test/DynamicJsonBuffer_String_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								test/DynamicJsonBuffer_String_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| // Copyright Benoit Blanchon 2014-2016 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <gtest/gtest.h> | ||||
|  | ||||
| TEST(DynamicJsonBuffer_String_Tests, WorksWhenBufferIsBigEnough) { | ||||
|   DynamicJsonBuffer jsonBuffer(6); | ||||
|  | ||||
|   DynamicJsonBuffer::String str = jsonBuffer.startString(); | ||||
|   str.append('h'); | ||||
|   str.append('e'); | ||||
|   str.append('l'); | ||||
|   str.append('l'); | ||||
|   str.append('o'); | ||||
|  | ||||
|   ASSERT_STREQ("hello", str.c_str()); | ||||
| } | ||||
|  | ||||
| TEST(DynamicJsonBuffer_String_Tests, GrowsWhenBufferIsTooSmall) { | ||||
|   DynamicJsonBuffer jsonBuffer(5); | ||||
|  | ||||
|   DynamicJsonBuffer::String str = jsonBuffer.startString(); | ||||
|   str.append('h'); | ||||
|   str.append('e'); | ||||
|   str.append('l'); | ||||
|   str.append('l'); | ||||
|   str.append('o'); | ||||
|  | ||||
|   ASSERT_STREQ("hello", str.c_str()); | ||||
| } | ||||
|  | ||||
| TEST(DynamicJsonBuffer_String_Tests, SizeIncreases) { | ||||
|   DynamicJsonBuffer jsonBuffer(5); | ||||
|  | ||||
|   DynamicJsonBuffer::String str = jsonBuffer.startString(); | ||||
|   ASSERT_EQ(0, jsonBuffer.size()); | ||||
|  | ||||
|   str.append('h'); | ||||
|   ASSERT_EQ(1, jsonBuffer.size()); | ||||
|  | ||||
|   str.c_str(); | ||||
|   ASSERT_EQ(2, jsonBuffer.size()); | ||||
| } | ||||
| @@ -5,12 +5,12 @@ | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <gtest/gtest.h> | ||||
|  | ||||
| class StaticJsonBuffer_ParseArray_Tests : public testing::Test { | ||||
|  protected: | ||||
|   void with(JsonBuffer& jsonBuffer) { | ||||
|   void with(StaticJsonBufferBase& jsonBuffer) { | ||||
|     _jsonBuffer = &jsonBuffer; | ||||
|   } | ||||
|  | ||||
| @@ -27,7 +27,7 @@ class StaticJsonBuffer_ParseArray_Tests : public testing::Test { | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonBuffer* _jsonBuffer; | ||||
|   StaticJsonBufferBase* _jsonBuffer; | ||||
|   char _jsonString[256]; | ||||
| }; | ||||
|  | ||||
| @@ -86,3 +86,11 @@ TEST_F(StaticJsonBuffer_ParseArray_Tests, ConstCharPtrNull) { | ||||
|                    .parseArray(static_cast<const char*>(0)) | ||||
|                    .success()); | ||||
| } | ||||
|  | ||||
| TEST_F(StaticJsonBuffer_ParseArray_Tests, CopyStringNotSpaces) { | ||||
|   StaticJsonBuffer<100> jsonBuffer; | ||||
|   jsonBuffer.parseArray("  [ \"1234567\" ] "); | ||||
|   ASSERT_EQ(JSON_ARRAY_SIZE(1) + sizeof("1234567"), jsonBuffer.size()); | ||||
|   // note we use a string of 8 bytes to be sure that the StaticJsonBuffer | ||||
|   // will not insert bytes to enforce alignement | ||||
| } | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|  | ||||
| class StaticJsonBuffer_ParseObject_Tests : public testing::Test { | ||||
|  protected: | ||||
|   void with(JsonBuffer& jsonBuffer) { | ||||
|   void with(StaticJsonBufferBase& jsonBuffer) { | ||||
|     _jsonBuffer = &jsonBuffer; | ||||
|   } | ||||
|  | ||||
| @@ -27,7 +27,7 @@ class StaticJsonBuffer_ParseObject_Tests : public testing::Test { | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   JsonBuffer* _jsonBuffer; | ||||
|   StaticJsonBufferBase* _jsonBuffer; | ||||
|   char _jsonString[256]; | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										48
									
								
								test/StaticJsonBuffer_String_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								test/StaticJsonBuffer_String_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| // Copyright Benoit Blanchon 2014-2016 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <gtest/gtest.h> | ||||
|  | ||||
| TEST(StaticJsonBuffer_String_Tests, WorksWhenBufferIsBigEnough) { | ||||
|   StaticJsonBuffer<6> jsonBuffer; | ||||
|  | ||||
|   StaticJsonBufferBase::String str = jsonBuffer.startString(); | ||||
|   str.append('h'); | ||||
|   str.append('e'); | ||||
|   str.append('l'); | ||||
|   str.append('l'); | ||||
|   str.append('o'); | ||||
|  | ||||
|   ASSERT_STREQ("hello", str.c_str()); | ||||
| } | ||||
|  | ||||
| TEST(StaticJsonBuffer_String_Tests, ReturnsNullWhenTooSmall) { | ||||
|   StaticJsonBuffer<5> jsonBuffer; | ||||
|  | ||||
|   StaticJsonBufferBase::String str = jsonBuffer.startString(); | ||||
|   str.append('h'); | ||||
|   str.append('e'); | ||||
|   str.append('l'); | ||||
|   str.append('l'); | ||||
|   str.append('o'); | ||||
|  | ||||
|   ASSERT_EQ(NULL, str.c_str()); | ||||
| } | ||||
|  | ||||
| TEST(StaticJsonBuffer_String_Tests, SizeIncreases) { | ||||
|   StaticJsonBuffer<5> jsonBuffer; | ||||
|  | ||||
|   StaticJsonBufferBase::String str = jsonBuffer.startString(); | ||||
|   ASSERT_EQ(0, jsonBuffer.size()); | ||||
|  | ||||
|   str.append('h'); | ||||
|   ASSERT_EQ(1, jsonBuffer.size()); | ||||
|  | ||||
|   str.c_str(); | ||||
|   ASSERT_EQ(2, jsonBuffer.size()); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user