Inverted dependency between MemoryPool and string adapters.

Inserted a null after each raw string in the pool.
This commit is contained in:
Benoit Blanchon
2020-07-08 09:38:27 +02:00
parent 7e58347fbe
commit 04c59985a1
25 changed files with 143 additions and 119 deletions

View File

@ -102,13 +102,13 @@ TEST_CASE("JsonArray::add()") {
SECTION("should duplicate char*") { SECTION("should duplicate char*") {
array.add(const_cast<char*>("world")); array.add(const_cast<char*>("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(6); const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate std::string") { SECTION("should duplicate std::string") {
array.add(std::string("world")); array.add(std::string("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(6); const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }

View File

@ -119,13 +119,13 @@ TEST_CASE("JsonArray::operator[]") {
SECTION("should duplicate char*") { SECTION("should duplicate char*") {
array[0] = const_cast<char*>("world"); array[0] = const_cast<char*>("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(6); const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate std::string") { SECTION("should duplicate std::string") {
array[0] = std::string("world"); array[0] = std::string("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(6); const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }

View File

@ -56,7 +56,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
deserializeJson(doc, " [ \"1234567\" ] "); deserializeJson(doc, " [ \"1234567\" ] ");
REQUIRE(JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(8) == doc.memoryUsage()); REQUIRE(JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(7) == doc.memoryUsage());
// note: we use a string of 8 bytes to be sure that the StaticMemoryPool // note: we use a string of 8 bytes to be sure that the StaticMemoryPool
// will not insert bytes to enforce alignement // will not insert bytes to enforce alignement
} }

View File

@ -94,8 +94,8 @@ TEST_CASE("BasicJsonDocument::shrinkToFit()") {
} }
SECTION("owned raw") { SECTION("owned raw") {
doc.set(serialized(std::string("[{},123]"))); doc.set(serialized(std::string("[{},12]")));
testShrinkToFit(doc, "[{},123]", 8); testShrinkToFit(doc, "[{},12]", 8);
} }
SECTION("linked key") { SECTION("linked key") {

View File

@ -107,43 +107,43 @@ TEST_CASE("JsonObject::operator[]") {
SECTION("should duplicate char* value") { SECTION("should duplicate char* value") {
obj["hello"] = const_cast<char*>("world"); obj["hello"] = const_cast<char*>("world");
const size_t expectedSize = JSON_OBJECT_SIZE(1) + JSON_STRING_SIZE(6); const size_t expectedSize = JSON_OBJECT_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate char* key") { SECTION("should duplicate char* key") {
obj[const_cast<char*>("hello")] = "world"; obj[const_cast<char*>("hello")] = "world";
const size_t expectedSize = JSON_OBJECT_SIZE(1) + JSON_STRING_SIZE(6); const size_t expectedSize = JSON_OBJECT_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate char* key&value") { SECTION("should duplicate char* key&value") {
obj[const_cast<char*>("hello")] = const_cast<char*>("world"); obj[const_cast<char*>("hello")] = const_cast<char*>("world");
const size_t expectedSize = JSON_OBJECT_SIZE(1) + 2 * JSON_STRING_SIZE(6); const size_t expectedSize = JSON_OBJECT_SIZE(1) + 2 * JSON_STRING_SIZE(5);
REQUIRE(expectedSize <= doc.memoryUsage()); REQUIRE(expectedSize <= doc.memoryUsage());
} }
SECTION("should duplicate std::string value") { SECTION("should duplicate std::string value") {
obj["hello"] = std::string("world"); obj["hello"] = std::string("world");
const size_t expectedSize = JSON_OBJECT_SIZE(1) + JSON_STRING_SIZE(6); const size_t expectedSize = JSON_OBJECT_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate std::string key") { SECTION("should duplicate std::string key") {
obj[std::string("hello")] = "world"; obj[std::string("hello")] = "world";
const size_t expectedSize = JSON_OBJECT_SIZE(1) + JSON_STRING_SIZE(6); const size_t expectedSize = JSON_OBJECT_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }
SECTION("should duplicate std::string key&value") { SECTION("should duplicate std::string key&value") {
obj[std::string("hello")] = std::string("world"); obj[std::string("hello")] = std::string("world");
const size_t expectedSize = JSON_OBJECT_SIZE(1) + 2 * JSON_STRING_SIZE(6); const size_t expectedSize = JSON_OBJECT_SIZE(1) + 2 * JSON_STRING_SIZE(5);
REQUIRE(expectedSize <= doc.memoryUsage()); REQUIRE(expectedSize <= doc.memoryUsage());
} }
SECTION("should duplicate a non-static JsonString key") { SECTION("should duplicate a non-static JsonString key") {
obj[JsonString("hello", false)] = "world"; obj[JsonString("hello", false)] = "world";
const size_t expectedSize = JSON_OBJECT_SIZE(1) + JSON_STRING_SIZE(6); const size_t expectedSize = JSON_OBJECT_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage()); REQUIRE(expectedSize == doc.memoryUsage());
} }

View File

@ -47,20 +47,20 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
var1.set(str); var1.set(str);
var2.set(var1); var2.set(var1);
REQUIRE(doc1.memoryUsage() == JSON_STRING_SIZE(8)); REQUIRE(doc1.memoryUsage() == JSON_STRING_SIZE(7));
REQUIRE(doc2.memoryUsage() == JSON_STRING_SIZE(8)); REQUIRE(doc2.memoryUsage() == JSON_STRING_SIZE(7));
} }
SECTION("stores std::string by copy") { SECTION("stores std::string by copy") {
var1.set(std::string("hello!!")); var1.set(std::string("hello!!"));
var2.set(var1); var2.set(var1);
REQUIRE(doc1.memoryUsage() == JSON_STRING_SIZE(8)); REQUIRE(doc1.memoryUsage() == JSON_STRING_SIZE(7));
REQUIRE(doc2.memoryUsage() == JSON_STRING_SIZE(8)); REQUIRE(doc2.memoryUsage() == JSON_STRING_SIZE(7));
} }
SECTION("stores Serialized<const char*> by reference") { SECTION("stores Serialized<const char*> by reference") {
var1.set(serialized("hello!!", JSON_STRING_SIZE(8))); var1.set(serialized("hello!!", 8));
var2.set(var1); var2.set(var1);
REQUIRE(doc1.memoryUsage() == 0); REQUIRE(doc1.memoryUsage() == 0);
@ -69,18 +69,18 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
SECTION("stores Serialized<char*> by copy") { SECTION("stores Serialized<char*> by copy") {
char str[] = "hello!!"; char str[] = "hello!!";
var1.set(serialized(str, 8)); var1.set(serialized(str, 7));
var2.set(var1); var2.set(var1);
REQUIRE(doc1.memoryUsage() == JSON_STRING_SIZE(8)); REQUIRE(doc1.memoryUsage() == JSON_STRING_SIZE(7));
REQUIRE(doc2.memoryUsage() == JSON_STRING_SIZE(8)); REQUIRE(doc2.memoryUsage() == JSON_STRING_SIZE(7));
} }
SECTION("stores Serialized<std::string> by copy") { SECTION("stores Serialized<std::string> by copy") {
var1.set(serialized(std::string("hello!!!"))); var1.set(serialized(std::string("hello!!")));
var2.set(var1); var2.set(var1);
REQUIRE(doc1.memoryUsage() == JSON_STRING_SIZE(8)); REQUIRE(doc1.memoryUsage() == JSON_STRING_SIZE(7));
REQUIRE(doc2.memoryUsage() == JSON_STRING_SIZE(8)); REQUIRE(doc2.memoryUsage() == JSON_STRING_SIZE(7));
} }
} }

View File

@ -36,6 +36,6 @@ TEST_CASE("StringBuilder") {
str.append('h'); str.append('h');
str.complete(); str.complete();
REQUIRE(JSON_STRING_SIZE(2) == pool.size()); REQUIRE(JSON_STRING_SIZE(1) == pool.size());
} }
} }

View File

@ -30,19 +30,19 @@ TEST_CASE("MemoryPool::size()") {
SECTION("Decreases after freezeString()") { SECTION("Decreases after freezeString()") {
StringSlot a = pool.allocExpandableString(); StringSlot a = pool.allocExpandableString();
pool.freezeString(a, 1); pool.freezeString(a, 1);
REQUIRE(pool.size() == JSON_STRING_SIZE(1)); REQUIRE(pool.size() == 1);
StringSlot b = pool.allocExpandableString(); StringSlot b = pool.allocExpandableString();
pool.freezeString(b, 1); pool.freezeString(b, 1);
REQUIRE(pool.size() == 2 * JSON_STRING_SIZE(1)); REQUIRE(pool.size() == 2);
} }
SECTION("Increases after allocFrozenString()") { SECTION("Increases after allocFrozenString()") {
pool.allocFrozenString(0); pool.allocFrozenString(1);
REQUIRE(pool.size() == JSON_STRING_SIZE(0)); REQUIRE(pool.size() == 1);
pool.allocFrozenString(0); pool.allocFrozenString(2);
REQUIRE(pool.size() == 2 * JSON_STRING_SIZE(0)); REQUIRE(pool.size() == 3);
} }
SECTION("Doesn't grow when memory pool is full") { SECTION("Doesn't grow when memory pool is full") {

View File

@ -145,4 +145,12 @@ TEST_CASE("IsString<T>") {
SECTION("const __FlashStringHelper*") { SECTION("const __FlashStringHelper*") {
CHECK(IsString<const __FlashStringHelper*>::value == true); CHECK(IsString<const __FlashStringHelper*>::value == true);
} }
SECTION("const char*") {
CHECK(IsString<const char*>::value == true);
}
SECTION("const char[]") {
CHECK(IsString<const char[8]>::value == true);
}
} }

View File

@ -7,9 +7,9 @@
template <size_t Capacity> template <size_t Capacity>
static void check(const char* input, DeserializationError expected) { static void check(const char* input, DeserializationError expected) {
StaticJsonDocument<Capacity> variant; StaticJsonDocument<Capacity> doc;
DeserializationError error = deserializeMsgPack(variant, input); DeserializationError error = deserializeMsgPack(doc, input);
CAPTURE(input); CAPTURE(input);
REQUIRE(error == expected); REQUIRE(error == expected);
@ -17,7 +17,7 @@ static void check(const char* input, DeserializationError expected) {
template <size_t Size> template <size_t Size>
static void checkString(const char* input, DeserializationError expected) { static void checkString(const char* input, DeserializationError expected) {
check<JSON_STRING_SIZE(Size)>(input, expected); check<Size>(input, expected);
} }
TEST_CASE("deserializeMsgPack(StaticJsonDocument&)") { TEST_CASE("deserializeMsgPack(StaticJsonDocument&)") {

View File

@ -60,6 +60,19 @@ class MemoryPool {
return s; return s;
} }
template <typename TAdaptedString>
char* saveString(const TAdaptedString& str) {
if (str.isNull())
return 0;
size_t n = str.size();
char* dup = allocFrozenString(n + 1);
if (dup) {
str.copyTo(dup, n);
dup[n] = 0; // force null-terminator
}
return dup;
}
StringSlot allocExpandableString() { StringSlot allocExpandableString() {
StringSlot s; StringSlot s;
s.value = _left; s.value = _left;

View File

@ -8,7 +8,7 @@
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Namespace.hpp>
#define JSON_STRING_SIZE(SIZE) (SIZE) #define JSON_STRING_SIZE(SIZE) (SIZE + 1)
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {

View File

@ -16,14 +16,8 @@ class ArduinoStringAdapter {
public: public:
ArduinoStringAdapter(const ::String& str) : _str(&str) {} ArduinoStringAdapter(const ::String& str) : _str(&str) {}
char* save(MemoryPool* pool) const { void copyTo(char* p, size_t n) const {
if (isNull()) memcpy(p, _str->c_str(), n);
return NULL;
size_t n = _str->length() + 1;
char* dup = pool->allocFrozenString(n);
if (dup)
memcpy(dup, _str->c_str(), n);
return dup;
} }
bool isNull() const { bool isNull() const {
@ -45,7 +39,7 @@ class ArduinoStringAdapter {
return _str->length(); return _str->length();
} }
typedef storage_policy::store_by_copy storage_policy; typedef storage_policies::store_by_copy storage_policy;
private: private:
const ::String* _str; const ::String* _str;

View File

@ -39,12 +39,18 @@ class ConstRamStringAdapter {
return _str; return _str;
} }
typedef storage_policy::store_by_address storage_policy; typedef storage_policies::store_by_address storage_policy;
protected: protected:
const char* _str; const char* _str;
}; };
template <>
struct IsString<const char*> : true_type {};
template <int N>
struct IsString<const char[N]> : true_type {};
inline ConstRamStringAdapter adaptString(const char* str) { inline ConstRamStringAdapter adaptString(const char* str) {
return ConstRamStringAdapter(str); return ConstRamStringAdapter(str);
} }

View File

@ -4,7 +4,6 @@
#pragma once #pragma once
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Polyfills/pgmspace.hpp> #include <ArduinoJson/Polyfills/pgmspace.hpp>
#include <ArduinoJson/Strings/IsString.hpp> #include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
@ -33,14 +32,8 @@ class FlashStringAdapter {
return !_str; return !_str;
} }
char* save(MemoryPool* pool) const { void copyTo(char* p, size_t n) const {
if (!_str) memcpy_P(p, reinterpret_cast<const char*>(_str), n);
return NULL;
size_t n = size() + 1; // copy the terminator
char* dup = pool->allocFrozenString(n);
if (dup)
memcpy_P(dup, reinterpret_cast<const char*>(_str), n);
return dup;
} }
size_t size() const { size_t size() const {
@ -49,7 +42,7 @@ class FlashStringAdapter {
return strlen_P(reinterpret_cast<const char*>(_str)); return strlen_P(reinterpret_cast<const char*>(_str));
} }
typedef storage_policy::store_by_copy storage_policy; typedef storage_policies::store_by_copy storage_policy;
private: private:
const __FlashStringHelper* _str; const __FlashStringHelper* _str;

View File

@ -4,7 +4,6 @@
#pragma once #pragma once
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp> #include <ArduinoJson/Strings/ConstRamStringAdapter.hpp>
#include <ArduinoJson/Strings/IsString.hpp> #include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
@ -15,17 +14,11 @@ class RamStringAdapter : public ConstRamStringAdapter {
public: public:
RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {} RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {}
char* save(MemoryPool* pool) const { void copyTo(char* p, size_t n) const {
if (!_str) memcpy(p, _str, n);
return NULL;
size_t n = size() + 1;
char* dup = pool->allocFrozenString(n);
if (dup)
memcpy(dup, _str, n);
return dup;
} }
typedef ARDUINOJSON_NAMESPACE::storage_policy::store_by_copy storage_policy; typedef ARDUINOJSON_NAMESPACE::storage_policies::store_by_copy storage_policy;
}; };
template <typename TChar> template <typename TChar>

View File

@ -33,20 +33,15 @@ class SizedFlashStringAdapter {
return !_str; return !_str;
} }
char* save(MemoryPool* pool) const { void copyTo(char* p, size_t n) const {
if (!_str) memcpy_P(p, reinterpret_cast<const char*>(_str), n);
return NULL;
char* dup = pool->allocFrozenString(_size);
if (dup)
memcpy_P(dup, reinterpret_cast<const char*>(_str), _size);
return dup;
} }
size_t size() const { size_t size() const {
return _size; return _size;
} }
typedef storage_policy::store_by_copy storage_policy; typedef storage_policies::store_by_copy storage_policy;
private: private:
const __FlashStringHelper* _str; const __FlashStringHelper* _str;

View File

@ -28,20 +28,15 @@ class SizedRamStringAdapter {
return !_str; return !_str;
} }
char* save(MemoryPool* pool) const { void copyTo(char* p, size_t n) const {
if (!_str) memcpy(p, _str, n);
return NULL;
char* dup = pool->allocFrozenString(_size);
if (dup)
memcpy(dup, _str, _size);
return dup;
} }
size_t size() const { size_t size() const {
return _size; return _size;
} }
typedef storage_policy::store_by_copy storage_policy; typedef storage_policies::store_by_copy storage_policy;
private: private:
const char* _str; const char* _str;

View File

@ -4,7 +4,6 @@
#pragma once #pragma once
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/IsString.hpp> #include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
@ -18,12 +17,8 @@ class StlStringAdapter {
public: public:
StlStringAdapter(const TString& str) : _str(&str) {} StlStringAdapter(const TString& str) : _str(&str) {}
char* save(MemoryPool* pool) const { void copyTo(char* p, size_t n) const {
size_t n = _str->length() + 1; memcpy(p, _str->c_str(), n);
char* dup = pool->allocFrozenString(n);
if (dup)
memcpy(dup, _str->c_str(), n);
return dup;
} }
bool isNull() const { bool isNull() const {
@ -46,7 +41,7 @@ class StlStringAdapter {
return _str->size(); return _str->size();
} }
typedef storage_policy::store_by_copy storage_policy; typedef storage_policies::store_by_copy storage_policy;
private: private:
const TString* _str; const TString* _str;

View File

@ -6,10 +6,10 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
namespace storage_policy { namespace storage_policies {
struct store_by_address {}; struct store_by_address {};
struct store_by_copy {}; struct store_by_copy {};
struct decide_at_runtime {}; struct decide_at_runtime {};
} // namespace storage_policy } // namespace storage_policies
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -38,8 +38,6 @@ class String {
return strcmp(lhs._data, rhs._data) == 0; return strcmp(lhs._data, rhs._data) == 0;
} }
typedef storage_policy::decide_at_runtime storage_policy;
private: private:
const char* _data; const char* _data;
bool _isStatic; bool _isStatic;
@ -54,11 +52,7 @@ class StringAdapter : public RamStringAdapter {
return _isStatic; return _isStatic;
} }
const char* save(MemoryPool* pool) const { typedef storage_policies::decide_at_runtime storage_policy;
if (_isStatic)
return data();
return RamStringAdapter::save(pool);
}
private: private:
bool _isStatic; bool _isStatic;

View File

@ -18,17 +18,17 @@ inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) {
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_policy::decide_at_runtime) { storage_policies::decide_at_runtime) {
if (key.isStatic()) { if (key.isStatic()) {
return slotSetKey(var, key, pool, storage_policy::store_by_address()); return slotSetKey(var, key, pool, storage_policies::store_by_address());
} else { } else {
return slotSetKey(var, key, pool, storage_policy::store_by_copy()); return slotSetKey(var, key, pool, storage_policies::store_by_copy());
} }
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*, inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*,
storage_policy::store_by_address) { storage_policies::store_by_address) {
ARDUINOJSON_ASSERT(var); ARDUINOJSON_ASSERT(var);
var->setLinkedKey(make_not_null(key.data())); var->setLinkedKey(make_not_null(key.data()));
return true; return true;
@ -36,8 +36,8 @@ inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*,
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_policy::store_by_copy) { storage_policies::store_by_copy) {
const char* dup = key.save(pool); const char* dup = pool->saveString(key);
if (!dup) if (!dup)
return false; return false;
ARDUINOJSON_ASSERT(var); ARDUINOJSON_ASSERT(var);

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Misc/SerializedValue.hpp> #include <ArduinoJson/Misc/SerializedValue.hpp>
#include <ArduinoJson/Numbers/convertNumber.hpp> #include <ArduinoJson/Numbers/convertNumber.hpp>
#include <ArduinoJson/Polyfills/gsl/not_null.hpp> #include <ArduinoJson/Polyfills/gsl/not_null.hpp>
@ -191,7 +192,7 @@ class VariantData {
template <typename T> template <typename T>
bool setOwnedRaw(SerializedValue<T> value, MemoryPool *pool) { bool setOwnedRaw(SerializedValue<T> value, MemoryPool *pool) {
char *dup = adaptString(value.data(), value.size()).save(pool); char *dup = pool->saveString(adaptString(value.data(), value.size()));
if (dup) { if (dup) {
setType(VALUE_IS_OWNED_RAW); setType(VALUE_IS_OWNED_RAW);
_content.asRaw.data = dup; _content.asRaw.data = dup;
@ -265,9 +266,9 @@ class VariantData {
} }
} }
template <typename T> template <typename TAdaptedString>
bool setOwnedString(T value, MemoryPool *pool) { bool setOwnedString(TAdaptedString value, MemoryPool *pool) {
return setOwnedString(value.save(pool)); return setOwnedString(pool->saveString(value));
} }
CollectionData &toArray() { CollectionData &toArray() {

View File

@ -119,11 +119,44 @@ inline bool variantSetOwnedString(VariantData *var, char *value) {
return true; return true;
} }
template <typename T> template <typename TAdaptedString>
inline bool variantSetOwnedString(VariantData *var, T value, MemoryPool *pool) { inline bool variantSetOwnedString(VariantData *var, TAdaptedString value,
MemoryPool *pool) {
return var != 0 && var->setOwnedString(value, pool); return var != 0 && var->setOwnedString(value, pool);
} }
template <typename TAdaptedString>
inline bool variantSetString(VariantData *var, TAdaptedString value,
MemoryPool *pool,
storage_policies::decide_at_runtime) {
if (value.isStatic())
return variantSetString(var, value, pool,
storage_policies::store_by_address());
else
return variantSetString(var, value, pool,
storage_policies::store_by_copy());
}
template <typename TAdaptedString>
inline bool variantSetString(VariantData *var, TAdaptedString value,
MemoryPool *pool) {
return variantSetString(var, value, pool,
typename TAdaptedString::storage_policy());
}
template <typename TAdaptedString>
inline bool variantSetString(VariantData *var, TAdaptedString value,
MemoryPool *, storage_policies::store_by_address) {
return variantSetLinkedString(var, value.data());
}
template <typename TAdaptedString>
inline bool variantSetString(VariantData *var, TAdaptedString value,
MemoryPool *pool,
storage_policies::store_by_copy) {
return variantSetOwnedString(var, value, pool);
}
template <typename T> template <typename T>
inline bool variantSetInteger(VariantData *var, T value) { inline bool variantSetInteger(VariantData *var, T value) {
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);

View File

@ -10,6 +10,7 @@
#include <ArduinoJson/Memory/MemoryPool.hpp> #include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Misc/Visitable.hpp> #include <ArduinoJson/Misc/Visitable.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantAs.hpp> #include <ArduinoJson/Variant/VariantAs.hpp>
#include <ArduinoJson/Variant/VariantFunctions.hpp> #include <ArduinoJson/Variant/VariantFunctions.hpp>
#include <ArduinoJson/Variant/VariantOperators.hpp> #include <ArduinoJson/Variant/VariantOperators.hpp>
@ -213,20 +214,15 @@ class VariantRef : public VariantRefBase<VariantData>,
FORCE_INLINE bool set( FORCE_INLINE bool set(
const T &value, const T &value,
typename enable_if<IsString<T>::value>::type * = 0) const { typename enable_if<IsString<T>::value>::type * = 0) const {
return variantSetOwnedString(_data, adaptString(value), _pool); return variantSetString(_data, adaptString(value), _pool);
} }
// set(char*) // set(char*)
// set(const __FlashStringHelper*) // set(const __FlashStringHelper*)
// set(const char*)
template <typename T> template <typename T>
FORCE_INLINE bool set( FORCE_INLINE bool set(
T *value, typename enable_if<IsString<T *>::value>::type * = 0) const { T *value, typename enable_if<IsString<T *>::value>::type * = 0) const {
return variantSetOwnedString(_data, adaptString(value), _pool); return variantSetString(_data, adaptString(value), _pool);
}
// set(const char*);
FORCE_INLINE bool set(const char *value) const {
return variantSetLinkedString(_data, value);
} }
// set(VariantRef) // set(VariantRef)
@ -247,6 +243,14 @@ class VariantRef : public VariantRefBase<VariantData>,
return variantSetInteger(_data, static_cast<Integer>(value)); return variantSetInteger(_data, static_cast<Integer>(value));
} }
#if ARDUINOJSON_HAS_NULLPTR
// set(nullptr_t)
FORCE_INLINE bool set(decltype(nullptr)) const {
variantSetNull(_data);
return true;
}
#endif
template <typename T> template <typename T>
FORCE_INLINE typename VariantAs<T>::type as() const { FORCE_INLINE typename VariantAs<T>::type as() const {
return variantAs<typename VariantAs<T>::type>(_data, _pool); return variantAs<typename VariantAs<T>::type>(_data, _pool);