diff --git a/CHANGELOG.md b/CHANGELOG.md index 657388601..2a7a2f4fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ ArduinoJson: change log ======================= -v5.0 (currently in development) +v5.0 (currently under development) ---- +* Added support of `String` class (issue #55, #56, #70, #77) * Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators. **BREAKING CHANGES**: @@ -11,6 +12,13 @@ v5.0 (currently in development) - `JsonArray::at()` and `JsonObject::at()` were renamed to `get()` - Number of digits of floating point value are now set with `double_with_n_digits()` +**Personal note about the `String` class**: +Support of the `String` class has been added to the library because many people use it in their programs. +However, you should not see this as an invitation to use the `String` class. +The `String` class is **bad** because it uses dynamic memory allocation. +Compared to static allocation, it compiles to a bigger, slower program, and is less predicate. +You certainly don't want that in an embedded environment! + v4.4 ---- @@ -143,4 +151,4 @@ v1.1 v1.0 ---- -Initial release \ No newline at end of file +Initial release diff --git a/include/ArduinoJson/Arduino/String.hpp b/include/ArduinoJson/Arduino/String.hpp new file mode 100644 index 000000000..3ddf246de --- /dev/null +++ b/include/ArduinoJson/Arduino/String.hpp @@ -0,0 +1,19 @@ +// Copyright Benoit Blanchon 2014-2015 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson + +#pragma once + +#ifndef ARDUINO + +#include + +typedef std::string String; + +#else + +#include + +#endif diff --git a/include/ArduinoJson/Internals/ForceInline.hpp b/include/ArduinoJson/Internals/ForceInline.hpp index fd43e7a7b..322e30b31 100644 --- a/include/ArduinoJson/Internals/ForceInline.hpp +++ b/include/ArduinoJson/Internals/ForceInline.hpp @@ -7,7 +7,7 @@ #pragma once #ifdef _MSC_VER -#define JSON_FORCE_INLINE __forceinline +#define FORCE_INLINE __forceinline #else -#define JSON_FORCE_INLINE __attribute__((always_inline)) +#define FORCE_INLINE __attribute__((always_inline)) #endif diff --git a/include/ArduinoJson/Internals/JsonParser.hpp b/include/ArduinoJson/Internals/JsonParser.hpp index c244ca8e8..9d8278a1d 100644 --- a/include/ArduinoJson/Internals/JsonParser.hpp +++ b/include/ArduinoJson/Internals/JsonParser.hpp @@ -29,7 +29,7 @@ class JsonParser { void skipSpaces(); bool parseAnythingTo(JsonVariant *destination); - JSON_FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination); + FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination); const char *parseString(); diff --git a/include/ArduinoJson/Internals/JsonVariantContent.ipp b/include/ArduinoJson/Internals/JsonVariantContent.ipp index 2c5a9ae68..c5fb36c0a 100644 --- a/include/ArduinoJson/Internals/JsonVariantContent.ipp +++ b/include/ArduinoJson/Internals/JsonVariantContent.ipp @@ -23,6 +23,11 @@ inline char const* JsonVariantContent::as() const { return asString; } +template <> +inline String JsonVariantContent::as() const { + return asString; +} + template <> inline double JsonVariantContent::as() const { return asDouble; diff --git a/include/ArduinoJson/Internals/List.hpp b/include/ArduinoJson/Internals/List.hpp index 675ed3b21..d5dc5976f 100644 --- a/include/ArduinoJson/Internals/List.hpp +++ b/include/ArduinoJson/Internals/List.hpp @@ -48,22 +48,7 @@ class List { const_iterator end() const { return const_iterator(NULL); } protected: - node_type *addNewNode() { - if (!_buffer) return NULL; - - node_type *newNode = new (_buffer) node_type(); - - if (_firstNode) { - node_type *lastNode = _firstNode; - while (lastNode->next) lastNode = lastNode->next; - lastNode->next = newNode; - } else { - _firstNode = newNode; - } - - return newNode; - } - + node_type *addNewNode(); void removeNode(node_type *nodeToRemove); JsonBuffer *_buffer; diff --git a/include/ArduinoJson/JsonArray.hpp b/include/ArduinoJson/JsonArray.hpp index 78e580697..3c8c3a7e5 100644 --- a/include/ArduinoJson/JsonArray.hpp +++ b/include/ArduinoJson/JsonArray.hpp @@ -42,27 +42,27 @@ class JsonArray : public Internals::JsonPrintable, : Internals::List(buffer) {} // Gets the value at the specified index - JSON_FORCE_INLINE const JsonArraySubscript operator[](size_t index) const; + FORCE_INLINE const JsonArraySubscript operator[](size_t index) const; // Gets or sets the value at specified index - JSON_FORCE_INLINE JsonArraySubscript operator[](size_t index); + FORCE_INLINE JsonArraySubscript operator[](size_t index); // Adds the specified value at the end of the array. - JSON_FORCE_INLINE bool add(const JsonVariant value); + FORCE_INLINE bool add(const JsonVariant value); // Sets the value at specified index. - JSON_FORCE_INLINE void set(size_t index, const JsonVariant value); + FORCE_INLINE void set(size_t index, const JsonVariant value); // Gets the value at the specified index. - JSON_FORCE_INLINE JsonVariant get(size_t index) const; + FORCE_INLINE JsonVariant get(size_t index) const; // Gets the value at the specified index. template - JSON_FORCE_INLINE T get(size_t index) const; + FORCE_INLINE T get(size_t index) const; // Check the type of the value at specified index. template - JSON_FORCE_INLINE T is(size_t index) const; + FORCE_INLINE T is(size_t index) const; // Creates a JsonArray and adds a reference at the end of the array. // It's a shortcut for JsonBuffer::createArray() and JsonArray::add() diff --git a/include/ArduinoJson/JsonArraySubscript.hpp b/include/ArduinoJson/JsonArraySubscript.hpp index 52ba828fd..4f2aca38c 100644 --- a/include/ArduinoJson/JsonArraySubscript.hpp +++ b/include/ArduinoJson/JsonArraySubscript.hpp @@ -11,25 +11,32 @@ namespace ArduinoJson { class JsonArraySubscript : public JsonVariantBase { public: - JSON_FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index) + FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index) : _array(array), _index(index) {} - JSON_FORCE_INLINE JsonArraySubscript& operator=(const JsonVariant& value) { + FORCE_INLINE JsonArraySubscript& operator=(const JsonVariant& value) { _array.set(_index, value); return *this; } - JSON_FORCE_INLINE bool success() const { return _index < _array.size(); } + FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& other) { + // to prevent Visual Studio warning C4512: assignment operator could not be + // generated + _array.set(_index, other._array.get(other._index)); + return *this; + } + + FORCE_INLINE bool success() const { return _index < _array.size(); } - JSON_FORCE_INLINE operator JsonVariant() const { return _array.get(_index); } + FORCE_INLINE operator JsonVariant() const { return _array.get(_index); } template - JSON_FORCE_INLINE T as() const { + FORCE_INLINE T as() const { return _array.get(_index); } template - JSON_FORCE_INLINE T is() const { + FORCE_INLINE T is() const { return _array.is(_index); } diff --git a/include/ArduinoJson/JsonBuffer.hpp b/include/ArduinoJson/JsonBuffer.hpp index aab79800f..e1ef3b818 100644 --- a/include/ArduinoJson/JsonBuffer.hpp +++ b/include/ArduinoJson/JsonBuffer.hpp @@ -9,6 +9,8 @@ #include // for size_t #include // for uint8_t +#include "Arduino/String.hpp" + #if defined(__clang__) #pragma clang diagnostic ignored "-Wnon-virtual-dtor" #elif defined(__GNUC__) @@ -55,6 +57,11 @@ class JsonBuffer { // allocation fails. JsonArray &parseArray(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); + // Same as above with a String class + JsonArray &parseArray(const String &json, uint8_t nesting = DEFAULT_LIMIT) { + return parseArray(const_cast(json.c_str()), nesting); + } + // Allocates and populate a JsonObject from a JSON string. // // The First argument is a pointer to the JSON string, the memory must be @@ -67,6 +74,12 @@ class JsonBuffer { // allocation fails. JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); + // Same as above with a String class + JsonObject &parseObject(const String &json, + uint8_t nestingLimit = DEFAULT_LIMIT) { + return parseObject(const_cast(json.c_str()), nestingLimit); + } + // Allocates n bytes in the JsonBuffer. // Return a pointer to the allocated memory or NULL if allocation fails. virtual void *alloc(size_t size) = 0; diff --git a/include/ArduinoJson/JsonObject.hpp b/include/ArduinoJson/JsonObject.hpp index 48d1ae185..d5da8e9e1 100644 --- a/include/ArduinoJson/JsonObject.hpp +++ b/include/ArduinoJson/JsonObject.hpp @@ -6,6 +6,7 @@ #pragma once +#include "Arduino/String.hpp" #include "Internals/JsonBufferAllocated.hpp" #include "Internals/JsonPrintable.hpp" #include "Internals/List.hpp" @@ -35,62 +36,59 @@ class JsonObject : public Internals::JsonPrintable, public Internals::List, public Internals::JsonBufferAllocated { public: - typedef const char *key_type; - typedef JsonPair value_type; - // Create an empty JsonArray attached to the specified JsonBuffer. // You should not use this constructor directly. // Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject(). - JSON_FORCE_INLINE explicit JsonObject(JsonBuffer *buffer) + FORCE_INLINE explicit JsonObject(JsonBuffer* buffer) : Internals::List(buffer) {} // Gets or sets the value associated with the specified key. - JSON_FORCE_INLINE JsonObjectSubscript operator[](key_type key); + FORCE_INLINE JsonObjectSubscript operator[](JsonObjectKey key); // Gets the value associated with the specified key. - JSON_FORCE_INLINE const JsonObjectSubscript operator[](key_type key) const; + FORCE_INLINE const JsonObjectSubscript operator[](JsonObjectKey key) const; // Sets the specified key with the specified value. - JSON_FORCE_INLINE bool set(key_type key, const JsonVariant value); + FORCE_INLINE bool set(JsonObjectKey key, JsonVariant value); // Gets the value associated with the specified key. - JSON_FORCE_INLINE JsonVariant get(key_type key) const; + FORCE_INLINE JsonVariant get(JsonObjectKey) const; // Gets the value associated with the specified key. template - JSON_FORCE_INLINE T get(key_type key) const; + FORCE_INLINE T get(JsonObjectKey) const; // Checks the type of the value associated with the specified key. template - JSON_FORCE_INLINE T is(key_type key) const; + FORCE_INLINE bool is(JsonObjectKey) const; // Creates and adds a JsonArray. // This is a shortcut for JsonBuffer::createArray() and JsonObject::add(). - JsonArray &createNestedArray(key_type key); + JsonArray& createNestedArray(JsonObjectKey key); // Creates and adds a JsonObject. // This is a shortcut for JsonBuffer::createObject() and JsonObject::add(). - JsonObject &createNestedObject(key_type key); + JsonObject& createNestedObject(JsonObjectKey key); // Tells weither the specified key is present and associated with a value. - JSON_FORCE_INLINE bool containsKey(key_type key) const; + FORCE_INLINE bool containsKey(JsonObjectKey key) const; // Removes the specified key and the associated value. - void remove(key_type key); + void remove(JsonObjectKey key); // Returns a reference an invalid JsonObject. // This object is meant to replace a NULL pointer. // This is used when memory allocation or JSON parsing fail. - static JsonObject &invalid() { return _invalid; } + static JsonObject& invalid() { return _invalid; } // Serialize the object to the specified JsonWriter - void writeTo(Internals::JsonWriter &writer) const; + void writeTo(Internals::JsonWriter& writer) const; private: // Returns the list node that matches the specified key. - node_type *getNodeAt(key_type key) const; + node_type* getNodeAt(JsonObjectKey key) const; - node_type *getOrCreateNodeAt(const char *key); + node_type* getOrCreateNodeAt(JsonObjectKey key); // The instance returned by JsonObject::invalid() static JsonObject _invalid; diff --git a/include/ArduinoJson/JsonObject.ipp b/include/ArduinoJson/JsonObject.ipp index a0e3a43b2..ab57dc514 100644 --- a/include/ArduinoJson/JsonObject.ipp +++ b/include/ArduinoJson/JsonObject.ipp @@ -11,38 +11,41 @@ namespace ArduinoJson { -inline JsonVariant JsonObject::get(key_type key) const { +inline JsonVariant JsonObject::get(JsonObjectKey key) const { node_type *node = getNodeAt(key); return node ? node->content.value : JsonVariant(); } template -inline T JsonObject::get(key_type key) const { +inline T JsonObject::get(JsonObjectKey key) const { node_type *node = getNodeAt(key); return node ? node->content.value.as() : JsonVariant::invalid(); } template -inline T JsonObject::is(key_type key) const { +inline bool JsonObject::is(JsonObjectKey key) const { node_type *node = getNodeAt(key); return node ? node->content.value.is() : false; } -inline JsonObjectSubscript JsonObject::operator[](key_type key) { +inline JsonObjectSubscript JsonObject::operator[](JsonObjectKey key) { return JsonObjectSubscript(*this, key); } -inline const JsonObjectSubscript JsonObject::operator[](key_type key) const { +inline const JsonObjectSubscript JsonObject::operator[]( + JsonObjectKey key) const { return JsonObjectSubscript(*const_cast(this), key); } -inline bool JsonObject::containsKey(key_type key) const { +inline bool JsonObject::containsKey(JsonObjectKey key) const { return getNodeAt(key) != NULL; } -inline void JsonObject::remove(key_type key) { removeNode(getNodeAt(key)); } +inline void JsonObject::remove(JsonObjectKey key) { + removeNode(getNodeAt(key)); +} -inline bool JsonObject::set(const char *key, const JsonVariant value) { +inline bool JsonObject::set(JsonObjectKey key, const JsonVariant value) { node_type *node = getOrCreateNodeAt(key); if (!node) return false; @@ -57,6 +60,12 @@ inline const JsonObjectSubscript JsonVariantBase::operator[]( return asObject()[key]; } +template +inline const JsonObjectSubscript JsonVariantBase::operator[]( + const String &key) const { + return asObject()[key]; +} + template <> inline JsonObject const &JsonVariant::invalid() { return JsonObject::invalid(); diff --git a/include/ArduinoJson/JsonObjectKey.hpp b/include/ArduinoJson/JsonObjectKey.hpp new file mode 100644 index 000000000..a9a398a56 --- /dev/null +++ b/include/ArduinoJson/JsonObjectKey.hpp @@ -0,0 +1,24 @@ +// Copyright Benoit Blanchon 2014-2015 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson + +#pragma once + +#include "Arduino/String.hpp" + +namespace ArduinoJson { + +class JsonObjectKey { + public: + JsonObjectKey() {} + JsonObjectKey(const char* key) : _data(key) {} + JsonObjectKey(const String& key) : _data(key.c_str()) {} + + operator const char*() const { return _data; } + + private: + const char* _data; +}; +} diff --git a/include/ArduinoJson/JsonObjectSubscript.hpp b/include/ArduinoJson/JsonObjectSubscript.hpp index 70f4a2292..77034713b 100644 --- a/include/ArduinoJson/JsonObjectSubscript.hpp +++ b/include/ArduinoJson/JsonObjectSubscript.hpp @@ -11,30 +11,38 @@ namespace ArduinoJson { class JsonObjectSubscript : public JsonVariantBase { public: - JSON_FORCE_INLINE JsonObjectSubscript(JsonObject& object, const char* key) + FORCE_INLINE JsonObjectSubscript(JsonObject& object, JsonObjectKey key) : _object(object), _key(key) {} - JSON_FORCE_INLINE JsonObjectSubscript& operator=(const JsonVariant& value) { + FORCE_INLINE JsonObjectSubscript& operator=(const JsonVariant& value) { _object.set(_key, value); return *this; } - JSON_FORCE_INLINE bool success() const { return _object.containsKey(_key); } + FORCE_INLINE JsonObjectSubscript& operator=( + const JsonObjectSubscript& other) { + // to prevent Visual Studio warning C4512: assignment operator could not be + // generated + _object.set(_key, other._object.get(other._key)); + return *this; + } + + FORCE_INLINE bool success() const { return _object.containsKey(_key); } - JSON_FORCE_INLINE operator JsonVariant() const { return _object.get(_key); } + FORCE_INLINE operator JsonVariant() const { return _object.get(_key); } template - JSON_FORCE_INLINE T as() const { + FORCE_INLINE T as() const { return _object.get(_key); } template - JSON_FORCE_INLINE T is() const { + FORCE_INLINE T is() const { return _object.is(_key); } private: JsonObject& _object; - const char* _key; + JsonObjectKey _key; }; } diff --git a/include/ArduinoJson/JsonPair.hpp b/include/ArduinoJson/JsonPair.hpp index 876a66cc0..0b6122bea 100644 --- a/include/ArduinoJson/JsonPair.hpp +++ b/include/ArduinoJson/JsonPair.hpp @@ -6,13 +6,14 @@ #pragma once +#include "JsonObjectKey.hpp" #include "JsonVariant.hpp" namespace ArduinoJson { // A key value pair for JsonObject. struct JsonPair { - const char* key; + JsonObjectKey key; JsonVariant value; }; } diff --git a/include/ArduinoJson/JsonVariant.hpp b/include/ArduinoJson/JsonVariant.hpp index a093264f1..0afd4b78c 100644 --- a/include/ArduinoJson/JsonVariant.hpp +++ b/include/ArduinoJson/JsonVariant.hpp @@ -9,6 +9,7 @@ #include #include // for uint8_t +#include "Arduino/String.hpp" #include "Internals/JsonPrintable.hpp" #include "Internals/JsonVariantContent.hpp" #include "Internals/JsonVariantType.hpp" @@ -31,46 +32,47 @@ class JsonVariant : public Internals::JsonPrintable, public JsonVariantBase { public: // Creates an uninitialized JsonVariant - JSON_FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {} + FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {} // Create a JsonVariant containing a boolean value. // It will be serialized as "true" or "false" in JSON. - JSON_FORCE_INLINE JsonVariant(bool value); + FORCE_INLINE JsonVariant(bool value); // Create a JsonVariant containing a floating point value. // The second argument specifies the number of decimal digits to write in // the JSON string. - JSON_FORCE_INLINE JsonVariant(float value, uint8_t decimals = 2); - JSON_FORCE_INLINE JsonVariant(double value, uint8_t decimals = 2); + FORCE_INLINE JsonVariant(float value, uint8_t decimals = 2); + FORCE_INLINE JsonVariant(double value, uint8_t decimals = 2); // Create a JsonVariant containing an integer value. - JSON_FORCE_INLINE JsonVariant(signed char value); - JSON_FORCE_INLINE JsonVariant(signed long value); - JSON_FORCE_INLINE JsonVariant(signed int value); - JSON_FORCE_INLINE JsonVariant(signed short value); - JSON_FORCE_INLINE JsonVariant(unsigned char value); - JSON_FORCE_INLINE JsonVariant(unsigned long value); - JSON_FORCE_INLINE JsonVariant(unsigned int value); - JSON_FORCE_INLINE JsonVariant(unsigned short value); + FORCE_INLINE JsonVariant(signed char value); + FORCE_INLINE JsonVariant(signed long value); + FORCE_INLINE JsonVariant(signed int value); + FORCE_INLINE JsonVariant(signed short value); + FORCE_INLINE JsonVariant(unsigned char value); + FORCE_INLINE JsonVariant(unsigned long value); + FORCE_INLINE JsonVariant(unsigned int value); + FORCE_INLINE JsonVariant(unsigned short value); // Create a JsonVariant containing a string. - JSON_FORCE_INLINE JsonVariant(const char *value); + FORCE_INLINE JsonVariant(const char *value); + FORCE_INLINE JsonVariant(const String &value); // Create a JsonVariant containing a reference to an array. - JSON_FORCE_INLINE JsonVariant(JsonArray &array); + FORCE_INLINE JsonVariant(JsonArray &array); // Create a JsonVariant containing a reference to an object. - JSON_FORCE_INLINE JsonVariant(JsonObject &object); + FORCE_INLINE JsonVariant(JsonObject &object); // Get the variant as the specified type. // See cast operators for details. template - JSON_FORCE_INLINE T as() const; + FORCE_INLINE T as() const; // Tells weither the variant has the specified type. // Returns true if the variant has type type T, false otherwise. template - JSON_FORCE_INLINE bool is() const; + FORCE_INLINE bool is() const; // Serialize the variant to a JsonWriter void writeTo(Internals::JsonWriter &writer) const; diff --git a/include/ArduinoJson/JsonVariant.ipp b/include/ArduinoJson/JsonVariant.ipp index c41366275..35460572d 100644 --- a/include/ArduinoJson/JsonVariant.ipp +++ b/include/ArduinoJson/JsonVariant.ipp @@ -20,6 +20,11 @@ inline JsonVariant::JsonVariant(const char *value) { _content.asString = value; } +inline JsonVariant::JsonVariant(const String &value) { + _type = Internals::JSON_STRING; + _content.asString = value.c_str(); +} + inline JsonVariant::JsonVariant(double value, uint8_t decimals) { _type = static_cast( Internals::JSON_DOUBLE_0_DECIMALS + decimals); @@ -107,6 +112,11 @@ inline bool JsonVariant::is() const { return _type == Internals::JSON_STRING; } +template <> +inline bool JsonVariant::is() const { + return _type == Internals::JSON_STRING; +} + template <> inline bool JsonVariant::is() const { return _type >= Internals::JSON_DOUBLE_0_DECIMALS; diff --git a/include/ArduinoJson/JsonVariantBase.hpp b/include/ArduinoJson/JsonVariantBase.hpp index c9a331ada..6939702f2 100644 --- a/include/ArduinoJson/JsonVariantBase.hpp +++ b/include/ArduinoJson/JsonVariantBase.hpp @@ -7,6 +7,7 @@ #pragma once #include "Internals/ForceInline.hpp" +#include "JsonObjectKey.hpp" namespace ArduinoJson { @@ -19,50 +20,45 @@ class JsonVariantBase { public: // Gets the variant as a boolean value. // Returns false if the variant is not a boolean value. - JSON_FORCE_INLINE operator bool() const { return as(); } + FORCE_INLINE operator bool() const { return as(); } // Gets the variant as a floating-point value. // Returns 0.0 if the variant is not a floating-point value - JSON_FORCE_INLINE operator double() const { return as(); } - JSON_FORCE_INLINE operator float() const { return as(); } + FORCE_INLINE operator double() const { return as(); } + FORCE_INLINE operator float() const { return as(); } // Gets the variant as an integer value. // Returns 0 if the variant is not an integer value. - JSON_FORCE_INLINE operator signed long() const { return as(); } - JSON_FORCE_INLINE operator signed char() const { return as(); } - JSON_FORCE_INLINE operator signed int() const { return as(); } - JSON_FORCE_INLINE operator signed short() const { return as(); } - JSON_FORCE_INLINE operator unsigned char() const { - return as(); - } - JSON_FORCE_INLINE operator unsigned int() const { return as(); } - JSON_FORCE_INLINE operator unsigned long() const { - return as(); - } - JSON_FORCE_INLINE operator unsigned short() const { - return as(); - } + FORCE_INLINE operator signed long() const { return as(); } + FORCE_INLINE operator signed char() const { return as(); } + FORCE_INLINE operator signed int() const { return as(); } + FORCE_INLINE operator signed short() const { return as(); } + FORCE_INLINE operator unsigned char() const { return as(); } + FORCE_INLINE operator unsigned int() const { return as(); } + FORCE_INLINE operator unsigned long() const { return as(); } + FORCE_INLINE operator unsigned short() const { return as(); } // Gets the variant as a string. // Returns NULL if variant is not a string. - JSON_FORCE_INLINE operator const char *() const { return as(); } - JSON_FORCE_INLINE const char *asString() const { return as(); } + FORCE_INLINE operator const char *() const { return as(); } + FORCE_INLINE const char *asString() const { return as(); } + FORCE_INLINE operator String() const { return as(); } // Gets the variant as an array. // Returns a reference to the JsonArray or JsonArray::invalid() if the // variant // is not an array. - JSON_FORCE_INLINE operator JsonArray &() const { return as(); } - JSON_FORCE_INLINE JsonArray &asArray() const { return as(); } + FORCE_INLINE operator JsonArray &() const { return as(); } + FORCE_INLINE JsonArray &asArray() const { return as(); } // Gets the variant as an object. // Returns a reference to the JsonObject or JsonObject::invalid() if the // variant is not an object. - JSON_FORCE_INLINE operator JsonObject &() const { return as(); } - JSON_FORCE_INLINE JsonObject &asObject() const { return as(); } + FORCE_INLINE operator JsonObject &() const { return as(); } + FORCE_INLINE JsonObject &asObject() const { return as(); } template - JSON_FORCE_INLINE const T as() const { + FORCE_INLINE const T as() const { return impl()->template as(); } @@ -74,13 +70,17 @@ class JsonVariantBase { // Mimics an array. // Returns the element at specified index if the variant is an array. // Returns JsonVariant::invalid() if the variant is not an array. - JSON_FORCE_INLINE const JsonArraySubscript operator[](int index) const; + FORCE_INLINE const JsonArraySubscript operator[](int index) const; // Mimics an object. // Returns the value associated with the specified key if the variant is // an object. // Return JsonVariant::invalid() if the variant is not an object. - JSON_FORCE_INLINE const JsonObjectSubscript operator[](const char *key) const; + FORCE_INLINE const JsonObjectSubscript operator[](const char *key) const; + FORCE_INLINE const JsonObjectSubscript operator[](const String &key) const; + + protected: + JsonVariantBase() {} private: const TImpl *impl() const { return static_cast(this); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2fe98745a..2a383ea0a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,6 @@ -file(GLOB_RECURSE INC_FILES ../include/*.hpp) -file(GLOB_RECURSE SRC_FILES *.cpp) +file(GLOB_RECURSE HPP_FILES ../include/*.hpp) +file(GLOB_RECURSE IPP_FILES ../include/*.ipp) +file(GLOB_RECURSE CPP_FILES *.cpp) if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") add_definitions( @@ -45,4 +46,4 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") ) endif() -add_library(ArduinoJson ${SRC_FILES} ${INC_FILES}) \ No newline at end of file +add_library(ArduinoJson ${CPP_FILES} ${HPP_FILES} ${IPP_FILES}) diff --git a/src/Internals/List.cpp b/src/Internals/List.cpp index 00ed3efe9..96f8503a1 100644 --- a/src/Internals/List.cpp +++ b/src/Internals/List.cpp @@ -19,6 +19,23 @@ size_t List::size() const { return nodeCount; } +template +typename List::node_type *List::addNewNode() { + if (!_buffer) return NULL; + + node_type *newNode = new (_buffer) node_type(); + + if (_firstNode) { + node_type *lastNode = _firstNode; + while (lastNode->next) lastNode = lastNode->next; + lastNode->next = newNode; + } else { + _firstNode = newNode; + } + + return newNode; +} + template void List::removeNode(node_type *nodeToRemove) { if (!nodeToRemove) return; diff --git a/src/JsonObject.cpp b/src/JsonObject.cpp index 1cc29859a..77aae4137 100644 --- a/src/JsonObject.cpp +++ b/src/JsonObject.cpp @@ -17,7 +17,7 @@ using namespace ArduinoJson::Internals; JsonObject JsonObject::_invalid(NULL); -JsonObject::node_type *JsonObject::getOrCreateNodeAt(const char *key) { +JsonObject::node_type *JsonObject::getOrCreateNodeAt(JsonObjectKey key) { node_type *existingNode = getNodeAt(key); if (existingNode) return existingNode; @@ -25,21 +25,21 @@ JsonObject::node_type *JsonObject::getOrCreateNodeAt(const char *key) { return newNode; } -JsonArray &JsonObject::createNestedArray(const char *key) { +JsonArray &JsonObject::createNestedArray(JsonObjectKey key) { if (!_buffer) return JsonArray::invalid(); JsonArray &array = _buffer->createArray(); set(key, array); return array; } -JsonObject &JsonObject::createNestedObject(const char *key) { +JsonObject &JsonObject::createNestedObject(JsonObjectKey key) { if (!_buffer) return JsonObject::invalid(); JsonObject &object = _buffer->createObject(); set(key, object); return object; } -JsonObject::node_type *JsonObject::getNodeAt(const char *key) const { +JsonObject::node_type *JsonObject::getNodeAt(JsonObjectKey key) const { for (node_type *node = _firstNode; node; node = node->next) { if (!strcmp(node->content.key, key)) return node; } diff --git a/test/ArduinoString_Tests.cpp b/test/ArduinoString_Tests.cpp new file mode 100644 index 000000000..2aa6c5405 --- /dev/null +++ b/test/ArduinoString_Tests.cpp @@ -0,0 +1,109 @@ +// Copyright Benoit Blanchon 2014-2015 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson + +#include +#include + +TEST(ArduinoStringTests, JsonBuffer_ParseArray) { + DynamicJsonBuffer jsonBuffer; + String json("[1,2]"); + JsonArray &array = jsonBuffer.parseArray(json); + ASSERT_TRUE(array.success()); +} + +TEST(ArduinoStringTests, JsonBuffer_ParseObject) { + DynamicJsonBuffer jsonBuffer; + String json("{\"a\":1,\"b\":2}"); + JsonObject &object = jsonBuffer.parseObject(json); + ASSERT_TRUE(object.success()); +} + +TEST(ArduinoStringTests, JsonVariant) { + String input = "Hello world!"; + JsonVariant variant(input); + ASSERT_TRUE(variant.is()); + String output = variant.as(); + ASSERT_EQ(input, output); +} + +TEST(ArduinoStringTests, JsonObject_Subscript) { + DynamicJsonBuffer jsonBuffer; + char json[] = "{\"key\":\"value\"}"; + JsonObject &object = jsonBuffer.parseObject(json); + ASSERT_STREQ("value", object[String("key")]); +} + +TEST(ArduinoStringTests, JsonObject_ConstSubscript) { + DynamicJsonBuffer jsonBuffer; + char json[] = "{\"key\":\"value\"}"; + const JsonObject &object = jsonBuffer.parseObject(json); + ASSERT_STREQ("value", object[String("key")]); +} + +TEST(ArduinoStringTests, JsonObject_Set) { + DynamicJsonBuffer jsonBuffer; + JsonObject &object = jsonBuffer.createObject(); + String key = "key"; + object.set(key, "value"); + ASSERT_STREQ("value", object["key"]); +} + +TEST(ArduinoStringTests, JsonObject_Get) { + DynamicJsonBuffer jsonBuffer; + char json[] = "{\"key\":\"value\"}"; + const JsonObject &object = jsonBuffer.parseObject(json); + ASSERT_STREQ("value", object.get(String("key"))); +} + +TEST(ArduinoStringTests, JsonObject_GetT) { + DynamicJsonBuffer jsonBuffer; + char json[] = "{\"key\":\"value\"}"; + const JsonObject &object = jsonBuffer.parseObject(json); + ASSERT_STREQ("value", object.get(String("key"))); +} + +TEST(ArduinoStringTests, JsonObject_IsT) { + DynamicJsonBuffer jsonBuffer; + char json[] = "{\"key\":\"value\"}"; + const JsonObject &object = jsonBuffer.parseObject(json); + ASSERT_TRUE(object.is(String("key"))); +} + +TEST(ArduinoStringTests, JsonObject_CreateNestedObject) { + DynamicJsonBuffer jsonBuffer; + String key = "key"; + char json[64]; + JsonObject &object = jsonBuffer.createObject(); + object.createNestedObject(key); + object.printTo(json, sizeof(json)); + ASSERT_STREQ("{\"key\":{}}", json); +} + +TEST(ArduinoStringTests, JsonObject_CreateNestedArray) { + DynamicJsonBuffer jsonBuffer; + String key = "key"; + char json[64]; + JsonObject &object = jsonBuffer.createObject(); + object.createNestedArray(key); + object.printTo(json, sizeof(json)); + ASSERT_STREQ("{\"key\":[]}", json); +} + +TEST(ArduinoStringTests, JsonObject_ContainsKey) { + DynamicJsonBuffer jsonBuffer; + char json[] = "{\"key\":\"value\"}"; + const JsonObject &object = jsonBuffer.parseObject(json); + ASSERT_TRUE(object.containsKey(String("key"))); +} + +TEST(ArduinoStringTests, JsonObject_Remove) { + DynamicJsonBuffer jsonBuffer; + char json[] = "{\"key\":\"value\"}"; + JsonObject &object = jsonBuffer.parseObject(json); + ASSERT_EQ(1, object.size()); + object.remove(String("key")); + ASSERT_EQ(0, object.size()); +} \ No newline at end of file diff --git a/test/JsonVariant_Undefined_Tests.cpp b/test/JsonVariant_Undefined_Tests.cpp index 5d1c7db35..98ef914a4 100644 --- a/test/JsonVariant_Undefined_Tests.cpp +++ b/test/JsonVariant_Undefined_Tests.cpp @@ -30,9 +30,25 @@ TEST_F(JsonVariant_Undefined_Tests, AsBoolReturnsFalse) { } TEST_F(JsonVariant_Undefined_Tests, AsArrayReturnInvalid) { - EXPECT_EQ(JsonArray::invalid(), variant.asArray()); + EXPECT_EQ(JsonArray::invalid(), variant.as()); +} + +TEST_F(JsonVariant_Undefined_Tests, AsConstArrayReturnInvalid) { + EXPECT_EQ(JsonArray::invalid(), variant.as()); } TEST_F(JsonVariant_Undefined_Tests, AsObjectReturnInvalid) { + EXPECT_EQ(JsonObject::invalid(), variant.as()); +} + +TEST_F(JsonVariant_Undefined_Tests, AsConstObjectReturnInvalid) { + EXPECT_EQ(JsonObject::invalid(), variant.as()); +} + +TEST_F(JsonVariant_Undefined_Tests, AsArrayWrapperReturnInvalid) { + EXPECT_EQ(JsonArray::invalid(), variant.asArray()); +} + +TEST_F(JsonVariant_Undefined_Tests, AsObjectWrapperReturnInvalid) { EXPECT_EQ(JsonObject::invalid(), variant.asObject()); }