forked from bblanchon/ArduinoJson
Removed the indirection via StringSlot
This commit is contained in:
@ -7,8 +7,8 @@ project(ArduinoJson)
|
|||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
|
add_definitions(-DARDUINOJSON_DEBUG)
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||||
add_definitions(-DARDUINOJSON_DEBUG)
|
|
||||||
add_compile_options(-g -O0)
|
add_compile_options(-g -O0)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
Version,Date,JsonParserExample,JsonGeneratorExample
|
Version,Date,JsonParserExample,JsonGeneratorExample
|
||||||
|
v6.6.0-beta-6-g8217012,2018-11-27,7204,7630
|
||||||
|
v6.6.0-beta-5-g13cc610,2018-11-27,7264,7850
|
||||||
v6.6.0-beta-2-g2bd280d,2018-11-16,7872,8446
|
v6.6.0-beta-2-g2bd280d,2018-11-16,7872,8446
|
||||||
v6.6.0-beta,2018-11-13,8380,8916
|
v6.6.0-beta,2018-11-13,8380,8916
|
||||||
v6.5.0-beta,2018-10-13,7384,7874
|
v6.5.0-beta,2018-10-13,7384,7874
|
||||||
|
|
@ -48,8 +48,6 @@ union JsonVariantContent {
|
|||||||
JsonArrayData asArray;
|
JsonArrayData asArray;
|
||||||
JsonObjectData asObject;
|
JsonObjectData asObject;
|
||||||
const char *asString;
|
const char *asString;
|
||||||
struct StringSlot *asOwnedString;
|
|
||||||
struct StringSlot *asOwnedRaw;
|
|
||||||
struct {
|
struct {
|
||||||
const char *data;
|
const char *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -103,9 +103,9 @@ inline bool objectCopy(JsonObjectData* dst, const JsonObjectData* src,
|
|||||||
for (VariantSlot* s = src->head; s; s = s->next) {
|
for (VariantSlot* s = src->head; s; s = s->next) {
|
||||||
JsonVariantData* var;
|
JsonVariantData* var;
|
||||||
if (s->value.keyIsOwned)
|
if (s->value.keyIsOwned)
|
||||||
var = objectAdd(dst, ZeroTerminatedRamString(s->ownedKey->value), pool);
|
var = objectAdd(dst, ZeroTerminatedRamString(s->key), pool);
|
||||||
else
|
else
|
||||||
var = objectAdd(dst, ZeroTerminatedRamStringConst(s->linkedKey), pool);
|
var = objectAdd(dst, ZeroTerminatedRamStringConst(s->key), pool);
|
||||||
if (!variantCopy(var, &s->value, pool)) return false;
|
if (!variantCopy(var, &s->value, pool)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -13,28 +13,28 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
template <typename TKey>
|
template <typename TKey>
|
||||||
inline bool slotSetKey(VariantSlot* var, TKey key, MemoryPool* pool) {
|
inline bool slotSetKey(VariantSlot* var, TKey key, MemoryPool* pool) {
|
||||||
StringSlot* slot = key.save(pool);
|
char* dup = key.save(pool);
|
||||||
if (!slot) return false;
|
if (!dup) return false;
|
||||||
var->ownedKey = slot;
|
var->key = dup;
|
||||||
var->value.keyIsOwned = true;
|
var->value.keyIsOwned = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool slotSetKey(VariantSlot* var, ZeroTerminatedRamStringConst key,
|
inline bool slotSetKey(VariantSlot* var, ZeroTerminatedRamStringConst key,
|
||||||
MemoryPool*) {
|
MemoryPool*) {
|
||||||
var->linkedKey = key.c_str();
|
var->key = key.c_str();
|
||||||
var->value.keyIsOwned = false;
|
var->value.keyIsOwned = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool slotSetKey(VariantSlot* var, StringInMemoryPool key, MemoryPool*) {
|
inline bool slotSetKey(VariantSlot* var, StringInMemoryPool key, MemoryPool*) {
|
||||||
var->ownedKey = key.slot();
|
var->key = key.c_str();
|
||||||
var->value.keyIsOwned = true;
|
var->value.keyIsOwned = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char* slotGetKey(const VariantSlot* var) {
|
inline const char* slotGetKey(const VariantSlot* var) {
|
||||||
return var->value.keyIsOwned ? var->ownedKey->value : var->linkedKey;
|
return var->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const VariantSlot* slotAdvance(const VariantSlot* var, size_t distance) {
|
inline const VariantSlot* slotAdvance(const VariantSlot* var, size_t distance) {
|
||||||
|
@ -22,9 +22,8 @@ inline T variantAsIntegral(const JsonVariantData* var) {
|
|||||||
case JSON_NEGATIVE_INTEGER:
|
case JSON_NEGATIVE_INTEGER:
|
||||||
return T(~var->content.asInteger + 1);
|
return T(~var->content.asInteger + 1);
|
||||||
case JSON_LINKED_STRING:
|
case JSON_LINKED_STRING:
|
||||||
return parseInteger<T>(var->content.asString);
|
|
||||||
case JSON_OWNED_STRING:
|
case JSON_OWNED_STRING:
|
||||||
return parseInteger<T>(var->content.asOwnedString->value);
|
return parseInteger<T>(var->content.asString);
|
||||||
case JSON_FLOAT:
|
case JSON_FLOAT:
|
||||||
return T(var->content.asFloat);
|
return T(var->content.asFloat);
|
||||||
default:
|
default:
|
||||||
@ -47,9 +46,8 @@ inline T variantAsFloat(const JsonVariantData* var) {
|
|||||||
case JSON_NEGATIVE_INTEGER:
|
case JSON_NEGATIVE_INTEGER:
|
||||||
return -static_cast<T>(var->content.asInteger);
|
return -static_cast<T>(var->content.asInteger);
|
||||||
case JSON_LINKED_STRING:
|
case JSON_LINKED_STRING:
|
||||||
return parseFloat<T>(var->content.asString);
|
|
||||||
case JSON_OWNED_STRING:
|
case JSON_OWNED_STRING:
|
||||||
return parseFloat<T>(var->content.asOwnedString->value);
|
return parseFloat<T>(var->content.asString);
|
||||||
case JSON_FLOAT:
|
case JSON_FLOAT:
|
||||||
return static_cast<T>(var->content.asFloat);
|
return static_cast<T>(var->content.asFloat);
|
||||||
default:
|
default:
|
||||||
@ -61,9 +59,8 @@ inline const char* variantAsString(const JsonVariantData* var) {
|
|||||||
if (!var) return 0;
|
if (!var) return 0;
|
||||||
switch (var->type) {
|
switch (var->type) {
|
||||||
case JSON_LINKED_STRING:
|
case JSON_LINKED_STRING:
|
||||||
return var->content.asString;
|
|
||||||
case JSON_OWNED_STRING:
|
case JSON_OWNED_STRING:
|
||||||
return var->content.asOwnedString->value;
|
return var->content.asString;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -144,10 +141,11 @@ template <typename T>
|
|||||||
inline bool variantSetOwnedRaw(JsonVariantData* var, SerializedValue<T> value,
|
inline bool variantSetOwnedRaw(JsonVariantData* var, SerializedValue<T> value,
|
||||||
MemoryPool* pool) {
|
MemoryPool* pool) {
|
||||||
if (!var) return false;
|
if (!var) return false;
|
||||||
StringSlot* slot = makeString(value.data(), value.size()).save(pool);
|
char* dup = makeString(value.data(), value.size()).save(pool);
|
||||||
if (slot) {
|
if (dup) {
|
||||||
var->type = JSON_OWNED_RAW;
|
var->type = JSON_OWNED_RAW;
|
||||||
var->content.asOwnedRaw = slot;
|
var->content.asRaw.data = dup;
|
||||||
|
var->content.asRaw.size = value.size();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
var->type = JSON_NULL;
|
var->type = JSON_NULL;
|
||||||
@ -158,10 +156,10 @@ inline bool variantSetOwnedRaw(JsonVariantData* var, SerializedValue<T> value,
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool variantSetString(JsonVariantData* var, T value, MemoryPool* pool) {
|
inline bool variantSetString(JsonVariantData* var, T value, MemoryPool* pool) {
|
||||||
if (!var) return false;
|
if (!var) return false;
|
||||||
StringSlot* slot = value.save(pool);
|
char* dup = value.save(pool);
|
||||||
if (slot) {
|
if (dup) {
|
||||||
var->type = JSON_OWNED_STRING;
|
var->type = JSON_OWNED_STRING;
|
||||||
var->content.asOwnedString = slot;
|
var->content.asString = dup;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
var->type = JSON_NULL;
|
var->type = JSON_NULL;
|
||||||
@ -169,10 +167,10 @@ inline bool variantSetString(JsonVariantData* var, T value, MemoryPool* pool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool variantSetOwnedString(JsonVariantData* var, StringSlot* slot) {
|
inline bool variantSetOwnedString(JsonVariantData* var, char* s) {
|
||||||
if (!var) return false;
|
if (!var) return false;
|
||||||
var->type = JSON_OWNED_STRING;
|
var->type = JSON_OWNED_STRING;
|
||||||
var->content.asOwnedString = slot;
|
var->content.asString = s;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,12 +216,11 @@ inline bool variantCopy(JsonVariantData* dst, const JsonVariantData* src,
|
|||||||
return objectCopy(variantToObject(dst), &src->content.asObject, pool);
|
return objectCopy(variantToObject(dst), &src->content.asObject, pool);
|
||||||
case JSON_OWNED_STRING:
|
case JSON_OWNED_STRING:
|
||||||
return variantSetString(
|
return variantSetString(
|
||||||
dst, makeString(src->content.asOwnedString->value), pool);
|
dst, ZeroTerminatedRamString(src->content.asString), pool);
|
||||||
case JSON_OWNED_RAW:
|
case JSON_OWNED_RAW:
|
||||||
return variantSetOwnedRaw(dst,
|
return variantSetOwnedRaw(
|
||||||
serialized(src->content.asOwnedRaw->value,
|
dst, serialized(src->content.asRaw.data, src->content.asRaw.size),
|
||||||
src->content.asOwnedRaw->size),
|
pool);
|
||||||
pool);
|
|
||||||
default:
|
default:
|
||||||
// caution: don't override keyIsOwned
|
// caution: don't override keyIsOwned
|
||||||
dst->type = src->type;
|
dst->type = src->type;
|
||||||
@ -266,16 +263,15 @@ inline bool variantEquals(const JsonVariantData* a, const JsonVariantData* b) {
|
|||||||
if (a->type != b->type) return false;
|
if (a->type != b->type) return false;
|
||||||
|
|
||||||
switch (a->type) {
|
switch (a->type) {
|
||||||
case JSON_LINKED_RAW:
|
|
||||||
case JSON_LINKED_STRING:
|
case JSON_LINKED_STRING:
|
||||||
|
case JSON_OWNED_STRING:
|
||||||
return !strcmp(a->content.asString, b->content.asString);
|
return !strcmp(a->content.asString, b->content.asString);
|
||||||
|
|
||||||
|
case JSON_LINKED_RAW:
|
||||||
case JSON_OWNED_RAW:
|
case JSON_OWNED_RAW:
|
||||||
case JSON_OWNED_STRING:
|
return a->content.asRaw.size == b->content.asRaw.size &&
|
||||||
return a->content.asOwnedString->size == b->content.asOwnedString->size &&
|
!memcmp(a->content.asRaw.data, b->content.asRaw.data,
|
||||||
!memcmp(a->content.asOwnedString->value,
|
a->content.asRaw.size);
|
||||||
b->content.asOwnedString->value,
|
|
||||||
a->content.asOwnedString->size);
|
|
||||||
|
|
||||||
case JSON_BOOLEAN:
|
case JSON_BOOLEAN:
|
||||||
case JSON_POSITIVE_INTEGER:
|
case JSON_POSITIVE_INTEGER:
|
||||||
|
@ -19,7 +19,7 @@ class JsonKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
return _slot == 0 || _slot->linkedKey == 0;
|
return _slot == 0 || _slot->key == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(JsonKey lhs, const char* rhs) {
|
friend bool operator==(JsonKey lhs, const char* rhs) {
|
||||||
|
@ -206,7 +206,8 @@ class JsonVariant : public JsonVariantProxy<JsonVariantData>,
|
|||||||
|
|
||||||
// for internal use only
|
// for internal use only
|
||||||
FORCE_INLINE bool set(StringInMemoryPool value) const {
|
FORCE_INLINE bool set(StringInMemoryPool value) const {
|
||||||
return variantSetOwnedString(_data, value.slot());
|
return variantSetOwnedString(_data,
|
||||||
|
value.save(_memoryPool)); // TODO: remove?
|
||||||
}
|
}
|
||||||
FORCE_INLINE bool set(ZeroTerminatedRamStringConst value) const {
|
FORCE_INLINE bool set(ZeroTerminatedRamStringConst value) const {
|
||||||
return variantSetString(_data, value.c_str());
|
return variantSetString(_data, value.c_str());
|
||||||
|
@ -89,15 +89,10 @@ inline void JsonVariantConst::accept(Visitor& visitor) const {
|
|||||||
return visitor.visitObject(JsonObjectConst(&_data->content.asObject));
|
return visitor.visitObject(JsonObjectConst(&_data->content.asObject));
|
||||||
|
|
||||||
case JSON_LINKED_STRING:
|
case JSON_LINKED_STRING:
|
||||||
|
case JSON_OWNED_STRING:
|
||||||
return visitor.visitString(_data->content.asString);
|
return visitor.visitString(_data->content.asString);
|
||||||
|
|
||||||
case JSON_OWNED_STRING:
|
|
||||||
return visitor.visitString(_data->content.asOwnedString->value);
|
|
||||||
|
|
||||||
case JSON_OWNED_RAW:
|
case JSON_OWNED_RAW:
|
||||||
return visitor.visitRawJson(_data->content.asOwnedRaw->value,
|
|
||||||
_data->content.asOwnedRaw->size);
|
|
||||||
|
|
||||||
case JSON_LINKED_RAW:
|
case JSON_LINKED_RAW:
|
||||||
return visitor.visitRawJson(_data->content.asRaw.data,
|
return visitor.visitRawJson(_data->content.asRaw.data,
|
||||||
_data->content.asRaw.size);
|
_data->content.asRaw.size);
|
||||||
|
@ -23,21 +23,6 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
// _left _right
|
// _left _right
|
||||||
|
|
||||||
class MemoryPool {
|
class MemoryPool {
|
||||||
class UpdateStringSlotAddress {
|
|
||||||
public:
|
|
||||||
UpdateStringSlotAddress(const char* address, size_t offset)
|
|
||||||
: _address(address), _offset(offset) {}
|
|
||||||
|
|
||||||
void operator()(StringSlot* slot) const {
|
|
||||||
ARDUINOJSON_ASSERT(slot != NULL);
|
|
||||||
if (slot->value > _address) slot->value -= _offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const char* _address;
|
|
||||||
size_t _offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MemoryPool(char* buf, size_t capa)
|
MemoryPool(char* buf, size_t capa)
|
||||||
: _begin(buf),
|
: _begin(buf),
|
||||||
@ -66,34 +51,26 @@ class MemoryPool {
|
|||||||
return allocRight<VariantSlot>();
|
return allocRight<VariantSlot>();
|
||||||
}
|
}
|
||||||
|
|
||||||
StringSlot* allocFrozenString(size_t n) {
|
char* allocFrozenString(size_t n) {
|
||||||
StringSlot* s = allocStringSlot();
|
|
||||||
if (!s) return 0;
|
|
||||||
if (!canAlloc(n)) return 0;
|
if (!canAlloc(n)) return 0;
|
||||||
|
char* s = _left;
|
||||||
s->value = _left;
|
|
||||||
s->size = n;
|
|
||||||
_left += n;
|
_left += n;
|
||||||
checkInvariants();
|
checkInvariants();
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringSlot* allocExpandableString() {
|
StringSlot allocExpandableString() {
|
||||||
StringSlot* s = allocStringSlot();
|
StringSlot s;
|
||||||
if (!s) return 0;
|
s.value = _left;
|
||||||
|
s.size = size_t(_right - _left);
|
||||||
s->value = _left;
|
|
||||||
s->size = size_t(_right - _left);
|
|
||||||
_left = _right;
|
_left = _right;
|
||||||
|
|
||||||
checkInvariants();
|
checkInvariants();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freezeString(StringSlot* slot, size_t newSize) {
|
void freezeString(StringSlot& s, size_t newSize) {
|
||||||
_left -= (slot->size - newSize);
|
_left -= (s.size - newSize);
|
||||||
slot->size = newSize;
|
s.size = newSize;
|
||||||
checkInvariants();
|
checkInvariants();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,28 +26,28 @@ class StringBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void append(char c) {
|
void append(char c) {
|
||||||
if (!_slot) return;
|
if (!_slot.value) return;
|
||||||
|
|
||||||
if (_size >= _slot->size) {
|
if (_size >= _slot.size) {
|
||||||
_slot = 0;
|
_slot.value = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_slot->value[_size++] = c;
|
_slot.value[_size++] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringType complete() {
|
StringType complete() {
|
||||||
append('\0');
|
append('\0');
|
||||||
if (_slot) {
|
if (_slot.value) {
|
||||||
_parent->freezeString(_slot, _size);
|
_parent->freezeString(_slot, _size);
|
||||||
}
|
}
|
||||||
return _slot;
|
return _slot.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryPool* _parent;
|
MemoryPool* _parent;
|
||||||
size_t _size;
|
size_t _size;
|
||||||
StringSlot* _slot;
|
StringSlot _slot;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -7,14 +7,12 @@
|
|||||||
#include <stddef.h> // for size_t
|
#include <stddef.h> // for size_t
|
||||||
#include "../Configuration.hpp"
|
#include "../Configuration.hpp"
|
||||||
|
|
||||||
#define JSON_STRING_SIZE(SIZE) \
|
#define JSON_STRING_SIZE(SIZE) (SIZE)
|
||||||
(sizeof(ARDUINOJSON_NAMESPACE::StringSlot) + (SIZE))
|
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
struct StringSlot {
|
struct StringSlot {
|
||||||
char *value;
|
char *value;
|
||||||
size_t size;
|
size_t size;
|
||||||
struct StringSlot *next;
|
|
||||||
};
|
};
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -12,10 +12,7 @@ struct VariantSlot {
|
|||||||
JsonVariantData value;
|
JsonVariantData value;
|
||||||
struct VariantSlot* next;
|
struct VariantSlot* next;
|
||||||
struct VariantSlot* prev;
|
struct VariantSlot* prev;
|
||||||
union {
|
const char* key;
|
||||||
const char* linkedKey;
|
|
||||||
StringSlot* ownedKey;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -12,13 +12,12 @@ class ArduinoString {
|
|||||||
public:
|
public:
|
||||||
ArduinoString(const ::String& str) : _str(&str) {}
|
ArduinoString(const ::String& str) : _str(&str) {}
|
||||||
|
|
||||||
template <typename TMemoryPool>
|
char* save(MemoryPool* memoryPool) const {
|
||||||
StringSlot* save(TMemoryPool* memoryPool) const {
|
|
||||||
if (isNull()) return NULL;
|
if (isNull()) return NULL;
|
||||||
size_t n = _str->length() + 1;
|
size_t n = _str->length() + 1;
|
||||||
StringSlot* slot = memoryPool->allocFrozenString(n);
|
char* dup = memoryPool->allocFrozenString(n);
|
||||||
if (slot) memcpy(slot->value, _str->c_str(), n);
|
if (dup) memcpy(dup, _str->c_str(), n);
|
||||||
return slot;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
|
@ -21,12 +21,11 @@ class FixedSizeFlashString {
|
|||||||
return !_str;
|
return !_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TMemoryPool>
|
char* save(MemoryPool* memoryPool) const {
|
||||||
StringSlot* save(TMemoryPool* memoryPool) const {
|
|
||||||
if (!_str) return NULL;
|
if (!_str) return NULL;
|
||||||
StringSlot* slot = memoryPool->allocFrozenString(_size);
|
char* dup = memoryPool->allocFrozenString(_size);
|
||||||
if (!slot) memcpy_P(slot->value, (const char*)_str, _size);
|
if (!dup) memcpy_P(dup, (const char*)_str, _size);
|
||||||
return slot;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
|
@ -23,11 +23,11 @@ class FixedSizeRamString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TMemoryPool>
|
template <typename TMemoryPool>
|
||||||
StringSlot* save(TMemoryPool* memoryPool) const {
|
char* save(TMemoryPool* memoryPool) const {
|
||||||
if (!_str) return NULL;
|
if (!_str) return NULL;
|
||||||
StringSlot* slot = memoryPool->allocFrozenString(_size);
|
char* dup = memoryPool->allocFrozenString(_size);
|
||||||
if (slot) memcpy(slot->value, _str, _size);
|
if (dup) memcpy(dup, _str, _size);
|
||||||
return slot;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
|
@ -12,12 +12,11 @@ class StlString {
|
|||||||
public:
|
public:
|
||||||
StlString(const std::string& str) : _str(&str) {}
|
StlString(const std::string& str) : _str(&str) {}
|
||||||
|
|
||||||
template <typename TMemoryPool>
|
char* save(MemoryPool* memoryPool) const {
|
||||||
StringSlot* save(TMemoryPool* memoryPool) const {
|
|
||||||
size_t n = _str->length() + 1;
|
size_t n = _str->length() + 1;
|
||||||
StringSlot* slot = memoryPool->allocFrozenString(n);
|
char* dup = memoryPool->allocFrozenString(n);
|
||||||
if (slot) memcpy(slot->value, _str->c_str(), n);
|
if (dup) memcpy(dup, _str->c_str(), n);
|
||||||
return slot;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
|
@ -5,44 +5,35 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../Memory/StringSlot.hpp"
|
#include "../Memory/MemoryPool.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
class StringInMemoryPool {
|
class StringInMemoryPool {
|
||||||
public:
|
public:
|
||||||
StringInMemoryPool(StringSlot* s = 0) : _slot(s) {}
|
StringInMemoryPool(char* s = 0) : _value(s) {}
|
||||||
|
|
||||||
bool equals(const char* expected) const {
|
bool equals(const char* expected) const {
|
||||||
if (!_slot) return expected == 0;
|
if (!_value) return expected == 0;
|
||||||
const char* actual = _slot->value;
|
const char* actual = _value;
|
||||||
if (actual == expected) return true;
|
if (actual == expected) return true;
|
||||||
return strcmp(actual, expected) == 0;
|
return strcmp(actual, expected) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* save(void*) {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
return !_slot;
|
return !_value;
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TMemoryPool>
|
|
||||||
StringSlot* save(TMemoryPool*) const {
|
|
||||||
return _slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const {
|
|
||||||
return _slot->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringSlot* slot() const {
|
|
||||||
return _slot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* c_str() const {
|
const char* c_str() const {
|
||||||
return _slot->value;
|
return _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StringSlot* _slot;
|
char* _value;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -20,13 +20,12 @@ class ZeroTerminatedFlashString {
|
|||||||
return !_str;
|
return !_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TMemoryPool>
|
char* save(MemoryPool* memoryPool) const {
|
||||||
StringSlot* save(TMemoryPool* memoryPool) const {
|
|
||||||
if (!_str) return NULL;
|
if (!_str) return NULL;
|
||||||
size_t n = size() + 1; // copy the terminator
|
size_t n = size() + 1; // copy the terminator
|
||||||
StringSlot* slot = memoryPool->allocFrozenString(n);
|
char* dup = memoryPool->allocFrozenString(n);
|
||||||
if (slot) memcpy_P(slot->value, reinterpret_cast<const char*>(_str), n);
|
if (dup) memcpy_P(dup, reinterpret_cast<const char*>(_str), n);
|
||||||
return slot;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
|
@ -14,12 +14,12 @@ class ZeroTerminatedRamString : public ZeroTerminatedRamStringConst {
|
|||||||
: ZeroTerminatedRamStringConst(str) {}
|
: ZeroTerminatedRamStringConst(str) {}
|
||||||
|
|
||||||
template <typename TMemoryPool>
|
template <typename TMemoryPool>
|
||||||
StringSlot* save(TMemoryPool* memoryPool) const {
|
char* save(TMemoryPool* memoryPool) const {
|
||||||
if (!_str) return NULL;
|
if (!_str) return NULL;
|
||||||
size_t n = size() + 1;
|
size_t n = size() + 1;
|
||||||
StringSlot* slot = memoryPool->allocFrozenString(n);
|
char* dup = memoryPool->allocFrozenString(n);
|
||||||
if (slot) memcpy(slot->value, _str, n);
|
if (dup) memcpy(dup, _str, n);
|
||||||
return slot;
|
return dup;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,12 +79,12 @@ TEST_CASE("JsonVariant with not enough memory") {
|
|||||||
JsonVariant v = doc.to<JsonVariant>();
|
JsonVariant v = doc.to<JsonVariant>();
|
||||||
|
|
||||||
SECTION("std::string") {
|
SECTION("std::string") {
|
||||||
v.set(std::string("hello"));
|
v.set(std::string("hello world!!"));
|
||||||
REQUIRE(v.isNull());
|
REQUIRE(v.isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Serialized<std::string>") {
|
SECTION("Serialized<std::string>") {
|
||||||
v.set(serialized(std::string("hello")));
|
v.set(serialized(std::string("hello world!!")));
|
||||||
REQUIRE(v.isNull());
|
REQUIRE(v.isNull());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,26 +9,22 @@ using namespace ARDUINOJSON_NAMESPACE;
|
|||||||
|
|
||||||
TEST_CASE("MemoryPool::allocFrozenString()") {
|
TEST_CASE("MemoryPool::allocFrozenString()") {
|
||||||
const size_t poolCapacity = 64;
|
const size_t poolCapacity = 64;
|
||||||
const size_t longestString = poolCapacity - sizeof(StringSlot);
|
const size_t longestString = poolCapacity;
|
||||||
char buffer[poolCapacity];
|
char buffer[poolCapacity];
|
||||||
MemoryPool pool(buffer, poolCapacity);
|
MemoryPool pool(buffer, poolCapacity);
|
||||||
|
|
||||||
SECTION("Returns different addresses") {
|
SECTION("Returns different addresses") {
|
||||||
StringSlot *a = pool.allocFrozenString(1);
|
char *a = pool.allocFrozenString(1);
|
||||||
StringSlot *b = pool.allocFrozenString(1);
|
char *b = pool.allocFrozenString(1);
|
||||||
REQUIRE(a != b);
|
REQUIRE(a != b);
|
||||||
REQUIRE(a->value != b->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Returns a StringSlot of the right size") {
|
|
||||||
StringSlot *s = pool.allocFrozenString(12);
|
|
||||||
REQUIRE(s->size == 12);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Returns NULL when full") {
|
SECTION("Returns NULL when full") {
|
||||||
pool.allocFrozenString(longestString);
|
void *p1 = pool.allocFrozenString(longestString);
|
||||||
void *p = pool.allocFrozenString(1);
|
REQUIRE(p1 != 0);
|
||||||
REQUIRE(0 == p);
|
|
||||||
|
void *p2 = pool.allocFrozenString(1);
|
||||||
|
REQUIRE(p2 == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Returns NULL when pool is too small") {
|
SECTION("Returns NULL when pool is too small") {
|
||||||
@ -46,22 +42,16 @@ TEST_CASE("MemoryPool::allocFrozenString()") {
|
|||||||
REQUIRE(0 == pool2.allocFrozenString(2));
|
REQUIRE(0 == pool2.allocFrozenString(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Returns aligned pointers") {
|
|
||||||
REQUIRE(isAligned(pool.allocFrozenString(1)));
|
|
||||||
REQUIRE(isAligned(pool.allocFrozenString(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Returns same address after clear()") {
|
SECTION("Returns same address after clear()") {
|
||||||
StringSlot *a = pool.allocFrozenString(1);
|
void *a = pool.allocFrozenString(1);
|
||||||
pool.clear();
|
pool.clear();
|
||||||
StringSlot *b = pool.allocFrozenString(1);
|
void *b = pool.allocFrozenString(1);
|
||||||
|
|
||||||
REQUIRE(a == b);
|
REQUIRE(a == b);
|
||||||
REQUIRE(a->value == b->value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Can use full capacity when fresh") {
|
SECTION("Can use full capacity when fresh") {
|
||||||
StringSlot *a = pool.allocFrozenString(longestString);
|
void *a = pool.allocFrozenString(longestString);
|
||||||
|
|
||||||
REQUIRE(a != 0);
|
REQUIRE(a != 0);
|
||||||
}
|
}
|
||||||
@ -70,7 +60,7 @@ TEST_CASE("MemoryPool::allocFrozenString()") {
|
|||||||
pool.allocFrozenString(longestString);
|
pool.allocFrozenString(longestString);
|
||||||
pool.clear();
|
pool.clear();
|
||||||
|
|
||||||
StringSlot *a = pool.allocFrozenString(longestString);
|
void *a = pool.allocFrozenString(longestString);
|
||||||
|
|
||||||
REQUIRE(a != 0);
|
REQUIRE(a != 0);
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,11 @@ TEST_CASE("MemoryPool::size()") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Decreases after freezeString()") {
|
SECTION("Decreases after freezeString()") {
|
||||||
StringSlot* a = memoryPool.allocExpandableString();
|
StringSlot a = memoryPool.allocExpandableString();
|
||||||
memoryPool.freezeString(a, 1);
|
memoryPool.freezeString(a, 1);
|
||||||
REQUIRE(memoryPool.size() == JSON_STRING_SIZE(1));
|
REQUIRE(memoryPool.size() == JSON_STRING_SIZE(1));
|
||||||
|
|
||||||
StringSlot* b = memoryPool.allocExpandableString();
|
StringSlot b = memoryPool.allocExpandableString();
|
||||||
memoryPool.freezeString(b, 1);
|
memoryPool.freezeString(b, 1);
|
||||||
REQUIRE(memoryPool.size() == 2 * JSON_STRING_SIZE(1));
|
REQUIRE(memoryPool.size() == 2 * JSON_STRING_SIZE(1));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user