Renamed JsonBuffer to MemoryPool

This commit is contained in:
Benoit Blanchon
2018-09-03 16:14:21 +02:00
parent e5c4778ff7
commit 2998a55f0b
48 changed files with 365 additions and 361 deletions

View File

@ -4,7 +4,7 @@
#pragma once #pragma once
#include "../Memory/JsonBuffer.hpp" #include "../Memory/MemoryPool.hpp"
#include "ListConstIterator.hpp" #include "ListConstIterator.hpp"
#include "ListIterator.hpp" #include "ListIterator.hpp"
@ -32,8 +32,8 @@ class List {
return nodeCount; return nodeCount;
} }
iterator add(JsonBuffer *buffer) { iterator add(MemoryPool *memoryPool) {
node_type *newNode = new (buffer) node_type(); node_type *newNode = new (memoryPool) node_type();
if (_firstNode) { if (_firstNode) {
node_type *lastNode = _firstNode; node_type *lastNode = _firstNode;

View File

@ -6,7 +6,7 @@
#include <stddef.h> // for NULL #include <stddef.h> // for NULL
#include "../Memory/JsonBufferAllocated.hpp" #include "../Memory/AllocableInMemoryPool.hpp"
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
@ -14,7 +14,7 @@ namespace Internals {
// A node for a singly-linked list. // A node for a singly-linked list.
// Used by List<T> and its iterators. // Used by List<T> and its iterators.
template <typename T> template <typename T>
struct ListNode : public Internals::JsonBufferAllocated { struct ListNode : public Internals::AllocableInMemoryPool {
ListNode() NOEXCEPT : next(NULL) {} ListNode() NOEXCEPT : next(NULL) {}
ListNode<T> *next; ListNode<T> *next;

View File

@ -16,11 +16,12 @@ namespace ArduinoJson {
namespace Internals { namespace Internals {
template <template <typename, typename> class TDeserializer, template <template <typename, typename> class TDeserializer,
typename TJsonBuffer, typename TReader, typename TWriter> typename TMemoryPool, typename TReader, typename TWriter>
TDeserializer<TReader, TWriter> makeDeserializer(TJsonBuffer *buffer, TDeserializer<TReader, TWriter> makeDeserializer(TMemoryPool &memoryPool,
TReader reader, TWriter writer, TReader reader, TWriter writer,
uint8_t nestingLimit) { uint8_t nestingLimit) {
return TDeserializer<TReader, TWriter>(buffer, reader, writer, nestingLimit); return TDeserializer<TReader, TWriter>(memoryPool, reader, writer,
nestingLimit);
} }
// DeserializationError deserialize(TDocument& doc, TString input); // DeserializationError deserialize(TDocument& doc, TString input);
@ -32,9 +33,9 @@ typename Internals::enable_if<!Internals::is_array<TString>::value,
DeserializationError>::type DeserializationError>::type
deserialize(TDocument &doc, const TString &input) { deserialize(TDocument &doc, const TString &input) {
using namespace Internals; using namespace Internals;
return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input), return makeDeserializer<TDeserializer>(
makeStringStorage(doc.buffer(), input), doc.memoryPool(), makeReader(input),
doc.nestingLimit) makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
.parse(doc.template to<JsonVariantData>()); .parse(doc.template to<JsonVariantData>());
} }
// //
@ -45,9 +46,9 @@ template <template <typename, typename> class TDeserializer, typename TDocument,
typename TChar> typename TChar>
DeserializationError deserialize(TDocument &doc, TChar *input) { DeserializationError deserialize(TDocument &doc, TChar *input) {
using namespace Internals; using namespace Internals;
return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input), return makeDeserializer<TDeserializer>(
makeStringStorage(doc.buffer(), input), doc.memoryPool(), makeReader(input),
doc.nestingLimit) makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
.parse(doc.template to<JsonVariantData>()); .parse(doc.template to<JsonVariantData>());
} }
// //
@ -61,8 +62,8 @@ DeserializationError deserialize(TDocument &doc, TChar *input,
size_t inputSize) { size_t inputSize) {
using namespace Internals; using namespace Internals;
return makeDeserializer<TDeserializer>( return makeDeserializer<TDeserializer>(
&doc.buffer(), makeReader(input, inputSize), doc.memoryPool(), makeReader(input, inputSize),
makeStringStorage(doc.buffer(), input), doc.nestingLimit) makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
.parse(doc.template to<JsonVariantData>()); .parse(doc.template to<JsonVariantData>());
} }
// //
@ -73,9 +74,9 @@ template <template <typename, typename> class TDeserializer, typename TDocument,
typename TStream> typename TStream>
DeserializationError deserialize(TDocument &doc, TStream &input) { DeserializationError deserialize(TDocument &doc, TStream &input) {
using namespace Internals; using namespace Internals;
return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input), return makeDeserializer<TDeserializer>(
makeStringStorage(doc.buffer(), input), doc.memoryPool(), makeReader(input),
doc.nestingLimit) makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
.parse(doc.template to<JsonVariantData>()); .parse(doc.template to<JsonVariantData>());
} }
} // namespace Internals } // namespace Internals

View File

@ -7,7 +7,7 @@
#include "JsonArray.hpp" #include "JsonArray.hpp"
#include "JsonObject.hpp" #include "JsonObject.hpp"
#include "JsonVariant.hpp" #include "JsonVariant.hpp"
#include "Memory/DynamicJsonBuffer.hpp" #include "Memory/DynamicMemoryPool.hpp"
namespace ArduinoJson { namespace ArduinoJson {
@ -17,7 +17,8 @@ class DynamicJsonDocument {
DynamicJsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} DynamicJsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
DynamicJsonDocument(size_t capacity) DynamicJsonDocument(size_t capacity)
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _buffer(capacity) {} : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT),
_memoryPool(capacity) {}
template <typename T> template <typename T>
bool is() const { bool is() const {
@ -35,7 +36,7 @@ class DynamicJsonDocument {
JsonObject>::type JsonObject>::type
to() { to() {
clear(); clear();
JsonObject object(&_buffer); JsonObject object(&_memoryPool);
getVariant().set(object); getVariant().set(object);
return object; return object;
} }
@ -46,7 +47,7 @@ class DynamicJsonDocument {
JsonArray>::type JsonArray>::type
to() { to() {
clear(); clear();
JsonArray array(&_buffer); JsonArray array(&_memoryPool);
getVariant().set(array); getVariant().set(array);
return array; return array;
} }
@ -70,17 +71,17 @@ class DynamicJsonDocument {
return _rootData; return _rootData;
} }
Internals::DynamicJsonBuffer& buffer() { Internals::DynamicMemoryPool& memoryPool() {
return _buffer; return _memoryPool;
} }
void clear() { void clear() {
_buffer.clear(); _memoryPool.clear();
_rootData.setNull(); _rootData.setNull();
} }
size_t memoryUsage() const { size_t memoryUsage() const {
return _buffer.size(); return _memoryPool.size();
} }
template <typename Visitor> template <typename Visitor>
@ -90,10 +91,10 @@ class DynamicJsonDocument {
private: private:
JsonVariant getVariant() const { JsonVariant getVariant() const {
return JsonVariant(&_buffer, &_rootData); return JsonVariant(&_memoryPool, &_rootData);
} }
mutable Internals::DynamicJsonBuffer _buffer; mutable Internals::DynamicMemoryPool _memoryPool;
mutable Internals::JsonVariantData _rootData; mutable Internals::JsonVariantData _rootData;
}; };
} // namespace ArduinoJson } // namespace ArduinoJson

View File

@ -6,7 +6,7 @@
#include "../Deserialization/deserialize.hpp" #include "../Deserialization/deserialize.hpp"
#include "../JsonVariant.hpp" #include "../JsonVariant.hpp"
#include "../Memory/JsonBuffer.hpp" #include "../Memory/MemoryPool.hpp"
#include "../Numbers/isFloat.hpp" #include "../Numbers/isFloat.hpp"
#include "../Numbers/isInteger.hpp" #include "../Numbers/isInteger.hpp"
#include "../Polyfills/type_traits.hpp" #include "../Polyfills/type_traits.hpp"
@ -18,9 +18,9 @@ namespace Internals {
template <typename TReader, typename TStringStorage> template <typename TReader, typename TStringStorage>
class JsonDeserializer { class JsonDeserializer {
public: public:
JsonDeserializer(JsonBuffer *buffer, TReader reader, JsonDeserializer(MemoryPool &memoryPool, TReader reader,
TStringStorage stringStorage, uint8_t nestingLimit) TStringStorage stringStorage, uint8_t nestingLimit)
: _buffer(buffer), : _memoryPool(&memoryPool),
_reader(reader), _reader(reader),
_stringStorage(stringStorage), _stringStorage(stringStorage),
_nestingLimit(nestingLimit), _nestingLimit(nestingLimit),
@ -68,7 +68,7 @@ class JsonDeserializer {
DeserializationError parseArray(JsonVariantData &variant) { DeserializationError parseArray(JsonVariantData &variant) {
if (_nestingLimit == 0) return DeserializationError::TooDeep; if (_nestingLimit == 0) return DeserializationError::TooDeep;
JsonArrayData *array = new (_buffer) JsonArrayData; JsonArrayData *array = new (_memoryPool) JsonArrayData;
if (!array) return DeserializationError::NoMemory; if (!array) return DeserializationError::NoMemory;
variant.setArray(*array); variant.setArray(*array);
@ -85,7 +85,7 @@ class JsonDeserializer {
// Read each value // Read each value
for (;;) { for (;;) {
// Allocate slot in array // Allocate slot in array
JsonVariantData *value = array->addSlot(_buffer); JsonVariantData *value = array->addSlot(_memoryPool);
if (!value) return DeserializationError::NoMemory; if (!value) return DeserializationError::NoMemory;
// 1 - Parse value // 1 - Parse value
@ -107,7 +107,7 @@ class JsonDeserializer {
DeserializationError parseObject(JsonVariantData &variant) { DeserializationError parseObject(JsonVariantData &variant) {
if (_nestingLimit == 0) return DeserializationError::TooDeep; if (_nestingLimit == 0) return DeserializationError::TooDeep;
JsonObjectData *object = new (_buffer) JsonObjectData; JsonObjectData *object = new (_memoryPool) JsonObjectData;
if (!object) return DeserializationError::NoMemory; if (!object) return DeserializationError::NoMemory;
variant.setObject(*object); variant.setObject(*object);
@ -134,7 +134,7 @@ class JsonDeserializer {
if (!eat(':')) return DeserializationError::InvalidInput; if (!eat(':')) return DeserializationError::InvalidInput;
// Allocate slot in object // Allocate slot in object
JsonVariantData *value = object->addSlot(_buffer, key); JsonVariantData *value = object->addSlot(_memoryPool, key);
if (!value) return DeserializationError::NoMemory; if (!value) return DeserializationError::NoMemory;
// Parse value // Parse value
@ -335,7 +335,7 @@ class JsonDeserializer {
} }
} }
JsonBuffer *_buffer; MemoryPool *_memoryPool;
TReader _reader; TReader _reader;
TStringStorage _stringStorage; TStringStorage _stringStorage;
uint8_t _nestingLimit; uint8_t _nestingLimit;

View File

@ -21,12 +21,12 @@ class JsonArray {
public: public:
typedef JsonArrayIterator iterator; typedef JsonArrayIterator iterator;
FORCE_INLINE JsonArray() : _buffer(0), _data(0) {} FORCE_INLINE JsonArray() : _memoryPool(0), _data(0) {}
FORCE_INLINE JsonArray(Internals::JsonBuffer* buf, FORCE_INLINE JsonArray(Internals::MemoryPool* buf,
Internals::JsonArrayData* arr) Internals::JsonArrayData* arr)
: _buffer(buf), _data(arr) {} : _memoryPool(buf), _data(arr) {}
FORCE_INLINE explicit JsonArray(Internals::JsonBuffer* buf) FORCE_INLINE explicit JsonArray(Internals::MemoryPool* buf)
: _buffer(buf), _data(new (buf) Internals::JsonArrayData()) {} : _memoryPool(buf), _data(new (buf) Internals::JsonArrayData()) {}
// Adds the specified value at the end of the array. // Adds the specified value at the end of the array.
// //
@ -47,7 +47,7 @@ class JsonArray {
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!_data) return iterator(); if (!_data) return iterator();
return iterator(_buffer, _data->begin()); return iterator(_memoryPool, _data->begin());
} }
FORCE_INLINE iterator end() const { FORCE_INLINE iterator end() const {
@ -192,12 +192,12 @@ class JsonArray {
template <typename TValueRef> template <typename TValueRef>
FORCE_INLINE bool add_impl(TValueRef value) { FORCE_INLINE bool add_impl(TValueRef value) {
if (!_data) return false; if (!_data) return false;
iterator it = iterator(_buffer, _data->add(_buffer)); iterator it = iterator(_memoryPool, _data->add(_memoryPool));
if (it == end()) return false; if (it == end()) return false;
return it->set(value); return it->set(value);
} }
Internals::JsonBuffer* _buffer; Internals::MemoryPool* _memoryPool;
Internals::JsonArrayData* _data; Internals::JsonArrayData* _data;
}; };
} // namespace ArduinoJson } // namespace ArduinoJson

View File

@ -6,11 +6,11 @@
#include "Data/JsonVariantData.hpp" #include "Data/JsonVariantData.hpp"
#include "Data/List.hpp" #include "Data/List.hpp"
#include "Memory/JsonBufferAllocated.hpp" #include "Memory/AllocableInMemoryPool.hpp"
#include "Polyfills/type_traits.hpp" #include "Polyfills/type_traits.hpp"
// Returns the size (in bytes) of an array with n elements. // Returns the size (in bytes) of an array with n elements.
// Can be very handy to determine the size of a StaticJsonBuffer. // Can be very handy to determine the size of a StaticMemoryPool.
#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ #define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
(sizeof(ArduinoJson::Internals::JsonArrayData) + \ (sizeof(ArduinoJson::Internals::JsonArrayData) + \
(NUMBER_OF_ELEMENTS) * \ (NUMBER_OF_ELEMENTS) * \
@ -18,9 +18,9 @@
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
struct JsonArrayData : List<JsonVariantData>, JsonBufferAllocated { struct JsonArrayData : List<JsonVariantData>, AllocableInMemoryPool {
JsonVariantData* addSlot(JsonBuffer* buffer) { JsonVariantData* addSlot(MemoryPool* memoryPool) {
iterator it = add(buffer); iterator it = add(memoryPool);
return it != end() ? &*it : 0; return it != end() ? &*it : 0;
} }
}; };

View File

@ -11,14 +11,14 @@ namespace ArduinoJson {
inline JsonArray JsonArray::createNestedArray() { inline JsonArray JsonArray::createNestedArray() {
if (!_data) return JsonArray(); if (!_data) return JsonArray();
JsonArray array(_buffer); JsonArray array(_memoryPool);
if (!array.isNull()) add(array); if (!array.isNull()) add(array);
return array; return array;
} }
inline JsonObject JsonArray::createNestedObject() { inline JsonObject JsonArray::createNestedObject() {
if (!_data) return JsonObject(); if (!_data) return JsonObject();
JsonObject object(_buffer); JsonObject object(_memoryPool);
if (!object.isNull()) add(object); if (!object.isNull()) add(object);
return object; return object;
} }

View File

@ -11,9 +11,9 @@ namespace ArduinoJson {
class JsonVariantPtr { class JsonVariantPtr {
public: public:
JsonVariantPtr(Internals::JsonBuffer *buffer, JsonVariantPtr(Internals::MemoryPool *memoryPool,
Internals::JsonVariantData *data) Internals::JsonVariantData *data)
: _variant(buffer, data) {} : _variant(memoryPool, data) {}
JsonVariant *operator->() { JsonVariant *operator->() {
return &_variant; return &_variant;
@ -32,15 +32,15 @@ class JsonArrayIterator {
public: public:
JsonArrayIterator() {} JsonArrayIterator() {}
explicit JsonArrayIterator(Internals::JsonBuffer *buffer, explicit JsonArrayIterator(Internals::MemoryPool *memoryPool,
internal_iterator iterator) internal_iterator iterator)
: _iterator(iterator), _buffer(buffer) {} : _iterator(iterator), _memoryPool(memoryPool) {}
JsonVariant operator*() const { JsonVariant operator*() const {
return JsonVariant(_buffer, &*_iterator); return JsonVariant(_memoryPool, &*_iterator);
} }
JsonVariantPtr operator->() { JsonVariantPtr operator->() {
return JsonVariantPtr(_buffer, &*_iterator); return JsonVariantPtr(_memoryPool, &*_iterator);
} }
bool operator==(const JsonArrayIterator &other) const { bool operator==(const JsonArrayIterator &other) const {
@ -67,6 +67,6 @@ class JsonArrayIterator {
private: private:
internal_iterator _iterator; internal_iterator _iterator;
Internals::JsonBuffer *_buffer; Internals::MemoryPool *_memoryPool;
}; };
} // namespace ArduinoJson } // namespace ArduinoJson

View File

@ -16,16 +16,16 @@ class JsonObject {
public: public:
typedef JsonObjectIterator iterator; typedef JsonObjectIterator iterator;
FORCE_INLINE JsonObject() : _buffer(0), _data(0) {} FORCE_INLINE JsonObject() : _memoryPool(0), _data(0) {}
FORCE_INLINE JsonObject(Internals::JsonBuffer* buf, FORCE_INLINE JsonObject(Internals::MemoryPool* buf,
Internals::JsonObjectData* object) Internals::JsonObjectData* object)
: _buffer(buf), _data(object) {} : _memoryPool(buf), _data(object) {}
FORCE_INLINE explicit JsonObject(Internals::JsonBuffer* buf) FORCE_INLINE explicit JsonObject(Internals::MemoryPool* buf)
: _buffer(buf), _data(new (buf) Internals::JsonObjectData()) {} : _memoryPool(buf), _data(new (buf) Internals::JsonObjectData()) {}
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!_data) return iterator(); if (!_data) return iterator();
return iterator(_buffer, _data->begin()); return iterator(_memoryPool, _data->begin());
} }
// Tells weither the specified key is present and associated with a value. // Tells weither the specified key is present and associated with a value.
@ -264,15 +264,17 @@ class JsonObject {
FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type get_impl( FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type get_impl(
TStringRef key) const { TStringRef key) const {
internal_iterator it = findKey<TStringRef>(key); internal_iterator it = findKey<TStringRef>(key);
return it != _data->end() ? JsonVariant(_buffer, &it->value).as<TValue>() return it != _data->end()
: TValue(); ? JsonVariant(_memoryPool, &it->value).as<TValue>()
: TValue();
} }
template <typename TStringRef, typename TValue> template <typename TStringRef, typename TValue>
FORCE_INLINE bool is_impl(TStringRef key) const { FORCE_INLINE bool is_impl(TStringRef key) const {
internal_iterator it = findKey<TStringRef>(key); internal_iterator it = findKey<TStringRef>(key);
return it != _data->end() ? JsonVariant(_buffer, &it->value).is<TValue>() return it != _data->end()
: false; ? JsonVariant(_memoryPool, &it->value).is<TValue>()
: false;
} }
template <typename TStringRef> template <typename TStringRef>
@ -293,13 +295,13 @@ class JsonObject {
if (it == _data->end()) { if (it == _data->end()) {
// add the key // add the key
// TODO: use JsonPairData directly, we don't need an iterator // TODO: use JsonPairData directly, we don't need an iterator
it = _data->add(_buffer); it = _data->add(_memoryPool);
if (it == _data->end()) return false; if (it == _data->end()) return false;
if (!set_key(it, key)) return false; if (!set_key(it, key)) return false;
} }
// save the value // save the value
return JsonVariant(_buffer, &it->value).set(value); return JsonVariant(_memoryPool, &it->value).set(value);
} }
FORCE_INLINE bool set_key(internal_iterator& it, const char* key) { FORCE_INLINE bool set_key(internal_iterator& it, const char* key) {
@ -309,13 +311,13 @@ class JsonObject {
template <typename T> template <typename T>
FORCE_INLINE bool set_key(internal_iterator& it, const T& key) { FORCE_INLINE bool set_key(internal_iterator& it, const T& key) {
const char* dup = Internals::makeString(key).save(_buffer); const char* dup = Internals::makeString(key).save(_memoryPool);
if (!dup) return false; if (!dup) return false;
it->key = dup; it->key = dup;
return true; return true;
} }
mutable Internals::JsonBuffer* _buffer; mutable Internals::MemoryPool* _memoryPool;
mutable Internals::JsonObjectData* _data; mutable Internals::JsonObjectData* _data;
}; };
} // namespace ArduinoJson } // namespace ArduinoJson

View File

@ -6,11 +6,11 @@
#include "Data/List.hpp" #include "Data/List.hpp"
#include "JsonPair.hpp" #include "JsonPair.hpp"
#include "Memory/JsonBufferAllocated.hpp" #include "Memory/AllocableInMemoryPool.hpp"
#include "Polyfills/type_traits.hpp" #include "Polyfills/type_traits.hpp"
// Returns the size (in bytes) of an object with n elements. // Returns the size (in bytes) of an object with n elements.
// Can be very handy to determine the size of a StaticJsonBuffer. // Can be very handy to determine the size of a StaticMemoryPool.
#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ #define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
(sizeof(ArduinoJson::Internals::JsonObjectData) + \ (sizeof(ArduinoJson::Internals::JsonObjectData) + \
(NUMBER_OF_ELEMENTS) * \ (NUMBER_OF_ELEMENTS) * \
@ -18,9 +18,9 @@
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
struct JsonObjectData : List<JsonPairData>, JsonBufferAllocated { struct JsonObjectData : List<JsonPairData>, AllocableInMemoryPool {
JsonVariantData* addSlot(JsonBuffer* buffer, const char* key) { JsonVariantData* addSlot(MemoryPool* memoryPool, const char* key) {
iterator it = add(buffer); iterator it = add(memoryPool);
if (it == end()) return 0; if (it == end()) return 0;
it->key = key; it->key = key;
return &it->value; return &it->value;

View File

@ -22,7 +22,7 @@ inline JsonArray JsonObject::createNestedArray(TString* key) {
template <typename TStringRef> template <typename TStringRef>
inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) { inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) {
if (!_data) return JsonArray(); if (!_data) return JsonArray();
JsonArray array(_buffer); JsonArray array(_memoryPool);
if (!array.isNull()) set(key, array); if (!array.isNull()) set(key, array);
return array; return array;
} }
@ -30,7 +30,7 @@ inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) {
template <typename TStringRef> template <typename TStringRef>
inline JsonObject JsonObject::createNestedObject_impl(TStringRef key) { inline JsonObject JsonObject::createNestedObject_impl(TStringRef key) {
if (!_data) return JsonObject(); if (!_data) return JsonObject();
JsonObject object(_buffer); JsonObject object(_memoryPool);
if (!object.isNull()) set(key, object); if (!object.isNull()) set(key, object);
return object; return object;
} }

View File

@ -11,8 +11,8 @@ namespace ArduinoJson {
class JsonPairPtr { class JsonPairPtr {
public: public:
JsonPairPtr(Internals::JsonBuffer *buffer, Internals::JsonPairData *data) JsonPairPtr(Internals::MemoryPool *memoryPool, Internals::JsonPairData *data)
: _pair(buffer, data) {} : _pair(memoryPool, data) {}
const JsonPair *operator->() const { const JsonPair *operator->() const {
return &_pair; return &_pair;
@ -32,15 +32,15 @@ class JsonObjectIterator {
public: public:
JsonObjectIterator() {} JsonObjectIterator() {}
explicit JsonObjectIterator(Internals::JsonBuffer *buffer, explicit JsonObjectIterator(Internals::MemoryPool *memoryPool,
internal_iterator iterator) internal_iterator iterator)
: _buffer(buffer), _iterator(iterator) {} : _memoryPool(memoryPool), _iterator(iterator) {}
JsonPair operator*() const { JsonPair operator*() const {
return JsonPair(_buffer, &*_iterator); return JsonPair(_memoryPool, &*_iterator);
} }
JsonPairPtr operator->() { JsonPairPtr operator->() {
return JsonPairPtr(_buffer, &*_iterator); return JsonPairPtr(_memoryPool, &*_iterator);
} }
bool operator==(const JsonObjectIterator &other) const { bool operator==(const JsonObjectIterator &other) const {
@ -66,7 +66,7 @@ class JsonObjectIterator {
} }
private: private:
Internals::JsonBuffer *_buffer; Internals::MemoryPool *_memoryPool;
internal_iterator _iterator; internal_iterator _iterator;
}; };
} // namespace ArduinoJson } // namespace ArduinoJson

View File

@ -19,8 +19,8 @@ struct JsonPairData {
// A key value pair for JsonObjectData. // A key value pair for JsonObjectData.
class JsonPair { class JsonPair {
public: public:
JsonPair(Internals::JsonBuffer* buffer, Internals::JsonPairData* data) JsonPair(Internals::MemoryPool* memoryPool, Internals::JsonPairData* data)
: _key(data->key), _value(buffer, &data->value) {} : _key(data->key), _value(memoryPool, &data->value) {}
const char* key() const { const char* key() const {
return _key; return _key;

View File

@ -10,7 +10,7 @@
#include "Data/JsonVariantData.hpp" #include "Data/JsonVariantData.hpp"
#include "JsonVariant.hpp" #include "JsonVariant.hpp"
#include "JsonVariantBase.hpp" #include "JsonVariantBase.hpp"
#include "Memory/JsonBuffer.hpp" #include "Memory/MemoryPool.hpp"
#include "Polyfills/type_traits.hpp" #include "Polyfills/type_traits.hpp"
#include "Serialization/DynamicStringWriter.hpp" #include "Serialization/DynamicStringWriter.hpp"
#include "SerializedValue.hpp" #include "SerializedValue.hpp"
@ -31,12 +31,12 @@ class JsonObject;
class JsonVariant : public Internals::JsonVariantBase<JsonVariant> { class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
public: public:
// Intenal use only // Intenal use only
FORCE_INLINE JsonVariant(Internals::JsonBuffer *buffer, FORCE_INLINE JsonVariant(Internals::MemoryPool *memoryPool,
Internals::JsonVariantData *data) Internals::JsonVariantData *data)
: _buffer(buffer), _data(data) {} : _memoryPool(memoryPool), _data(data) {}
// Creates an uninitialized JsonVariant // Creates an uninitialized JsonVariant
FORCE_INLINE JsonVariant() : _buffer(0), _data(0) {} FORCE_INLINE JsonVariant() : _memoryPool(0), _data(0) {}
// set(bool value) // set(bool value)
FORCE_INLINE bool set(bool value) { FORCE_INLINE bool set(bool value) {
@ -106,7 +106,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
!Internals::is_same<const char *, T>::value>::type * = 0) { !Internals::is_same<const char *, T>::value>::type * = 0) {
if (!_data) return false; if (!_data) return false;
const char *dup = const char *dup =
Internals::makeString(value.data(), value.size()).save(_buffer); Internals::makeString(value.data(), value.size()).save(_memoryPool);
if (dup) if (dup)
_data->setRaw(dup, value.size()); _data->setRaw(dup, value.size());
else else
@ -122,7 +122,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
typename Internals::enable_if<Internals::IsString<T>::value>::type * = typename Internals::enable_if<Internals::IsString<T>::value>::type * =
0) { 0) {
if (!_data) return false; if (!_data) return false;
const char *dup = Internals::makeString(value).save(_buffer); const char *dup = Internals::makeString(value).save(_memoryPool);
if (dup) { if (dup) {
_data->setString(dup); _data->setString(dup);
return true; return true;
@ -139,7 +139,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
typename Internals::enable_if<Internals::IsString<T *>::value>::type * = typename Internals::enable_if<Internals::IsString<T *>::value>::type * =
0) { 0) {
if (!_data) return false; if (!_data) return false;
const char *dup = Internals::makeString(value).save(_buffer); const char *dup = Internals::makeString(value).save(_memoryPool);
if (dup) { if (dup) {
_data->setString(dup); _data->setString(dup);
return true; return true;
@ -341,7 +341,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
} }
private: private:
Internals::JsonBuffer *_buffer; Internals::MemoryPool *_memoryPool;
Internals::JsonVariantData *_data; Internals::JsonVariantData *_data;
}; // namespace ArduinoJson }; // namespace ArduinoJson
} // namespace ArduinoJson } // namespace ArduinoJson

View File

@ -49,7 +49,7 @@ inline typename Internals::enable_if<
JsonArray>::value, JsonArray>::value,
JsonArray>::type JsonArray>::type
JsonVariant::as() const { JsonVariant::as() const {
return _data ? JsonArray(_buffer, _data->asArray()) : JsonArray(); return _data ? JsonArray(_memoryPool, _data->asArray()) : JsonArray();
} }
template <typename T> template <typename T>
@ -58,6 +58,6 @@ inline typename Internals::enable_if<
JsonObject>::value, JsonObject>::value,
T>::type T>::type
JsonVariant::as() const { JsonVariant::as() const {
return _data ? JsonObject(_buffer, _data->asObject()) : JsonObject(); return _data ? JsonObject(_memoryPool, _data->asObject()) : JsonObject();
} }
} // namespace ArduinoJson } // namespace ArduinoJson

View File

@ -0,0 +1,22 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "MemoryPool.hpp"
namespace ArduinoJson {
namespace Internals {
class AllocableInMemoryPool {
public:
void *operator new(size_t n, MemoryPool *memoryPool) NOEXCEPT {
if (!memoryPool) return NULL;
return memoryPool->alloc(n);
}
void operator delete(void *, MemoryPool *)NOEXCEPT {}
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -4,7 +4,7 @@
#pragma once #pragma once
#include "JsonBuffer.hpp" #include "MemoryPool.hpp"
#include <stdlib.h> #include <stdlib.h>
@ -31,7 +31,7 @@ class DefaultAllocator {
}; };
template <typename TAllocator> template <typename TAllocator>
class DynamicJsonBufferBase : public JsonBuffer { class DynamicMemoryPoolBase : public MemoryPool {
struct Block; struct Block;
struct EmptyBlock { struct EmptyBlock {
Block* next; Block* next;
@ -45,27 +45,27 @@ class DynamicJsonBufferBase : public JsonBuffer {
public: public:
enum { EmptyBlockSize = sizeof(EmptyBlock) }; enum { EmptyBlockSize = sizeof(EmptyBlock) };
DynamicJsonBufferBase(size_t initialSize = 256) DynamicMemoryPoolBase(size_t initialSize = 256)
: _head(NULL), _nextBlockCapacity(initialSize) {} : _head(NULL), _nextBlockCapacity(initialSize) {}
~DynamicJsonBufferBase() { ~DynamicMemoryPoolBase() {
clear(); clear();
} }
// Gets the number of bytes occupied in the buffer // Gets the number of bytes occupied in the memoryPool
size_t size() const { size_t size() const {
size_t total = 0; size_t total = 0;
for (const Block* b = _head; b; b = b->next) total += b->size; for (const Block* b = _head; b; b = b->next) total += b->size;
return total; return total;
} }
// Allocates the specified amount of bytes in the buffer // Allocates the specified amount of bytes in the memoryPool
virtual void* alloc(size_t bytes) { virtual void* alloc(size_t bytes) {
alignNextAlloc(); alignNextAlloc();
return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes); return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
} }
// Resets the buffer. // Resets the memoryPool.
// USE WITH CAUTION: this invalidates all previously allocated data // USE WITH CAUTION: this invalidates all previously allocated data
void clear() { void clear() {
Block* currentBlock = _head; Block* currentBlock = _head;
@ -80,7 +80,7 @@ class DynamicJsonBufferBase : public JsonBuffer {
class String { class String {
public: public:
String(DynamicJsonBufferBase* parent) String(DynamicMemoryPoolBase* parent)
: _parent(parent), _start(NULL), _length(0) {} : _parent(parent), _start(NULL), _length(0) {}
void append(char c) { void append(char c) {
@ -104,7 +104,7 @@ class DynamicJsonBufferBase : public JsonBuffer {
} }
private: private:
DynamicJsonBufferBase* _parent; DynamicMemoryPoolBase* _parent;
char* _start; char* _start;
size_t _length; size_t _length;
}; };
@ -152,11 +152,11 @@ class DynamicJsonBufferBase : public JsonBuffer {
size_t _nextBlockCapacity; size_t _nextBlockCapacity;
}; };
// Implements a JsonBuffer with dynamic memory allocation. // Implements a MemoryPool with dynamic memory allocation.
// You are strongly encouraged to consider using StaticJsonBuffer which is much // You are strongly encouraged to consider using StaticMemoryPool which is much
// more suitable for embedded systems. // more suitable for embedded systems.
typedef Internals::DynamicJsonBufferBase<Internals::DefaultAllocator> typedef Internals::DynamicMemoryPoolBase<Internals::DefaultAllocator>
DynamicJsonBuffer; DynamicMemoryPool;
} // namespace Internals } // namespace Internals
#if defined(__clang__) #if defined(__clang__)

View File

@ -1,22 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "JsonBuffer.hpp"
namespace ArduinoJson {
namespace Internals {
class JsonBufferAllocated {
public:
void *operator new(size_t n, JsonBuffer *jsonBuffer) NOEXCEPT {
if (!jsonBuffer) return NULL;
return jsonBuffer->alloc(n);
}
void operator delete(void *, JsonBuffer *)NOEXCEPT {}
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -14,11 +14,11 @@
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
// Handle the memory management (done in derived classes) and calls the parser. // Handle the memory management (done in derived classes) and calls the parser.
// This abstract class is implemented by StaticJsonBuffer which implements a // This abstract class is implemented by StaticMemoryPool which implements a
// fixed memory allocation. // fixed memory allocation.
class JsonBuffer { class MemoryPool {
public: public:
// Allocates n bytes in the JsonBuffer. // Allocates n bytes in the MemoryPool.
// Return a pointer to the allocated memory or NULL if allocation fails. // Return a pointer to the allocated memory or NULL if allocation fails.
virtual void *alloc(size_t size) = 0; virtual void *alloc(size_t size) = 0;
@ -26,7 +26,7 @@ class JsonBuffer {
// CAUTION: NO VIRTUAL DESTRUCTOR! // CAUTION: NO VIRTUAL DESTRUCTOR!
// If we add a virtual constructor the Arduino compiler will add malloc() // If we add a virtual constructor the Arduino compiler will add malloc()
// and free() to the binary, adding 706 useless bytes. // and free() to the binary, adding 706 useless bytes.
~JsonBuffer() {} ~MemoryPool() {}
// Preserve aligment if necessary // Preserve aligment if necessary
static FORCE_INLINE size_t round_size_up(size_t bytes) { static FORCE_INLINE size_t round_size_up(size_t bytes) {

View File

@ -5,16 +5,16 @@
#pragma once #pragma once
#include "../Polyfills/mpl/max.hpp" #include "../Polyfills/mpl/max.hpp"
#include "JsonBuffer.hpp" #include "MemoryPool.hpp"
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
class StaticJsonBufferBase : public JsonBuffer { class StaticMemoryPoolBase : public MemoryPool {
public: public:
class String { class String {
public: public:
String(StaticJsonBufferBase* parent) : _parent(parent) { String(StaticMemoryPoolBase* parent) : _parent(parent) {
_start = parent->_buffer + parent->_size; _start = parent->_buffer + parent->_size;
} }
@ -36,31 +36,31 @@ class StaticJsonBufferBase : public JsonBuffer {
} }
private: private:
StaticJsonBufferBase* _parent; StaticMemoryPoolBase* _parent;
char* _start; char* _start;
}; };
StaticJsonBufferBase(char* buffer, size_t capa) StaticMemoryPoolBase(char* memoryPool, size_t capa)
: _buffer(buffer), _capacity(capa), _size(0) {} : _buffer(memoryPool), _capacity(capa), _size(0) {}
// Gets the capacity of the buffer in bytes // Gets the capacity of the memoryPool in bytes
size_t capacity() const { size_t capacity() const {
return _capacity; return _capacity;
} }
// Gets the current usage of the buffer in bytes // Gets the current usage of the memoryPool in bytes
size_t size() const { size_t size() const {
return _size; return _size;
} }
// Allocates the specified amount of bytes in the buffer // Allocates the specified amount of bytes in the memoryPool
virtual void* alloc(size_t bytes) { virtual void* alloc(size_t bytes) {
alignNextAlloc(); alignNextAlloc();
if (!canAlloc(bytes)) return NULL; if (!canAlloc(bytes)) return NULL;
return doAlloc(bytes); return doAlloc(bytes);
} }
// Resets the buffer. // Resets the memoryPool.
// USE WITH CAUTION: this invalidates all previously allocated data // USE WITH CAUTION: this invalidates all previously allocated data
void clear() { void clear() {
_size = 0; _size = 0;
@ -71,7 +71,7 @@ class StaticJsonBufferBase : public JsonBuffer {
} }
protected: protected:
~StaticJsonBufferBase() {} ~StaticMemoryPoolBase() {}
private: private:
void alignNextAlloc() { void alignNextAlloc() {
@ -103,16 +103,16 @@ class StaticJsonBufferBase : public JsonBuffer {
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif #endif
// Implements a JsonBuffer with fixed memory allocation. // Implements a MemoryPool with fixed memory allocation.
// The template paramenter CAPACITY specifies the capacity of the buffer in // The template paramenter CAPACITY specifies the capacity of the memoryPool in
// bytes. // bytes.
template <size_t CAPACITY> template <size_t CAPACITY>
class StaticJsonBuffer : public Internals::StaticJsonBufferBase { class StaticMemoryPool : public Internals::StaticMemoryPoolBase {
static const size_t ACTUAL_CAPACITY = Internals::Max<1, CAPACITY>::value; static const size_t ACTUAL_CAPACITY = Internals::Max<1, CAPACITY>::value;
public: public:
explicit StaticJsonBuffer() explicit StaticMemoryPool()
: Internals::StaticJsonBufferBase(_buffer, ACTUAL_CAPACITY) {} : Internals::StaticMemoryPoolBase(_buffer, ACTUAL_CAPACITY) {}
private: private:
char _buffer[ACTUAL_CAPACITY]; char _buffer[ACTUAL_CAPACITY];

View File

@ -6,7 +6,7 @@
#include "../Deserialization/deserialize.hpp" #include "../Deserialization/deserialize.hpp"
#include "../JsonVariant.hpp" #include "../JsonVariant.hpp"
#include "../Memory/JsonBuffer.hpp" #include "../Memory/MemoryPool.hpp"
#include "../Polyfills/type_traits.hpp" #include "../Polyfills/type_traits.hpp"
#include "./endianess.hpp" #include "./endianess.hpp"
#include "./ieee754.hpp" #include "./ieee754.hpp"
@ -17,9 +17,9 @@ namespace Internals {
template <typename TReader, typename TStringStorage> template <typename TReader, typename TStringStorage>
class MsgPackDeserializer { class MsgPackDeserializer {
public: public:
MsgPackDeserializer(JsonBuffer *buffer, TReader reader, MsgPackDeserializer(MemoryPool &memoryPool, TReader reader,
TStringStorage stringStorage, uint8_t nestingLimit) TStringStorage stringStorage, uint8_t nestingLimit)
: _buffer(buffer), : _memoryPool(&memoryPool),
_reader(reader), _reader(reader),
_stringStorage(stringStorage), _stringStorage(stringStorage),
_nestingLimit(nestingLimit) {} _nestingLimit(nestingLimit) {}
@ -240,7 +240,7 @@ class MsgPackDeserializer {
} }
DeserializationError readArray(JsonVariantData &variant, size_t n) { DeserializationError readArray(JsonVariantData &variant, size_t n) {
JsonArrayData *array = new (_buffer) JsonArrayData; JsonArrayData *array = new (_memoryPool) JsonArrayData;
if (!array) return DeserializationError::NoMemory; if (!array) return DeserializationError::NoMemory;
variant.setArray(*array); variant.setArray(*array);
@ -251,7 +251,7 @@ class MsgPackDeserializer {
if (_nestingLimit == 0) return DeserializationError::TooDeep; if (_nestingLimit == 0) return DeserializationError::TooDeep;
--_nestingLimit; --_nestingLimit;
for (; n; --n) { for (; n; --n) {
JsonVariantData *value = array.addSlot(_buffer); JsonVariantData *value = array.addSlot(_memoryPool);
if (!value) return DeserializationError::NoMemory; if (!value) return DeserializationError::NoMemory;
DeserializationError err = parse(*value); DeserializationError err = parse(*value);
@ -269,7 +269,7 @@ class MsgPackDeserializer {
} }
DeserializationError readObject(JsonVariantData &variant, size_t n) { DeserializationError readObject(JsonVariantData &variant, size_t n) {
JsonObjectData *object = new (_buffer) JsonObjectData; JsonObjectData *object = new (_memoryPool) JsonObjectData;
if (!object) return DeserializationError::NoMemory; if (!object) return DeserializationError::NoMemory;
variant.setObject(*object); variant.setObject(*object);
@ -285,7 +285,7 @@ class MsgPackDeserializer {
if (err) return err; if (err) return err;
if (!key.isString()) return DeserializationError::NotSupported; if (!key.isString()) return DeserializationError::NotSupported;
JsonVariantData *value = object.addSlot(_buffer, key.asString()); JsonVariantData *value = object.addSlot(_memoryPool, key.asString());
if (!value) return DeserializationError::NoMemory; if (!value) return DeserializationError::NoMemory;
err = parse(*value); err = parse(*value);
@ -295,7 +295,7 @@ class MsgPackDeserializer {
return DeserializationError::Ok; return DeserializationError::Ok;
} }
JsonBuffer *_buffer; MemoryPool *_memoryPool;
TReader _reader; TReader _reader;
TStringStorage _stringStorage; TStringStorage _stringStorage;
uint8_t _nestingLimit; uint8_t _nestingLimit;

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "JsonVariant.hpp" #include "JsonVariant.hpp"
#include "Memory/StaticJsonBuffer.hpp" #include "Memory/StaticMemoryPool.hpp"
namespace ArduinoJson { namespace ArduinoJson {
@ -16,8 +16,8 @@ class StaticJsonDocument {
StaticJsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} StaticJsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
Internals::StaticJsonBufferBase& buffer() { Internals::StaticMemoryPoolBase& memoryPool() {
return _buffer; return _memoryPool;
} }
template <typename T> template <typename T>
@ -36,7 +36,7 @@ class StaticJsonDocument {
JsonObject>::type JsonObject>::type
to() { to() {
clear(); clear();
JsonObject object(&_buffer); JsonObject object(&_memoryPool);
getVariant().set(object); getVariant().set(object);
return object; return object;
} }
@ -47,7 +47,7 @@ class StaticJsonDocument {
JsonArray>::type JsonArray>::type
to() { to() {
clear(); clear();
JsonArray array(&_buffer); JsonArray array(&_memoryPool);
getVariant().set(array); getVariant().set(array);
return array; return array;
} }
@ -72,12 +72,12 @@ class StaticJsonDocument {
} }
void clear() { void clear() {
_buffer.clear(); _memoryPool.clear();
_rootData.setNull(); _rootData.setNull();
} }
size_t memoryUsage() const { size_t memoryUsage() const {
return _buffer.size(); return _memoryPool.size();
} }
template <typename Visitor> template <typename Visitor>
@ -87,10 +87,10 @@ class StaticJsonDocument {
private: private:
JsonVariant getVariant() const { JsonVariant getVariant() const {
return JsonVariant(&_buffer, &_rootData); return JsonVariant(&_memoryPool, &_rootData);
} }
mutable Internals::StaticJsonBuffer<CAPACITY> _buffer; mutable Internals::StaticMemoryPool<CAPACITY> _memoryPool;
mutable Internals::JsonVariantData _rootData; mutable Internals::JsonVariantData _rootData;
}; };

View File

@ -7,19 +7,19 @@
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
template <typename TJsonBuffer> template <typename TMemoryPool>
class StringCopier { class StringCopier {
public: public:
StringCopier(TJsonBuffer& jb) : _jb(&jb) {} StringCopier(TMemoryPool& memoryPool) : _memoryPool(&memoryPool) {}
typedef typename TJsonBuffer::String String; typedef typename TMemoryPool::String String;
String startString() { String startString() {
return _jb->startString(); return _memoryPool->startString();
} }
private: private:
TJsonBuffer* _jb; TMemoryPool* _memoryPool;
}; };
} // namespace Internals } // namespace Internals
} // namespace ArduinoJson } // namespace ArduinoJson

View File

@ -28,7 +28,7 @@ class StringMover {
TChar* _startPtr; TChar* _startPtr;
}; };
StringMover(TChar* buffer) : _ptr(buffer) {} StringMover(TChar* ptr) : _ptr(ptr) {}
String startString() { String startString() {
return String(&_ptr); return String(&_ptr);

View File

@ -10,35 +10,35 @@
namespace ArduinoJson { namespace ArduinoJson {
namespace Internals { namespace Internals {
template <typename TJsonBuffer, typename TInput, typename Enable = void> template <typename TMemoryPool, typename TInput, typename Enable = void>
struct StringStorage { struct StringStorage {
typedef StringCopier<TJsonBuffer> type; typedef StringCopier<TMemoryPool> type;
static type create(TJsonBuffer& jb, TInput&) { static type create(TMemoryPool& jb, TInput&) {
return type(jb); return type(jb);
} }
}; };
template <typename TJsonBuffer, typename TChar> template <typename TMemoryPool, typename TChar>
struct StringStorage<TJsonBuffer, TChar*, struct StringStorage<TMemoryPool, TChar*,
typename enable_if<!is_const<TChar>::value>::type> { typename enable_if<!is_const<TChar>::value>::type> {
typedef StringMover<TChar> type; typedef StringMover<TChar> type;
static type create(TJsonBuffer&, TChar* input) { static type create(TMemoryPool&, TChar* input) {
return type(input); return type(input);
} }
}; };
template <typename TJsonBuffer, typename TInput> template <typename TMemoryPool, typename TInput>
typename StringStorage<TJsonBuffer, TInput>::type makeStringStorage( typename StringStorage<TMemoryPool, TInput>::type makeStringStorage(
TJsonBuffer& jb, TInput& input) { TMemoryPool& jb, TInput& input) {
return StringStorage<TJsonBuffer, TInput>::create(jb, input); return StringStorage<TMemoryPool, TInput>::create(jb, input);
} }
template <typename TJsonBuffer, typename TChar> template <typename TMemoryPool, typename TChar>
typename StringStorage<TJsonBuffer, TChar*>::type makeStringStorage( typename StringStorage<TMemoryPool, TChar*>::type makeStringStorage(
TJsonBuffer& jb, TChar* input) { TMemoryPool& jb, TChar* input) {
return StringStorage<TJsonBuffer, TChar*>::create(jb, input); return StringStorage<TMemoryPool, TChar*>::create(jb, input);
} }
} // namespace Internals } // namespace Internals
} // namespace ArduinoJson } // namespace ArduinoJson

View File

@ -14,10 +14,10 @@ class ArduinoString {
ArduinoString(const ::String& str) : _str(&str) {} ArduinoString(const ::String& str) : _str(&str) {}
template <typename Buffer> template <typename Buffer>
const char* save(Buffer* buffer) const { const char* save(Buffer* memoryPool) const {
if (is_null()) return NULL; if (is_null()) return NULL;
size_t n = _str->length() + 1; size_t n = _str->length() + 1;
void* dup = buffer->alloc(n); void* dup = memoryPool->alloc(n);
if (dup != NULL) memcpy(dup, _str->c_str(), n); if (dup != NULL) memcpy(dup, _str->c_str(), n);
return static_cast<const char*>(dup); return static_cast<const char*>(dup);
} }

View File

@ -23,9 +23,9 @@ class FixedSizeFlashString {
} }
template <typename Buffer> template <typename Buffer>
const char* save(Buffer* buffer) const { const char* save(Buffer* memoryPool) const {
if (!_str) return NULL; if (!_str) return NULL;
void* dup = buffer->alloc(_size); void* dup = memoryPool->alloc(_size);
if (dup != NULL) memcpy_P(dup, (const char*)_str, _size); if (dup != NULL) memcpy_P(dup, (const char*)_str, _size);
return static_cast<const char*>(dup); return static_cast<const char*>(dup);
} }

View File

@ -24,9 +24,9 @@ class FixedSizeRamString {
} }
template <typename Buffer> template <typename Buffer>
const char* save(Buffer* buffer) const { const char* save(Buffer* memoryPool) const {
if (!_str) return NULL; if (!_str) return NULL;
void* dup = buffer->alloc(_size); void* dup = memoryPool->alloc(_size);
if (!dup) return NULL; if (!dup) return NULL;
memcpy(dup, _str, _size); memcpy(dup, _str, _size);
return static_cast<const char*>(dup); return static_cast<const char*>(dup);

View File

@ -14,9 +14,9 @@ class StlString {
StlString(const std::string& str) : _str(&str) {} StlString(const std::string& str) : _str(&str) {}
template <typename Buffer> template <typename Buffer>
const char* save(Buffer* buffer) const { const char* save(Buffer* memoryPool) const {
size_t n = _str->length() + 1; size_t n = _str->length() + 1;
void* dup = buffer->alloc(n); void* dup = memoryPool->alloc(n);
if (dup != NULL) memcpy(dup, _str->c_str(), n); if (dup != NULL) memcpy(dup, _str->c_str(), n);
return static_cast<const char*>(dup); return static_cast<const char*>(dup);
} }

View File

@ -22,10 +22,10 @@ class ZeroTerminatedFlashString {
} }
template <typename Buffer> template <typename Buffer>
const char* save(Buffer* buffer) const { const char* save(Buffer* 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
void* dup = buffer->alloc(n); void* dup = memoryPool->alloc(n);
if (dup != NULL) memcpy_P(dup, (const char*)_str, n); if (dup != NULL) memcpy_P(dup, (const char*)_str, n);
return static_cast<const char*>(dup); return static_cast<const char*>(dup);
} }

View File

@ -22,10 +22,10 @@ class ZeroTerminatedRamString {
} }
template <typename Buffer> template <typename Buffer>
const char* save(Buffer* buffer) const { const char* save(Buffer* memoryPool) const {
if (!_str) return NULL; if (!_str) return NULL;
size_t n = size() + 1; size_t n = size() + 1;
void* dup = buffer->alloc(n); void* dup = memoryPool->alloc(n);
if (!dup) return NULL; if (!dup) return NULL;
memcpy(dup, _str, n); memcpy(dup, _str, n);
return static_cast<const char*>(dup); return static_cast<const char*>(dup);

View File

@ -71,7 +71,7 @@ if(MSVC)
) )
endif() endif()
add_subdirectory(DynamicJsonBuffer) add_subdirectory(DynamicMemoryPool)
add_subdirectory(IntegrationTests) add_subdirectory(IntegrationTests)
add_subdirectory(JsonArray) add_subdirectory(JsonArray)
add_subdirectory(JsonDeserializer) add_subdirectory(JsonDeserializer)
@ -84,4 +84,4 @@ add_subdirectory(Misc)
add_subdirectory(MsgPackDeserializer) add_subdirectory(MsgPackDeserializer)
add_subdirectory(MsgPackSerializer) add_subdirectory(MsgPackSerializer)
add_subdirectory(Numbers) add_subdirectory(Numbers)
add_subdirectory(StaticJsonBuffer) add_subdirectory(StaticMemoryPool)

View File

@ -1,13 +0,0 @@
# ArduinoJson - arduinojson.org
# Copyright Benoit Blanchon 2014-2018
# MIT License
add_executable(DynamicJsonBufferTests
alloc.cpp
no_memory.cpp
size.cpp
startString.cpp
)
target_link_libraries(DynamicJsonBufferTests catch)
add_test(DynamicJsonBuffer DynamicJsonBufferTests)

View File

@ -1,29 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson/Memory/DynamicJsonBuffer.hpp>
#include <catch.hpp>
using namespace ArduinoJson::Internals;
TEST_CASE("DynamicJsonBuffer::size()") {
DynamicJsonBuffer buffer;
SECTION("Initial size is 0") {
REQUIRE(0 == buffer.size());
}
SECTION("Increases after alloc()") {
buffer.alloc(1);
REQUIRE(1U <= buffer.size());
buffer.alloc(1);
REQUIRE(2U <= buffer.size());
}
SECTION("Goes back to 0 after clear()") {
buffer.alloc(1);
buffer.clear();
REQUIRE(0 == buffer.size());
}
}

View File

@ -0,0 +1,13 @@
# ArduinoJson - arduinojson.org
# Copyright Benoit Blanchon 2014-2018
# MIT License
add_executable(DynamicMemoryPoolTests
alloc.cpp
no_memory.cpp
size.cpp
startString.cpp
)
target_link_libraries(DynamicMemoryPoolTests catch)
add_test(DynamicMemoryPool DynamicMemoryPoolTests)

View File

@ -18,7 +18,7 @@ std::stringstream allocatorLog;
struct SpyingAllocator : DefaultAllocator { struct SpyingAllocator : DefaultAllocator {
void* allocate(size_t n) { void* allocate(size_t n) {
allocatorLog << "A" << (n - DynamicJsonBuffer::EmptyBlockSize); allocatorLog << "A" << (n - DynamicMemoryPool::EmptyBlockSize);
return DefaultAllocator::allocate(n); return DefaultAllocator::allocate(n);
} }
void deallocate(void* p) { void deallocate(void* p) {
@ -27,20 +27,20 @@ struct SpyingAllocator : DefaultAllocator {
} }
}; };
TEST_CASE("DynamicJsonBuffer::alloc()") { TEST_CASE("DynamicMemoryPool::alloc()") {
SECTION("Returns different pointers") { SECTION("Returns different pointers") {
DynamicJsonBuffer buffer; DynamicMemoryPool memoryPool;
void* p1 = buffer.alloc(1); void* p1 = memoryPool.alloc(1);
void* p2 = buffer.alloc(2); void* p2 = memoryPool.alloc(2);
REQUIRE(p1 != p2); REQUIRE(p1 != p2);
} }
SECTION("Doubles allocation size when full") { SECTION("Doubles allocation size when full") {
allocatorLog.str(""); allocatorLog.str("");
{ {
DynamicJsonBufferBase<SpyingAllocator> buffer(1); DynamicMemoryPoolBase<SpyingAllocator> memoryPool(1);
buffer.alloc(1); memoryPool.alloc(1);
buffer.alloc(1); memoryPool.alloc(1);
} }
REQUIRE(allocatorLog.str() == "A1A2FF"); REQUIRE(allocatorLog.str() == "A1A2FF");
} }
@ -48,11 +48,11 @@ TEST_CASE("DynamicJsonBuffer::alloc()") {
SECTION("Resets allocation size after clear()") { SECTION("Resets allocation size after clear()") {
allocatorLog.str(""); allocatorLog.str("");
{ {
DynamicJsonBufferBase<SpyingAllocator> buffer(1); DynamicMemoryPoolBase<SpyingAllocator> memoryPool(1);
buffer.alloc(1); memoryPool.alloc(1);
buffer.alloc(1); memoryPool.alloc(1);
buffer.clear(); memoryPool.clear();
buffer.alloc(1); memoryPool.alloc(1);
} }
REQUIRE(allocatorLog.str() == "A1A2FFA1F"); REQUIRE(allocatorLog.str() == "A1A2FFA1F");
} }
@ -60,15 +60,15 @@ TEST_CASE("DynamicJsonBuffer::alloc()") {
SECTION("Makes a big allocation when needed") { SECTION("Makes a big allocation when needed") {
allocatorLog.str(""); allocatorLog.str("");
{ {
DynamicJsonBufferBase<SpyingAllocator> buffer(1); DynamicMemoryPoolBase<SpyingAllocator> memoryPool(1);
buffer.alloc(42); memoryPool.alloc(42);
} }
REQUIRE(allocatorLog.str() == "A42F"); REQUIRE(allocatorLog.str() == "A42F");
} }
SECTION("Alignment") { SECTION("Alignment") {
// make room for two but not three // make room for two but not three
DynamicJsonBuffer tinyBuf(2 * sizeof(void*) + 1); DynamicMemoryPool tinyBuf(2 * sizeof(void*) + 1);
REQUIRE(isAligned(tinyBuf.alloc(1))); // this on is aligned by design REQUIRE(isAligned(tinyBuf.alloc(1))); // this on is aligned by design
REQUIRE(isAligned(tinyBuf.alloc(1))); // this one fits in the first block REQUIRE(isAligned(tinyBuf.alloc(1))); // this one fits in the first block

View File

@ -14,8 +14,8 @@ struct NoMemoryAllocator {
void deallocate(void*) {} void deallocate(void*) {}
}; };
TEST_CASE("DynamicJsonBuffer no memory") { TEST_CASE("DynamicMemoryPool no memory") {
DynamicJsonBufferBase<NoMemoryAllocator> _jsonBuffer; DynamicMemoryPoolBase<NoMemoryAllocator> _memoryPool;
SECTION("FixCodeCoverage") { SECTION("FixCodeCoverage") {
// call this function to fix code coverage // call this function to fix code coverage
@ -33,8 +33,8 @@ TEST_CASE("DynamicJsonBuffer no memory") {
// } // }
SECTION("startString()") { SECTION("startString()") {
DynamicJsonBufferBase<NoMemoryAllocator>::String str = DynamicMemoryPoolBase<NoMemoryAllocator>::String str =
_jsonBuffer.startString(); _memoryPool.startString();
str.append('!'); str.append('!');
REQUIRE(0 == str.c_str()); REQUIRE(0 == str.c_str());
} }

View File

@ -0,0 +1,29 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson/Memory/DynamicMemoryPool.hpp>
#include <catch.hpp>
using namespace ArduinoJson::Internals;
TEST_CASE("DynamicMemoryPool::size()") {
DynamicMemoryPool memoryPool;
SECTION("Initial size is 0") {
REQUIRE(0 == memoryPool.size());
}
SECTION("Increases after alloc()") {
memoryPool.alloc(1);
REQUIRE(1U <= memoryPool.size());
memoryPool.alloc(1);
REQUIRE(2U <= memoryPool.size());
}
SECTION("Goes back to 0 after clear()") {
memoryPool.alloc(1);
memoryPool.clear();
REQUIRE(0 == memoryPool.size());
}
}

View File

@ -2,16 +2,16 @@
// Copyright Benoit Blanchon 2014-2018 // Copyright Benoit Blanchon 2014-2018
// MIT License // MIT License
#include <ArduinoJson/Memory/DynamicJsonBuffer.hpp> #include <ArduinoJson/Memory/DynamicMemoryPool.hpp>
#include <catch.hpp> #include <catch.hpp>
using namespace ArduinoJson::Internals; using namespace ArduinoJson::Internals;
TEST_CASE("DynamicJsonBuffer::startString()") { TEST_CASE("DynamicMemoryPool::startString()") {
SECTION("WorksWhenBufferIsBigEnough") { SECTION("WorksWhenBufferIsBigEnough") {
DynamicJsonBuffer jsonBuffer(6); DynamicMemoryPool memoryPool(6);
DynamicJsonBuffer::String str = jsonBuffer.startString(); DynamicMemoryPool::String str = memoryPool.startString();
str.append('h'); str.append('h');
str.append('e'); str.append('e');
str.append('l'); str.append('l');
@ -22,9 +22,9 @@ TEST_CASE("DynamicJsonBuffer::startString()") {
} }
SECTION("GrowsWhenBufferIsTooSmall") { SECTION("GrowsWhenBufferIsTooSmall") {
DynamicJsonBuffer jsonBuffer(5); DynamicMemoryPool memoryPool(5);
DynamicJsonBuffer::String str = jsonBuffer.startString(); DynamicMemoryPool::String str = memoryPool.startString();
str.append('h'); str.append('h');
str.append('e'); str.append('e');
str.append('l'); str.append('l');
@ -35,15 +35,15 @@ TEST_CASE("DynamicJsonBuffer::startString()") {
} }
SECTION("SizeIncreases") { SECTION("SizeIncreases") {
DynamicJsonBuffer jsonBuffer(5); DynamicMemoryPool memoryPool(5);
DynamicJsonBuffer::String str = jsonBuffer.startString(); DynamicMemoryPool::String str = memoryPool.startString();
REQUIRE(0 == jsonBuffer.size()); REQUIRE(0 == memoryPool.size());
str.append('h'); str.append('h');
REQUIRE(1 == jsonBuffer.size()); REQUIRE(1 == memoryPool.size());
str.c_str(); str.c_str();
REQUIRE(2 == jsonBuffer.size()); REQUIRE(2 == memoryPool.size());
} }
} }

View File

@ -19,7 +19,7 @@ TEST_CASE("JsonArray::copyFrom()") {
REQUIRE(std::string("[1,2,3]") == json); REQUIRE(std::string("[1,2,3]") == json);
} }
SECTION("OneDimension_JsonBufferTooSmall") { SECTION("OneDimension_MemoryPoolTooSmall") {
const size_t SIZE = JSON_ARRAY_SIZE(2); const size_t SIZE = JSON_ARRAY_SIZE(2);
StaticJsonDocument<SIZE> doc; StaticJsonDocument<SIZE> doc;
JsonArray array = doc.to<JsonArray>(); JsonArray array = doc.to<JsonArray>();
@ -46,7 +46,7 @@ TEST_CASE("JsonArray::copyFrom()") {
REQUIRE(std::string("[[1,2,3],[4,5,6]]") == json); REQUIRE(std::string("[[1,2,3],[4,5,6]]") == json);
} }
SECTION("TwoDimensions_JsonBufferTooSmall") { SECTION("TwoDimensions_MemoryPoolTooSmall") {
const size_t SIZE = const size_t SIZE =
JSON_ARRAY_SIZE(2) + JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(2); JSON_ARRAY_SIZE(2) + JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(2);
StaticJsonDocument<SIZE> doc; StaticJsonDocument<SIZE> doc;

View File

@ -57,7 +57,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
deserializeJson(doc, " [ \"1234567\" ] "); deserializeJson(doc, " [ \"1234567\" ] ");
REQUIRE(JSON_ARRAY_SIZE(1) + sizeof("1234567") == doc.memoryUsage()); REQUIRE(JSON_ARRAY_SIZE(1) + sizeof("1234567") == doc.memoryUsage());
// note: we use a string of 8 bytes to be sure that the StaticJsonBuffer // 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

@ -1,12 +0,0 @@
# ArduinoJson - arduinojson.org
# Copyright Benoit Blanchon 2014-2018
# MIT License
add_executable(StaticJsonBufferTests
alloc.cpp
size.cpp
startString.cpp
)
target_link_libraries(StaticJsonBufferTests catch)
add_test(StaticJsonBuffer StaticJsonBufferTests)

View File

@ -1,44 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson/Memory/StaticJsonBuffer.hpp>
#include <catch.hpp>
using namespace ArduinoJson::Internals;
TEST_CASE("StaticJsonBuffer::size()") {
StaticJsonBuffer<64> buffer;
SECTION("Capacity equals template parameter") {
REQUIRE(64 == buffer.capacity());
}
SECTION("Initial size is 0") {
REQUIRE(0 == buffer.size());
}
SECTION("Increases after alloc()") {
buffer.alloc(1);
REQUIRE(1U <= buffer.size());
buffer.alloc(1);
REQUIRE(2U <= buffer.size());
}
SECTION("Doesn't grow when buffer is full") {
buffer.alloc(64);
buffer.alloc(1);
REQUIRE(64 == buffer.size());
}
SECTION("Does't grow when buffer is too small for alloc") {
buffer.alloc(65);
REQUIRE(0 == buffer.size());
}
SECTION("Goes back to zero after clear()") {
buffer.alloc(1);
buffer.clear();
REQUIRE(0 == buffer.size());
}
}

View File

@ -0,0 +1,12 @@
# ArduinoJson - arduinojson.org
# Copyright Benoit Blanchon 2014-2018
# MIT License
add_executable(StaticMemoryPoolTests
alloc.cpp
size.cpp
startString.cpp
)
target_link_libraries(StaticMemoryPoolTests catch)
add_test(StaticMemoryPool StaticMemoryPoolTests)

View File

@ -2,7 +2,7 @@
// Copyright Benoit Blanchon 2014-2018 // Copyright Benoit Blanchon 2014-2018
// MIT License // MIT License
#include <ArduinoJson/Memory/StaticJsonBuffer.hpp> #include <ArduinoJson/Memory/StaticMemoryPool.hpp>
#include <catch.hpp> #include <catch.hpp>
using namespace ArduinoJson::Internals; using namespace ArduinoJson::Internals;
@ -13,42 +13,42 @@ static bool isAligned(void *ptr) {
return (addr & mask) == 0; return (addr & mask) == 0;
} }
TEST_CASE("StaticJsonBuffer::alloc()") { TEST_CASE("StaticMemoryPool::alloc()") {
StaticJsonBuffer<64> buffer; StaticMemoryPool<64> memoryPool;
SECTION("Returns different addresses") { SECTION("Returns different addresses") {
void *p1 = buffer.alloc(1); void *p1 = memoryPool.alloc(1);
void *p2 = buffer.alloc(1); void *p2 = memoryPool.alloc(1);
REQUIRE(p1 != p2); REQUIRE(p1 != p2);
} }
SECTION("Returns non-NULL when using full capacity") { SECTION("Returns non-NULL when using full capacity") {
void *p = buffer.alloc(64); void *p = memoryPool.alloc(64);
REQUIRE(0 != p); REQUIRE(0 != p);
} }
SECTION("Returns NULL when full") { SECTION("Returns NULL when full") {
buffer.alloc(64); memoryPool.alloc(64);
void *p = buffer.alloc(1); void *p = memoryPool.alloc(1);
REQUIRE(0 == p); REQUIRE(0 == p);
} }
SECTION("Returns NULL when buffer is too small") { SECTION("Returns NULL when memoryPool is too small") {
void *p = buffer.alloc(65); void *p = memoryPool.alloc(65);
REQUIRE(0 == p); REQUIRE(0 == p);
} }
SECTION("Returns aligned pointers") { SECTION("Returns aligned pointers") {
for (size_t size = 1; size <= sizeof(void *); size++) { for (size_t size = 1; size <= sizeof(void *); size++) {
void *p = buffer.alloc(1); void *p = memoryPool.alloc(1);
REQUIRE(isAligned(p)); REQUIRE(isAligned(p));
} }
} }
SECTION("Returns same address after clear()") { SECTION("Returns same address after clear()") {
void *p1 = buffer.alloc(1); void *p1 = memoryPool.alloc(1);
buffer.clear(); memoryPool.clear();
void *p2 = buffer.alloc(1); void *p2 = memoryPool.alloc(1);
REQUIRE(p1 == p2); REQUIRE(p1 == p2);
} }
} }

View File

@ -0,0 +1,44 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson/Memory/StaticMemoryPool.hpp>
#include <catch.hpp>
using namespace ArduinoJson::Internals;
TEST_CASE("StaticMemoryPool::size()") {
StaticMemoryPool<64> memoryPool;
SECTION("Capacity equals template parameter") {
REQUIRE(64 == memoryPool.capacity());
}
SECTION("Initial size is 0") {
REQUIRE(0 == memoryPool.size());
}
SECTION("Increases after alloc()") {
memoryPool.alloc(1);
REQUIRE(1U <= memoryPool.size());
memoryPool.alloc(1);
REQUIRE(2U <= memoryPool.size());
}
SECTION("Doesn't grow when memoryPool is full") {
memoryPool.alloc(64);
memoryPool.alloc(1);
REQUIRE(64 == memoryPool.size());
}
SECTION("Does't grow when memoryPool is too small for alloc") {
memoryPool.alloc(65);
REQUIRE(0 == memoryPool.size());
}
SECTION("Goes back to zero after clear()") {
memoryPool.alloc(1);
memoryPool.clear();
REQUIRE(0 == memoryPool.size());
}
}

View File

@ -7,11 +7,11 @@
using namespace ArduinoJson::Internals; using namespace ArduinoJson::Internals;
TEST_CASE("StaticJsonBuffer::startString()") { TEST_CASE("StaticMemoryPool::startString()") {
SECTION("WorksWhenBufferIsBigEnough") { SECTION("WorksWhenBufferIsBigEnough") {
StaticJsonBuffer<6> jsonBuffer; StaticMemoryPool<6> memoryPool;
StaticJsonBufferBase::String str = jsonBuffer.startString(); StaticMemoryPoolBase::String str = memoryPool.startString();
str.append('h'); str.append('h');
str.append('e'); str.append('e');
str.append('l'); str.append('l');
@ -22,9 +22,9 @@ TEST_CASE("StaticJsonBuffer::startString()") {
} }
SECTION("ReturnsNullWhenTooSmall") { SECTION("ReturnsNullWhenTooSmall") {
StaticJsonBuffer<5> jsonBuffer; StaticMemoryPool<5> memoryPool;
StaticJsonBufferBase::String str = jsonBuffer.startString(); StaticMemoryPoolBase::String str = memoryPool.startString();
str.append('h'); str.append('h');
str.append('e'); str.append('e');
str.append('l'); str.append('l');
@ -35,15 +35,15 @@ TEST_CASE("StaticJsonBuffer::startString()") {
} }
SECTION("SizeIncreases") { SECTION("SizeIncreases") {
StaticJsonBuffer<5> jsonBuffer; StaticMemoryPool<5> memoryPool;
StaticJsonBufferBase::String str = jsonBuffer.startString(); StaticMemoryPoolBase::String str = memoryPool.startString();
REQUIRE(0 == jsonBuffer.size()); REQUIRE(0 == memoryPool.size());
str.append('h'); str.append('h');
REQUIRE(1 == jsonBuffer.size()); REQUIRE(1 == memoryPool.size());
str.c_str(); str.c_str();
REQUIRE(2 == jsonBuffer.size()); REQUIRE(2 == memoryPool.size());
} }
} }