Optimize deserializeMsgPack()

This commit is contained in:
Benoit Blanchon
2024-05-01 17:58:51 +02:00
parent 82de20ee14
commit 4d074840da
5 changed files with 627 additions and 693 deletions

View File

@ -4,6 +4,7 @@ ArduinoJson: change log
* Add `ARDUINOJSON_STRING_LENGTH_SIZE` to the namespace name * Add `ARDUINOJSON_STRING_LENGTH_SIZE` to the namespace name
* Add MsgPack bin8/bin16/bin32 support (PR #2078 by @Sanae6) * Add MsgPack bin8/bin16/bin32 support (PR #2078 by @Sanae6)
* Make string support even more generic (PR #2084 by @d-a-v) * Make string support even more generic (PR #2084 by @d-a-v)
* Optimize `deserializeMsgPack()`
v7.0.4 (2024-03-12) v7.0.4 (2024-03-12)
------ ------

View File

@ -228,12 +228,12 @@ TEST_CASE("deserializeMsgPack() under memory constaints") {
checkError(0, "\x80", DeserializationError::Ok); checkError(0, "\x80", DeserializationError::Ok);
} }
SECTION("{H:1}") { SECTION("{H:1}") {
checkError(0, "\x81\xA1H\x01", DeserializationError::NoMemory); checkError(1, "\x81\xA1H\x01", DeserializationError::NoMemory);
checkError(3, "\x81\xA1H\x01", DeserializationError::Ok); checkError(2, "\x81\xA1H\x01", DeserializationError::Ok);
} }
SECTION("{H:1,W:2}") { SECTION("{H:1,W:2}") {
checkError(3, "\x82\xA1H\x01\xA1W\x02", DeserializationError::NoMemory); checkError(2, "\x82\xA1H\x01\xA1W\x02", DeserializationError::NoMemory);
checkError(5, "\x82\xA1H\x01\xA1W\x02", DeserializationError::Ok); checkError(3, "\x82\xA1H\x01\xA1W\x02", DeserializationError::Ok);
} }
} }
@ -242,13 +242,13 @@ TEST_CASE("deserializeMsgPack() under memory constaints") {
checkError(0, "\xDE\x00\x00", DeserializationError::Ok); checkError(0, "\xDE\x00\x00", DeserializationError::Ok);
} }
SECTION("{H:1}") { SECTION("{H:1}") {
checkError(2, "\xDE\x00\x01\xA1H\x01", DeserializationError::NoMemory); checkError(1, "\xDE\x00\x01\xA1H\x01", DeserializationError::NoMemory);
checkError(3, "\xDE\x00\x01\xA1H\x01", DeserializationError::Ok); checkError(2, "\xDE\x00\x01\xA1H\x01", DeserializationError::Ok);
} }
SECTION("{H:1,W:2}") { SECTION("{H:1,W:2}") {
checkError(3, "\xDE\x00\x02\xA1H\x01\xA1W\x02", checkError(2, "\xDE\x00\x02\xA1H\x01\xA1W\x02",
DeserializationError::NoMemory); DeserializationError::NoMemory);
checkError(5, "\xDE\x00\x02\xA1H\x01\xA1W\x02", DeserializationError::Ok); checkError(3, "\xDE\x00\x02\xA1H\x01\xA1W\x02", DeserializationError::Ok);
} }
} }
@ -257,14 +257,14 @@ TEST_CASE("deserializeMsgPack() under memory constaints") {
checkError(0, "\xDF\x00\x00\x00\x00", DeserializationError::Ok); checkError(0, "\xDF\x00\x00\x00\x00", DeserializationError::Ok);
} }
SECTION("{H:1}") { SECTION("{H:1}") {
checkError(2, "\xDF\x00\x00\x00\x01\xA1H\x01", checkError(1, "\xDF\x00\x00\x00\x01\xA1H\x01",
DeserializationError::NoMemory); DeserializationError::NoMemory);
checkError(3, "\xDF\x00\x00\x00\x01\xA1H\x01", DeserializationError::Ok); checkError(2, "\xDF\x00\x00\x00\x01\xA1H\x01", DeserializationError::Ok);
} }
SECTION("{H:1,W:2}") { SECTION("{H:1,W:2}") {
checkError(3, "\xDF\x00\x00\x00\x02\xA1H\x01\xA1W\x02", checkError(2, "\xDF\x00\x00\x00\x02\xA1H\x01\xA1W\x02",
DeserializationError::NoMemory); DeserializationError::NoMemory);
checkError(5, "\xDF\x00\x00\x00\x02\xA1H\x01\xA1W\x02", checkError(3, "\xDF\x00\x00\x00\x02\xA1H\x01\xA1W\x02",
DeserializationError::Ok); DeserializationError::Ok);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/ResourceManager.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class StringBuffer {
public:
StringBuffer(ResourceManager* resources) : resources_(resources) {}
~StringBuffer() {
if (node_)
resources_->destroyString(node_);
}
char* reserve(size_t capacity) {
if (node_ && capacity > node_->length) {
// existing buffer is too small, we need to reallocate
resources_->destroyString(node_);
node_ = nullptr;
}
if (!node_)
node_ = resources_->createString(capacity);
if (!node_)
return nullptr;
size_ = capacity;
node_->data[capacity] = 0; // null-terminate the string
return node_->data;
}
StringNode* save() {
ARDUINOJSON_ASSERT(node_ != nullptr);
node_->data[size_] = 0;
auto node = resources_->getString(adaptString(node_->data, size_));
if (node) {
node->references++;
return node;
}
if (node_->length != size_) {
node = resources_->resizeString(node_, size_);
ARDUINOJSON_ASSERT(node != nullptr); // realloc to smaller can't fail
} else {
node = node_;
}
node_ = nullptr;
resources_->saveString(node);
return node;
}
JsonString str() const {
ARDUINOJSON_ASSERT(node_ != nullptr);
return JsonString(node_->data, node_->length, JsonString::Copied);
}
private:
ResourceManager* resources_;
StringNode* node_ = nullptr;
size_t size_ = 0;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -6,6 +6,7 @@
#include <ArduinoJson/Deserialization/deserialize.hpp> #include <ArduinoJson/Deserialization/deserialize.hpp>
#include <ArduinoJson/Memory/ResourceManager.hpp> #include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Memory/StringBuffer.hpp>
#include <ArduinoJson/MsgPack/endianness.hpp> #include <ArduinoJson/MsgPack/endianness.hpp>
#include <ArduinoJson/MsgPack/ieee754.hpp> #include <ArduinoJson/MsgPack/ieee754.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
@ -19,7 +20,7 @@ class MsgPackDeserializer {
MsgPackDeserializer(ResourceManager* resources, TReader reader) MsgPackDeserializer(ResourceManager* resources, TReader reader)
: resources_(resources), : resources_(resources),
reader_(reader), reader_(reader),
stringBuilder_(resources), stringBuffer_(resources),
foundSomething_(false) {} foundSomething_(false) {}
template <typename TFilter> template <typename TFilter>
@ -239,7 +240,7 @@ class MsgPackDeserializer {
return DeserializationError::Ok; return DeserializationError::Ok;
} }
DeserializationError::Code readBytes(uint8_t* p, size_t n) { DeserializationError::Code readBytes(void* p, size_t n) {
if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n) if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n)
return DeserializationError::Ok; return DeserializationError::Ok;
return DeserializationError::IncompleteInput; return DeserializationError::IncompleteInput;
@ -247,7 +248,7 @@ class MsgPackDeserializer {
template <typename T> template <typename T>
DeserializationError::Code readBytes(T& value) { DeserializationError::Code readBytes(T& value) {
return readBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value)); return readBytes(&value, sizeof(value));
} }
DeserializationError::Code skipBytes(size_t n) { DeserializationError::Code skipBytes(size_t n) {
@ -379,28 +380,16 @@ class MsgPackDeserializer {
if (err) if (err)
return err; return err;
variant->setOwnedString(stringBuilder_.save()); variant->setOwnedString(stringBuffer_.save());
return DeserializationError::Ok; return DeserializationError::Ok;
} }
DeserializationError::Code readString(size_t n) { DeserializationError::Code readString(size_t n) {
DeserializationError::Code err; char* p = stringBuffer_.reserve(n);
if (!p)
stringBuilder_.startString();
for (; n; --n) {
uint8_t c;
err = readBytes(c);
if (err)
return err;
stringBuilder_.append(static_cast<char>(c));
}
if (!stringBuilder_.isValid())
return DeserializationError::NoMemory; return DeserializationError::NoMemory;
return DeserializationError::Ok; return readBytes(p, n);
} }
template <typename T> template <typename T>
@ -422,7 +411,7 @@ class MsgPackDeserializer {
if (err) if (err)
return err; return err;
variant->setBinary(stringBuilder_.save()); variant->setBinary(stringBuffer_.save());
return DeserializationError::Ok; return DeserializationError::Ok;
} }
@ -517,7 +506,7 @@ class MsgPackDeserializer {
if (err) if (err)
return err; return err;
JsonString key = stringBuilder_.str(); JsonString key = stringBuffer_.str();
TFilter memberFilter = filter[key.c_str()]; TFilter memberFilter = filter[key.c_str()];
VariantData* member; VariantData* member;
@ -525,7 +514,7 @@ class MsgPackDeserializer {
ARDUINOJSON_ASSERT(object != 0); ARDUINOJSON_ASSERT(object != 0);
// Save key in memory pool. // Save key in memory pool.
auto savedKey = stringBuilder_.save(); auto savedKey = stringBuffer_.save();
member = object->addMember(savedKey, resources_); member = object->addMember(savedKey, resources_);
if (!member) if (!member)
@ -582,7 +571,7 @@ class MsgPackDeserializer {
ResourceManager* resources_; ResourceManager* resources_;
TReader reader_; TReader reader_;
StringBuilder stringBuilder_; StringBuffer stringBuffer_;
bool foundSomething_; bool foundSomething_;
}; };