diff --git a/CHANGELOG.md b/CHANGELOG.md index 8efccbc7..20db31b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,37 @@ ArduinoJson: change log HEAD ---- +* Templatized all functions using `String` or `std::string` +* Removed `ArduinoJson::String` +* Removed `JsonVariant::defaultValue()` +* Removed non-template `JsonObject::get()` and `JsonArray.get()` +* Fixed support for `StringSumHelper` (issue #184) +* Replaced `ARDUINOJSON_USE_ARDUINO_STRING` by `ARDUINOJSON_ENABLE_STD_STRING` and `ARDUINOJSON_ENABLE_ARDUINO_STRING` (issue #378) +* Added example `StringExample.ino` to show where `String` can be used * Increased default nesting limit to 50 when compiled for a computer (issue #349) +**BREAKING CHANGES**: + +The non-template functions `JsonObject::get()` and `JsonArray.get()` have been removed. This means that you need to explicitely tell the type you expect in return. + +Old code: + +```c++ +#define ARDUINOJSON_USE_ARDUINO_STRING 0 +JsonVariant value1 = myObject.get("myKey"); +JsonVariant value2 = myArray.get(0); +``` + +New code: + +```c++ +#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 +#define ARDUINOJSON_ENABLE_STD_STRING 1 +JsonVariant value1 = myObject.get("myKey"); +JsonVariant value2 = myArray.get(0); +``` + + v5.6.7 ------ diff --git a/examples/StringExample/StringExample.ino b/examples/StringExample/StringExample.ino new file mode 100644 index 00000000..780cb435 --- /dev/null +++ b/examples/StringExample/StringExample.ino @@ -0,0 +1,53 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include + +// About +// ----- +// This example shows the different ways you can use String with ArduinoJson. +// Please don't see this as an invitation to use String. +// On the contrary, you should always use char[] when possible, it's much more +// efficient in term of code size, speed and memory usage. + +void setup() { + DynamicJsonBuffer jsonBuffer; + + // You can use a String as your JSON input. + // WARNING: the content of the String will be duplicated in the JsonBuffer. + String input = + "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}"; + JsonObject& root = jsonBuffer.parseObject(input); + + // You can use a String to get an element of a JsonObject + // No duplication is done. + long time = root[String("time")]; + + // You can use a String to set an element of a JsonObject + // WARNING: the content of the String will be duplicated in the JsonBuffer. + root[String("time")] = time; + + // You can get a String from a JsonObject or JsonArray: + // No duplication is done, at least not in the JsonBuffer. + String sensor = root[String("sensor")]; + + // You can set a String to a JsonObject or JsonArray: + // WARNING: the content of the String will be duplicated in the JsonBuffer. + root["sensor"] = sensor; + + // You can also concatenate strings + // WARNING: the content of the String will be duplicated in the JsonBuffer. + root[String("sen") + "sor"] = String("gp") + "s"; + + // Lastly, you can print the resulting JSON to a String + String output; + root.printTo(output); +} + +void loop() { + // not used in this example +} diff --git a/include/ArduinoJson/Configuration.hpp b/include/ArduinoJson/Configuration.hpp index 073bd652..32b71b7d 100644 --- a/include/ArduinoJson/Configuration.hpp +++ b/include/ArduinoJson/Configuration.hpp @@ -22,12 +22,17 @@ #define ARDUINOJSON_USE_INT64 0 #endif -// arduino has its own implementation of String to replace std::string -#ifndef ARDUINOJSON_USE_ARDUINO_STRING -#define ARDUINOJSON_USE_ARDUINO_STRING 1 +// Arduino has its own implementation of String to replace std::string +#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING +#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 #endif -// arduino doesn't support STL stream +// Arduino doesn't have std::string +#ifndef ARDUINOJSON_ENABLE_STD_STRING +#define ARDUINOJSON_ENABLE_STD_STRING 0 +#endif + +// Arduino doesn't support STL stream #ifndef ARDUINOJSON_ENABLE_STD_STREAM #define ARDUINOJSON_ENABLE_STD_STREAM 0 #endif @@ -73,8 +78,13 @@ #endif // on a computer, we can use std::string -#ifndef ARDUINOJSON_USE_ARDUINO_STRING -#define ARDUINOJSON_USE_ARDUINO_STRING 0 +#ifndef ARDUINOJSON_ENABLE_STD_STRING +#define ARDUINOJSON_ENABLE_STD_STRING 1 +#endif + +// on a computer, there is no reason to beleive Arduino String is available +#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING +#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 #endif // on a computer, we can assume that the STL is there diff --git a/include/ArduinoJson/Internals/DynamicStringBuilder.hpp b/include/ArduinoJson/Internals/DynamicStringBuilder.hpp index 035646ff..d7d921a1 100644 --- a/include/ArduinoJson/Internals/DynamicStringBuilder.hpp +++ b/include/ArduinoJson/Internals/DynamicStringBuilder.hpp @@ -8,26 +8,26 @@ #pragma once #include "../Print.hpp" -#include "../String.hpp" +#include "StringFuncs.hpp" namespace ArduinoJson { namespace Internals { // A Print implementation that allows to write in a String +template class DynamicStringBuilder : public Print { public: - DynamicStringBuilder(String &str) : _str(str) {} + DynamicStringBuilder(TString &str) : _str(str) {} virtual size_t write(uint8_t c) { - // Need to cast to char, otherwise String will print a number (issue #120) - _str += static_cast(c); + StringFuncs::append(_str, static_cast(c)); return 1; } private: DynamicStringBuilder &operator=(const DynamicStringBuilder &); - String &_str; + TString &_str; }; } } diff --git a/include/ArduinoJson/Internals/JsonPrintable.hpp b/include/ArduinoJson/Internals/JsonPrintable.hpp index 620f79b9..71c58206 100644 --- a/include/ArduinoJson/Internals/JsonPrintable.hpp +++ b/include/ArduinoJson/Internals/JsonPrintable.hpp @@ -8,6 +8,7 @@ #pragma once #include "../Configuration.hpp" +#include "../TypeTraits/EnableIf.hpp" #include "DummyPrint.hpp" #include "DynamicStringBuilder.hpp" #include "IndentedPrint.hpp" @@ -49,8 +50,10 @@ class JsonPrintable { return printTo(sb); } - size_t printTo(String &str) const { - DynamicStringBuilder sb(str); + template + typename TypeTraits::EnableIf::has_append, size_t>::type + printTo(TString &str) const { + DynamicStringBuilder sb(str); return printTo(sb); } @@ -69,8 +72,10 @@ class JsonPrintable { return prettyPrintTo(indentedPrint); } - size_t prettyPrintTo(String &str) const { - DynamicStringBuilder sb(str); + template + typename TypeTraits::EnableIf::has_append, size_t>::type + prettyPrintTo(TString &str) const { + DynamicStringBuilder sb(str); return prettyPrintTo(sb); } diff --git a/include/ArduinoJson/TypeTraits/IsReference.hpp b/include/ArduinoJson/Internals/JsonVariantDefault.hpp similarity index 53% rename from include/ArduinoJson/TypeTraits/IsReference.hpp rename to include/ArduinoJson/Internals/JsonVariantDefault.hpp index 51923fea..c3a31ad0 100644 --- a/include/ArduinoJson/TypeTraits/IsReference.hpp +++ b/include/ArduinoJson/Internals/JsonVariantDefault.hpp @@ -8,17 +8,19 @@ #pragma once namespace ArduinoJson { -namespace TypeTraits { +namespace Internals { -// A meta-function that returns true if T is a reference template -struct IsReference { - static const bool value = false; +struct JsonVariantDefault { + static T get() { + return T(); + } }; template -struct IsReference { - static const bool value = true; -}; +struct JsonVariantDefault : JsonVariantDefault {}; + +template +struct JsonVariantDefault : JsonVariantDefault {}; } } diff --git a/include/ArduinoJson/Internals/StringFuncs.hpp b/include/ArduinoJson/Internals/StringFuncs.hpp new file mode 100644 index 00000000..bba4e603 --- /dev/null +++ b/include/ArduinoJson/Internals/StringFuncs.hpp @@ -0,0 +1,94 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../Configuration.hpp" + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#include +#endif + +#if ARDUINOJSON_ENABLE_STD_STRING +#include +#endif + +namespace ArduinoJson { +namespace Internals { + +template +struct StringFuncs {}; + +template +struct StringFuncs : StringFuncs {}; + +template +struct StringFuncs : StringFuncs {}; + +struct CharPtrFuncs { + static bool equals(const char* str, const char* expected) { + return strcmp(str, expected) == 0; + } + + template + static char* duplicate(const char* str, Buffer* buffer) { + if (!str) return NULL; + size_t size = strlen(str) + 1; + void* dup = buffer->alloc(size); + if (dup != NULL) memcpy(dup, str, size); + return static_cast(dup); + } + + static const bool has_append = false; + static const bool should_duplicate = false; +}; + +template <> +struct StringFuncs : CharPtrFuncs {}; + +template <> +struct StringFuncs : CharPtrFuncs {}; + +template +struct StringFuncs : CharPtrFuncs {}; + +template +struct StdStringFuncs { + template + static char* duplicate(const TString& str, Buffer* buffer) { + if (!str.c_str()) return NULL; // <- Arduino string can return NULL + size_t size = str.length() + 1; + void* dup = buffer->alloc(size); + if (dup != NULL) memcpy(dup, str.c_str(), size); + return static_cast(dup); + } + + static bool equals(const TString& str, const char* expected) { + return str == expected; + } + + static void append(TString& str, char c) { + str += c; + } + + static const bool has_append = true; + static const bool should_duplicate = true; +}; + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +template <> +struct StringFuncs : StdStringFuncs {}; +template <> +struct StringFuncs : StdStringFuncs {}; +#endif + +#if ARDUINOJSON_ENABLE_STD_STRING +template <> +struct StringFuncs : StdStringFuncs {}; +#endif +} +} diff --git a/include/ArduinoJson/Internals/ValueSetter.hpp b/include/ArduinoJson/Internals/ValueSetter.hpp new file mode 100644 index 00000000..418c0022 --- /dev/null +++ b/include/ArduinoJson/Internals/ValueSetter.hpp @@ -0,0 +1,41 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "../JsonBuffer.hpp" +#include "../JsonVariant.hpp" +#include "../TypeTraits/EnableIf.hpp" +#include "StringFuncs.hpp" + +namespace ArduinoJson { +namespace Internals { + +template +struct ValueSetter { + template + static bool set(JsonBuffer*, TDestination& destination, + const TSource& source) { + destination = source; + return true; + } +}; + +template +struct ValueSetter::should_duplicate>::type> { + template + static bool set(JsonBuffer* buffer, TDestination& destination, + const TSource& source) { + const char* copy = buffer->strdup(source); + if (!copy) return false; + destination = copy; + return true; + } +}; +} +} diff --git a/include/ArduinoJson/JsonArray.hpp b/include/ArduinoJson/JsonArray.hpp index 9f4344f6..6faf0304 100644 --- a/include/ArduinoJson/JsonArray.hpp +++ b/include/ArduinoJson/JsonArray.hpp @@ -11,10 +11,12 @@ #include "Internals/JsonPrintable.hpp" #include "Internals/List.hpp" #include "Internals/ReferenceType.hpp" +#include "Internals/StringFuncs.hpp" +#include "Internals/ValueSetter.hpp" #include "JsonVariant.hpp" +#include "TypeTraits/ConstRefOrConstPtr.hpp" #include "TypeTraits/EnableIf.hpp" #include "TypeTraits/IsFloatingPoint.hpp" -#include "TypeTraits/IsReference.hpp" #include "TypeTraits/IsSame.hpp" // Returns the size (in bytes) of an array with n elements. @@ -40,15 +42,6 @@ class JsonArray : public Internals::JsonPrintable, public Internals::List, public Internals::JsonBufferAllocated { public: - // A meta-function that returns true if type T can be used in - // JsonArray::set() - template - struct CanSet { - static const bool value = JsonVariant::IsConstructibleFrom::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value; - }; - // Create an empty JsonArray attached to the specified JsonBuffer. // You should not call this constructor directly. // Instead, use JsonBuffer::createArray() or JsonBuffer::parseArray(). @@ -57,7 +50,7 @@ class JsonArray : public Internals::JsonPrintable, // Gets the value at the specified index JsonVariant operator[](size_t index) const { - return get(index); + return get(index); } // Gets or sets the value at specified index @@ -73,29 +66,24 @@ class JsonArray : public Internals::JsonPrintable, // bool add(float value); // bool add(double value); // bool add(const char*); - template - bool add( - T value, - typename TypeTraits::EnableIf< - CanSet::value && !TypeTraits::IsReference::value>::type * = 0) { - return addNode(value); - } + // 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&); template - bool add(const T &value, - typename TypeTraits::EnableIf::value>::type * = 0) { - return addNode(const_cast(value)); + bool add(const T &value) { + // reduce the number of template function instanciation to reduce code size + return addNodeImpl::type>(value); } // bool add(float value, uint8_t decimals); // bool add(double value, uint8_t decimals); template - bool add(T value, uint8_t decimals, - typename TypeTraits::EnableIf< - TypeTraits::IsFloatingPoint::value>::type * = 0) { - return addNode(JsonVariant(value, decimals)); + bool add(T value, uint8_t decimals) { + return add(JsonVariant(value, decimals)); } // Sets the value at specified index. @@ -104,42 +92,33 @@ class JsonArray : public Internals::JsonPrintable, // bool set(size_t index, long value); // bool set(size_t index, int value); // bool set(size_t index, short value); - template - bool set( - size_t index, T value, - typename TypeTraits::EnableIf< - CanSet::value && !TypeTraits::IsReference::value>::type * = 0) { - return setNodeAt(index, 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&); template - bool set(size_t index, const T &value, - typename TypeTraits::EnableIf::value>::type * = 0) { - return setNodeAt(index, const_cast(value)); + bool set(size_t index, const T &value) { + // reduce the number of template function instanciation to reduce code size + return setNodeAt::type>(index, + value); } // bool set(size_t index, float value, uint8_t decimals = 2); // bool set(size_t index, double value, uint8_t decimals = 2); template - bool set(size_t index, T value, uint8_t decimals, - typename TypeTraits::EnableIf< - TypeTraits::IsFloatingPoint::value>::type * = 0) { - return setNodeAt(index, JsonVariant(value, decimals)); - } - - // Gets the value at the specified index. - JsonVariant get(size_t index) const { - node_type *node = getNodeAt(index); - return node ? node->content : JsonVariant(); + typename TypeTraits::EnableIf::value, + bool>::type + set(size_t index, T value, uint8_t decimals) { + return set(index, JsonVariant(value, decimals)); } // Gets the value at the specified index. template typename Internals::JsonVariantAs::type get(size_t index) const { node_type *node = getNodeAt(index); - return node ? node->content.as() : JsonVariant::defaultValue(); + return node ? node->content.as() + : Internals::JsonVariantDefault::get(); + ; } // Check the type of the value at specified index. @@ -172,7 +151,7 @@ class JsonArray : public Internals::JsonPrintable, // Imports a 1D array template - bool copyFrom(T(&array)[N]) { + bool copyFrom(T (&array)[N]) { return copyFrom(array, N); } @@ -188,7 +167,7 @@ class JsonArray : public Internals::JsonPrintable, // Imports a 2D array template - bool copyFrom(T(&array)[N1][N2]) { + bool copyFrom(T (&array)[N1][N2]) { bool ok = true; for (size_t i = 0; i < N1; i++) { JsonArray &nestedArray = createNestedArray(); @@ -201,7 +180,7 @@ class JsonArray : public Internals::JsonPrintable, // Exports a 1D array template - size_t copyTo(T(&array)[N]) const { + size_t copyTo(T (&array)[N]) const { return copyTo(array, N); } @@ -216,7 +195,7 @@ class JsonArray : public Internals::JsonPrintable, // Exports a 2D array template - void copyTo(T(&array)[N1][N2]) const { + void copyTo(T (&array)[N1][N2]) const { size_t i = 0; for (const_iterator it = begin(); it != end() && i < N1; ++it) { it->asArray().copyTo(array[i++]); @@ -230,22 +209,22 @@ class JsonArray : public Internals::JsonPrintable, return node; } - template - bool setNodeAt(size_t index, TValue value) { + template + bool setNodeAt(size_t index, TValueRef value) { node_type *node = getNodeAt(index); - return node != NULL && setNodeValue(node, value); + if (!node) return false; + + return Internals::ValueSetter::set(_buffer, node->content, + value); } - template - bool addNode(TValue value) { + template + bool addNodeImpl(TValueRef value) { node_type *node = addNewNode(); - return node != NULL && setNodeValue(node, value); - } + if (!node) return false; - template - bool setNodeValue(node_type *node, T value) { - node->content = value; - return true; + return Internals::ValueSetter::set(_buffer, node->content, + value); } }; } diff --git a/include/ArduinoJson/JsonArray.ipp b/include/ArduinoJson/JsonArray.ipp index 4058c91c..9d44a885 100644 --- a/include/ArduinoJson/JsonArray.ipp +++ b/include/ArduinoJson/JsonArray.ipp @@ -13,50 +13,31 @@ namespace ArduinoJson { -inline JsonVariant::JsonVariant(JsonArray &array) { +inline JsonVariant::JsonVariant(const JsonArray &array) { if (array.success()) { _type = Internals::JSON_ARRAY; - _content.asArray = &array; + _content.asArray = const_cast(&array); } else { _type = Internals::JSON_UNDEFINED; } } -inline JsonVariant::JsonVariant(JsonObject &object) { +inline JsonVariant::JsonVariant(const JsonObject &object) { if (object.success()) { _type = Internals::JSON_OBJECT; - _content.asObject = &object; + _content.asObject = const_cast(&object); } else { _type = Internals::JSON_UNDEFINED; } } +namespace Internals { template <> -inline bool JsonArray::setNodeValue(node_type *node, String &value) { - const char *copy = _buffer->strdup(value); - if (!copy) return false; - node->content = copy; - return true; -} - -template <> -inline JsonArray &JsonVariant::defaultValue() { - return JsonArray::invalid(); -} - -template <> -inline JsonArray &JsonVariant::defaultValue() { - return JsonArray::invalid(); -} - -template <> -inline const JsonArray &JsonVariant::defaultValue() { - return JsonArray::invalid(); -} - -template <> -inline const JsonArray &JsonVariant::defaultValue() { - return JsonArray::invalid(); +struct JsonVariantDefault { + static JsonArray &get() { + return JsonArray::invalid(); + } +}; } inline JsonArray &JsonVariant::asArray() const { @@ -71,10 +52,11 @@ inline JsonArray &JsonArray::createNestedArray() { return array; } -inline JsonArray &JsonObject::createNestedArray(JsonObjectKey key) { +template +inline JsonArray &JsonObject::createNestedArray(const TString &key) { if (!_buffer) return JsonArray::invalid(); JsonArray &array = _buffer->createArray(); - setNodeAt(key, array); + set(key, array); return array; } } diff --git a/include/ArduinoJson/JsonArraySubscript.hpp b/include/ArduinoJson/JsonArraySubscript.hpp index 3151ec6a..eea1b80b 100644 --- a/include/ArduinoJson/JsonArraySubscript.hpp +++ b/include/ArduinoJson/JsonArraySubscript.hpp @@ -21,24 +21,14 @@ class JsonArraySubscript : public JsonVariantBase { FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index) : _array(array), _index(index) {} - JsonArraySubscript& operator=(const JsonArraySubscript& src) { - _array.set(_index, src); + FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) { + _array.set(_index, src); return *this; } template - typename TypeTraits::EnableIf::value, - JsonArraySubscript>::type& - operator=(const T& src) { - _array.set(_index, const_cast(src)); - return *this; - } - - template - typename TypeTraits::EnableIf::value, - JsonArraySubscript>::type& - operator=(T src) { - _array.set(_index, src); + FORCE_INLINE JsonArraySubscript& operator=(const T& src) { + _array.set(_index, src); return *this; } @@ -46,10 +36,6 @@ class JsonArraySubscript : public JsonVariantBase { return _index < _array.size(); } - FORCE_INLINE operator JsonVariant() const { - return _array.get(_index); - } - template FORCE_INLINE typename Internals::JsonVariantAs::type as() const { return _array.get(_index); @@ -61,7 +47,7 @@ class JsonArraySubscript : public JsonVariantBase { } template - void set(TValue value) { + FORCE_INLINE void set(const TValue& value) { _array.set(_index, value); } diff --git a/include/ArduinoJson/JsonBuffer.hpp b/include/ArduinoJson/JsonBuffer.hpp index f05449dd..220a805c 100644 --- a/include/ArduinoJson/JsonBuffer.hpp +++ b/include/ArduinoJson/JsonBuffer.hpp @@ -12,7 +12,6 @@ #include #include "JsonVariant.hpp" -#include "String.hpp" #if defined(__clang__) #pragma clang diagnostic push @@ -58,67 +57,56 @@ class JsonBuffer { // writable // because the parser will insert null-terminators and replace escaped chars. // - // The second argument set the nesting limit (see comment on DEFAULT_LIMIT) + // The second argument set the nesting limit // // Returns a reference to the new JsonObject or JsonObject::invalid() if the // allocation fails. - JsonArray &parseArray(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); + JsonArray &parseArray( + char *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT); - // Same with a const char*. // With this overload, the JsonBuffer will make a copy of the string - JsonArray &parseArray(const char *json, uint8_t nesting = DEFAULT_LIMIT) { + template + JsonArray &parseArray(const TString &json, + uint8_t nesting = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { return parseArray(strdup(json), nesting); } - // Same as above with a String class - JsonArray &parseArray(const String &json, uint8_t nesting = DEFAULT_LIMIT) { - return parseArray(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 // writable // because the parser will insert null-terminators and replace escaped chars. // - // The second argument set the nesting limit (see comment on DEFAULT_LIMIT) + // The second argument set the nesting limit // // Returns a reference to the new JsonObject or JsonObject::invalid() if the // allocation fails. - JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); + JsonObject &parseObject( + char *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT); - // Same with a const char*. // With this overload, the JsonBuffer will make a copy of the string - JsonObject &parseObject(const char *json, uint8_t nesting = DEFAULT_LIMIT) { + template + JsonObject &parseObject(const TString &json, + uint8_t nesting = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { return parseObject(strdup(json), nesting); } - // Same as above with a String class - JsonObject &parseObject(const String &json, uint8_t nesting = DEFAULT_LIMIT) { - return parseObject(json.c_str(), nesting); - } - // Generalized version of parseArray() and parseObject(), also works for // integral types. - JsonVariant parse(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); + JsonVariant parse(char *json, + uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT); - // Same with a const char*. // With this overload, the JsonBuffer will make a copy of the string - JsonVariant parse(const char *json, uint8_t nesting = DEFAULT_LIMIT) { + template + JsonVariant parse(const TString &json, + uint8_t nesting = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { return parse(strdup(json), nesting); } - // Same as above with a String class - JsonVariant parse(const String &json, uint8_t nesting = DEFAULT_LIMIT) { - return parse(json.c_str(), nesting); - } - // Duplicate a string - char *strdup(const char *src) { - return src ? strdup(src, strlen(src)) : NULL; - } - char *strdup(const String &src) { - return strdup(src.c_str(), src.length()); + template + char *strdup(const TString &src) { + return Internals::StringFuncs::duplicate(src, this); } // Allocates n bytes in the JsonBuffer. @@ -135,23 +123,6 @@ class JsonBuffer { return bytes; #endif } - - private: - char *strdup(const char *, size_t); - - // Default value of nesting limit of parseArray() and parseObject(). - // - // The nesting limit is a constrain on the level of nesting allowed in the - // JSON string. - // If set to 0, only a flat array or objects can be parsed. - // If set to 1, the object can contain nested arrays or objects but only 1 - // level deep. - // And bigger values will allow more level of nesting. - // - // The purpose of this feature is to prevent stack overflow that could - // lead to - // a security risk. - static const uint8_t DEFAULT_LIMIT = ARDUINOJSON_DEFAULT_NESTING_LIMIT; }; } diff --git a/include/ArduinoJson/JsonBuffer.ipp b/include/ArduinoJson/JsonBuffer.ipp index 5f8294af..6b86f27c 100644 --- a/include/ArduinoJson/JsonBuffer.ipp +++ b/include/ArduinoJson/JsonBuffer.ipp @@ -36,11 +36,3 @@ inline ArduinoJson::JsonVariant ArduinoJson::JsonBuffer::parse( Internals::JsonParser parser(this, json, nestingLimit); return parser.parseVariant(); } - -inline char *ArduinoJson::JsonBuffer::strdup(const char *source, - size_t length) { - size_t size = length + 1; - char *dest = static_cast(alloc(size)); - if (dest != NULL) memcpy(dest, source, size); - return dest; -} diff --git a/include/ArduinoJson/JsonObject.hpp b/include/ArduinoJson/JsonObject.hpp index 6e098d22..d72aa14a 100644 --- a/include/ArduinoJson/JsonObject.hpp +++ b/include/ArduinoJson/JsonObject.hpp @@ -7,15 +7,16 @@ #pragma once -#include "String.hpp" #include "Internals/JsonBufferAllocated.hpp" #include "Internals/JsonPrintable.hpp" #include "Internals/List.hpp" #include "Internals/ReferenceType.hpp" +#include "Internals/StringFuncs.hpp" +#include "Internals/ValueSetter.hpp" #include "JsonPair.hpp" +#include "TypeTraits/ConstRefOrConstPtr.hpp" #include "TypeTraits/EnableIf.hpp" #include "TypeTraits/IsFloatingPoint.hpp" -#include "TypeTraits/IsReference.hpp" #include "TypeTraits/IsSame.hpp" // Returns the size (in bytes) of an object with n elements. @@ -40,27 +41,19 @@ class JsonObject : public Internals::JsonPrintable, public Internals::List, public Internals::JsonBufferAllocated { public: - // A meta-function that returns true if type T can be used in - // JsonObject::set() - template - struct CanSet { - static const bool value = JsonVariant::IsConstructibleFrom::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value; - }; - // Create an empty JsonArray attached to the specified JsonBuffer. // You should not use this constructor directly. // Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject(). explicit JsonObject(JsonBuffer* buffer) : Internals::List(buffer) {} // Gets or sets the value associated with the specified key. - JsonObjectSubscript operator[](const char* key); - JsonObjectSubscript operator[](const String& key); + template + JsonObjectSubscript operator[](const TString& key); // Gets the value associated with the specified key. - JsonVariant operator[](JsonObjectKey key) const { - return get(key); + template + JsonVariant operator[](const TString& key) const { + return get(key); } // Sets the specified key with the specified value. @@ -73,67 +66,62 @@ class JsonObject : public Internals::JsonPrintable, // bool set(TKey key, double value); // bool set(TKey key, const char* value); // bool set(TKey key, RawJson value); - template - bool set( - JsonObjectKey key, T value, - typename TypeTraits::EnableIf< - CanSet::value && !TypeTraits::IsReference::value>::type* = 0) { - return setNodeAt(key, value); - } // bool set(Key, String&); // bool set(Key, JsonArray&); // bool set(Key, JsonObject&); // bool set(Key, JsonVariant&); - template - bool set(JsonObjectKey key, const T& value, - typename TypeTraits::EnableIf::value>::type* = 0) { - return setNodeAt(key, const_cast(value)); + template + bool set(const TString& key, const TValue& value) { + // reduce the number of template function instanciation to reduce code size + return setNodeAt::type, + typename TypeTraits::ConstRefOrConstPtr::type>( + key, value); } // bool set(Key, float value, uint8_t decimals); // bool set(Key, double value, uint8_t decimals); - template - bool set(JsonObjectKey key, TValue value, uint8_t decimals, - typename TypeTraits::EnableIf< - TypeTraits::IsFloatingPoint::value>::type* = 0) { - return setNodeAt(key, JsonVariant(value, decimals)); + template + typename TypeTraits::EnableIf::value, + bool>::type + set(const TString& key, TValue value, uint8_t decimals) { + return set(key, JsonVariant(value, decimals)); } // Gets the value associated with the specified key. - JsonVariant get(JsonObjectKey key) const { - node_type* node = getNodeAt(key.c_str()); - return node ? node->content.value : JsonVariant(); - } - - // Gets the value associated with the specified key. - template - typename Internals::JsonVariantAs::type get(JsonObjectKey key) const { - node_type* node = getNodeAt(key.c_str()); - return node ? node->content.value.as() : JsonVariant::defaultValue(); + template + typename Internals::JsonVariantAs::type get( + const TString& key) const { + node_type* node = getNodeAt(key); + return node ? node->content.value.as() + : Internals::JsonVariantDefault::get(); } // Checks the type of the value associated with the specified key. - template - bool is(JsonObjectKey key) const { - node_type* node = getNodeAt(key.c_str()); - return node ? node->content.value.is() : false; + template + bool is(const TString& key) const { + node_type* node = getNodeAt(key); + return node ? node->content.value.is() : false; } // Creates and adds a JsonArray. // This is a shortcut for JsonBuffer::createArray() and JsonObject::add(). - JsonArray& createNestedArray(JsonObjectKey key); + template + JsonArray& createNestedArray(const TString& key); // Creates and adds a JsonObject. // This is a shortcut for JsonBuffer::createObject() and JsonObject::add(). - JsonObject& createNestedObject(JsonObjectKey key); + template + JsonObject& createNestedObject(const TString& key); // Tells weither the specified key is present and associated with a value. - bool containsKey(JsonObjectKey key) const { - return getNodeAt(key.c_str()) != NULL; + template + bool containsKey(const TString& key) const { + return getNodeAt(key) != NULL; } // Removes the specified key and the associated value. - void remove(JsonObjectKey key) { - removeNode(getNodeAt(key.c_str())); + template + void remove(const TString& key) { + removeNode(getNodeAt(key)); } // Returns a reference an invalid JsonObject. @@ -146,37 +134,35 @@ class JsonObject : public Internals::JsonPrintable, private: // Returns the list node that matches the specified key. - node_type* getNodeAt(const char* key) const { + template + node_type* getNodeAt(const TString& key) const { + // reduce the number of template function instanciation to reduce code size + return getNodeAtImpl< + typename TypeTraits::ConstRefOrConstPtr::type>(key); + } + + template + node_type* getNodeAtImpl(TStringRef key) const { for (node_type* node = _firstNode; node; node = node->next) { - if (!strcmp(node->content.key, key)) return node; + if (Internals::StringFuncs::equals(key, node->content.key)) + return node; } return NULL; } - template - bool setNodeAt(JsonObjectKey key, T value) { - node_type* node = getNodeAt(key.c_str()); + template + bool setNodeAt(TStringRef key, TValueRef value) { + node_type* node = getNodeAtImpl(key); if (!node) { node = addNewNode(); - if (!node || !setNodeKey(node, key)) return false; - } - return setNodeValue(node, value); - } + if (!node) return false; - bool setNodeKey(node_type* node, JsonObjectKey key) { - if (key.needs_copy()) { - node->content.key = _buffer->strdup(key.c_str()); - if (node->content.key == NULL) return false; - } else { - node->content.key = key.c_str(); + bool key_ok = Internals::ValueSetter::set( + _buffer, node->content.key, key); + if (!key_ok) return false; } - return true; - } - - template - bool setNodeValue(node_type* node, T value) { - node->content.value = value; - return true; + return Internals::ValueSetter::set(_buffer, node->content.value, + value); } }; } diff --git a/include/ArduinoJson/JsonObject.ipp b/include/ArduinoJson/JsonObject.ipp index 4a86c061..25f85101 100644 --- a/include/ArduinoJson/JsonObject.ipp +++ b/include/ArduinoJson/JsonObject.ipp @@ -13,38 +13,13 @@ namespace ArduinoJson { +namespace Internals { template <> -inline bool JsonObject::setNodeValue(node_type *node, String &value) { - const char *dup = _buffer->strdup(value); - node->content.value = dup; - return dup != NULL; -} - -template <> -inline bool JsonObject::setNodeValue(node_type *node, const String &value) { - const char *dup = _buffer->strdup(value); - node->content.value = dup; - return dup != NULL; -} - -template <> -inline const JsonObject &JsonVariant::defaultValue() { - return JsonObject::invalid(); -} - -template <> -inline const JsonObject &JsonVariant::defaultValue() { - return JsonObject::invalid(); -} - -template <> -inline JsonObject &JsonVariant::defaultValue() { - return JsonObject::invalid(); -} - -template <> -inline JsonObject &JsonVariant::defaultValue() { - return JsonObject::invalid(); +struct JsonVariantDefault { + static JsonObject &get() { + return JsonObject::invalid(); + } +}; } inline JsonObject &JsonVariant::asObject() const { @@ -52,11 +27,12 @@ inline JsonObject &JsonVariant::asObject() const { return JsonObject::invalid(); } -inline JsonObject &JsonObject::createNestedObject(JsonObjectKey key) { +template +inline JsonObject &JsonObject::createNestedObject(const TString &key) { if (!_buffer) return JsonObject::invalid(); - JsonObject &array = _buffer->createObject(); - setNodeAt(key, array); - return array; + JsonObject &object = _buffer->createObject(); + set(key, object); + return object; } inline JsonObject &JsonArray::createNestedObject() { diff --git a/include/ArduinoJson/JsonObjectKey.hpp b/include/ArduinoJson/JsonObjectKey.hpp deleted file mode 100644 index 982a989f..00000000 --- a/include/ArduinoJson/JsonObjectKey.hpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright Benoit Blanchon 2014-2016 -// MIT License -// -// Arduino JSON library -// https://github.com/bblanchon/ArduinoJson -// If you like this project, please add a star! - -#pragma once - -#include "String.hpp" - -namespace ArduinoJson { - -// Represents a key in a JsonObject -class JsonObjectKey { - public: - JsonObjectKey(const char* key) : _value(key), _needs_copy(false) {} - JsonObjectKey(const String& key) : _value(key.c_str()), _needs_copy(true) {} - - const char* c_str() const { return _value; } - bool needs_copy() const { return _needs_copy; } - - private: - const char* _value; - bool _needs_copy; -}; -} diff --git a/include/ArduinoJson/JsonObjectSubscript.hpp b/include/ArduinoJson/JsonObjectSubscript.hpp index 37827759..b56a2212 100644 --- a/include/ArduinoJson/JsonObjectSubscript.hpp +++ b/include/ArduinoJson/JsonObjectSubscript.hpp @@ -9,6 +9,7 @@ #include "Configuration.hpp" #include "JsonVariantBase.hpp" +#include "TypeTraits/ConstRefOrConstPtr.hpp" #include "TypeTraits/EnableIf.hpp" #ifdef _MSC_VER @@ -18,30 +19,27 @@ namespace ArduinoJson { -template -class JsonObjectSubscript : public JsonVariantBase > { +template +class JsonObjectSubscript + : public JsonVariantBase > { + // const String& + // const std::string& + // const char* + typedef typename TypeTraits::ConstRefOrConstPtr::type TStringRef; + public: - FORCE_INLINE JsonObjectSubscript(JsonObject& object, TKey key) + FORCE_INLINE JsonObjectSubscript(JsonObject& object, TStringRef key) : _object(object), _key(key) {} - JsonObjectSubscript& operator=(const JsonObjectSubscript& src) { - _object.set(_key, src); + FORCE_INLINE JsonObjectSubscript& operator=( + const JsonObjectSubscript& src) { + _object.set(_key, src); return *this; } template - typename TypeTraits::EnableIf::value, - JsonObjectSubscript >::type& - operator=(const T& src) { - _object.set(_key, const_cast(src)); - return *this; - } - - template - typename TypeTraits::EnableIf::value, - JsonObjectSubscript >::type& - operator=(T src) { - _object.set(_key, src); + FORCE_INLINE JsonObjectSubscript& operator=(const T& src) { + _object.set(_key, src); return *this; } @@ -49,13 +47,9 @@ class JsonObjectSubscript : public JsonVariantBase > { return _object.containsKey(_key); } - FORCE_INLINE operator JsonVariant() const { - return _object.get(_key); - } - template FORCE_INLINE typename Internals::JsonVariantAs::type as() const { - return _object.get(_key); + return _object.get(_key); } template @@ -64,58 +58,39 @@ class JsonObjectSubscript : public JsonVariantBase > { } template - FORCE_INLINE bool set(TValue value) { - return _object.set(_key, value); + FORCE_INLINE bool set(const TValue& value) { + return _object.set(_key, value); } template - FORCE_INLINE bool set(TValue value, uint8_t decimals) { + FORCE_INLINE bool set(const TValue& value, uint8_t decimals) { return _object.set(_key, value, decimals); } - FORCE_INLINE JsonVariant get() { - return _object.get(_key); - } - private: JsonObject& _object; - TKey _key; + TStringRef _key; }; #if ARDUINOJSON_ENABLE_STD_STREAM -inline std::ostream& operator<<( - std::ostream& os, const JsonObjectSubscript& source) { - return source.printTo(os); -} - -inline std::ostream& operator<<( - std::ostream& os, const JsonObjectSubscript& source) { +template +inline std::ostream& operator<<(std::ostream& os, + const JsonObjectSubscript& source) { return source.printTo(os); } #endif -inline JsonObjectSubscript JsonObject::operator[]( - const char* key) { - return JsonObjectSubscript(*this, key); -} - -inline JsonObjectSubscript JsonObject::operator[]( - const String& key) { - return JsonObjectSubscript(*this, key); +template +inline JsonObjectSubscript JsonObject::operator[](const TString& key) { + return JsonObjectSubscript(*this, key); } template -inline const JsonObjectSubscript JsonVariantBase:: -operator[](const char* key) const { +template +inline const JsonObjectSubscript JsonVariantBase::operator[]( + const TString& key) const { return asObject()[key]; } - -template -inline const JsonObjectSubscript JsonVariantBase:: -operator[](const String& key) const { - return asObject()[key]; -} - } // namespace ArduinoJson #ifdef _MSC_VER diff --git a/include/ArduinoJson/JsonPair.hpp b/include/ArduinoJson/JsonPair.hpp index 4a201721..faaeb905 100644 --- a/include/ArduinoJson/JsonPair.hpp +++ b/include/ArduinoJson/JsonPair.hpp @@ -7,7 +7,6 @@ #pragma once -#include "JsonObjectKey.hpp" #include "JsonVariant.hpp" namespace ArduinoJson { diff --git a/include/ArduinoJson/JsonVariant.hpp b/include/ArduinoJson/JsonVariant.hpp index 9627fdeb..735821b8 100644 --- a/include/ArduinoJson/JsonVariant.hpp +++ b/include/ArduinoJson/JsonVariant.hpp @@ -12,6 +12,7 @@ #include "Internals/JsonPrintable.hpp" #include "Internals/JsonVariantContent.hpp" +#include "Internals/JsonVariantDefault.hpp" #include "Internals/JsonVariantType.hpp" #include "JsonVariantBase.hpp" #include "RawJson.hpp" @@ -19,6 +20,8 @@ #include "TypeTraits/IsFloatingPoint.hpp" #include "TypeTraits/IsIntegral.hpp" #include "TypeTraits/IsSame.hpp" +#include "TypeTraits/IsSignedIntegral.hpp" +#include "TypeTraits/IsUnsignedIntegral.hpp" #include "TypeTraits/RemoveConst.hpp" #include "TypeTraits/RemoveReference.hpp" @@ -40,9 +43,6 @@ class JsonVariant : public JsonVariantBase { JsonWriter &); public: - template - struct IsConstructibleFrom; - // Creates an uninitialized JsonVariant JsonVariant() : _type(Internals::JSON_UNDEFINED) {} @@ -110,10 +110,14 @@ class JsonVariant : public JsonVariantBase { } // Create a JsonVariant containing a reference to an array. - JsonVariant(JsonArray &array); + // CAUTION: we are lying about constness, because the array can be modified if + // the variant is converted back to a JsonArray& + JsonVariant(const JsonArray &array); // Create a JsonVariant containing a reference to an object. - JsonVariant(JsonObject &object); + // CAUTION: we are lying about constness, because the object can be modified + // if the variant is converted back to a JsonObject& + JsonVariant(const JsonObject &object); // Get the variant as the specified type. // @@ -146,14 +150,6 @@ class JsonVariant : public JsonVariantBase { return static_cast(asFloat()); } // - // const String as() const; - template - const typename TypeTraits::EnableIf::value, - T>::type - as() const { - return toString(); - } - // // const char* as() const; // const char* as() const; template @@ -164,6 +160,18 @@ class JsonVariant : public JsonVariantBase { return asString(); } // + // std::string as() const; + // String as() const; + template + typename TypeTraits::EnableIf::has_append, T>::type + as() const { + const char *cstr = asString(); + if (cstr) return T(cstr); + T s; + printTo(s); + return s; + } + // // const bool as() const template const typename TypeTraits::EnableIf::value, @@ -230,7 +238,8 @@ class JsonVariant : public JsonVariantBase { // int as() const; // long as() const; template - const typename TypeTraits::EnableIf::value, + const typename TypeTraits::EnableIf::value && + !TypeTraits::IsSame::value, bool>::type is() const { return isInteger(); @@ -296,12 +305,6 @@ class JsonVariant : public JsonVariantBase { return _type != Internals::JSON_UNDEFINED; } - // Value returned if the variant has an incompatible type - template - static typename Internals::JsonVariantAs::type defaultValue() { - return T(); - } - // DEPRECATED: use as() instead const char *asString() const; @@ -317,7 +320,6 @@ class JsonVariant : public JsonVariantBase { JsonVariant(T value, typename TypeTraits::EnableIf< TypeTraits::IsSame::value>::type * = 0); - String toString() const; Internals::JsonFloat asFloat() const; Internals::JsonInteger asInteger() const; Internals::JsonUInt asUnsignedInteger() const; @@ -350,27 +352,4 @@ inline JsonVariant float_with_n_digits(float value, uint8_t digits) { inline JsonVariant double_with_n_digits(double value, uint8_t digits) { return JsonVariant(value, digits); } - -template -struct JsonVariant::IsConstructibleFrom { - static const bool value = - TypeTraits::IsIntegral::value || - TypeTraits::IsFloatingPoint::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame &>::value || - TypeTraits::IsSame &>::value || - TypeTraits::IsSame &>::value || - TypeTraits::IsSame &>::value || - TypeTraits::IsSame::value || - TypeTraits::IsSame::value; -}; } diff --git a/include/ArduinoJson/JsonVariant.ipp b/include/ArduinoJson/JsonVariant.ipp index a9446ac1..01291f9b 100644 --- a/include/ArduinoJson/JsonVariant.ipp +++ b/include/ArduinoJson/JsonVariant.ipp @@ -8,14 +8,14 @@ #pragma once #include "Configuration.hpp" -#include "JsonVariant.hpp" #include "Internals/Parse.hpp" #include "JsonArray.hpp" #include "JsonObject.hpp" +#include "JsonVariant.hpp" -#include // for strcmp #include // for errno #include // for strtol, strtod +#include // for strcmp namespace ArduinoJson { @@ -85,17 +85,6 @@ inline Internals::JsonFloat JsonVariant::asFloat() const { } } -inline String JsonVariant::toString() const { - using namespace Internals; - String s; - if ((_type == JSON_STRING || _type == JSON_UNPARSED) && - _content.asString != NULL) - s = _content.asString; - else - printTo(s); - return s; -} - inline bool JsonVariant::isBoolean() const { using namespace Internals; if (_type == JSON_BOOLEAN) return true; diff --git a/include/ArduinoJson/JsonVariantBase.hpp b/include/ArduinoJson/JsonVariantBase.hpp index e1e6e536..11c678d7 100644 --- a/include/ArduinoJson/JsonVariantBase.hpp +++ b/include/ArduinoJson/JsonVariantBase.hpp @@ -8,7 +8,6 @@ #pragma once #include "Internals/JsonVariantAs.hpp" -#include "JsonObjectKey.hpp" #include "Polyfills/attributes.hpp" namespace ArduinoJson { @@ -77,10 +76,9 @@ class JsonVariantBase : public Internals::JsonPrintable { // Returns the value associated with the specified key if the variant is // an object. // Return JsonVariant::invalid() if the variant is not an object. - FORCE_INLINE const JsonObjectSubscript operator[]( - const char *key) const; - FORCE_INLINE const JsonObjectSubscript operator[]( - const String &key) const; + template + FORCE_INLINE const JsonObjectSubscript operator[]( + const TString &key) const; private: const TImpl *impl() const { diff --git a/include/ArduinoJson/RawJson.hpp b/include/ArduinoJson/RawJson.hpp index 40eae2ce..1141e8a1 100644 --- a/include/ArduinoJson/RawJson.hpp +++ b/include/ArduinoJson/RawJson.hpp @@ -13,7 +13,9 @@ namespace ArduinoJson { class RawJson { public: explicit RawJson(const char* str) : _str(str) {} - operator const char*() const { return _str; } + operator const char*() const { + return _str; + } private: const char* _str; diff --git a/include/ArduinoJson/String.hpp b/include/ArduinoJson/String.hpp deleted file mode 100644 index 92580052..00000000 --- a/include/ArduinoJson/String.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright Benoit Blanchon 2014-2016 -// MIT License -// -// Arduino JSON library -// https://github.com/bblanchon/ArduinoJson -// If you like this project, please add a star! - -#pragma once - -#include "Configuration.hpp" - -#if ARDUINOJSON_USE_ARDUINO_STRING - -#include - -#else - -#include - -namespace ArduinoJson { -typedef std::string String; -} - -#endif diff --git a/include/ArduinoJson/TypeTraits/ConstRefOrConstPtr.hpp b/include/ArduinoJson/TypeTraits/ConstRefOrConstPtr.hpp new file mode 100644 index 00000000..cdfd7fc2 --- /dev/null +++ b/include/ArduinoJson/TypeTraits/ConstRefOrConstPtr.hpp @@ -0,0 +1,31 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that return the type T without the const modifier +template +struct ConstRefOrConstPtr { + typedef const T& type; +}; +template +struct ConstRefOrConstPtr { + typedef const T* type; +}; +template +struct ConstRefOrConstPtr { + typedef const T* type; +}; +template +struct ConstRefOrConstPtr { + typedef const T* type; +}; +} +} diff --git a/include/ArduinoJson/TypeTraits/IsIntegral.hpp b/include/ArduinoJson/TypeTraits/IsIntegral.hpp index 9bad95cd..7849dcff 100644 --- a/include/ArduinoJson/TypeTraits/IsIntegral.hpp +++ b/include/ArduinoJson/TypeTraits/IsIntegral.hpp @@ -7,7 +7,6 @@ #pragma once -#include "../Configuration.hpp" #include "IsSame.hpp" #include "IsSignedIntegral.hpp" #include "IsUnsignedIntegral.hpp" @@ -20,7 +19,11 @@ template struct IsIntegral { static const bool value = TypeTraits::IsSignedIntegral::value || TypeTraits::IsUnsignedIntegral::value || - TypeTraits::IsSame::value; + TypeTraits::IsSame::value || + TypeTraits::IsSame::value; }; + +template +struct IsIntegral : IsIntegral {}; } } diff --git a/test/DynamicJsonBuffer_Basic_Tests.cpp b/test/DynamicJsonBuffer_Basic_Tests.cpp index db52d886..31d94f8f 100644 --- a/test/DynamicJsonBuffer_Basic_Tests.cpp +++ b/test/DynamicJsonBuffer_Basic_Tests.cpp @@ -5,8 +5,8 @@ // https://github.com/bblanchon/ArduinoJson // If you like this project, please add a star! -#include #include +#include class DynamicJsonBuffer_Basic_Tests : public testing::Test { protected: @@ -38,3 +38,16 @@ TEST_F(DynamicJsonBuffer_Basic_Tests, Alignment) { ASSERT_EQ(0, addr & mask); } } + +TEST_F(DynamicJsonBuffer_Basic_Tests, strdup) { + char original[] = "hello"; + char* copy = buffer.strdup(original); + strcpy(original, "world"); + ASSERT_STREQ("hello", copy); +} + +TEST_F(DynamicJsonBuffer_Basic_Tests, strdup_givenNull) { + const char* original = NULL; + char* copy = buffer.strdup(original); + ASSERT_EQ(NULL, copy); +} diff --git a/test/JsonObject_Get_Tests.cpp b/test/JsonObject_Get_Tests.cpp new file mode 100644 index 00000000..dfd9d08c --- /dev/null +++ b/test/JsonObject_Get_Tests.cpp @@ -0,0 +1,26 @@ +// Copyright Benoit Blanchon 2014-2016 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include +#include + +class JsonObject_Get_Tests : public ::testing::Test { + public: + JsonObject_Get_Tests() : _object(_jsonBuffer.createObject()) {} + + protected: + DynamicJsonBuffer _jsonBuffer; + JsonObject& _object; +}; + +#define TEST_(name) TEST_F(JsonObject_Get_Tests, name) + +TEST_(GetConstCharPointer_GivenStringLiteral) { + _object.set("hello", "world"); + const char* value = _object.get("hello"); + EXPECT_STREQ("world", value); +} diff --git a/test/JsonObject_Invalid_Tests.cpp b/test/JsonObject_Invalid_Tests.cpp index 96c129b2..3964d216 100644 --- a/test/JsonObject_Invalid_Tests.cpp +++ b/test/JsonObject_Invalid_Tests.cpp @@ -5,11 +5,11 @@ // https://github.com/bblanchon/ArduinoJson // If you like this project, please add a star! -#include #include +#include TEST(JsonObject_Invalid_Tests, SubscriptFails) { - ASSERT_FALSE(JsonObject::invalid()[0].success()); + ASSERT_FALSE(JsonObject::invalid()["key"].success()); } TEST(JsonObject_Invalid_Tests, AddFails) { diff --git a/test/JsonObject_Set_Tests.cpp b/test/JsonObject_Set_Tests.cpp index cc49b0e1..29bb9996 100644 --- a/test/JsonObject_Set_Tests.cpp +++ b/test/JsonObject_Set_Tests.cpp @@ -5,8 +5,8 @@ // https://github.com/bblanchon/ArduinoJson // If you like this project, please add a star! -#include #include +#include class JsonObject_Set_Tests : public ::testing::Test { public: @@ -112,7 +112,7 @@ TEST_(ShouldReturnTrue_WhenAllocationSucceeds) { StaticJsonBuffer jsonBuffer; JsonObject& obj = jsonBuffer.createObject(); - bool result = obj.set(String("hello"), String("world")); + bool result = obj.set(std::string("hello"), std::string("world")); ASSERT_TRUE(result); } @@ -121,7 +121,7 @@ TEST_(ShouldReturnFalse_WhenAllocationFails) { StaticJsonBuffer jsonBuffer; JsonObject& obj = jsonBuffer.createObject(); - bool result = obj.set(String("hello"), String("world")); + bool result = obj.set(std::string("hello"), std::string("world")); ASSERT_FALSE(result); } diff --git a/test/JsonVariant_As_Tests.cpp b/test/JsonVariant_As_Tests.cpp index 06582e05..144f2b09 100644 --- a/test/JsonVariant_As_Tests.cpp +++ b/test/JsonVariant_As_Tests.cpp @@ -24,7 +24,7 @@ TEST(JsonVariant_As_Tests, DoubleAsCstr) { TEST(JsonVariant_As_Tests, DoubleAsString) { JsonVariant variant = 4.2; - ASSERT_EQ(String("4.20"), variant.as()); + ASSERT_EQ(std::string("4.20"), variant.as()); } TEST(JsonVariant_As_Tests, DoubleAsLong) { @@ -64,7 +64,7 @@ TEST(JsonVariant_As_Tests, FalseAsLong) { TEST(JsonVariant_As_Tests, FalseAsString) { JsonVariant variant = false; - ASSERT_EQ(String("false"), variant.as()); + ASSERT_EQ(std::string("false"), variant.as()); } TEST(JsonVariant_As_Tests, TrueAsBool) { @@ -84,7 +84,7 @@ TEST(JsonVariant_As_Tests, TrueAsLong) { TEST(JsonVariant_As_Tests, TrueAsString) { JsonVariant variant = true; - ASSERT_EQ(String("true"), variant.as()); + ASSERT_EQ(std::string("true"), variant.as()); } TEST(JsonVariant_As_Tests, LongAsBool) { @@ -109,7 +109,7 @@ TEST(JsonVariant_As_Tests, NegativeLongAsDouble) { TEST(JsonVariant_As_Tests, LongAsString) { JsonVariant variant = 42L; - ASSERT_EQ(String("42"), variant.as()); + ASSERT_EQ(std::string("42"), variant.as()); } TEST(JsonVariant_As_Tests, LongZeroAsDouble) { @@ -134,7 +134,7 @@ TEST(JsonVariant_As_Tests, NullAsLong) { TEST(JsonVariant_As_Tests, NullAsString) { JsonVariant variant = null; - ASSERT_EQ(String("null"), variant.as()); + ASSERT_EQ(std::string("null"), variant.as()); } TEST(JsonVariant_As_Tests, NumberStringAsBool) { @@ -181,7 +181,7 @@ TEST(JsonVariant_As_Tests, RandomStringAsCharPtr) { TEST(JsonVariant_As_Tests, RandomStringAsString) { JsonVariant variant = "hello"; - ASSERT_EQ(String("hello"), variant.as()); + ASSERT_EQ(std::string("hello"), variant.as()); } TEST(JsonVariant_As_Tests, TrueStringAsBool) { @@ -201,7 +201,7 @@ TEST(JsonVariant_As_Tests, ObjectAsString) { obj["key"] = "value"; JsonVariant variant = obj; - ASSERT_EQ(String("{\"key\":\"value\"}"), variant.as()); + ASSERT_EQ(std::string("{\"key\":\"value\"}"), variant.as()); } TEST(JsonVariant_As_Tests, ArrayAsString) { @@ -212,7 +212,7 @@ TEST(JsonVariant_As_Tests, ArrayAsString) { arr.add(2); JsonVariant variant = arr; - ASSERT_EQ(String("[4,2]"), variant.as()); + ASSERT_EQ(std::string("[4,2]"), variant.as()); } TEST(JsonVariant_As_Tests, ArrayAsJsonArray) { diff --git a/test/ArduinoString_Tests.cpp b/test/String_Tests.cpp similarity index 60% rename from test/ArduinoString_Tests.cpp rename to test/String_Tests.cpp index 82da09e1..bd572853 100644 --- a/test/ArduinoString_Tests.cpp +++ b/test/String_Tests.cpp @@ -5,12 +5,12 @@ // https://github.com/bblanchon/ArduinoJson // If you like this project, please add a star! -#include #include +#include -class ArduinoStringTests : public ::testing::Test { +class StringTests : public ::testing::Test { protected: - static void eraseString(String &str) { + static void eraseString(std::string &str) { char *p = const_cast(str.c_str()); while (*p) *p++ = '*'; } @@ -18,100 +18,100 @@ class ArduinoStringTests : public ::testing::Test { DynamicJsonBuffer _jsonBuffer; }; -TEST_F(ArduinoStringTests, JsonBuffer_ParseArray) { - String json("[\"hello\"]"); +TEST_F(StringTests, JsonBuffer_ParseArray) { + std::string json("[\"hello\"]"); JsonArray &array = _jsonBuffer.parseArray(json); eraseString(json); ASSERT_TRUE(array.success()); ASSERT_STREQ("hello", array[0]); } -TEST_F(ArduinoStringTests, JsonBuffer_ParseObject) { - String json("{\"hello\":\"world\"}"); +TEST_F(StringTests, JsonBuffer_ParseObject) { + std::string json("{\"hello\":\"world\"}"); JsonObject &object = _jsonBuffer.parseObject(json); eraseString(json); ASSERT_TRUE(object.success()); ASSERT_STREQ("world", object["hello"]); } -TEST_F(ArduinoStringTests, JsonObject_Subscript) { +TEST_F(StringTests, JsonObject_Subscript) { char json[] = "{\"key\":\"value\"}"; JsonObject &object = _jsonBuffer.parseObject(json); - ASSERT_STREQ("value", object[String("key")]); + ASSERT_STREQ("value", object[std::string("key")]); } -TEST_F(ArduinoStringTests, JsonObject_ConstSubscript) { +TEST_F(StringTests, JsonObject_ConstSubscript) { char json[] = "{\"key\":\"value\"}"; const JsonObject &object = _jsonBuffer.parseObject(json); - ASSERT_STREQ("value", object[String("key")]); + ASSERT_STREQ("value", object[std::string("key")]); } -TEST_F(ArduinoStringTests, JsonObject_SetKey) { +TEST_F(StringTests, JsonObject_SetKey) { JsonObject &object = _jsonBuffer.createObject(); - String key("hello"); + std::string key("hello"); object.set(key, "world"); eraseString(key); ASSERT_STREQ("world", object["hello"]); } -TEST_F(ArduinoStringTests, JsonObject_SetValue) { +TEST_F(StringTests, JsonObject_SetValue) { JsonObject &object = _jsonBuffer.createObject(); - String value("world"); + std::string value("world"); object.set("hello", value); eraseString(value); ASSERT_STREQ("world", object["hello"]); } -TEST_F(ArduinoStringTests, JsonObject_SetKeyValue) { +TEST_F(StringTests, JsonObject_SetKeyValue) { JsonObject &object = _jsonBuffer.createObject(); - String key("hello"); - String value("world"); + std::string key("hello"); + std::string value("world"); object.set(key, value); eraseString(key); eraseString(value); ASSERT_STREQ("world", object["hello"]); } -TEST_F(ArduinoStringTests, JsonObject_SetToArraySubscript) { +TEST_F(StringTests, JsonObject_SetToArraySubscript) { JsonArray &arr = _jsonBuffer.createArray(); arr.add("world"); JsonObject &object = _jsonBuffer.createObject(); - object.set(String("hello"), arr[0]); + object.set(std::string("hello"), arr[0]); ASSERT_STREQ("world", object["hello"]); } -TEST_F(ArduinoStringTests, JsonObject_SetToObjectSubscript) { +TEST_F(StringTests, JsonObject_SetToObjectSubscript) { JsonObject &arr = _jsonBuffer.createObject(); arr.set("x", "world"); JsonObject &object = _jsonBuffer.createObject(); - object.set(String("hello"), arr["x"]); + object.set(std::string("hello"), arr["x"]); ASSERT_STREQ("world", object["hello"]); } -TEST_F(ArduinoStringTests, JsonObject_Get) { +TEST_F(StringTests, JsonObject_Get) { char json[] = "{\"key\":\"value\"}"; const JsonObject &object = _jsonBuffer.parseObject(json); - ASSERT_STREQ("value", object.get(String("key"))); + ASSERT_STREQ("value", object.get(std::string("key"))); } -TEST_F(ArduinoStringTests, JsonObject_GetT) { +TEST_F(StringTests, JsonObject_GetT) { char json[] = "{\"key\":\"value\"}"; const JsonObject &object = _jsonBuffer.parseObject(json); - ASSERT_STREQ("value", object.get(String("key"))); + ASSERT_STREQ("value", object.get(std::string("key"))); } -TEST_F(ArduinoStringTests, JsonObject_IsT) { +TEST_F(StringTests, JsonObject_IsT) { char json[] = "{\"key\":\"value\"}"; const JsonObject &object = _jsonBuffer.parseObject(json); - ASSERT_TRUE(object.is(String("key"))); + ASSERT_TRUE(object.is(std::string("key"))); } -TEST_F(ArduinoStringTests, JsonObject_CreateNestedObject) { - String key = "key"; +TEST_F(StringTests, JsonObject_CreateNestedObject) { + std::string key = "key"; char json[64]; JsonObject &object = _jsonBuffer.createObject(); object.createNestedObject(key); @@ -120,8 +120,8 @@ TEST_F(ArduinoStringTests, JsonObject_CreateNestedObject) { ASSERT_STREQ("{\"key\":{}}", json); } -TEST_F(ArduinoStringTests, JsonObject_CreateNestedArray) { - String key = "key"; +TEST_F(StringTests, JsonObject_CreateNestedArray) { + std::string key = "key"; char json[64]; JsonObject &object = _jsonBuffer.createObject(); object.createNestedArray(key); @@ -130,99 +130,99 @@ TEST_F(ArduinoStringTests, JsonObject_CreateNestedArray) { ASSERT_STREQ("{\"key\":[]}", json); } -TEST_F(ArduinoStringTests, JsonObject_ContainsKey) { +TEST_F(StringTests, JsonObject_ContainsKey) { char json[] = "{\"key\":\"value\"}"; const JsonObject &object = _jsonBuffer.parseObject(json); - ASSERT_TRUE(object.containsKey(String("key"))); + ASSERT_TRUE(object.containsKey(std::string("key"))); } -TEST_F(ArduinoStringTests, JsonObject_Remove) { +TEST_F(StringTests, JsonObject_Remove) { char json[] = "{\"key\":\"value\"}"; JsonObject &object = _jsonBuffer.parseObject(json); ASSERT_EQ(1, object.size()); - object.remove(String("key")); + object.remove(std::string("key")); ASSERT_EQ(0, object.size()); } -TEST_F(ArduinoStringTests, JsonObjectSubscript_SetKey) { +TEST_F(StringTests, JsonObjectSubscript_SetKey) { JsonObject &object = _jsonBuffer.createObject(); - String key("hello"); + std::string key("hello"); object[key] = "world"; eraseString(key); ASSERT_STREQ("world", object["hello"]); } -TEST_F(ArduinoStringTests, JsonObjectSubscript_SetValue) { +TEST_F(StringTests, JsonObjectSubscript_SetValue) { JsonObject &object = _jsonBuffer.createObject(); - String value("world"); + std::string value("world"); object["hello"] = value; eraseString(value); ASSERT_STREQ("world", object["hello"]); } -TEST_F(ArduinoStringTests, JsonArray_Add) { +TEST_F(StringTests, JsonArray_Add) { JsonArray &array = _jsonBuffer.createArray(); - String value("hello"); + std::string value("hello"); array.add(value); eraseString(value); ASSERT_STREQ("hello", array[0]); } -TEST_F(ArduinoStringTests, JsonArray_Set) { +TEST_F(StringTests, JsonArray_Set) { JsonArray &array = _jsonBuffer.createArray(); - String value("world"); + std::string value("world"); array.add("hello"); array.set(0, value); eraseString(value); ASSERT_STREQ("world", array[0]); } -TEST_F(ArduinoStringTests, JsonArraySubscript) { +TEST_F(StringTests, JsonArraySubscript) { JsonArray &array = _jsonBuffer.createArray(); - String value("world"); + std::string value("world"); array.add("hello"); array[0] = value; eraseString(value); ASSERT_STREQ("world", array[0]); } -TEST_F(ArduinoStringTests, JsonArray_PrintTo) { +TEST_F(StringTests, JsonArray_PrintTo) { JsonArray &array = _jsonBuffer.createArray(); array.add(4); array.add(2); - String json; + std::string json; array.printTo(json); - ASSERT_EQ(String("[4,2]"), json); + ASSERT_EQ(std::string("[4,2]"), json); } -TEST_F(ArduinoStringTests, JsonArray_PrettyPrintTo) { +TEST_F(StringTests, JsonArray_PrettyPrintTo) { JsonArray &array = _jsonBuffer.createArray(); array.add(4); array.add(2); - String json; + std::string json; array.prettyPrintTo(json); - ASSERT_EQ(String("[\r\n 4,\r\n 2\r\n]"), json); + ASSERT_EQ(std::string("[\r\n 4,\r\n 2\r\n]"), json); } -TEST_F(ArduinoStringTests, JsonObject_PrintTo) { +TEST_F(StringTests, JsonObject_PrintTo) { JsonObject &object = _jsonBuffer.createObject(); object["key"] = "value"; - String json; + std::string json; object.printTo(json); - ASSERT_EQ(String("{\"key\":\"value\"}"), json); + ASSERT_EQ(std::string("{\"key\":\"value\"}"), json); } -TEST_F(ArduinoStringTests, JsonObject_PrettyPrintTo) { +TEST_F(StringTests, JsonObject_PrettyPrintTo) { JsonObject &object = _jsonBuffer.createObject(); object["key"] = "value"; - String json; + std::string json; object.prettyPrintTo(json); - ASSERT_EQ(String("{\r\n \"key\": \"value\"\r\n}"), json); + ASSERT_EQ(std::string("{\r\n \"key\": \"value\"\r\n}"), json); } -TEST_F(ArduinoStringTests, JsonBuffer_GrowWhenAddingNewKey) { +TEST_F(StringTests, JsonBuffer_GrowWhenAddingNewKey) { JsonObject &object = _jsonBuffer.createObject(); - String key1("hello"), key2("world"); + std::string key1("hello"), key2("world"); object[key1] = 1; size_t sizeBefore = _jsonBuffer.size(); @@ -232,9 +232,9 @@ TEST_F(ArduinoStringTests, JsonBuffer_GrowWhenAddingNewKey) { ASSERT_GT(sizeAfter - sizeBefore, key2.size()); } -TEST_F(ArduinoStringTests, JsonBuffer_DontGrowWhenReusingKey) { +TEST_F(StringTests, JsonBuffer_DontGrowWhenReusingKey) { JsonObject &object = _jsonBuffer.createObject(); - String key("hello"); + std::string key("hello"); object[key] = 1; size_t sizeBefore = _jsonBuffer.size(); @@ -243,3 +243,10 @@ TEST_F(ArduinoStringTests, JsonBuffer_DontGrowWhenReusingKey) { ASSERT_EQ(sizeBefore, sizeAfter); } + +TEST_F(StringTests, JsonBuffer_strdup) { + std::string original("hello"); + char *copy = _jsonBuffer.strdup(original); + original[0] = 'w'; + ASSERT_STREQ("hello", copy); +}