Add CopiedString and LinkedString

This commit is contained in:
Benoit Blanchon
2021-11-22 09:40:20 +01:00
parent b06bbd9d2a
commit 62f9b94ab1
13 changed files with 83 additions and 50 deletions

View File

@ -19,7 +19,8 @@ TEST_CASE("StringCopier") {
str.append('\0'); str.append('\0');
REQUIRE(str.isValid() == true); REQUIRE(str.isValid() == true);
REQUIRE(str.c_str() == std::string("hello")); REQUIRE(std::string(str.str()) == "hello");
REQUIRE(pool.overflowed() == false);
} }
SECTION("Returns null when too small") { SECTION("Returns null when too small") {
@ -49,7 +50,7 @@ static const char* addStringToPool(MemoryPool& pool, const char* s) {
str.startString(); str.startString();
str.append(s); str.append(s);
str.append('\0'); str.append('\0');
return str.save(); return str.save().c_str();
} }
TEST_CASE("StringCopier::save() deduplicates strings") { TEST_CASE("StringCopier::save() deduplicates strings") {

View File

@ -19,7 +19,7 @@ static void testCodepoint(uint32_t codepoint, std::string expected) {
Utf8::encodeCodepoint(codepoint, str); Utf8::encodeCodepoint(codepoint, str);
str.append('\0'); str.append('\0');
REQUIRE(str.c_str() == expected); REQUIRE(str.str().c_str() == expected);
} }
TEST_CASE("Utf8::encodeCodepoint()") { TEST_CASE("Utf8::encodeCodepoint()") {

View File

@ -231,12 +231,12 @@ class JsonDeserializer {
return false; return false;
} }
const char *key = _stringStorage.c_str(); typename TStringStorage::string_type key = _stringStorage.str();
TFilter memberFilter = filter[key]; TFilter memberFilter = filter[key.c_str()];
if (memberFilter.allow()) { if (memberFilter.allow()) {
VariantData *variant = object.getMember(adaptString(key)); VariantData *variant = object.getMember(adaptString(key.c_str()));
if (!variant) { if (!variant) {
// Save key in memory pool. // Save key in memory pool.
// This MUST be done before adding the slot. // This MUST be done before adding the slot.
@ -249,7 +249,7 @@ class JsonDeserializer {
return false; return false;
} }
slot->setKey(key, typename TStringStorage::storage_policy()); slot->setKey(key);
variant = slot->data(); variant = slot->data();
} }
@ -345,8 +345,7 @@ class JsonDeserializer {
_stringStorage.startString(); _stringStorage.startString();
if (!parseQuotedString()) if (!parseQuotedString())
return false; return false;
const char *value = _stringStorage.save(); variant.setString(_stringStorage.save());
variant.setStringPointer(value, typename TStringStorage::storage_policy());
return true; return true;
} }

View File

@ -331,8 +331,7 @@ class MsgPackDeserializer {
bool readString(VariantData *variant, size_t n) { bool readString(VariantData *variant, size_t n) {
if (!readString(n)) if (!readString(n))
return false; return false;
variant->setStringPointer(_stringStorage.save(), variant->setString(_stringStorage.save());
typename TStringStorage::storage_policy());
return true; return true;
} }
@ -419,8 +418,8 @@ class MsgPackDeserializer {
if (!readKey()) if (!readKey())
return false; return false;
const char *key = _stringStorage.c_str(); typename TStringStorage::string_type key = _stringStorage.str();
TFilter memberFilter = filter[key]; TFilter memberFilter = filter[key.c_str()];
VariantData *member; VariantData *member;
if (memberFilter.allow()) { if (memberFilter.allow()) {
@ -434,7 +433,7 @@ class MsgPackDeserializer {
return false; return false;
} }
slot->setKey(key, typename TStringStorage::storage_policy()); slot->setKey(key);
member = slot->data(); member = slot->data();
} else { } else {

View File

@ -7,6 +7,7 @@
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Namespace.hpp>
#include <stdint.h> // int8_t #include <stdint.h> // int8_t
#include <string.h> // strcmp
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {

View File

@ -10,6 +10,8 @@ namespace ARDUINOJSON_NAMESPACE {
class StringCopier { class StringCopier {
public: public:
typedef CopiedString string_type;
StringCopier(MemoryPool& pool) : _pool(&pool) {} StringCopier(MemoryPool& pool) : _pool(&pool) {}
void startString() { void startString() {
@ -17,7 +19,7 @@ class StringCopier {
_size = 0; _size = 0;
} }
const char* save() { string_type save() {
ARDUINOJSON_ASSERT(_ptr); ARDUINOJSON_ASSERT(_ptr);
return _pool->saveStringFromFreeZone(_size); return _pool->saveStringFromFreeZone(_size);
} }
@ -47,12 +49,10 @@ class StringCopier {
return _ptr != 0; return _ptr != 0;
} }
const char* c_str() { string_type str() const {
return _ptr; return _ptr;
} }
typedef storage_policies::store_by_copy storage_policy;
private: private:
MemoryPool* _pool; MemoryPool* _pool;

View File

@ -5,19 +5,21 @@
#pragma once #pragma once
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoredString.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class StringMover { class StringMover {
public: public:
typedef LinkedString string_type;
StringMover(char* ptr) : _writePtr(ptr) {} StringMover(char* ptr) : _writePtr(ptr) {}
void startString() { void startString() {
_startPtr = _writePtr; _startPtr = _writePtr;
} }
const char* save() const { FORCE_INLINE string_type save() {
return _startPtr; return _startPtr;
} }
@ -29,12 +31,10 @@ class StringMover {
return true; return true;
} }
const char* c_str() const { string_type str() const {
return _startPtr; return string_type(_startPtr);
} }
typedef storage_policies::store_by_address storage_policy;
private: private:
char* _writePtr; char* _writePtr;
char* _startPtr; char* _startPtr;

View File

@ -0,0 +1,32 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/safe_strcmp.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TStoragePolicy>
class StoredString {
public:
StoredString(const char* p) : _data(p) {}
operator const char*() const {
return _data;
}
const char* c_str() const {
return _data;
}
private:
const char* _data;
};
typedef StoredString<storage_policies::store_by_address> LinkedString;
typedef StoredString<storage_policies::store_by_copy> CopiedString;
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -173,7 +173,7 @@ struct Converter<SerializedValue<T>,
VariantData* data = getData(dst); VariantData* data = getData(dst);
MemoryPool* pool = getPool(dst); MemoryPool* pool = getPool(dst);
if (data) if (data)
data->setOwnedRaw(src, pool); data->storeOwnedRaw(src, pool);
} }
}; };
@ -203,7 +203,7 @@ class MemoryPoolPrint : public Print {
pool->getFreeZone(&_string, &_capacity); pool->getFreeZone(&_string, &_capacity);
} }
const char* c_str() { CopiedString str() {
_string[_size++] = 0; _string[_size++] = 0;
ARDUINOJSON_ASSERT(_size <= _capacity); ARDUINOJSON_ASSERT(_size <= _capacity);
return _pool->saveStringFromFreeZone(_size); return _pool->saveStringFromFreeZone(_size);
@ -250,7 +250,7 @@ inline void convertToJson(const ::Printable& src, VariantRef dst) {
data->setNull(); data->setNull();
return; return;
} }
data->setStringPointer(print.c_str(), storage_policies::store_by_copy()); data->setString(print.str());
} }
#endif #endif

View File

@ -30,18 +30,18 @@ template <typename TAdaptedString>
inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*, inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*,
storage_policies::store_by_address) { storage_policies::store_by_address) {
ARDUINOJSON_ASSERT(var); ARDUINOJSON_ASSERT(var);
var->setKey(key.data(), storage_policies::store_by_address()); var->setKey(LinkedString(key.data()));
return true; return true;
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool,
storage_policies::store_by_copy) { storage_policies::store_by_copy) {
const char* dup = pool->saveString(key); CopiedString dup = pool->saveString(key);
if (!dup) if (!dup)
return false; return false;
ARDUINOJSON_ASSERT(var); ARDUINOJSON_ASSERT(var);
var->setKey(dup, storage_policies::store_by_copy()); var->setKey(dup);
return true; return true;
} }

View File

@ -104,10 +104,10 @@ class VariantData {
case VALUE_IS_OBJECT: case VALUE_IS_OBJECT:
return toObject().copyFrom(src._content.asCollection, pool); return toObject().copyFrom(src._content.asCollection, pool);
case VALUE_IS_OWNED_STRING: case VALUE_IS_OWNED_STRING:
return setString(adaptString(const_cast<char *>(src._content.asString)), return storeString(
pool); adaptString(const_cast<char *>(src._content.asString)), pool);
case VALUE_IS_OWNED_RAW: case VALUE_IS_OWNED_RAW:
return setOwnedRaw( return storeOwnedRaw(
serialized(src._content.asRaw.data, src._content.asRaw.size), pool); serialized(src._content.asRaw.data, src._content.asRaw.size), pool);
default: default:
setType(src.type()); setType(src.type());
@ -194,7 +194,7 @@ class VariantData {
} }
template <typename T> template <typename T>
bool setOwnedRaw(SerializedValue<T> value, MemoryPool *pool) { bool storeOwnedRaw(SerializedValue<T> value, MemoryPool *pool) {
const char *dup = pool->saveString(adaptString(value.data(), value.size())); const char *dup = pool->saveString(adaptString(value.data(), value.size()));
if (dup) { if (dup) {
setType(VALUE_IS_OWNED_RAW); setType(VALUE_IS_OWNED_RAW);
@ -223,20 +223,20 @@ class VariantData {
setType(VALUE_IS_NULL); setType(VALUE_IS_NULL);
} }
void setStringPointer(const char *s, storage_policies::store_by_copy) { void setString(CopiedString s) {
ARDUINOJSON_ASSERT(s != 0); ARDUINOJSON_ASSERT(s);
setType(VALUE_IS_OWNED_STRING); setType(VALUE_IS_OWNED_STRING);
_content.asString = s; _content.asString = s.c_str();
} }
void setStringPointer(const char *s, storage_policies::store_by_address) { void setString(LinkedString s) {
ARDUINOJSON_ASSERT(s != 0); ARDUINOJSON_ASSERT(s);
setType(VALUE_IS_LINKED_STRING); setType(VALUE_IS_LINKED_STRING);
_content.asString = s; _content.asString = s.c_str();
} }
template <typename TAdaptedString> template <typename TAdaptedString>
bool setString(TAdaptedString value, MemoryPool *pool) { bool storeString(TAdaptedString value, MemoryPool *pool) {
return storeString(value, pool, typename TAdaptedString::storage_policy()); return storeString(value, pool, typename TAdaptedString::storage_policy());
} }
@ -342,7 +342,7 @@ class VariantData {
if (value.isNull()) if (value.isNull())
setNull(); setNull();
else else
setStringPointer(value.data(), storage_policies::store_by_address()); setString(LinkedString(value.data()));
return true; return true;
} }
@ -358,7 +358,7 @@ class VariantData {
setNull(); setNull();
return false; return false;
} }
setStringPointer(copy, storage_policies::store_by_copy()); setString(CopiedString(copy));
return true; return true;
} }
}; };

View File

@ -54,7 +54,7 @@ inline bool variantSetString(VariantData *var, TAdaptedString value,
MemoryPool *pool) { MemoryPool *pool) {
if (!var) if (!var)
return false; return false;
return var->setString(value, pool); return var->storeString(value, pool);
} }
inline size_t variantSize(const VariantData *var) { inline size_t variantSize(const VariantData *var) {

View File

@ -8,6 +8,7 @@
#include <ArduinoJson/Polyfills/limits.hpp> #include <ArduinoJson/Polyfills/limits.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StoredString.hpp>
#include <ArduinoJson/Variant/VariantContent.hpp> #include <ArduinoJson/Variant/VariantContent.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@ -77,16 +78,16 @@ class VariantSlot {
_next = VariantSlotDiff(slot - this); _next = VariantSlotDiff(slot - this);
} }
void setKey(const char* k, storage_policies::store_by_copy) { void setKey(CopiedString k) {
ARDUINOJSON_ASSERT(k != NULL); ARDUINOJSON_ASSERT(k);
_flags |= OWNED_KEY_BIT; _flags |= OWNED_KEY_BIT;
_key = k; _key = k.c_str();
} }
void setKey(const char* k, storage_policies::store_by_address) { void setKey(LinkedString k) {
ARDUINOJSON_ASSERT(k != NULL); ARDUINOJSON_ASSERT(k);
_flags &= VALUE_MASK; _flags &= VALUE_MASK;
_key = k; _key = k.c_str();
} }
const char* key() const { const char* key() const {