Reduced stack usage when compiled with -Og (issue #1210)

This saves 128 bytes on ESP8266
This commit is contained in:
Benoit Blanchon
2020-07-26 14:51:58 +02:00
parent 51b177ce47
commit d6c50c3596

View File

@ -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>