mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Refactored StringBuilder into StringStorage
This commit is contained in:
		| @@ -525,7 +525,7 @@ TEST_CASE("Filtering") { | |||||||
|       10, |       10, | ||||||
|       DeserializationError::InvalidInput, |       DeserializationError::InvalidInput, | ||||||
|       "{}",  |       "{}",  | ||||||
|       JSON_OBJECT_SIZE(0) + 8 |       JSON_OBJECT_SIZE(0) | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       // incomplete comment after key |       // incomplete comment after key | ||||||
| @@ -534,7 +534,7 @@ TEST_CASE("Filtering") { | |||||||
|       10, |       10, | ||||||
|       DeserializationError::IncompleteInput, |       DeserializationError::IncompleteInput, | ||||||
|       "{}",  |       "{}",  | ||||||
|       JSON_OBJECT_SIZE(0) + 8 |       JSON_OBJECT_SIZE(0) | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       // invalid comment after colon |       // invalid comment after colon | ||||||
| @@ -730,20 +730,3 @@ TEST_CASE("Overloads") { | |||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST_CASE("StringMover::reclaim()") { |  | ||||||
|   StaticJsonDocument<200> filter; |  | ||||||
|   filter["a"] = true; |  | ||||||
|   filter["c"] = true; |  | ||||||
|   char input[] = "{\"a\":1,\"b\":2,\"c\":1}"; |  | ||||||
|  |  | ||||||
|   StaticJsonDocument<200> doc; |  | ||||||
|   deserializeJson(doc, input, DeserializationOption::Filter(filter)); |  | ||||||
|  |  | ||||||
|   REQUIRE(doc.as<std::string>() == "{\"a\":1,\"c\":1}"); |  | ||||||
|  |  | ||||||
|   CHECK(input[0] == 'a'); |  | ||||||
|   CHECK(input[1] == 0); |  | ||||||
|   CHECK(input[2] == 'c'); |  | ||||||
|   CHECK(input[3] == 0); |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ add_executable(MemoryPoolTests | |||||||
| 	allocString.cpp | 	allocString.cpp | ||||||
| 	clear.cpp | 	clear.cpp | ||||||
| 	size.cpp | 	size.cpp | ||||||
| 	StringBuilder.cpp | 	StringCopier.cpp | ||||||
| ) | ) | ||||||
|  |  | ||||||
| add_test(MemoryPool MemoryPoolTests) | add_test(MemoryPool MemoryPoolTests) | ||||||
|   | |||||||
| @@ -2,40 +2,44 @@ | |||||||
| // Copyright Benoit Blanchon 2014-2020
 | // Copyright Benoit Blanchon 2014-2020
 | ||||||
| // MIT License
 | // MIT License
 | ||||||
| 
 | 
 | ||||||
| #include <ArduinoJson/Memory/MemoryPool.hpp> | #include <ArduinoJson/StringStorage/StringCopier.hpp> | ||||||
| #include <ArduinoJson/Memory/StringBuilder.hpp> |  | ||||||
| #include <catch.hpp> | #include <catch.hpp> | ||||||
| 
 | 
 | ||||||
| using namespace ARDUINOJSON_NAMESPACE; | using namespace ARDUINOJSON_NAMESPACE; | ||||||
| 
 | 
 | ||||||
| TEST_CASE("StringBuilder") { | TEST_CASE("StringCopier") { | ||||||
|   char buffer[4096]; |   char buffer[4096]; | ||||||
| 
 | 
 | ||||||
|   SECTION("Works when buffer is big enough") { |   SECTION("Works when buffer is big enough") { | ||||||
|     MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6))); |     MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6))); | ||||||
|  |     StringCopier str; | ||||||
| 
 | 
 | ||||||
|     StringBuilder str(&pool); |     str.startString(&pool); | ||||||
|     str.append("hello"); |     str.append("hello"); | ||||||
|  |     str.append('\0'); | ||||||
| 
 | 
 | ||||||
|     REQUIRE(str.complete() == std::string("hello")); |     REQUIRE(str.isValid() == true); | ||||||
|  |     REQUIRE(str.c_str() == std::string("hello")); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   SECTION("Returns null when too small") { |   SECTION("Returns null when too small") { | ||||||
|     MemoryPool pool(buffer, sizeof(void*)); |     MemoryPool pool(buffer, sizeof(void*)); | ||||||
|  |     StringCopier str; | ||||||
| 
 | 
 | ||||||
|     StringBuilder str(&pool); |     str.startString(&pool); | ||||||
|     str.append("hello world!"); |     str.append("hello world!"); | ||||||
| 
 | 
 | ||||||
|     REQUIRE(str.complete() == 0); |     REQUIRE(str.isValid() == false); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   SECTION("Increases size of memory pool") { |   SECTION("Increases size of memory pool") { | ||||||
|     MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6))); |     MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6))); | ||||||
|  |     StringCopier str; | ||||||
| 
 | 
 | ||||||
|     StringBuilder str(&pool); |     str.startString(&pool); | ||||||
|     str.append('h'); |     str.append('h'); | ||||||
|     str.complete(); |     str.commit(&pool); | ||||||
| 
 | 
 | ||||||
|     REQUIRE(JSON_STRING_SIZE(1) == pool.size()); |     REQUIRE(1 == pool.size()); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -22,11 +22,6 @@ TEST_CASE("MemoryPool::size()") { | |||||||
|     REQUIRE(0 == pool.size()); |     REQUIRE(0 == pool.size()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   SECTION("size() == capacity() after allocExpandableString()") { |  | ||||||
|     pool.allocExpandableString(); |  | ||||||
|     REQUIRE(pool.size() == pool.capacity()); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   SECTION("Decreases after freezeString()") { |   SECTION("Decreases after freezeString()") { | ||||||
|     StringSlot a = pool.allocExpandableString(); |     StringSlot a = pool.allocExpandableString(); | ||||||
|     pool.freezeString(a, 1); |     pool.freezeString(a, 1); | ||||||
|   | |||||||
| @@ -12,12 +12,14 @@ using namespace ARDUINOJSON_NAMESPACE; | |||||||
| static void testCodepoint(uint32_t codepoint, std::string expected) { | static void testCodepoint(uint32_t codepoint, std::string expected) { | ||||||
|   char buffer[4096]; |   char buffer[4096]; | ||||||
|   MemoryPool pool(buffer, 4096); |   MemoryPool pool(buffer, 4096); | ||||||
|   StringBuilder str(&pool); |   StringCopier str; | ||||||
|  |   str.startString(&pool); | ||||||
|  |  | ||||||
|   CAPTURE(codepoint); |   CAPTURE(codepoint); | ||||||
|   Utf8::encodeCodepoint(codepoint, str); |   Utf8::encodeCodepoint(codepoint, str); | ||||||
|  |  | ||||||
|   REQUIRE(str.complete() == expected); |   str.append('\0'); | ||||||
|  |   REQUIRE(str.c_str() == expected); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST_CASE("Utf8::encodeCodepoint()") { | TEST_CASE("Utf8::encodeCodepoint()") { | ||||||
|   | |||||||
| @@ -32,9 +32,8 @@ deserialize(JsonDocument &doc, const TString &input, NestingLimit nestingLimit, | |||||||
|             TFilter filter) { |             TFilter filter) { | ||||||
|   Reader<TString> reader(input); |   Reader<TString> reader(input); | ||||||
|   doc.clear(); |   doc.clear(); | ||||||
|   return makeDeserializer<TDeserializer>( |   return makeDeserializer<TDeserializer>(doc.memoryPool(), reader, | ||||||
|              doc.memoryPool(), reader, |                                          makeStringStorage(input)) | ||||||
|              makeStringStorage(doc.memoryPool(), input)) |  | ||||||
|       .parse(doc.data(), filter, nestingLimit); |       .parse(doc.data(), filter, nestingLimit); | ||||||
| } | } | ||||||
| // | // | ||||||
| @@ -48,9 +47,8 @@ DeserializationError deserialize(JsonDocument &doc, TChar *input, | |||||||
|                                  TFilter filter) { |                                  TFilter filter) { | ||||||
|   BoundedReader<TChar *> reader(input, inputSize); |   BoundedReader<TChar *> reader(input, inputSize); | ||||||
|   doc.clear(); |   doc.clear(); | ||||||
|   return makeDeserializer<TDeserializer>( |   return makeDeserializer<TDeserializer>(doc.memoryPool(), reader, | ||||||
|              doc.memoryPool(), reader, |                                          makeStringStorage(input)) | ||||||
|              makeStringStorage(doc.memoryPool(), input)) |  | ||||||
|       .parse(doc.data(), filter, nestingLimit); |       .parse(doc.data(), filter, nestingLimit); | ||||||
| } | } | ||||||
| // | // | ||||||
| @@ -62,9 +60,8 @@ DeserializationError deserialize(JsonDocument &doc, TStream &input, | |||||||
|                                  NestingLimit nestingLimit, TFilter filter) { |                                  NestingLimit nestingLimit, TFilter filter) { | ||||||
|   Reader<TStream> reader(input); |   Reader<TStream> reader(input); | ||||||
|   doc.clear(); |   doc.clear(); | ||||||
|   return makeDeserializer<TDeserializer>( |   return makeDeserializer<TDeserializer>(doc.memoryPool(), reader, | ||||||
|              doc.memoryPool(), reader, |                                          makeStringStorage(input)) | ||||||
|              makeStringStorage(doc.memoryPool(), input)) |  | ||||||
|       .parse(doc.data(), filter, nestingLimit); |       .parse(doc.data(), filter, nestingLimit); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,22 +19,10 @@ namespace ARDUINOJSON_NAMESPACE { | |||||||
|  |  | ||||||
| template <typename TReader, typename TStringStorage> | template <typename TReader, typename TStringStorage> | ||||||
| class JsonDeserializer { | class JsonDeserializer { | ||||||
|   typedef typename remove_reference<TStringStorage>::type::StringBuilder |  | ||||||
|       StringBuilder; |  | ||||||
|  |  | ||||||
|   struct StringOrError { |  | ||||||
|     DeserializationError err; |  | ||||||
|     const char *value; |  | ||||||
|  |  | ||||||
|     StringOrError(DeserializationError e) : err(e) {} |  | ||||||
|     StringOrError(DeserializationError::Code c) : err(c) {} |  | ||||||
|     StringOrError(const char *s) : err(DeserializationError::Ok), value(s) {} |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   JsonDeserializer(MemoryPool &pool, TReader reader, |   JsonDeserializer(MemoryPool &pool, TReader reader, | ||||||
|                    TStringStorage stringStorage) |                    TStringStorage stringStorage) | ||||||
|       : _pool(&pool), _stringStorage(stringStorage), _latch(reader) {} |       : _stringStorage(stringStorage), _latch(reader), _pool(&pool) {} | ||||||
|  |  | ||||||
|   template <typename TFilter> |   template <typename TFilter> | ||||||
|   DeserializationError parse(VariantData &variant, TFilter filter, |   DeserializationError parse(VariantData &variant, TFilter filter, | ||||||
| @@ -224,9 +212,10 @@ class JsonDeserializer { | |||||||
|  |  | ||||||
|     // Read each key value pair |     // Read each key value pair | ||||||
|     for (;;) { |     for (;;) { | ||||||
|  |       _stringStorage.startString(_pool); | ||||||
|  |  | ||||||
|       // Parse key |       // Parse key | ||||||
|       StringOrError key = parseKey(); |       err = parseKey(); | ||||||
|       err = key.err;  // <- this trick saves 62 bytes on AVR |  | ||||||
|       if (err) |       if (err) | ||||||
|         return err; |         return err; | ||||||
|  |  | ||||||
| @@ -237,17 +226,21 @@ class JsonDeserializer { | |||||||
|       if (!eat(':')) |       if (!eat(':')) | ||||||
|         return DeserializationError::InvalidInput; |         return DeserializationError::InvalidInput; | ||||||
|  |  | ||||||
|       TFilter memberFilter = filter[key.value]; |       const char *key = _stringStorage.c_str(); | ||||||
|  |  | ||||||
|  |       TFilter memberFilter = filter[key]; | ||||||
|  |  | ||||||
|       if (memberFilter.allow()) { |       if (memberFilter.allow()) { | ||||||
|         VariantData *variant = object.getMember(adaptString(key.value)); |         VariantData *variant = object.getMember(adaptString(key)); | ||||||
|         if (!variant) { |         if (!variant) { | ||||||
|  |           _stringStorage.commit(_pool); | ||||||
|  |  | ||||||
|           // Allocate slot in object |           // Allocate slot in object | ||||||
|           VariantSlot *slot = object.addSlot(_pool); |           VariantSlot *slot = object.addSlot(_pool); | ||||||
|           if (!slot) |           if (!slot) | ||||||
|             return DeserializationError::NoMemory; |             return DeserializationError::NoMemory; | ||||||
|  |  | ||||||
|           slot->setOwnedKey(make_not_null(key.value)); |           slot->setOwnedKey(make_not_null(key)); | ||||||
|  |  | ||||||
|           variant = slot->data(); |           variant = slot->data(); | ||||||
|         } |         } | ||||||
| @@ -257,7 +250,6 @@ class JsonDeserializer { | |||||||
|         if (err) |         if (err) | ||||||
|           return err; |           return err; | ||||||
|       } else { |       } else { | ||||||
|         _stringStorage.reclaim(key.value); |  | ||||||
|         err = skipVariant(nestingLimit.decrement()); |         err = skipVariant(nestingLimit.decrement()); | ||||||
|         if (err) |         if (err) | ||||||
|           return err; |           return err; | ||||||
| @@ -332,7 +324,7 @@ class JsonDeserializer { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   StringOrError parseKey() { |   DeserializationError parseKey() { | ||||||
|     if (isQuote(current())) { |     if (isQuote(current())) { | ||||||
|       return parseQuotedString(); |       return parseQuotedString(); | ||||||
|     } else { |     } else { | ||||||
| @@ -341,15 +333,16 @@ class JsonDeserializer { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   DeserializationError parseStringValue(VariantData &variant) { |   DeserializationError parseStringValue(VariantData &variant) { | ||||||
|     StringOrError result = parseQuotedString(); |     _stringStorage.startString(_pool); | ||||||
|     if (result.err) |     DeserializationError err = parseQuotedString(); | ||||||
|       return result.err; |     if (err) | ||||||
|     variant.setOwnedString(make_not_null(result.value)); |       return err; | ||||||
|  |     _stringStorage.commit(_pool); | ||||||
|  |     variant.setOwnedString(make_not_null(_stringStorage.c_str())); | ||||||
|     return DeserializationError::Ok; |     return DeserializationError::Ok; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   StringOrError parseQuotedString() { |   DeserializationError parseQuotedString() { | ||||||
|     StringBuilder builder = _stringStorage.startString(); |  | ||||||
| #if ARDUINOJSON_DECODE_UNICODE | #if ARDUINOJSON_DECODE_UNICODE | ||||||
|     Utf16::Codepoint codepoint; |     Utf16::Codepoint codepoint; | ||||||
| #endif | #endif | ||||||
| @@ -377,7 +370,7 @@ class JsonDeserializer { | |||||||
|           if (err) |           if (err) | ||||||
|             return err; |             return err; | ||||||
|           if (codepoint.append(codeunit)) |           if (codepoint.append(codeunit)) | ||||||
|             Utf8::encodeCodepoint(codepoint.value(), builder); |             Utf8::encodeCodepoint(codepoint.value(), _stringStorage); | ||||||
|           continue; |           continue; | ||||||
| #else | #else | ||||||
|           return DeserializationError::NotSupported; |           return DeserializationError::NotSupported; | ||||||
| @@ -390,35 +383,37 @@ class JsonDeserializer { | |||||||
|         move(); |         move(); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       builder.append(c); |       _stringStorage.append(c); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const char *result = builder.complete(); |     _stringStorage.append('\0'); | ||||||
|     if (!result) |  | ||||||
|  |     if (!_stringStorage.isValid()) | ||||||
|       return DeserializationError::NoMemory; |       return DeserializationError::NoMemory; | ||||||
|     return result; |  | ||||||
|  |     return DeserializationError::Ok; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   StringOrError parseNonQuotedString() { |   DeserializationError parseNonQuotedString() { | ||||||
|     StringBuilder builder = _stringStorage.startString(); |  | ||||||
|  |  | ||||||
|     char c = current(); |     char c = current(); | ||||||
|     ARDUINOJSON_ASSERT(c); |     ARDUINOJSON_ASSERT(c); | ||||||
|  |  | ||||||
|     if (canBeInNonQuotedString(c)) {  // no quotes |     if (canBeInNonQuotedString(c)) {  // no quotes | ||||||
|       do { |       do { | ||||||
|         move(); |         move(); | ||||||
|         builder.append(c); |         _stringStorage.append(c); | ||||||
|         c = current(); |         c = current(); | ||||||
|       } while (canBeInNonQuotedString(c)); |       } while (canBeInNonQuotedString(c)); | ||||||
|     } else { |     } else { | ||||||
|       return DeserializationError::InvalidInput; |       return DeserializationError::InvalidInput; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const char *result = builder.complete(); |     _stringStorage.append('\0'); | ||||||
|     if (!result) |  | ||||||
|  |     if (!_stringStorage.isValid()) | ||||||
|       return DeserializationError::NoMemory; |       return DeserializationError::NoMemory; | ||||||
|     return result; |  | ||||||
|  |     return DeserializationError::Ok; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   DeserializationError skipString() { |   DeserializationError skipString() { | ||||||
| @@ -597,9 +592,9 @@ class JsonDeserializer { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   MemoryPool *_pool; |  | ||||||
|   TStringStorage _stringStorage; |   TStringStorage _stringStorage; | ||||||
|   Latch<TReader> _latch; |   Latch<TReader> _latch; | ||||||
|  |   MemoryPool *_pool; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // deserializeJson(JsonDocument&, const std::string&, ...) | // deserializeJson(JsonDocument&, const std::string&, ...) | ||||||
|   | |||||||
| @@ -77,21 +77,16 @@ class MemoryPool { | |||||||
|     StringSlot s; |     StringSlot s; | ||||||
|     s.value = _left; |     s.value = _left; | ||||||
|     s.size = size_t(_right - _left); |     s.size = size_t(_right - _left); | ||||||
|     _left = _right; |  | ||||||
|     checkInvariants(); |     checkInvariants(); | ||||||
|     return s; |     return s; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void freezeString(StringSlot& s, size_t newSize) { |   void freezeString(StringSlot& s, size_t newSize) { | ||||||
|     _left -= (s.size - newSize); |     _left = (s.value + newSize); | ||||||
|     s.size = newSize; |     s.size = newSize; | ||||||
|     checkInvariants(); |     checkInvariants(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void reclaimLastString(const char* s) { |  | ||||||
|     _left = const_cast<char*>(s); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void clear() { |   void clear() { | ||||||
|     _left = _begin; |     _left = _begin; | ||||||
|     _right = _end; |     _right = _end; | ||||||
|   | |||||||
| @@ -1,51 +0,0 @@ | |||||||
| // ArduinoJson - arduinojson.org |  | ||||||
| // Copyright Benoit Blanchon 2014-2020 |  | ||||||
| // MIT License |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include <ArduinoJson/Memory/MemoryPool.hpp> |  | ||||||
|  |  | ||||||
| namespace ARDUINOJSON_NAMESPACE { |  | ||||||
|  |  | ||||||
| class StringBuilder { |  | ||||||
|  public: |  | ||||||
|   explicit StringBuilder(MemoryPool* parent) : _parent(parent), _size(0) { |  | ||||||
|     _slot = _parent->allocExpandableString(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void append(const char* s) { |  | ||||||
|     while (*s) append(*s++); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void append(const char* s, size_t n) { |  | ||||||
|     while (n-- > 0) append(*s++); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void append(char c) { |  | ||||||
|     if (!_slot.value) |  | ||||||
|       return; |  | ||||||
|  |  | ||||||
|     if (_size >= _slot.size) { |  | ||||||
|       _slot.value = 0; |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     _slot.value[_size++] = c; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   char* complete() { |  | ||||||
|     append('\0'); |  | ||||||
|     if (_slot.value) { |  | ||||||
|       _parent->freezeString(_slot, _size); |  | ||||||
|     } |  | ||||||
|     return _slot.value; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  private: |  | ||||||
|   MemoryPool* _parent; |  | ||||||
|   size_t _size; |  | ||||||
|   StringSlot _slot; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| }  // namespace ARDUINOJSON_NAMESPACE |  | ||||||
| @@ -15,9 +15,6 @@ namespace ARDUINOJSON_NAMESPACE { | |||||||
|  |  | ||||||
| template <typename TReader, typename TStringStorage> | template <typename TReader, typename TStringStorage> | ||||||
| class MsgPackDeserializer { | class MsgPackDeserializer { | ||||||
|   typedef typename remove_reference<TStringStorage>::type::StringBuilder |  | ||||||
|       StringBuilder; |  | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   MsgPackDeserializer(MemoryPool &pool, TReader reader, |   MsgPackDeserializer(MemoryPool &pool, TReader reader, | ||||||
|                       TStringStorage stringStorage) |                       TStringStorage stringStorage) | ||||||
| @@ -241,16 +238,18 @@ class MsgPackDeserializer { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   DeserializationError readString(const char *&result, size_t n) { |   DeserializationError readString(const char *&result, size_t n) { | ||||||
|     StringBuilder builder = _stringStorage.startString(); |     _stringStorage.startString(_pool); | ||||||
|     for (; n; --n) { |     for (; n; --n) { | ||||||
|       uint8_t c; |       uint8_t c; | ||||||
|       if (!readBytes(c)) |       if (!readBytes(c)) | ||||||
|         return DeserializationError::IncompleteInput; |         return DeserializationError::IncompleteInput; | ||||||
|       builder.append(static_cast<char>(c)); |       _stringStorage.append(static_cast<char>(c)); | ||||||
|     } |     } | ||||||
|     result = builder.complete(); |     _stringStorage.append('\0'); | ||||||
|     if (!result) |     if (!_stringStorage.isValid()) | ||||||
|       return DeserializationError::NoMemory; |       return DeserializationError::NoMemory; | ||||||
|  |     _stringStorage.commit(_pool); | ||||||
|  |     result = _stringStorage.c_str(); | ||||||
|     return DeserializationError::Ok; |     return DeserializationError::Ok; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,25 +5,51 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <ArduinoJson/Memory/MemoryPool.hpp> | #include <ArduinoJson/Memory/MemoryPool.hpp> | ||||||
| #include <ArduinoJson/Memory/StringBuilder.hpp> |  | ||||||
|  |  | ||||||
| namespace ARDUINOJSON_NAMESPACE { | namespace ARDUINOJSON_NAMESPACE { | ||||||
|  |  | ||||||
| class StringCopier { | class StringCopier { | ||||||
|  public: |  public: | ||||||
|   typedef ARDUINOJSON_NAMESPACE::StringBuilder StringBuilder; |   void startString(MemoryPool* pool) { | ||||||
|  |     _slot = pool->allocExpandableString(); | ||||||
|   StringCopier(MemoryPool* pool) : _pool(pool) {} |     _size = 0; | ||||||
|  |  | ||||||
|   StringBuilder startString() { |  | ||||||
|     return StringBuilder(_pool); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void reclaim(const char* s) { |   void commit(MemoryPool* pool) { | ||||||
|     _pool->reclaimLastString(s); |     ARDUINOJSON_ASSERT(_slot.value); | ||||||
|  |     pool->freezeString(_slot, _size); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void append(const char* s) { | ||||||
|  |     while (*s) append(*s++); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void append(const char* s, size_t n) { | ||||||
|  |     while (n-- > 0) append(*s++); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void append(char c) { | ||||||
|  |     if (!_slot.value) | ||||||
|  |       return; | ||||||
|  |  | ||||||
|  |     if (_size >= _slot.size) { | ||||||
|  |       _slot.value = 0; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _slot.value[_size++] = c; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool isValid() { | ||||||
|  |     return _slot.value != 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const char* c_str() { | ||||||
|  |     return _slot.value; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   MemoryPool* _pool; |   size_t _size; | ||||||
|  |   StringSlot _slot; | ||||||
| }; | }; | ||||||
| }  // namespace ARDUINOJSON_NAMESPACE | }  // namespace ARDUINOJSON_NAMESPACE | ||||||
|   | |||||||
| @@ -10,36 +10,28 @@ namespace ARDUINOJSON_NAMESPACE { | |||||||
|  |  | ||||||
| class StringMover { | class StringMover { | ||||||
|  public: |  public: | ||||||
|   class StringBuilder { |   StringMover(char* ptr) : _writePtr(ptr) {} | ||||||
|    public: |  | ||||||
|     StringBuilder(char** ptr) : _writePtr(ptr), _startPtr(*ptr) {} |  | ||||||
|  |  | ||||||
|     void append(char c) { |   void startString(MemoryPool*) { | ||||||
|       *(*_writePtr)++ = char(c); |     _startPtr = _writePtr; | ||||||
|     } |  | ||||||
|  |  | ||||||
|     char* complete() const { |  | ||||||
|       *(*_writePtr)++ = 0; |  | ||||||
|       return _startPtr; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|    private: |  | ||||||
|     char** _writePtr; |  | ||||||
|     char* _startPtr; |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   StringMover(char* ptr) : _ptr(ptr) {} |  | ||||||
|  |  | ||||||
|   StringBuilder startString() { |  | ||||||
|     return StringBuilder(&_ptr); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // recover memory from last string |   void commit(MemoryPool*) const {} | ||||||
|   void reclaim(const char* str) { |  | ||||||
|     _ptr = const_cast<char*>(str); |   void append(char c) { | ||||||
|  |     *_writePtr++ = c; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool isValid() const { | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const char* c_str() const { | ||||||
|  |     return _startPtr; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   char* _ptr; |   char* _writePtr; | ||||||
|  |   char* _startPtr; | ||||||
| }; | }; | ||||||
| }  // namespace ARDUINOJSON_NAMESPACE | }  // namespace ARDUINOJSON_NAMESPACE | ||||||
|   | |||||||
| @@ -13,8 +13,8 @@ template <typename TInput, typename Enable = void> | |||||||
| struct StringStorage { | struct StringStorage { | ||||||
|   typedef StringCopier type; |   typedef StringCopier type; | ||||||
|  |  | ||||||
|   static type create(MemoryPool& pool, TInput&) { |   static type create(TInput&) { | ||||||
|     return type(&pool); |     return type(); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -23,20 +23,18 @@ struct StringStorage<TChar*, | |||||||
|                      typename enable_if<!is_const<TChar>::value>::type> { |                      typename enable_if<!is_const<TChar>::value>::type> { | ||||||
|   typedef StringMover type; |   typedef StringMover type; | ||||||
|  |  | ||||||
|   static type create(MemoryPool&, TChar* input) { |   static type create(TChar* input) { | ||||||
|     return type(reinterpret_cast<char*>(input)); |     return type(reinterpret_cast<char*>(input)); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename TInput> | template <typename TInput> | ||||||
| typename StringStorage<TInput>::type makeStringStorage(MemoryPool& pool, | typename StringStorage<TInput>::type makeStringStorage(TInput& input) { | ||||||
|                                                        TInput& input) { |   return StringStorage<TInput>::create(input); | ||||||
|   return StringStorage<TInput>::create(pool, input); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename TChar> | template <typename TChar> | ||||||
| typename StringStorage<TChar*>::type makeStringStorage(MemoryPool& pool, | typename StringStorage<TChar*>::type makeStringStorage(TChar* input) { | ||||||
|                                                        TChar* input) { |   return StringStorage<TChar*>::create(input); | ||||||
|   return StringStorage<TChar*>::create(pool, input); |  | ||||||
| } | } | ||||||
| }  // namespace ARDUINOJSON_NAMESPACE | }  // namespace ARDUINOJSON_NAMESPACE | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user