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