Fixed errors with Variable Length Arrays (issue #416)

This commit is contained in:
Benoit Blanchon
2017-01-15 15:11:26 +01:00
parent 11432253a1
commit 8499f0b960
15 changed files with 822 additions and 165 deletions

View File

@ -5,6 +5,7 @@ HEAD
----
* Fixed error when assigning a `volatile int` to a `JsonVariant` (issue #415)
* Fixed errors with Variable Length Arrays (issue #416)
v5.8.0
------

View File

@ -94,10 +94,6 @@ struct JsonParserBuilder<TJsonBuffer, char *> {
}
};
template <typename TJsonBuffer, size_t N>
struct JsonParserBuilder<TJsonBuffer, char[N]>
: JsonParserBuilder<TJsonBuffer, char *> {};
template <typename TJsonBuffer, typename TString>
inline typename JsonParserBuilder<TJsonBuffer, TString>::TParser makeParser(
TJsonBuffer *buffer, TString &json, uint8_t nestingLimit) {

View File

@ -14,8 +14,8 @@
#include "JsonVariant.hpp"
#include "Serialization/JsonPrintable.hpp"
#include "StringTraits/StringTraits.hpp"
#include "TypeTraits/ConstRefOrConstPtr.hpp"
#include "TypeTraits/EnableIf.hpp"
#include "TypeTraits/IsArray.hpp"
#include "TypeTraits/IsFloatingPoint.hpp"
#include "TypeTraits/IsSame.hpp"
@ -58,73 +58,70 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// Adds the specified value at the end of the array.
//
// bool add(bool);
// bool add(char);
// bool add(long);
// bool add(int);
// bool add(short);
// bool add(float value);
// bool add(double value);
// bool add(const char*);
// bool add(const char[]);
// bool add(const char[N]);
// bool add(RawJson);
// bool add(const std::string&)
// bool add(const String&)
// bool add(const JsonVariant&);
// bool add(JsonArray&);
// bool add(JsonObject&);
// bool add(TValue);
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename T>
bool add(const T &value) {
// reduce the number of template function instanciation to reduce code size
return addNodeImpl<typename TypeTraits::ConstRefOrConstPtr<T>::type>(value);
typename TypeTraits::EnableIf<!TypeTraits::IsArray<T>::value, bool>::type add(
const T &value) {
return add_impl<const T &>(value);
}
// bool add(float value, uint8_t decimals);
// bool add(double value, uint8_t decimals);
//
// bool add(TValue);
// TValue = const char*, const char[N], const FlashStringHelper*
template <typename T>
bool add(const T *value) {
return add_impl<const T *>(value);
}
//
// bool add(TValue value, uint8_t decimals);
// TValue = float, double
template <typename T>
bool add(T value, uint8_t decimals) {
return add(JsonVariant(value, decimals));
return add_impl<const JsonVariant &>(JsonVariant(value, decimals));
}
// Sets the value at specified index.
//
// bool set(size_t index, bool value);
// bool set(size_t index, long value);
// bool set(size_t index, int value);
// bool set(size_t index, short value);
// bool set(size_t index, const std::string&)
// bool set(size_t index, const String&)
// bool set(size_t index, const JsonVariant&);
// bool set(size_t index, JsonArray&);
// bool set(size_t index, JsonObject&);
// bool add(size_t index, TValue);
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename T>
bool set(size_t index, const T &value) {
// reduce the number of template function instanciation to reduce code size
return setNodeAt<typename TypeTraits::ConstRefOrConstPtr<T>::type>(index,
value);
typename TypeTraits::EnableIf<!TypeTraits::IsArray<T>::value, bool>::type set(
size_t index, const T &value) {
return set_impl<const T &>(index, value);
}
// bool set(size_t index, float value, uint8_t decimals = 2);
// bool set(size_t index, double value, uint8_t decimals = 2);
//
// bool add(size_t index, TValue);
// TValue = const char*, const char[N], const FlashStringHelper*
template <typename T>
bool set(size_t index, const T *value) {
return set_impl<const T *>(index, value);
}
//
// bool set(size_t index, TValue value, uint8_t decimals);
// TValue = float, double
template <typename T>
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value,
bool>::type
set(size_t index, T value, uint8_t decimals) {
return set(index, JsonVariant(value, decimals));
return set_impl<const JsonVariant &>(index, JsonVariant(value, decimals));
}
// Gets the value at the specified index.
template <typename T>
typename Internals::JsonVariantAs<T>::type get(size_t index) const {
node_type *node = getNodeAt(index);
node_type *node = findNode(index);
return node ? node->content.as<T>()
: Internals::JsonVariantDefault<T>::get();
;
}
// Check the type of the value at specified index.
template <typename T>
bool is(size_t index) const {
node_type *node = getNodeAt(index);
node_type *node = findNode(index);
return node ? node->content.is<T>() : false;
}
@ -138,7 +135,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// Removes element at specified index.
void removeAt(size_t index) {
removeNode(getNodeAt(index));
removeNode(findNode(index));
}
// Returns a reference an invalid JsonArray.
@ -203,15 +200,15 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
}
private:
node_type *getNodeAt(size_t index) const {
node_type *findNode(size_t index) const {
node_type *node = _firstNode;
while (node && index--) node = node->next;
return node;
}
template <typename TValueRef>
bool setNodeAt(size_t index, TValueRef value) {
node_type *node = getNodeAt(index);
bool set_impl(size_t index, TValueRef value) {
node_type *node = findNode(index);
if (!node) return false;
return Internals::ValueSetter<TValueRef>::set(_buffer, node->content,
@ -219,7 +216,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
}
template <typename TValueRef>
bool addNodeImpl(TValueRef value) {
bool add_impl(TValueRef value) {
node_type *node = addNewNode();
if (!node) return false;

View File

@ -26,11 +26,25 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
return *this;
}
// Replaces the value
//
// operator=(TValue)
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename T>
FORCE_INLINE JsonArraySubscript& operator=(const T& src) {
_array.set(_index, src);
return *this;
}
//
// operator=(TValue)
// TValue = const char*, const char[N], const FlashStringHelper*
template <typename T>
FORCE_INLINE JsonArraySubscript& operator=(const T* src) {
_array.set(_index, src);
return *this;
}
FORCE_INLINE bool success() const {
return _index < _array.size();
@ -46,9 +60,29 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
return _array.is<T>(_index);
}
// Replaces the value
//
// bool set(TValue)
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename TValue>
FORCE_INLINE void set(const TValue& value) {
_array.set(_index, value);
FORCE_INLINE bool set(const TValue& value) {
return _array.set(_index, value);
}
//
// bool set(TValue)
// TValue = const char*, const char[N], const FlashStringHelper*
template <typename TValue>
FORCE_INLINE bool set(const TValue* value) {
return _array.set(_index, value);
}
//
// bool set(TValue, uint8_t decimals);
// TValue = float, double
template <typename TValue>
FORCE_INLINE bool set(const TValue& value, uint8_t decimals) {
return _array.set(_index, value, decimals);
}
private:

View File

@ -12,6 +12,8 @@
#include <string.h>
#include "JsonVariant.hpp"
#include "TypeTraits/EnableIf.hpp"
#include "TypeTraits/IsArray.hpp"
#if defined(__clang__)
#pragma clang diagnostic push
@ -51,11 +53,23 @@ class JsonBuffer {
// allocation fails.
JsonObject &createObject();
// Duplicate a string
// Duplicates a string
//
// char* strdup(TValue);
// TValue = const std::string&, const String&,
template <typename TString>
char *strdup(const TString &src) {
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
char *>::type
strdup(const TString &src) {
return Internals::StringFuncs<TString>::duplicate(src, this);
}
//
// char* strdup(TValue);
// TValue = const char*, const char[N], const FlashStringHelper*
template <typename TString>
char *strdup(const TString *src) {
return Internals::StringFuncs<const TString *>::duplicate(src, this);
}
// Allocates n bytes in the JsonBuffer.
// Return a pointer to the allocated memory or NULL if allocation fails.

View File

@ -34,12 +34,27 @@ class JsonBufferBase : public JsonBuffer {
// Returns a reference to the new JsonObject or JsonObject::invalid() if the
// allocation fails.
// With this overload, the JsonBuffer will make a copy of the string
//
// JsonArray& parseArray(TString);
// TString = const std::string&, const String&
template <typename TString>
JsonArray &parseArray(
const TString &json,
uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
JsonArray &>::type
parseArray(const TString &json,
uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
return Internals::makeParser(that(), json, nestingLimit).parseArray();
}
//
// JsonArray& parseArray(TString);
// TString = const char*, const char[N], const FlashStringHelper*
template <typename TString>
JsonArray &parseArray(
TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
return Internals::makeParser(that(), json, nestingLimit).parseArray();
}
//
// JsonArray& parseArray(TString);
// TString = std::istream&, Stream&
template <typename TString>
JsonArray &parseArray(
TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
@ -56,12 +71,27 @@ class JsonBufferBase : public JsonBuffer {
//
// Returns a reference to the new JsonObject or JsonObject::invalid() if the
// allocation fails.
//
// JsonObject& parseObject(TString);
// TString = const std::string&, const String&
template <typename TString>
JsonObject &parseObject(
const TString &json,
uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
JsonObject &>::type
parseObject(const TString &json,
uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
return Internals::makeParser(that(), json, nestingLimit).parseObject();
}
//
// JsonObject& parseObject(TString);
// TString = const char*, const char[N], const FlashStringHelper*
template <typename TString>
JsonObject &parseObject(
TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
return Internals::makeParser(that(), json, nestingLimit).parseObject();
}
//
// JsonObject& parseObject(TString);
// TString = std::istream&, Stream&
template <typename TString>
JsonObject &parseObject(
TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
@ -70,11 +100,27 @@ class JsonBufferBase : public JsonBuffer {
// Generalized version of parseArray() and parseObject(), also works for
// integral types.
//
// JsonVariant parse(TString);
// TString = const std::string&, const String&
template <typename TString>
JsonVariant parse(const TString &json,
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
JsonVariant>::type
parse(const TString &json,
uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
return Internals::makeParser(that(), json, nestingLimit).parseVariant();
}
//
// JsonVariant parse(TString);
// TString = const char*, const char[N], const FlashStringHelper*
template <typename TString>
JsonVariant parse(TString *json,
uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
return Internals::makeParser(that(), json, nestingLimit).parseVariant();
}
//
// JsonVariant parse(TString);
// TString = std::istream&, Stream&
template <typename TString>
JsonVariant parse(TString &json,
uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {

View File

@ -14,8 +14,8 @@
#include "JsonPair.hpp"
#include "Serialization/JsonPrintable.hpp"
#include "StringTraits/StringTraits.hpp"
#include "TypeTraits/ConstRefOrConstPtr.hpp"
#include "TypeTraits/EnableIf.hpp"
#include "TypeTraits/IsArray.hpp"
#include "TypeTraits/IsFloatingPoint.hpp"
#include "TypeTraits/IsSame.hpp"
@ -47,81 +47,226 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
explicit JsonObject(JsonBuffer* buffer) : Internals::List<JsonPair>(buffer) {}
// Gets or sets the value associated with the specified key.
//
// JsonObjectSubscript operator[](TKey)
// TKey = const std::string&, const String&
template <typename TString>
JsonObjectSubscript<TString> operator[](const TString& key);
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
JsonObjectSubscript<const TString&> >::type
operator[](const TString& key) {
return JsonObjectSubscript<const TString&>(*this, key);
}
//
// JsonObjectSubscript operator[](TKey)
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
JsonObjectSubscript<const TString*> operator[](const TString* key) {
return JsonObjectSubscript<const TString*>(*this, key);
}
// Gets the value associated with the specified key.
//
// JsonVariant operator[](TKey) const;
// TKey = const std::string&, const String&
template <typename TString>
JsonVariant operator[](const TString& key) const {
return get<JsonVariant>(key);
const JsonVariant operator[](const TString& key) const {
return get_impl<const TString&, JsonVariant>(key);
}
//
// JsonVariant operator[](TKey) const;
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
const JsonVariant operator[](const TString* key) const {
return get_impl<const TString*, JsonVariant>(key);
}
// Sets the specified key with the specified value.
// bool set(TKey key, bool value);
// bool set(TKey key, char value);
// bool set(TKey key, long value);
// bool set(TKey key, int value);
// bool set(TKey key, short value);
// bool set(TKey key, float value);
// bool set(TKey key, double value);
// bool set(TKey key, const char* value);
// bool set(TKey key, RawJson value);
// bool set(Key, String&);
// bool set(Key, JsonArray&);
// bool set(Key, JsonObject&);
// bool set(Key, JsonVariant&);
//
// bool set(TKey, TValue);
// TKey = const std::string&, const String&
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename TValue, typename TString>
bool set(const TString& key, const TValue& value) {
// reduce the number of template function instanciation to reduce code size
return setNodeAt<typename TypeTraits::ConstRefOrConstPtr<TString>::type,
typename TypeTraits::ConstRefOrConstPtr<TValue>::type>(
key, value);
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value &&
!TypeTraits::IsArray<TValue>::value,
bool>::type
set(const TString& key, const TValue& value) {
return set_impl<const TString&, const TValue&>(key, value);
}
// bool set(Key, float value, uint8_t decimals);
// bool set(Key, double value, uint8_t decimals);
//
// bool set(TKey, TValue);
// TKey = const std::string&, const String&
// TValue = const char*, const char[N], const FlashStringHelper*
template <typename TValue, typename TString>
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
bool>::type
set(const TString& key, const TValue* value) {
return set_impl<const TString&, const TValue*>(key, value);
}
//
// bool set(TKey, TValue);
// TKey = const char*, const char[N], const FlashStringHelper*
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename TValue, typename TString>
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TValue>::value, bool>::type
set(const TString* key, const TValue& value) {
return set_impl<const TString*, const TValue&>(key, value);
}
//
// bool set(TKey, TValue);
// TKey = const char*, const char[N], const FlashStringHelper*
// TValue = const char*, const char[N], const FlashStringHelper*
template <typename TValue, typename TString>
bool set(const TString* key, const TValue* value) {
return set_impl<const TString*, const TValue*>(key, value);
}
//
// bool set(TKey, TValue, uint8_t decimals);
// TKey = const std::string&, const String&
// TValue = float, double
template <typename TValue, typename TString>
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<TValue>::value &&
!TypeTraits::IsArray<TString>::value,
bool>::type
set(const TString& key, TValue value, uint8_t decimals) {
return set_impl<const TString&, const JsonVariant&>(
key, JsonVariant(value, decimals));
}
//
// bool set(TKey, TValue, uint8_t decimals);
// TKey = const char*, const char[N], const FlashStringHelper*
// TValue = float, double
template <typename TValue, typename TString>
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<TValue>::value,
bool>::type
set(const TString& key, TValue value, uint8_t decimals) {
return set(key, JsonVariant(value, decimals));
set(const TString* key, TValue value, uint8_t decimals) {
return set_impl<const TString*, const JsonVariant&>(
key, JsonVariant(value, decimals));
}
// Gets the value associated with the specified key.
//
// TValue get<TValue>(TKey);
// TKey = const std::string&, const String&
// TValue = bool, char, long, int, short, float, double,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename TValue, typename TString>
typename TypeTraits::EnableIf<
!TypeTraits::IsArray<TString>::value,
typename Internals::JsonVariantAs<TValue>::type>::type
get(const TString& key) const {
return get_impl<const TString&, TValue>(key);
}
//
// TValue get<TValue>(TKey);
// TKey = const char*, const char[N], const FlashStringHelper*
// TValue = bool, char, long, int, short, float, double,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename TValue, typename TString>
typename Internals::JsonVariantAs<TValue>::type get(
const TString& key) const {
node_type* node = getNodeAt(key);
return node ? node->content.value.as<TValue>()
: Internals::JsonVariantDefault<TValue>::get();
const TString* key) const {
return get_impl<const TString*, TValue>(key);
}
// Checks the type of the value associated with the specified key.
//
//
// bool is<TValue>(TKey) const;
// TKey = const std::string&, const String&
// TValue = bool, char, long, int, short, float, double,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename TValue, typename TString>
bool is(const TString& key) const {
node_type* node = getNodeAt(key);
return node ? node->content.value.is<TValue>() : false;
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
bool>::type
is(const TString& key) const {
return is_impl<const TString&, TValue>(key);
}
//
// bool is<TValue>(TKey) const;
// TKey = const char*, const char[N], const FlashStringHelper*
// TValue = bool, char, long, int, short, float, double,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename TValue, typename TString>
bool is(const TString* key) const {
return is_impl<const TString*, TValue>(key);
}
// Creates and adds a JsonArray.
// This is a shortcut for JsonBuffer::createArray() and JsonObject::add().
//
// JsonArray& createNestedArray(TKey);
// TKey = const std::string&, const String&
template <typename TString>
JsonArray& createNestedArray(const TString& key);
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
JsonArray&>::type
createNestedArray(const TString& key) {
return createNestedArray_impl<const TString&>(key);
}
// JsonArray& createNestedArray(TKey);
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
JsonArray& createNestedArray(const TString* key) {
return createNestedArray_impl<const TString*>(key);
}
// Creates and adds a JsonObject.
// This is a shortcut for JsonBuffer::createObject() and JsonObject::add().
//
// JsonObject& createNestedObject(TKey);
// TKey = const std::string&, const String&
template <typename TString>
JsonObject& createNestedObject(const TString& key);
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
JsonObject&>::type
createNestedObject(const TString& key) {
return createNestedObject_impl<const TString&>(key);
}
//
// JsonObject& createNestedObject(TKey);
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
JsonObject& createNestedObject(const TString* key) {
return createNestedObject_impl<const TString*>(key);
}
// Tells weither the specified key is present and associated with a value.
//
// bool containsKey(TKey);
// TKey = const std::string&, const String&
template <typename TString>
bool containsKey(const TString& key) const {
return getNodeAt(key) != NULL;
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
bool>::type
containsKey(const TString& key) const {
return findNode<const TString&>(key) != NULL;
}
//
// bool containsKey(TKey);
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
bool containsKey(const TString* key) const {
return findNode<const TString*>(key) != NULL;
}
// Removes the specified key and the associated value.
//
// void remove(TKey);
// TKey = const std::string&, const String&
template <typename TString>
void remove(const TString& key) {
removeNode(getNodeAt(key));
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
void>::type
remove(const TString& key) {
removeNode(findNode<const TString&>(key));
}
//
// void remove(TKey);
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
void remove(const TString* key) {
removeNode(findNode<const TString*>(key));
}
// Returns a reference an invalid JsonObject.
@ -134,15 +279,8 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
private:
// Returns the list node that matches the specified key.
template <typename TString>
node_type* getNodeAt(const TString& key) const {
// reduce the number of template function instanciation to reduce code size
return getNodeAtImpl<
typename TypeTraits::ConstRefOrConstPtr<TString>::type>(key);
}
template <typename TStringRef>
node_type* getNodeAtImpl(TStringRef key) const {
node_type* findNode(TStringRef key) const {
for (node_type* node = _firstNode; node; node = node->next) {
if (Internals::StringFuncs<TStringRef>::equals(key, node->content.key))
return node;
@ -150,9 +288,17 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
return NULL;
}
template <typename TStringRef, typename TValue>
typename Internals::JsonVariantAs<TValue>::type get_impl(
TStringRef key) const {
node_type* node = findNode<TStringRef>(key);
return node ? node->content.value.as<TValue>()
: Internals::JsonVariantDefault<TValue>::get();
}
template <typename TStringRef, typename TValueRef>
bool setNodeAt(TStringRef key, TValueRef value) {
node_type* node = getNodeAtImpl<TStringRef>(key);
bool set_impl(TStringRef key, TValueRef value) {
node_type* node = findNode<TStringRef>(key);
if (!node) {
node = addNewNode();
if (!node) return false;
@ -164,6 +310,18 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
return Internals::ValueSetter<TValueRef>::set(_buffer, node->content.value,
value);
}
template <typename TStringRef, typename TValue>
bool is_impl(TStringRef key) const {
node_type* node = findNode<TStringRef>(key);
return node ? node->content.value.is<TValue>() : false;
}
template <typename TStringRef>
JsonArray& createNestedArray_impl(TStringRef key);
template <typename TStringRef>
JsonObject& createNestedObject_impl(TStringRef key);
};
namespace Internals {

View File

@ -13,19 +13,19 @@
namespace ArduinoJson {
template <typename TString>
inline JsonObject &JsonObject::createNestedObject(const TString &key) {
if (!_buffer) return JsonObject::invalid();
JsonObject &object = _buffer->createObject();
set(key, object);
return object;
}
template <typename TString>
inline JsonArray &JsonObject::createNestedArray(const TString &key) {
template <typename TStringRef>
inline JsonArray &JsonObject::createNestedArray_impl(TStringRef key) {
if (!_buffer) return JsonArray::invalid();
JsonArray &array = _buffer->createArray();
set(key, array);
return array;
}
template <typename TStringRef>
inline JsonObject &JsonObject::createNestedObject_impl(TStringRef key) {
if (!_buffer) return JsonObject::invalid();
JsonObject &object = _buffer->createObject();
set(key, object);
return object;
}
}

View File

@ -9,7 +9,6 @@
#include "Configuration.hpp"
#include "JsonVariantBase.hpp"
#include "TypeTraits/ConstRefOrConstPtr.hpp"
#include "TypeTraits/EnableIf.hpp"
#ifdef _MSC_VER
@ -19,26 +18,39 @@
namespace ArduinoJson {
template <typename TString>
template <typename TStringRef>
class JsonObjectSubscript
: public JsonVariantBase<JsonObjectSubscript<TString> > {
// const String&
// const std::string&
// const char*
typedef typename TypeTraits::ConstRefOrConstPtr<TString>::type TStringRef;
: public JsonVariantBase<JsonObjectSubscript<TStringRef> > {
typedef JsonObjectSubscript<TStringRef> this_type;
public:
FORCE_INLINE JsonObjectSubscript(JsonObject& object, TStringRef key)
: _object(object), _key(key) {}
FORCE_INLINE JsonObjectSubscript<TString>& operator=(
const JsonObjectSubscript<TString>& src) {
FORCE_INLINE this_type& operator=(const this_type& src) {
_object.set(_key, src);
return *this;
}
template <typename T>
FORCE_INLINE JsonObjectSubscript<TString>& operator=(const T& src) {
// Set the specified value
//
// operator=(TValue);
// TValue = bool, char, long, int, short, float, double,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename TValue>
FORCE_INLINE
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TValue>::value,
this_type&>::type
operator=(const TValue& src) {
_object.set(_key, src);
return *this;
}
//
// operator=(TValue);
// TValue = const char*, const char[N], const FlashStringHelper*
template <typename TValue>
FORCE_INLINE this_type& operator=(const TValue* src) {
_object.set(_key, src);
return *this;
}
@ -49,7 +61,7 @@ class JsonObjectSubscript
template <typename TValue>
FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type as() const {
return _object.get<TValue, TStringRef>(_key);
return _object.get<TValue>(_key);
}
template <typename TValue>
@ -57,11 +69,29 @@ class JsonObjectSubscript
return _object.is<TValue>(_key);
}
// Sets the specified value.
//
// bool set(TValue);
// TValue = bool, char, long, int, short, float, double, RawJson, JsonVariant,
// const std::string&, const String&,
// const JsonArray&, const JsonObject&
template <typename TValue>
FORCE_INLINE bool set(const TValue& value) {
FORCE_INLINE
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TValue>::value,
bool>::type
set(const TValue& value) {
return _object.set(_key, value);
}
//
// bool set(TValue);
// TValue = const char*, const char[N], const FlashStringHelper*
template <typename TValue>
FORCE_INLINE bool set(const TValue* value) {
return _object.set(_key, value);
}
//
// bool set(TValue, uint8_t decimals);
// TValue = float, double
template <typename TValue>
FORCE_INLINE bool set(const TValue& value, uint8_t decimals) {
return _object.set(_key, value, decimals);
@ -73,17 +103,12 @@ class JsonObjectSubscript
};
#if ARDUINOJSON_ENABLE_STD_STREAM
template <typename TString>
template <typename TStringRef>
inline std::ostream& operator<<(std::ostream& os,
const JsonObjectSubscript<TString>& source) {
const JsonObjectSubscript<TStringRef>& source) {
return source.printTo(os);
}
#endif
template <typename TString>
inline JsonObjectSubscript<TString> JsonObject::operator[](const TString& key) {
return JsonObjectSubscript<TString>(*this, key);
}
} // namespace ArduinoJson
#ifdef _MSC_VER

View File

@ -78,20 +78,46 @@ class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
// Returns the value associated with the specified key if the variant is
// an object.
// Return JsonVariant::invalid() if the variant is not an object.
//
// const JsonObjectSubscript operator[](TKey) const;
// TKey = const std::string&, const String&
template <typename TString>
FORCE_INLINE
typename TypeTraits::EnableIf<Internals::StringFuncs<TString>::has_equals,
const JsonObjectSubscript<TString> >::type
operator[](const TString &key) const {
FORCE_INLINE typename TypeTraits::EnableIf<
Internals::StringFuncs<TString>::has_equals,
const JsonObjectSubscript<const TString &> >::type
operator[](const TString &key) const {
return asObject()[key];
}
//
// const JsonObjectSubscript operator[](TKey) const;
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
FORCE_INLINE
typename TypeTraits::EnableIf<Internals::StringFuncs<TString>::has_equals,
JsonObjectSubscript<TString> >::type
JsonObjectSubscript<const TString &> >::type
operator[](const TString &key) {
return asObject()[key];
}
//
// JsonObjectSubscript operator[](TKey);
// TKey = const std::string&, const String&
template <typename TString>
FORCE_INLINE typename TypeTraits::EnableIf<
Internals::StringFuncs<TString *>::has_equals,
JsonObjectSubscript<const TString *> >::type
operator[](const TString *key) {
return asObject()[key];
}
//
// JsonObjectSubscript operator[](TKey);
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
FORCE_INLINE typename TypeTraits::EnableIf<
Internals::StringFuncs<TString *>::has_equals,
const JsonObjectSubscript<const TString *> >::type
operator[](const TString *key) const {
return asObject()[key];
}
private:
const TImpl *impl() const {

View File

@ -47,11 +47,5 @@ struct StringFuncs<const char*, void> : CharPtrFuncs {};
template <>
struct StringFuncs<char*, void> : CharPtrFuncs {};
template <size_t N>
struct StringFuncs<char[N], void> : CharPtrFuncs {};
template <size_t N>
struct StringFuncs<const char[N], void> : CharPtrFuncs {};
}
}

View File

@ -12,20 +12,16 @@ namespace TypeTraits {
// A meta-function that return the type T without the const modifier
template <typename T>
struct ConstRefOrConstPtr {
typedef const T& type;
struct IsArray {
static const bool value = false;
};
template <typename T>
struct ConstRefOrConstPtr<T*> {
typedef const T* type;
};
template <typename T>
struct ConstRefOrConstPtr<T[]> {
typedef const T* type;
struct IsArray<T[]> {
static const bool value = true;
};
template <typename T, size_t N>
struct ConstRefOrConstPtr<T[N]> {
typedef const T* type;
struct IsArray<T[N]> {
static const bool value = true;
};
}
}

View File

@ -49,6 +49,13 @@ TEST_(StoreDouble) {
EXPECT_FALSE(_array[0].is<int>());
}
TEST_(StoreDoubleWithDecimals) {
_array[0].set(123.45, 2);
EXPECT_EQ(123.45, _array[0].as<double>());
EXPECT_TRUE(_array[0].is<double>());
EXPECT_FALSE(_array[0].is<int>());
}
TEST_(StoreBoolean) {
_array[0] = true;
EXPECT_EQ(true, _array[0].as<bool>());

View File

@ -15,3 +15,9 @@ TEST(StdStream, IsBaseOf) {
ASSERT_FALSE((IsBaseOf<std::istream, std::ostringstream>::value));
ASSERT_TRUE((IsBaseOf<std::istream, std::istringstream>::value));
}
TEST(StdStream, IsArray) {
ASSERT_FALSE((IsArray<const char*>::value));
ASSERT_TRUE((IsArray<const char[]>::value));
ASSERT_TRUE((IsArray<const char[10]>::value));
}

View File

@ -0,0 +1,357 @@
// Copyright Benoit Blanchon 2014-2017
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include <ArduinoJson.h>
#include <gtest/gtest.h>
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wvla-extension"
#define CONFLICTS_WITH_BUILTIN_OPERATOR
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wvla"
#else
#define VLA_NOT_SUPPORTED
#endif
#ifndef VLA_NOT_SUPPORTED
TEST(VariableLengthArray, ParseArray) {
int i = 8;
char vla[i];
strcpy(vla, "[42]");
StaticJsonBuffer<JSON_ARRAY_SIZE(1)> jsonBuffer;
JsonArray& arr = jsonBuffer.parseArray(vla);
EXPECT_TRUE(arr.success());
}
TEST(VariableLengthArray, ParseObject) {
int i = 16;
char vla[i];
strcpy(vla, "{\"a\":42}");
StaticJsonBuffer<JSON_OBJECT_SIZE(1)> jsonBuffer;
JsonObject& obj = jsonBuffer.parseObject(vla);
EXPECT_TRUE(obj.success());
}
TEST(VariableLengthArray, Parse) {
int i = 16;
char vla[i];
strcpy(vla, "42");
StaticJsonBuffer<1> jsonBuffer;
JsonVariant variant = jsonBuffer.parse(vla);
EXPECT_EQ(42, variant.as<int>());
}
TEST(VariableLengthArray, JsonVariant_Constructor) {
int i = 16;
char vla[i];
strcpy(vla, "42");
JsonVariant variant(vla);
EXPECT_EQ(42, variant.as<int>());
}
TEST(VariableLengthArray, JsonVariant_Assign) {
int i = 16;
char vla[i];
strcpy(vla, "42");
JsonVariant variant(666);
variant = vla;
EXPECT_EQ(42, variant.as<int>());
}
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
TEST(VariableLengthArray, JsonVariant_Subscript) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
JsonVariant variant = jsonBuffer.parseObject("{\"hello\":\"world\"}");
EXPECT_STREQ("world", variant[vla]);
}
#endif
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
TEST(VariableLengthArray, JsonVariant_Subscript_Const) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
const JsonVariant variant = jsonBuffer.parseObject("{\"hello\":\"world\"}");
EXPECT_STREQ("world", variant[vla]);
}
#endif
TEST(VariableLengthArray, JsonVariant_Equals) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
const JsonVariant variant = "hello";
EXPECT_TRUE(vla == variant);
EXPECT_TRUE(variant == vla);
EXPECT_FALSE(vla != variant);
EXPECT_FALSE(variant != vla);
}
TEST(VariableLengthArray, JsonVariant_Differs) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
const JsonVariant variant = "world";
EXPECT_TRUE(vla != variant);
EXPECT_TRUE(variant != vla);
EXPECT_FALSE(vla == variant);
EXPECT_FALSE(variant == vla);
}
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
TEST(VariableLengthArray, JsonObject_Subscript) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj[vla] = "world";
EXPECT_STREQ("world", obj["hello"]);
}
#endif
TEST(VariableLengthArray, JsonObject_Subscript_Assign) { // issue #416
int i = 32;
char vla[i];
strcpy(vla, "world");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj["hello"] = vla;
EXPECT_STREQ("world", obj["hello"].as<char*>());
}
TEST(VariableLengthArray, JsonObject_Subscript_Set) {
int i = 32;
char vla[i];
strcpy(vla, "world");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj["hello"].set(vla);
EXPECT_STREQ("world", obj["hello"].as<char*>());
}
#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR
TEST(VariableLengthArray, JsonObject_Subscript_Const) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
const JsonObject& obj = jsonBuffer.parseObject("{\"hello\":\"world\"}");
EXPECT_STREQ("world", obj[vla]);
}
#endif
TEST(VariableLengthArray, JsonObject_Get) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.parseObject("{\"hello\":\"world\"}");
EXPECT_STREQ("world", obj.get<char*>(vla));
}
TEST(VariableLengthArray, JsonObject_Set_Key) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj.set(vla, "world");
EXPECT_STREQ("world", obj["hello"]);
}
TEST(VariableLengthArray, JsonObject_Set_Value) {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj.set("hello", vla);
EXPECT_STREQ("world", obj["hello"]);
}
TEST(VariableLengthArray, JsonObject_Set_Key_WithDecimals) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj.set(vla, 3.14, 2);
EXPECT_EQ(3.14, obj["hello"]);
}
TEST(VariableLengthArray, JsonObject_Set_KeyAndValue) {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj.set(vla, vla);
EXPECT_STREQ("world", obj["world"]);
}
TEST(VariableLengthArray, JsonObject_ContainsKey) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
const JsonObject& obj = jsonBuffer.parseObject("{\"hello\":\"world\"}");
EXPECT_TRUE(obj.containsKey(vla));
}
TEST(VariableLengthArray, JsonObject_Remove) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.parseObject("{\"hello\":\"world\"}");
obj.remove(vla);
EXPECT_EQ(0, obj.size());
}
TEST(VariableLengthArray, JsonObject_Is) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.parseObject("{\"hello\":42}");
EXPECT_TRUE(obj.is<int>(vla));
}
TEST(VariableLengthArray, JsonObject_CreateNestedArray) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj.createNestedArray(vla);
}
TEST(VariableLengthArray, JsonObject_CreateNestedObject) {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj.createNestedObject(vla);
}
TEST(VariableLengthArray, JsonArray_Add) {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonBuffer jsonBuffer;
JsonArray& arr = jsonBuffer.createArray();
arr.add(vla);
EXPECT_STREQ("world", arr[0]);
}
TEST(VariableLengthArray, JsonArray_Set) {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonBuffer jsonBuffer;
JsonArray& arr = jsonBuffer.createArray();
arr.add("hello");
arr.set(0, vla);
EXPECT_STREQ("world", arr[0]);
}
TEST(VariableLengthArray, JsonArraySubscript_Set) {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonBuffer jsonBuffer;
JsonArray& arr = jsonBuffer.createArray();
arr.add("hello");
arr[0].set(vla);
EXPECT_STREQ("world", arr[0]);
}
TEST(VariableLengthArray, JsonArraySubscript_Assign) {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonBuffer jsonBuffer;
JsonArray& arr = jsonBuffer.createArray();
arr.add("hello");
arr[0] = vla;
EXPECT_STREQ("world", arr[0]);
}
TEST(VariableLengthArray, JsonBuffer_strdup) {
int i = 16;
char vla[i];
strcpy(vla, "world");
DynamicJsonBuffer jsonBuffer;
const char* dup = jsonBuffer.strdup(vla);
EXPECT_NE(static_cast<const void*>(vla), static_cast<const void*>(dup));
EXPECT_STREQ("world", dup);
}
#endif