mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-18 13:02:25 +02: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