Separate string adapter from storage policy

This commit is contained in:
Benoit Blanchon
2021-11-21 15:07:56 +01:00
parent 51937778dd
commit ca24ed48f5
37 changed files with 697 additions and 724 deletions

View File

@ -92,10 +92,9 @@ TEST_CASE("StringViewAdapter") {
std::string_view str("bravoXXX", 5);
auto adapter = adaptString(str);
CHECK(adapter.compare(NULL) > 0);
CHECK(adapter.compare("alpha") > 0);
CHECK(adapter.compare("bravo") == 0);
CHECK(adapter.compare("charlie") < 0);
CHECK(stringCompare(adapter, adaptString("alpha", 5)) > 0);
CHECK(stringCompare(adapter, adaptString("bravo", 5)) == 0);
CHECK(stringCompare(adapter, adaptString("charlie", 7)) < 0);
CHECK(adapter.size() == 5);
}

View File

@ -15,106 +15,75 @@
using namespace ARDUINOJSON_NAMESPACE;
TEST_CASE("const char*") {
TEST_CASE("ZeroTerminatedRamString") {
SECTION("null") {
StringAdapter<const char*> adapter(NULL);
ZeroTerminatedRamString s = adaptString(static_cast<const char*>(0));
CHECK(adapter.compare("bravo") < 0);
CHECK(adapter.compare(NULL) == 0);
CHECK(adapter.size() == 0);
CHECK(s.isNull() == true);
CHECK(s.size() == 0);
}
SECTION("non-null") {
StringAdapter<const char*> adapter("bravo");
ZeroTerminatedRamString s = adaptString("bravo");
CHECK(adapter.compare(NULL) > 0);
CHECK(adapter.compare("alpha") > 0);
CHECK(adapter.compare("bravo") == 0);
CHECK(adapter.compare("charlie") < 0);
CHECK(adapter.size() == 5);
CHECK(s.isNull() == false);
CHECK(s.size() == 5);
}
}
TEST_CASE("const char* + size") {
TEST_CASE("SizedRamString") {
SECTION("null") {
StringAdapter<const char*, true> adapter(NULL, 10);
SizedRamString s = adaptString(static_cast<const char*>(0), 10);
CHECK(adapter.compare("bravo") < 0);
CHECK(adapter.compare(NULL) == 0);
CHECK(adapter.size() == 10);
CHECK(s.isNull() == true);
}
SECTION("non-null") {
StringAdapter<const char*, true> adapter("bravo", 5);
SizedRamString s = adaptString("bravo", 5);
CHECK(adapter.compare(NULL) > 0);
CHECK(adapter.compare("alpha") > 0);
CHECK(adapter.compare("bravo") == 0);
CHECK(adapter.compare("charlie") < 0);
CHECK(adapter.size() == 5);
CHECK(s.isNull() == false);
CHECK(s.size() == 5);
}
}
TEST_CASE("const __FlashStringHelper*") {
TEST_CASE("FlashString") {
SECTION("null") {
StringAdapter<const __FlashStringHelper*> adapter(NULL);
FlashString s = adaptString(static_cast<const __FlashStringHelper*>(0));
CHECK(adapter.compare("bravo") < 0);
CHECK(adapter.compare(NULL) == 0);
CHECK(adapter.size() == 0);
CHECK(s.isNull() == true);
CHECK(s.size() == 0);
}
SECTION("non-null") {
StringAdapter<const __FlashStringHelper*> adapter = adaptString(F("bravo"));
FlashString s = adaptString(F("bravo"));
CHECK(adapter.compare(NULL) > 0);
CHECK(adapter.compare("alpha") > 0);
CHECK(adapter.compare("bravo") == 0);
CHECK(adapter.compare("charlie") < 0);
CHECK(adapter.size() == 5);
CHECK(s.isNull() == false);
CHECK(s.size() == 5);
}
}
TEST_CASE("std::string") {
std::string str("bravo");
StringAdapter<std::string> adapter(str);
std::string orig("bravo");
SizedRamString s = adaptString(orig);
CHECK(adapter.compare(NULL) > 0);
CHECK(adapter.compare("alpha") > 0);
CHECK(adapter.compare("bravo") == 0);
CHECK(adapter.compare("charlie") < 0);
CHECK(adapter.size() == 5);
CHECK(s.isNull() == false);
CHECK(s.size() == 5);
}
TEST_CASE("Arduino String") {
::String str("bravo");
StringAdapter< ::String> adapter(str);
::String orig("bravo");
SizedRamString s = adaptString(orig);
CHECK(adapter.compare(NULL) > 0);
CHECK(adapter.compare("alpha") > 0);
CHECK(adapter.compare("bravo") == 0);
CHECK(adapter.compare("charlie") < 0);
CHECK(adapter.size() == 5);
CHECK(s.isNull() == false);
CHECK(s.size() == 5);
}
TEST_CASE("custom_string") {
custom_string str("bravo");
StringAdapter<custom_string> adapter(str);
custom_string orig("bravo");
SizedRamString s = adaptString(orig);
CHECK(adapter.compare(NULL) > 0);
CHECK(adapter.compare("alpha") > 0);
CHECK(adapter.compare("bravo") == 0);
CHECK(adapter.compare("charlie") < 0);
CHECK(adapter.size() == 5);
CHECK(s.isNull() == false);
CHECK(s.size() == 5);
}
TEST_CASE("IsString<T>") {
@ -142,3 +111,93 @@ TEST_CASE("IsString<T>") {
CHECK(IsString<const char[8]>::value == true);
}
}
TEST_CASE("stringCompare") {
SECTION("ZeroTerminatedRamString vs ZeroTerminatedRamString") {
CHECK(stringCompare(adaptString("bravo"), adaptString("alpha")) > 0);
CHECK(stringCompare(adaptString("bravo"), adaptString("bravo")) == 0);
CHECK(stringCompare(adaptString("bravo"), adaptString("charlie")) < 0);
}
SECTION("ZeroTerminatedRamString vs SizedRamString") {
CHECK(stringCompare(adaptString("bravo"), adaptString("alpha?", 5)) > 0);
CHECK(stringCompare(adaptString("bravo"), adaptString("bravo?", 4)) > 0);
CHECK(stringCompare(adaptString("bravo"), adaptString("bravo?", 5)) == 0);
CHECK(stringCompare(adaptString("bravo"), adaptString("bravo?", 6)) < 0);
CHECK(stringCompare(adaptString("bravo"), adaptString("charlie?", 7)) < 0);
}
SECTION("SizedRamString vs SizedRamString") {
// clang-format off
CHECK(stringCompare(adaptString("bravo!", 5), adaptString("alpha?", 5)) > 0);
CHECK(stringCompare(adaptString("bravo!", 5), adaptString("bravo?", 5)) == 0);
CHECK(stringCompare(adaptString("bravo!", 5), adaptString("charlie?", 7)) < 0);
CHECK(stringCompare(adaptString("bravo!", 5), adaptString("bravo!", 4)) > 0);
CHECK(stringCompare(adaptString("bravo!", 5), adaptString("bravo!", 5)) == 0);
CHECK(stringCompare(adaptString("bravo!", 5), adaptString("bravo!", 6)) < 0);
// clang-format on
}
SECTION("FlashString vs FlashString") {
// clang-format off
CHECK(stringCompare(adaptString(F("bravo")), adaptString(F("alpha"))) > 0);
CHECK(stringCompare(adaptString(F("bravo")), adaptString(F("bravo"))) == 0);
CHECK(stringCompare(adaptString(F("bravo")), adaptString(F("charlie"))) < 0);
// clang-format on
}
SECTION("FlashString vs SizedRamString") {
// clang-format off
CHECK(stringCompare(adaptString(F("bravo")), adaptString("alpha?", 5)) > 0);
CHECK(stringCompare(adaptString(F("bravo")), adaptString("bravo?", 5)) == 0);
CHECK(stringCompare(adaptString(F("bravo")), adaptString("charlie?", 7)) < 0);
CHECK(stringCompare(adaptString(F("bravo")), adaptString("bravo!", 4)) > 0);
CHECK(stringCompare(adaptString(F("bravo")), adaptString("bravo!", 5)) == 0);
CHECK(stringCompare(adaptString(F("bravo")), adaptString("bravo!", 6)) < 0);
// clang-format on
}
SECTION("ZeroTerminatedRamString vs FlashString") {
// clang-format off
CHECK(stringCompare(adaptString("bravo"), adaptString(F("alpha?"), 5)) > 0);
CHECK(stringCompare(adaptString("bravo"), adaptString(F("bravo?"), 4)) > 0);
CHECK(stringCompare(adaptString("bravo"), adaptString(F("bravo?"), 5)) == 0);
CHECK(stringCompare(adaptString("bravo"), adaptString(F("bravo?"), 6)) < 0);
CHECK(stringCompare(adaptString("bravo"), adaptString(F("charlie?"), 7)) < 0);
// clang-format on
}
}
TEST_CASE("stringEquals()") {
SECTION("ZeroTerminatedRamString vs ZeroTerminatedRamString") {
CHECK(stringEquals(adaptString("bravo"), adaptString("brav")) == false);
CHECK(stringEquals(adaptString("bravo"), adaptString("bravo")) == true);
CHECK(stringEquals(adaptString("bravo"), adaptString("bravo!")) == false);
}
SECTION("ZeroTerminatedRamString vs SizedRamString") {
// clang-format off
CHECK(stringEquals(adaptString("bravo"), adaptString("bravo!", 4)) == false);
CHECK(stringEquals(adaptString("bravo"), adaptString("bravo!", 5)) == true);
CHECK(stringEquals(adaptString("bravo"), adaptString("bravo!", 6)) == false);
// clang-format on
}
SECTION("FlashString vs SizedRamString") {
// clang-format off
CHECK(stringEquals(adaptString(F("bravo")), adaptString("bravo!", 4)) == false);
CHECK(stringEquals(adaptString(F("bravo")), adaptString("bravo!", 5)) == true);
CHECK(stringEquals(adaptString(F("bravo")), adaptString("bravo!", 6)) == false);
// clang-format on
}
SECTION("SizedRamString vs SizedRamString") {
// clang-format off
CHECK(stringEquals(adaptString("bravo?", 5), adaptString("bravo!", 4)) == false);
CHECK(stringEquals(adaptString("bravo?", 5), adaptString("bravo!", 5)) == true);
CHECK(stringEquals(adaptString("bravo?", 5), adaptString("bravo!", 6)) == false);
// clang-format on
}
}

View File

@ -40,14 +40,15 @@ class CollectionData {
// Object only
template <typename TAdaptedString>
VariantData *addMember(TAdaptedString key, MemoryPool *pool);
template <typename TAdaptedString, typename TStoragePolicy>
VariantData *addMember(TAdaptedString key, MemoryPool *pool, TStoragePolicy);
template <typename TAdaptedString>
VariantData *getMember(TAdaptedString key) const;
template <typename TAdaptedString>
VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool);
template <typename TAdaptedString, typename TStoragePolicy>
VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool,
TStoragePolicy);
template <typename TAdaptedString>
void removeMember(TAdaptedString key) {

View File

@ -5,6 +5,8 @@
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
namespace ARDUINOJSON_NAMESPACE {
@ -34,11 +36,12 @@ inline VariantData* CollectionData::addElement(MemoryPool* pool) {
return slotData(addSlot(pool));
}
template <typename TAdaptedString>
template <typename TAdaptedString, typename TStoragePolicy>
inline VariantData* CollectionData::addMember(TAdaptedString key,
MemoryPool* pool) {
MemoryPool* pool,
TStoragePolicy storage) {
VariantSlot* slot = addSlot(pool);
if (!slotSetKey(slot, key, pool)) {
if (!slotSetKey(slot, key, pool, storage)) {
removeSlot(slot);
return 0;
}
@ -61,10 +64,8 @@ inline bool CollectionData::copyFrom(const CollectionData& src,
for (VariantSlot* s = src._head; s; s = s->next()) {
VariantData* var;
if (s->key() != 0) {
if (s->ownsKey())
var = addMember(adaptString(const_cast<char*>(s->key())), pool);
else
var = addMember(adaptString(s->key()), pool);
String key(s->key(), !s->ownsKey());
var = addMember(adaptString(key), pool, getStringStoragePolicy(key));
} else {
var = addElement(pool);
}
@ -105,9 +106,11 @@ inline bool CollectionData::equalsArray(const CollectionData& other) const {
template <typename TAdaptedString>
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
if (key.isNull())
return 0;
VariantSlot* slot = _head;
while (slot) {
if (key.compare(slot->key()) == 0)
if (stringEquals(key, adaptString(slot->key())))
break;
slot = slot->next();
}
@ -137,9 +140,9 @@ inline VariantData* CollectionData::getMember(TAdaptedString key) const {
return slot ? slot->data() : 0;
}
template <typename TAdaptedString>
inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
MemoryPool* pool) {
template <typename TAdaptedString, typename TStoragePolicy>
inline VariantData* CollectionData::getOrAddMember(
TAdaptedString key, MemoryPool* pool, TStoragePolicy storage_policy) {
// ignore null key
if (key.isNull())
return 0;
@ -149,7 +152,7 @@ inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
if (slot)
return slot->data();
return addMember(key, pool);
return addMember(key, pool, storage_policy);
}
inline VariantData* CollectionData::getElement(size_t index) const {

View File

@ -8,6 +8,7 @@
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Object/MemberProxy.hpp>
#include <ArduinoJson/Object/ObjectRef.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp>
@ -244,14 +245,18 @@ class JsonDocument : public Visitable {
// getOrAddMember(const __FlashStringHelper*)
template <typename TChar>
FORCE_INLINE VariantRef getOrAddMember(TChar* key) {
return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool));
return VariantRef(&_pool,
_data.getOrAddMember(adaptString(key), &_pool,
getStringStoragePolicy(key)));
}
// getOrAddMember(const std::string&)
// getOrAddMember(const String&)
template <typename TString>
FORCE_INLINE VariantRef getOrAddMember(const TString& key) {
return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool));
return VariantRef(&_pool,
_data.getOrAddMember(adaptString(key), &_pool,
getStringStoragePolicy(key)));
}
FORCE_INLINE VariantRef addElement() {

View File

@ -60,7 +60,7 @@ class MemoryPool {
}
template <typename TAdaptedString>
const char* saveString(const TAdaptedString& str) {
const char* saveString(TAdaptedString str) {
if (str.isNull())
return CopiedString();
@ -74,7 +74,7 @@ class MemoryPool {
char* newCopy = allocString(n + 1);
if (newCopy) {
str.copyTo(newCopy, n);
stringGetChars(str, newCopy, n);
newCopy[n] = 0; // force null-terminator
}
return CopiedString(newCopy, n);
@ -165,22 +165,11 @@ class MemoryPool {
}
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
template <typename TAdaptedString>
static bool stringEquals(const char* p, size_t n, const TAdaptedString& s) {
if (p[n]) // check terminator first
return false;
for (size_t i = 0; i < n; i++) {
if (p[i] != s[i])
return false;
}
return true;
}
template <typename TAdaptedString>
const char* findString(const TAdaptedString& str) const {
size_t n = str.size();
for (char* next = _begin; next + n < _left; ++next) {
if (stringEquals(next, n, str))
if (next[n] == '\0' && stringEquals(str, adaptString(next, n)))
return next;
// jump to next terminator

View File

@ -40,12 +40,13 @@ void objectRemove(CollectionData *obj, TAdaptedString key) {
obj->removeMember(key);
}
template <typename TAdaptedString>
template <typename TAdaptedString, typename TStoragePolicy>
inline VariantData *objectGetOrAddMember(CollectionData *obj,
TAdaptedString key, MemoryPool *pool) {
TAdaptedString key, MemoryPool *pool,
TStoragePolicy storage_policy) {
if (!obj)
return 0;
return obj->getOrAddMember(key, pool);
return obj->getOrAddMember(key, pool, storage_policy);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -196,7 +196,8 @@ class ObjectRef : public ObjectRefBase<CollectionData>,
template <typename TString>
FORCE_INLINE VariantRef getOrAddMember(const TString& key) const {
return VariantRef(_pool,
objectGetOrAddMember(_data, adaptString(key), _pool));
objectGetOrAddMember(_data, adaptString(key), _pool,
getStringStoragePolicy(key)));
}
// getOrAddMember(char*) const
@ -205,7 +206,8 @@ class ObjectRef : public ObjectRefBase<CollectionData>,
template <typename TChar>
FORCE_INLINE VariantRef getOrAddMember(TChar* key) const {
return VariantRef(_pool,
objectGetOrAddMember(_data, adaptString(key), _pool));
objectGetOrAddMember(_data, adaptString(key), _pool,
getStringStoragePolicy(key)));
}
FORCE_INLINE bool operator==(ObjectRef rhs) const {

View File

@ -65,6 +65,22 @@ inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) {
}
#endif
#ifndef memcmp_P
inline int memcmp_P(const void* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) {
const uint8_t* p1 = reinterpret_cast<const uint8_t*>(a);
const char* p2 = b.address;
ARDUINOJSON_ASSERT(p1 != NULL);
ARDUINOJSON_ASSERT(p2 != NULL);
while (n-- > 0) {
uint8_t v1 = *p1++;
uint8_t v2 = pgm_read_byte(p2++);
if (v1 != v2)
return v1 - v2;
}
return 0;
}
#endif
#ifndef memcpy_P
inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) {
uint8_t* d = reinterpret_cast<uint8_t*>(dst);

View File

@ -1,33 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <stdint.h> // int8_t
#include <string.h> // strcmp
namespace ARDUINOJSON_NAMESPACE {
inline int safe_strcmp(const char* a, const char* b) {
if (a == b)
return 0;
if (!a)
return -1;
if (!b)
return 1;
return strcmp(a, b);
}
inline int safe_strncmp(const char* a, const char* b, size_t n) {
if (a == b)
return 0;
if (!a)
return -1;
if (!b)
return 1;
return strncmp(a, b, n);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,24 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <Arduino.h>
#include <ArduinoJson/Strings/Adapters/RamString.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
namespace ARDUINOJSON_NAMESPACE {
inline SizedRamString adaptString(const ::String& s) {
return SizedRamString(s.c_str(), s.length());
}
template <>
struct IsString< ::String> : true_type {};
template <>
struct IsString< ::StringSumHelper> : true_type {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,56 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <Arduino.h>
#include <ArduinoJson/Polyfills/safe_strcmp.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <>
class StringAdapter< ::String> {
public:
StringAdapter(const ::String& str) : _str(&str) {}
void copyTo(char* p, size_t n) const {
memcpy(p, _str->c_str(), n);
}
bool isNull() const {
// Arduino's String::c_str() can return NULL
return !_str->c_str();
}
int compare(const char* other) const {
// Arduino's String::c_str() can return NULL
const char* me = _str->c_str();
return safe_strcmp(me, other);
}
char operator[](size_t i) const {
ARDUINOJSON_ASSERT(_str != 0);
return _str->operator[](static_cast<unsigned int>(i));
}
size_t size() const {
return _str->length();
}
typedef storage_policies::store_by_copy storage_policy;
private:
const ::String* _str;
};
template <>
class StringAdapter< ::StringSumHelper> : public StringAdapter< ::String> {
public:
StringAdapter(const ::String& s) : StringAdapter< ::String>(s) {}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,58 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <stddef.h> // size_t
#include <string.h> // strcmp
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/safe_strcmp.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <>
class StringAdapter<const char*> {
public:
StringAdapter(const char* str = 0) : _str(str) {}
int compare(const char* other) const {
return safe_strcmp(_str, other);
}
bool isNull() const {
return !_str;
}
size_t size() const {
if (!_str)
return 0;
return strlen(_str);
}
char operator[](size_t i) const {
ARDUINOJSON_ASSERT(_str != 0);
ARDUINOJSON_ASSERT(i <= size());
return _str[i];
}
const char* data() const {
return _str;
}
typedef storage_policies::store_by_address storage_policy;
protected:
const char* _str;
};
template <int N>
class StringAdapter<const char[N]> : public StringAdapter<const char*> {
public:
StringAdapter(const char* s) : StringAdapter<const char*>(s) {}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,80 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <Arduino.h>
#include <ArduinoJson/Polyfills/pgmspace.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
namespace ARDUINOJSON_NAMESPACE {
class FlashString {
public:
static const size_t typeSortKey = 1;
FlashString(const __FlashStringHelper* str, size_t sz)
: _str(reinterpret_cast<const char*>(str)), _size(sz) {}
bool isNull() const {
return !_str;
}
char operator[](size_t i) const {
ARDUINOJSON_ASSERT(_str != 0);
ARDUINOJSON_ASSERT(i <= _size);
return static_cast<char>(pgm_read_byte(_str + i));
}
size_t size() const {
return _size;
}
friend bool stringEquals(FlashString a, SizedRamString b) {
ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey);
ARDUINOJSON_ASSERT(!a.isNull());
ARDUINOJSON_ASSERT(!b.isNull());
if (a.size() != b.size())
return false;
return ::memcmp_P(b.data(), a._str, a._size) == 0;
}
friend int stringCompare(FlashString a, SizedRamString b) {
ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey);
ARDUINOJSON_ASSERT(!a.isNull());
ARDUINOJSON_ASSERT(!b.isNull());
size_t minsize = a.size() < b.size() ? a.size() : b.size();
int res = ::memcmp_P(b.data(), a._str, minsize);
if (res)
return -res;
if (a.size() < b.size())
return -1;
if (a.size() > b.size())
return 1;
return 0;
}
friend void stringGetChars(FlashString s, char* p, size_t n) {
ARDUINOJSON_ASSERT(s.size() <= n);
::memcpy_P(p, s._str, n);
}
private:
const char* _str;
size_t _size;
};
inline FlashString adaptString(const __FlashStringHelper* s) {
return FlashString(s, s ? strlen_P(reinterpret_cast<const char*>(s)) : 0);
}
inline FlashString adaptString(const __FlashStringHelper* s, size_t n) {
return FlashString(s, n);
}
template <>
struct IsString<const __FlashStringHelper*> : true_type {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,55 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/pgmspace.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <>
class StringAdapter<const __FlashStringHelper*> {
public:
StringAdapter(const __FlashStringHelper* str) : _str(str) {}
int compare(const char* other) const {
if (!other && !_str)
return 0;
if (!_str)
return -1;
if (!other)
return 1;
return -strcmp_P(other, reinterpret_cast<const char*>(_str));
}
bool isNull() const {
return !_str;
}
void copyTo(char* p, size_t n) const {
memcpy_P(p, reinterpret_cast<const char*>(_str), n);
}
size_t size() const {
if (!_str)
return 0;
return strlen_P(reinterpret_cast<const char*>(_str));
}
char operator[](size_t i) const {
ARDUINOJSON_ASSERT(_str != 0);
ARDUINOJSON_ASSERT(i <= size());
return static_cast<char>(
pgm_read_byte(reinterpret_cast<const char*>(_str) + i));
}
typedef storage_policies::store_by_copy storage_policy;
private:
const __FlashStringHelper* _str;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,20 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Strings/Adapters/RamString.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/String.hpp>
namespace ARDUINOJSON_NAMESPACE {
inline SizedRamString adaptString(const String& s) {
return SizedRamString(s.c_str(), s.size());
}
template <>
struct IsString<String> : true_type {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,27 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Strings/Adapters/RamStringAdapter.hpp>
#include <ArduinoJson/Strings/String.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <>
class StringAdapter<String> : public StringAdapter<char*> {
public:
StringAdapter(const String& str)
: StringAdapter<char*>(str.c_str()), _isStatic(str.isStatic()) {}
bool isStatic() const {
return _isStatic;
}
typedef storage_policies::decide_at_runtime storage_policy;
private:
bool _isStatic;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,119 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <stddef.h> // size_t
#include <string.h> // strcmp
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
namespace ARDUINOJSON_NAMESPACE {
class ZeroTerminatedRamString {
public:
static const size_t typeSortKey = 3;
ZeroTerminatedRamString(const char* str) : _str(str) {}
bool isNull() const {
return !_str;
}
size_t size() const {
return _str ? ::strlen(_str) : 0;
}
char operator[](size_t i) const {
ARDUINOJSON_ASSERT(_str != 0);
ARDUINOJSON_ASSERT(i <= size());
return _str[i];
}
const char* data() const {
return _str;
}
friend int stringCompare(ZeroTerminatedRamString a,
ZeroTerminatedRamString b) {
ARDUINOJSON_ASSERT(!a.isNull());
ARDUINOJSON_ASSERT(!b.isNull());
return ::strcmp(a._str, b._str);
}
friend bool stringEquals(ZeroTerminatedRamString a,
ZeroTerminatedRamString b) {
return stringCompare(a, b) == 0;
}
protected:
const char* _str;
};
template <>
struct IsString<char*> : true_type {};
inline ZeroTerminatedRamString adaptString(const char* s) {
return ZeroTerminatedRamString(s);
}
template <>
struct IsString<unsigned char*> : true_type {};
inline ZeroTerminatedRamString adaptString(const unsigned char* s) {
return adaptString(reinterpret_cast<const char*>(s));
}
template <>
struct IsString<signed char*> : true_type {};
inline ZeroTerminatedRamString adaptString(const signed char* s) {
return adaptString(reinterpret_cast<const char*>(s));
}
class SizedRamString {
public:
static const size_t typeSortKey = 2;
SizedRamString(const char* str, size_t sz) : _str(str), _size(sz) {}
bool isNull() const {
return !_str;
}
size_t size() const {
return _size;
}
char operator[](size_t i) const {
ARDUINOJSON_ASSERT(_str != 0);
ARDUINOJSON_ASSERT(i <= size());
return _str[i];
}
const char* data() const {
return _str;
}
protected:
const char* _str;
size_t _size;
};
inline SizedRamString adaptString(const char* s, size_t n) {
return SizedRamString(s, n);
}
template <int N>
struct IsString<char[N]> : true_type {};
template <int N>
struct IsString<const char[N]> : true_type {};
template <int N>
inline SizedRamString adaptString(char s[N]) {
return SizedRamString(s, strlen(s));
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,29 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TChar>
class StringAdapter<TChar*, false,
typename enable_if<sizeof(TChar) == 1 &&
!is_same<TChar, void>::value>::type>
: public StringAdapter<const char*> {
public:
StringAdapter(const TChar* str)
: StringAdapter<const char*>(reinterpret_cast<const char*>(str)) {}
void copyTo(char* p, size_t n) const {
memcpy(p, _str, n);
}
typedef ARDUINOJSON_NAMESPACE::storage_policies::store_by_copy storage_policy;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,56 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <>
class StringAdapter<const __FlashStringHelper*, true> {
public:
StringAdapter(const __FlashStringHelper* str, size_t sz)
: _str(str), _size(sz) {}
int compare(const char* other) const {
if (!other && !_str)
return 0;
if (!_str)
return -1;
if (!other)
return 1;
return -strncmp_P(other, reinterpret_cast<const char*>(_str), _size);
}
bool isNull() const {
return !_str;
}
void copyTo(char* p, size_t n) const {
memcpy_P(p, reinterpret_cast<const char*>(_str), n);
}
// TODO: not covered by the tests
char operator[](size_t i) const {
ARDUINOJSON_ASSERT(_str != 0);
ARDUINOJSON_ASSERT(i <= _size);
return static_cast<char>(
pgm_read_byte(reinterpret_cast<const char*>(_str) + i));
}
size_t size() const {
return _size;
}
typedef storage_policies::store_by_copy storage_policy;
private:
const __FlashStringHelper* _str;
size_t _size;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,49 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
#include <string.h> // strcmp
namespace ARDUINOJSON_NAMESPACE {
template <typename TChar>
class StringAdapter<TChar*, true> {
public:
StringAdapter(const char* str, size_t n) : _str(str), _size(n) {}
int compare(const char* other) const {
return safe_strncmp(_str, other, _size);
}
bool isNull() const {
return !_str;
}
void copyTo(char* p, size_t n) const {
memcpy(p, _str, n);
}
size_t size() const {
return _size;
}
char operator[](size_t i) const {
ARDUINOJSON_ASSERT(_str != 0);
ARDUINOJSON_ASSERT(i <= _size);
return _str[i];
}
typedef storage_policies::store_by_copy storage_policy;
private:
const char* _str;
size_t _size;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,23 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Strings/Adapters/RamString.hpp>
#include <string>
namespace ARDUINOJSON_NAMESPACE {
template <typename TCharTraits, typename TAllocator>
inline SizedRamString adaptString(
const std::basic_string<char, TCharTraits, TAllocator>& s) {
return SizedRamString(s.c_str(), s.size());
}
template <typename TCharTraits, typename TAllocator>
struct IsString<std::basic_string<char, TCharTraits, TAllocator> > : true_type {
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,51 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
#include <string>
namespace ARDUINOJSON_NAMESPACE {
template <typename TCharTraits, typename TAllocator>
class StringAdapter<std::basic_string<char, TCharTraits, TAllocator> > {
public:
typedef std::basic_string<char, TCharTraits, TAllocator> string_type;
StringAdapter(const string_type& str) : _str(&str) {}
void copyTo(char* p, size_t n) const {
memcpy(p, _str->c_str(), n);
}
bool isNull() const {
return false;
}
int compare(const char* other) const {
if (!other)
return 1;
return _str->compare(other);
}
char operator[](size_t i) const {
ARDUINOJSON_ASSERT(i <= size());
return _str->operator[](i);
}
size_t size() const {
return _str->size();
}
typedef storage_policies::store_by_copy storage_policy;
private:
const string_type* _str;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,20 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Strings/Adapters/RamString.hpp>
#include <string_view>
namespace ARDUINOJSON_NAMESPACE {
inline SizedRamString adaptString(const std::string_view& s) {
return SizedRamString(s.data(), s.size());
}
template <>
struct IsString<std::string_view> : true_type {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,49 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
#include <string_view>
namespace ARDUINOJSON_NAMESPACE {
template <>
class StringAdapter<std::string_view> {
public:
StringAdapter(std::string_view str) : _str(str) {}
void copyTo(char* p, size_t n) const {
memcpy(p, _str.data(), n);
}
bool isNull() const {
return false;
}
int compare(const char* other) const {
if (!other)
return 1;
return _str.compare(other);
}
char operator[](size_t i) const {
ARDUINOJSON_ASSERT(i <= size());
return _str[i];
}
size_t size() const {
return _str.size();
}
typedef storage_policies::store_by_copy storage_policy;
private:
std::string_view _str;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,17 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename T, typename Enable = void>
struct IsString : false_type {};
template <typename TChar>
struct IsString<const TChar*> : IsString<TChar*> {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -4,12 +4,56 @@
#pragma once
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Strings/StoredString.hpp>
#include <ArduinoJson/Strings/String.hpp>
namespace ARDUINOJSON_NAMESPACE {
namespace storage_policies {
struct store_by_address {};
struct store_by_copy {};
struct decide_at_runtime {};
} // namespace storage_policies
struct LinkStringStoragePolicy {
template <typename TAdaptedString, typename TCallback>
bool store(TAdaptedString str, MemoryPool *, TCallback callback) {
LinkedString storedString(str.data(), str.size());
callback(storedString);
return !str.isNull();
}
};
struct CopyStringStoragePolicy {
typedef CopiedString TResult;
template <typename TAdaptedString, typename TCallback>
bool store(TAdaptedString str, MemoryPool *pool, TCallback callback);
};
class LinkOrCopyStringStoragePolicy : LinkStringStoragePolicy,
CopyStringStoragePolicy {
public:
LinkOrCopyStringStoragePolicy(bool link) : _link(link) {}
template <typename TAdaptedString, typename TCallback>
bool store(TAdaptedString str, MemoryPool *pool, TCallback callback) {
if (_link)
return LinkStringStoragePolicy::store(str, pool, callback);
else
return CopyStringStoragePolicy::store(str, pool, callback);
}
private:
bool _link;
};
template <typename T>
inline CopyStringStoragePolicy getStringStoragePolicy(const T &) {
return CopyStringStoragePolicy();
}
inline LinkStringStoragePolicy getStringStoragePolicy(const char *) {
return LinkStringStoragePolicy();
}
inline LinkOrCopyStringStoragePolicy getStringStoragePolicy(const String &s) {
return LinkOrCopyStringStoragePolicy(s.isStatic());
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -4,12 +4,9 @@
#pragma once
#include <ArduinoJson/Polyfills/safe_strcmp.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TStoragePolicy>
template <bool linked>
class StoredString {
public:
StoredString() : _data(0), _size(0) {}
@ -32,7 +29,7 @@ class StoredString {
size_t _size;
};
typedef StoredString<storage_policies::store_by_address> LinkedString;
typedef StoredString<storage_policies::store_by_copy> CopiedString;
typedef StoredString<true> LinkedString;
typedef StoredString<false> CopiedString;
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,32 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename T, bool bounded = false, typename Enable = void>
class StringAdapter;
template <typename T>
inline StringAdapter<T, false> adaptString(const T& str) {
return StringAdapter<T, false>(str);
}
template <typename T>
inline StringAdapter<T, true> adaptString(const T& str, size_t sz) {
return StringAdapter<T, true>(str, sz);
}
template <typename T, typename Enable = void>
struct IsString : false_type {};
template <typename T>
struct IsString<
T, typename make_void<typename StringAdapter<T>::storage_policy>::type>
: true_type {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -4,24 +4,85 @@
#pragma once
#include <ArduinoJson/Strings/Adapters/ConstRamStringAdapter.hpp>
#include <ArduinoJson/Strings/Adapters/JsonStringAdapter.hpp>
#include <ArduinoJson/Strings/Adapters/RamStringAdapter.hpp>
#include <ArduinoJson/Strings/Adapters/SizedRamStringAdapter.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/Adapters/JsonString.hpp>
#include <ArduinoJson/Strings/Adapters/RamString.hpp>
#if ARDUINOJSON_ENABLE_STD_STRING
# include <ArduinoJson/Strings/Adapters/StdStringAdapter.hpp>
# include <ArduinoJson/Strings/Adapters/StdString.hpp>
#endif
#if ARDUINOJSON_ENABLE_STRING_VIEW
# include <ArduinoJson/Strings/Adapters/StringViewAdapter.hpp>
# include <ArduinoJson/Strings/Adapters/StringView.hpp>
#endif
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
# include <ArduinoJson/Strings/Adapters/ArduinoStringAdapter.hpp>
# include <ArduinoJson/Strings/Adapters/ArduinoString.hpp>
#endif
#if ARDUINOJSON_ENABLE_PROGMEM
# include <ArduinoJson/Strings/Adapters/FlashStringAdapter.hpp>
# include <ArduinoJson/Strings/Adapters/SizedFlashStringAdapter.hpp>
# include <ArduinoJson/Strings/Adapters/FlashString.hpp>
#endif
namespace ARDUINOJSON_NAMESPACE {
template <typename TAdaptedString1, typename TAdaptedString2>
typename enable_if<TAdaptedString1::typeSortKey <= TAdaptedString2::typeSortKey,
int>::type
stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) {
ARDUINOJSON_ASSERT(!s1.isNull());
ARDUINOJSON_ASSERT(!s2.isNull());
size_t size1 = s1.size();
size_t size2 = s2.size();
size_t n = size1 < size2 ? size1 : size2;
for (size_t i = 0; i < n; i++) {
if (s1[i] != s2[i])
return s1[i] - s2[i];
}
if (size1 < size2)
return -1;
if (size1 > size2)
return 1;
return 0;
}
template <typename TAdaptedString1, typename TAdaptedString2>
typename enable_if<
(TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), int>::type
stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) {
return -stringCompare(s2, s1);
}
template <typename TAdaptedString1, typename TAdaptedString2>
typename enable_if<TAdaptedString1::typeSortKey <= TAdaptedString2::typeSortKey,
bool>::type
stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) {
ARDUINOJSON_ASSERT(!s1.isNull());
ARDUINOJSON_ASSERT(!s2.isNull());
size_t size1 = s1.size();
size_t size2 = s2.size();
if (size1 != size2)
return false;
for (size_t i = 0; i < size1; i++) {
if (s1[i] != s2[i])
return false;
}
return true;
}
template <typename TAdaptedString1, typename TAdaptedString2>
typename enable_if<
(TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), bool>::type
stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) {
return stringEquals(s2, s1);
}
template <typename TAdaptedString>
static void stringGetChars(TAdaptedString s, char* p, size_t n) {
ARDUINOJSON_ASSERT(s.size() <= n);
for (size_t i = 0; i < n; i++) {
p[i] = s[i];
}
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -115,7 +115,8 @@ struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> {
template <>
struct Converter<const char*> {
static void toJson(const char* src, VariantRef dst) {
variantSetString(getData(dst), adaptString(src), getPool(dst));
variantSetString(getData(dst), adaptString(src), getPool(dst),
getStringStoragePolicy(src));
}
static const char* fromJson(VariantConstRef src) {
@ -132,7 +133,8 @@ struct Converter<const char*> {
template <>
struct Converter<String> {
static void toJson(String src, VariantRef dst) {
variantSetString(getData(dst), adaptString(src), getPool(dst));
variantSetString(getData(dst), adaptString(src), getPool(dst),
getStringStoragePolicy(src));
}
static String fromJson(VariantConstRef src) {
@ -151,7 +153,8 @@ inline typename enable_if<IsString<T>::value, bool>::type convertToJson(
const T& src, VariantRef dst) {
VariantData* data = getData(dst);
MemoryPool* pool = getPool(dst);
return variantSetString(data, adaptString(src), pool);
return variantSetString(data, adaptString(src), pool,
getStringStoragePolicy(src));
}
template <>

View File

@ -9,40 +9,24 @@
namespace ARDUINOJSON_NAMESPACE {
template <typename TAdaptedString>
inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) {
if (!var)
return false;
return slotSetKey(var, key, pool, typename TAdaptedString::storage_policy());
}
struct SlotKeySetter {
SlotKeySetter(VariantSlot* instance) : _instance(instance) {}
template <typename TAdaptedString>
inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool,
storage_policies::decide_at_runtime) {
if (key.isStatic()) {
return slotSetKey(var, key, pool, storage_policies::store_by_address());
} else {
return slotSetKey(var, key, pool, storage_policies::store_by_copy());
template <typename TStoredString>
void operator()(TStoredString s) {
if (!s)
return;
ARDUINOJSON_ASSERT(_instance != 0);
_instance->setKey(s);
}
}
template <typename TAdaptedString>
inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*,
storage_policies::store_by_address) {
ARDUINOJSON_ASSERT(var);
var->setKey(LinkedString(key.data(), key.size()));
return true;
}
VariantSlot* _instance;
};
template <typename TAdaptedString>
template <typename TAdaptedString, typename TStoragePolicy>
inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool,
storage_policies::store_by_copy) {
CopiedString dup(pool->saveString(key), key.size());
if (!dup)
return false;
ARDUINOJSON_ASSERT(var);
var->setKey(dup);
return true;
TStoragePolicy storage) {
return storage.store(key, pool, SlotKeySetter(var));
}
inline size_t slotSize(const VariantSlot* var) {

View File

@ -8,7 +8,7 @@
#include <ArduinoJson/Misc/Visitable.hpp>
#include <ArduinoJson/Numbers/arithmeticCompare.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/Visitor.hpp>
namespace ARDUINOJSON_NAMESPACE {
@ -23,12 +23,12 @@ struct Comparer;
template <typename T>
struct Comparer<T, typename enable_if<IsString<T>::value>::type>
: ComparerBase {
T rhs;
T rhs; // TODO: store adapted string?
explicit Comparer(T value) : rhs(value) {}
CompareResult visitString(const char *lhs, size_t) {
int i = adaptString(rhs).compare(lhs);
CompareResult visitString(const char *lhs, size_t n) {
int i = stringCompare(adaptString(rhs), adaptString(lhs, n));
if (i < 0)
return COMPARE_RESULT_GREATER;
else if (i > 0)

View File

@ -99,27 +99,7 @@ class VariantData {
return const_cast<VariantData *>(this)->asObject();
}
bool copyFrom(const VariantData &src, MemoryPool *pool) {
switch (src.type()) {
case VALUE_IS_ARRAY:
return toArray().copyFrom(src._content.asCollection, pool);
case VALUE_IS_OBJECT:
return toObject().copyFrom(src._content.asCollection, pool);
case VALUE_IS_OWNED_STRING:
return storeString(
adaptString(const_cast<char *>(src._content.asString.data),
src._content.asString.size),
pool);
case VALUE_IS_OWNED_RAW:
return storeOwnedRaw(
serialized(src._content.asString.data, src._content.asString.size),
pool);
default:
setType(src.type());
_content = src._content;
return true;
}
}
bool copyFrom(const VariantData &src, MemoryPool *pool);
bool isArray() const {
return (_flags & VALUE_IS_ARRAY) != 0;
@ -242,11 +222,6 @@ class VariantData {
_content.asString.size = s.size();
}
template <typename TAdaptedString>
bool storeString(TAdaptedString value, MemoryPool *pool) {
return storeString(value, pool, typename TAdaptedString::storage_policy());
}
CollectionData &toArray() {
setType(VALUE_IS_ARRAY);
_content.asCollection.clear();
@ -307,13 +282,14 @@ class VariantData {
return isObject() ? _content.asCollection.getMember(key) : 0;
}
template <typename TAdaptedString>
VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) {
template <typename TAdaptedString, typename TStoragePolicy>
VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool,
TStoragePolicy storage_policy) {
if (isNull())
toObject();
if (!isObject())
return 0;
return _content.asCollection.getOrAddMember(key, pool);
return _content.asCollection.getOrAddMember(key, pool, storage_policy);
}
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) {
@ -327,46 +303,36 @@ class VariantData {
return _flags & VALUE_MASK;
}
template <typename TAdaptedString, typename TStoragePolicy>
inline bool storeString(TAdaptedString value, MemoryPool *pool,
TStoragePolicy storage) {
if (value.isNull()) {
setNull();
return true;
}
return storage.store(value, pool, VariantStringSetter(this));
}
private:
void setType(uint8_t t) {
_flags &= OWNED_KEY_BIT;
_flags |= t;
}
template <typename TAdaptedString>
inline bool storeString(TAdaptedString value, MemoryPool *pool,
storage_policies::decide_at_runtime) {
if (value.isStatic())
return storeString(value, pool, storage_policies::store_by_address());
struct VariantStringSetter {
VariantStringSetter(VariantData *instance) : _instance(instance) {}
template <typename TStoredString>
void operator()(TStoredString s) {
if (s)
_instance->setString(s);
else
return storeString(value, pool, storage_policies::store_by_copy());
_instance->setNull();
}
template <typename TAdaptedString>
inline bool storeString(TAdaptedString value, MemoryPool *,
storage_policies::store_by_address) {
if (value.isNull())
setNull();
else
setString(LinkedString(value.data(), value.size()));
return true;
}
template <typename TAdaptedString>
inline bool storeString(TAdaptedString value, MemoryPool *pool,
storage_policies::store_by_copy) {
if (value.isNull()) {
setNull();
return true;
}
const char *copy = pool->saveString(value);
if (!copy) {
setNull();
return false;
}
setString(CopiedString(copy, value.size()));
return true;
}
VariantData *_instance;
};
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -5,6 +5,7 @@
#pragma once
#include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
namespace ARDUINOJSON_NAMESPACE {
@ -49,12 +50,10 @@ inline void variantSetNull(VariantData *var) {
var->setNull();
}
template <typename TAdaptedString>
template <typename TAdaptedString, typename TStoragePolicy>
inline bool variantSetString(VariantData *var, TAdaptedString value,
MemoryPool *pool) {
if (!var)
return false;
return var->storeString(value, pool);
MemoryPool *pool, TStoragePolicy storage_policy) {
return var != 0 ? var->storeString(value, pool, storage_policy) : 0;
}
inline size_t variantSize(const VariantData *var) {
@ -87,14 +86,18 @@ inline NO_INLINE VariantData *variantGetOrAddElement(VariantData *var,
template <typename TChar>
NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, TChar *key,
MemoryPool *pool) {
return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0;
return var != 0 ? var->getOrAddMember(adaptString(key), pool,
getStringStoragePolicy(key))
: 0;
}
template <typename TString>
NO_INLINE VariantData *variantGetOrAddMember(VariantData *var,
const TString &key,
MemoryPool *pool) {
return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0;
return var != 0 ? var->getOrAddMember(adaptString(key), pool,
getStringStoragePolicy(key))
: 0;
}
inline bool variantIsNull(const VariantData *var) {

View File

@ -81,6 +81,28 @@ inline String VariantData::asString() const {
}
}
inline bool VariantData::copyFrom(const VariantData &src, MemoryPool *pool) {
switch (src.type()) {
case VALUE_IS_ARRAY:
return toArray().copyFrom(src._content.asCollection, pool);
case VALUE_IS_OBJECT:
return toObject().copyFrom(src._content.asCollection, pool);
case VALUE_IS_OWNED_STRING: {
String value = src.asString();
return storeString(adaptString(value), pool,
getStringStoragePolicy(value));
}
case VALUE_IS_OWNED_RAW:
return storeOwnedRaw(
serialized(src._content.asString.data, src._content.asString.size),
pool);
default:
setType(src.type());
_content = src._content;
return true;
}
}
template <typename T>
inline typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type
VariantRef::to() const {
@ -146,4 +168,15 @@ inline VariantConstRef operator|(VariantConstRef preferedValue,
inline bool VariantRef::set(char value) const {
return set<signed char>(value);
}
// TODO: move somewhere else
template <typename TAdaptedString, typename TCallback>
bool CopyStringStoragePolicy::store(TAdaptedString str, MemoryPool *pool,
TCallback callback) {
const char *copy = pool->saveString(str);
CopiedString storedString(copy, str.size());
callback(storedString);
return copy != 0;
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -7,7 +7,6 @@
#include <ArduinoJson/Polyfills/integer.hpp>
#include <ArduinoJson/Polyfills/limits.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StoredString.hpp>
#include <ArduinoJson/Variant/VariantContent.hpp>