mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Reduced stack usage when compiled with -Og (issue #1210)
This saves 128 bytes on ESP8266
This commit is contained in:
		| @@ -18,28 +18,34 @@ class MsgPackDeserializer { | |||||||
|  public: |  public: | ||||||
|   MsgPackDeserializer(MemoryPool &pool, TReader reader, |   MsgPackDeserializer(MemoryPool &pool, TReader reader, | ||||||
|                       TStringStorage stringStorage) |                       TStringStorage stringStorage) | ||||||
|       : _pool(&pool), _reader(reader), _stringStorage(stringStorage) {} |       : _pool(&pool), | ||||||
|  |         _reader(reader), | ||||||
|  |         _stringStorage(stringStorage), | ||||||
|  |         _error(DeserializationError::Ok) {} | ||||||
|  |  | ||||||
|   // TODO: add support for filter |   // TODO: add support for filter | ||||||
|   DeserializationError parse(VariantData &variant, AllowAllFilter, |   DeserializationError parse(VariantData &variant, AllowAllFilter, | ||||||
|                              NestingLimit nestingLimit) { |                              NestingLimit nestingLimit) { | ||||||
|     return parse(variant, nestingLimit); |     parseVariant(variant, nestingLimit); | ||||||
|  |     return _error; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   DeserializationError parse(VariantData &variant, NestingLimit nestingLimit) { |  private: | ||||||
|  |   bool parseVariant(VariantData &variant, NestingLimit nestingLimit) { | ||||||
|     uint8_t code; |     uint8_t code; | ||||||
|     if (!readByte(code)) |     if (!readByte(code)) { | ||||||
|       return DeserializationError::IncompleteInput; |       _error = DeserializationError::IncompleteInput; | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if ((code & 0x80) == 0) { |     if ((code & 0x80) == 0) { | ||||||
|       variant.setUnsignedInteger(code); |       variant.setUnsignedInteger(code); | ||||||
|       return DeserializationError::Ok; |       return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if ((code & 0xe0) == 0xe0) { |     if ((code & 0xe0) == 0xe0) { | ||||||
|       // TODO: add setNegativeInteger() |  | ||||||
|       variant.setSignedInteger(static_cast<int8_t>(code)); |       variant.setSignedInteger(static_cast<int8_t>(code)); | ||||||
|       return DeserializationError::Ok; |       return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if ((code & 0xe0) == 0xa0) { |     if ((code & 0xe0) == 0xa0) { | ||||||
| @@ -57,15 +63,15 @@ class MsgPackDeserializer { | |||||||
|     switch (code) { |     switch (code) { | ||||||
|       case 0xc0: |       case 0xc0: | ||||||
|         // already null |         // already null | ||||||
|         return DeserializationError::Ok; |         return true; | ||||||
|  |  | ||||||
|       case 0xc2: |       case 0xc2: | ||||||
|         variant.setBoolean(false); |         variant.setBoolean(false); | ||||||
|         return DeserializationError::Ok; |         return true; | ||||||
|  |  | ||||||
|       case 0xc3: |       case 0xc3: | ||||||
|         variant.setBoolean(true); |         variant.setBoolean(true); | ||||||
|         return DeserializationError::Ok; |         return true; | ||||||
|  |  | ||||||
|       case 0xcc: |       case 0xcc: | ||||||
|         return readInteger<uint8_t>(variant); |         return readInteger<uint8_t>(variant); | ||||||
| @@ -76,11 +82,9 @@ class MsgPackDeserializer { | |||||||
|       case 0xce: |       case 0xce: | ||||||
|         return readInteger<uint32_t>(variant); |         return readInteger<uint32_t>(variant); | ||||||
|  |  | ||||||
|       case 0xcf: |  | ||||||
| #if ARDUINOJSON_USE_LONG_LONG | #if ARDUINOJSON_USE_LONG_LONG | ||||||
|  |       case 0xcf: | ||||||
|         return readInteger<uint64_t>(variant); |         return readInteger<uint64_t>(variant); | ||||||
| #else |  | ||||||
|         return DeserializationError::NotSupported; |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|       case 0xd0: |       case 0xd0: | ||||||
| @@ -92,11 +96,9 @@ class MsgPackDeserializer { | |||||||
|       case 0xd2: |       case 0xd2: | ||||||
|         return readInteger<int32_t>(variant); |         return readInteger<int32_t>(variant); | ||||||
|  |  | ||||||
|       case 0xd3: |  | ||||||
| #if ARDUINOJSON_USE_LONG_LONG | #if ARDUINOJSON_USE_LONG_LONG | ||||||
|  |       case 0xd3: | ||||||
|         return readInteger<int64_t>(variant); |         return readInteger<int64_t>(variant); | ||||||
| #else |  | ||||||
|         return DeserializationError::NotSupported; |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|       case 0xca: |       case 0xca: | ||||||
| @@ -127,7 +129,8 @@ class MsgPackDeserializer { | |||||||
|         return readObject<uint32_t>(variant.toObject(), nestingLimit); |         return readObject<uint32_t>(variant.toObject(), nestingLimit); | ||||||
|  |  | ||||||
|       default: |       default: | ||||||
|         return DeserializationError::NotSupported; |         _error = DeserializationError::NotSupported; | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -137,14 +140,19 @@ class MsgPackDeserializer { | |||||||
|  |  | ||||||
|   bool readByte(uint8_t &value) { |   bool readByte(uint8_t &value) { | ||||||
|     int c = _reader.read(); |     int c = _reader.read(); | ||||||
|     if (c < 0) |     if (c < 0) { | ||||||
|  |       _error = DeserializationError::IncompleteInput; | ||||||
|       return false; |       return false; | ||||||
|  |     } | ||||||
|     value = static_cast<uint8_t>(c); |     value = static_cast<uint8_t>(c); | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   bool readBytes(uint8_t *p, size_t n) { |   bool readBytes(uint8_t *p, size_t n) { | ||||||
|     return _reader.readBytes(reinterpret_cast<char *>(p), n) == n; |     if (_reader.readBytes(reinterpret_cast<char *>(p), n) == n) | ||||||
|  |       return true; | ||||||
|  |     _error = DeserializationError::IncompleteInput; | ||||||
|  |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename T> |   template <typename T> | ||||||
| @@ -152,14 +160,6 @@ class MsgPackDeserializer { | |||||||
|     return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value)); |     return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename T> |  | ||||||
|   T readInteger() { |  | ||||||
|     T value; |  | ||||||
|     readBytes(value); |  | ||||||
|     fixEndianess(value); |  | ||||||
|     return value; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   template <typename T> |   template <typename T> | ||||||
|   bool readInteger(T &value) { |   bool readInteger(T &value) { | ||||||
|     if (!readBytes(value)) |     if (!readBytes(value)) | ||||||
| @@ -169,155 +169,159 @@ class MsgPackDeserializer { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename T> |   template <typename T> | ||||||
|   DeserializationError readInteger(VariantData &variant) { |   bool readInteger(VariantData &variant) { | ||||||
|     T value; |     T value; | ||||||
|     if (!readInteger(value)) |     if (!readInteger(value)) | ||||||
|       return DeserializationError::IncompleteInput; |       return false; | ||||||
|     variant.setInteger(value); |     variant.setInteger(value); | ||||||
|     return DeserializationError::Ok; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename T> |   template <typename T> | ||||||
|   typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat( |   typename enable_if<sizeof(T) == 4, bool>::type readFloat( | ||||||
|       VariantData &variant) { |       VariantData &variant) { | ||||||
|     T value; |     T value; | ||||||
|     if (!readBytes(value)) |     if (!readBytes(value)) | ||||||
|       return DeserializationError::IncompleteInput; |       return false; | ||||||
|     fixEndianess(value); |     fixEndianess(value); | ||||||
|     variant.setFloat(value); |     variant.setFloat(value); | ||||||
|     return DeserializationError::Ok; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename T> |   template <typename T> | ||||||
|   typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble( |   typename enable_if<sizeof(T) == 8, bool>::type readDouble( | ||||||
|       VariantData &variant) { |       VariantData &variant) { | ||||||
|     T value; |     T value; | ||||||
|     if (!readBytes(value)) |     if (!readBytes(value)) | ||||||
|       return DeserializationError::IncompleteInput; |       return false; | ||||||
|     fixEndianess(value); |     fixEndianess(value); | ||||||
|     variant.setFloat(value); |     variant.setFloat(value); | ||||||
|     return DeserializationError::Ok; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename T> |   template <typename T> | ||||||
|   typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble( |   typename enable_if<sizeof(T) == 4, bool>::type readDouble( | ||||||
|       VariantData &variant) { |       VariantData &variant) { | ||||||
|     uint8_t i[8];  // input is 8 bytes |     uint8_t i[8];  // input is 8 bytes | ||||||
|     T value;       // output is 4 bytes |     T value;       // output is 4 bytes | ||||||
|     uint8_t *o = reinterpret_cast<uint8_t *>(&value); |     uint8_t *o = reinterpret_cast<uint8_t *>(&value); | ||||||
|     if (!readBytes(i, 8)) |     if (!readBytes(i, 8)) | ||||||
|       return DeserializationError::IncompleteInput; |       return false; | ||||||
|     doubleToFloat(i, o); |     doubleToFloat(i, o); | ||||||
|     fixEndianess(value); |     fixEndianess(value); | ||||||
|     variant.setFloat(value); |     variant.setFloat(value); | ||||||
|     return DeserializationError::Ok; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename T> |   template <typename T> | ||||||
|   DeserializationError readString(VariantData &variant) { |   bool readString(VariantData &variant) { | ||||||
|     T size; |     T size; | ||||||
|     if (!readInteger(size)) |     if (!readInteger(size)) | ||||||
|       return DeserializationError::IncompleteInput; |       return false; | ||||||
|     return readString(variant, size); |     return readString(variant, size); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename T> |   template <typename T> | ||||||
|   DeserializationError readString(const char *&str) { |   bool readString(const char *&str) { | ||||||
|     T size; |     T size; | ||||||
|     if (!readInteger(size)) |     if (!readInteger(size)) | ||||||
|       return DeserializationError::IncompleteInput; |       return false; | ||||||
|     return readString(str, size); |     return readString(str, size); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   DeserializationError readString(VariantData &variant, size_t n) { |   bool readString(VariantData &variant, size_t n) { | ||||||
|     const char *s = 0;  // <- mute "maybe-uninitialized" (+4 bytes on AVR) |     const char *s = 0;  // <- mute "maybe-uninitialized" (+4 bytes on AVR) | ||||||
|     DeserializationError err = readString(s, n); |     if (!readString(s, n)) | ||||||
|     if (!err) |       return false; | ||||||
|       variant.setString(make_not_null(s), |     variant.setString(make_not_null(s), | ||||||
|                         typename TStringStorage::storage_policy()); |                       typename TStringStorage::storage_policy()); | ||||||
|     return err; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   DeserializationError readString(const char *&result, size_t n) { |   bool readString(const char *&result, size_t n) { | ||||||
|     _stringStorage.startString(_pool); |     _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 false; | ||||||
|       _stringStorage.append(static_cast<char>(c)); |       _stringStorage.append(static_cast<char>(c)); | ||||||
|     } |     } | ||||||
|     _stringStorage.append('\0'); |     _stringStorage.append('\0'); | ||||||
|     if (!_stringStorage.isValid()) |     if (!_stringStorage.isValid()) { | ||||||
|       return DeserializationError::NoMemory; |       _error = DeserializationError::NoMemory; | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     result = _stringStorage.save(_pool); |     result = _stringStorage.save(_pool); | ||||||
|     return DeserializationError::Ok; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename TSize> |   template <typename TSize> | ||||||
|   DeserializationError readArray(CollectionData &array, |   bool readArray(CollectionData &array, NestingLimit nestingLimit) { | ||||||
|                                  NestingLimit nestingLimit) { |  | ||||||
|     TSize size; |     TSize size; | ||||||
|     if (!readInteger(size)) |     if (!readInteger(size)) | ||||||
|       return DeserializationError::IncompleteInput; |       return false; | ||||||
|     return readArray(array, size, nestingLimit); |     return readArray(array, size, nestingLimit); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   DeserializationError readArray(CollectionData &array, size_t n, |   bool readArray(CollectionData &array, size_t n, NestingLimit nestingLimit) { | ||||||
|                                  NestingLimit nestingLimit) { |     if (nestingLimit.reached()) { | ||||||
|     if (nestingLimit.reached()) |       _error = DeserializationError::TooDeep; | ||||||
|       return DeserializationError::TooDeep; |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     for (; n; --n) { |     for (; n; --n) { | ||||||
|       VariantData *value = array.addElement(_pool); |       VariantData *value = array.addElement(_pool); | ||||||
|       if (!value) |       if (!value) { | ||||||
|         return DeserializationError::NoMemory; |         _error = DeserializationError::NoMemory; | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  |  | ||||||
|       DeserializationError err = parse(*value, nestingLimit.decrement()); |       if (!parseVariant(*value, nestingLimit.decrement())) | ||||||
|       if (err) |         return false; | ||||||
|         return err; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return DeserializationError::Ok; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename TSize> |   template <typename TSize> | ||||||
|   DeserializationError readObject(CollectionData &object, |   bool readObject(CollectionData &object, NestingLimit nestingLimit) { | ||||||
|                                   NestingLimit nestingLimit) { |  | ||||||
|     TSize size; |     TSize size; | ||||||
|     if (!readInteger(size)) |     if (!readInteger(size)) | ||||||
|       return DeserializationError::IncompleteInput; |       return false; | ||||||
|     return readObject(object, size, nestingLimit); |     return readObject(object, size, nestingLimit); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   DeserializationError readObject(CollectionData &object, size_t n, |   bool readObject(CollectionData &object, size_t n, NestingLimit nestingLimit) { | ||||||
|                                   NestingLimit nestingLimit) { |     if (nestingLimit.reached()) { | ||||||
|     if (nestingLimit.reached()) |       _error = DeserializationError::TooDeep; | ||||||
|       return DeserializationError::TooDeep; |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     for (; n; --n) { |     for (; n; --n) { | ||||||
|       VariantSlot *slot = object.addSlot(_pool); |       VariantSlot *slot = object.addSlot(_pool); | ||||||
|       if (!slot) |       if (!slot) { | ||||||
|         return DeserializationError::NoMemory; |         _error = DeserializationError::NoMemory; | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  |  | ||||||
|       const char *key = 0;  // <- mute "maybe-uninitialized" (+4 bytes on AVR) |       const char *key = 0;  // <- mute "maybe-uninitialized" (+4 bytes on AVR) | ||||||
|       DeserializationError err = parseKey(key); |       if (!parseKey(key)) | ||||||
|       if (err) |         return false; | ||||||
|         return err; |  | ||||||
|       slot->setKey(key, typename TStringStorage::storage_policy()); |       slot->setKey(key, typename TStringStorage::storage_policy()); | ||||||
|  |  | ||||||
|       err = parse(*slot->data(), nestingLimit.decrement()); |       if (!parseVariant(*slot->data(), nestingLimit.decrement())) | ||||||
|       if (err) |         return false; | ||||||
|         return err; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return DeserializationError::Ok; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   DeserializationError parseKey(const char *&key) { |   bool parseKey(const char *&key) { | ||||||
|     uint8_t code; |     uint8_t code; | ||||||
|     if (!readByte(code)) |     if (!readByte(code)) | ||||||
|       return DeserializationError::IncompleteInput; |       return false; | ||||||
|  |  | ||||||
|     if ((code & 0xe0) == 0xa0) |     if ((code & 0xe0) == 0xa0) | ||||||
|       return readString(key, code & 0x1f); |       return readString(key, code & 0x1f); | ||||||
| @@ -333,13 +337,15 @@ class MsgPackDeserializer { | |||||||
|         return readString<uint32_t>(key); |         return readString<uint32_t>(key); | ||||||
|  |  | ||||||
|       default: |       default: | ||||||
|         return DeserializationError::NotSupported; |         _error = DeserializationError::NotSupported; | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   MemoryPool *_pool; |   MemoryPool *_pool; | ||||||
|   TReader _reader; |   TReader _reader; | ||||||
|   TStringStorage _stringStorage; |   TStringStorage _stringStorage; | ||||||
|  |   DeserializationError _error; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename TInput> | template <typename TInput> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user