diff --git a/CHANGELOG.md b/CHANGELOG.md index b68c75b7..867227fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,22 @@ ArduinoJson: change log ======================= +HEAD +---- + +* Changed the rules of string duplication (issue #658) + +> ### New rules for string duplication +> +> | type | duplication | +> |:-------------|:------------| +> | const char* | no | +> | char* | ~~no~~ yes | +> | String | yes | +> | std::string | yes | +> +> These new rules make `JsonBuffer::strdup()` useless. + v5.12.0 ------- diff --git a/src/ArduinoJson/Data/ValueSaver.hpp b/src/ArduinoJson/Data/ValueSaver.hpp new file mode 100644 index 00000000..0a9e1883 --- /dev/null +++ b/src/ArduinoJson/Data/ValueSaver.hpp @@ -0,0 +1,34 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#include "../JsonBuffer.hpp" +#include "../JsonVariant.hpp" +#include "../StringTraits/StringTraits.hpp" +#include "../TypeTraits/EnableIf.hpp" + +namespace ArduinoJson { +namespace Internals { + +template +struct ValueSaver { + template + static bool save(JsonBuffer*, Destination& destination, Source source) { + destination = source; + return true; + } +}; + +template +struct ValueSaver::value>::type> { + template + static bool save(JsonBuffer* buffer, Destination& destination, + Source source) { + return StringTraits::save(source, destination, buffer); + } +}; +} +} diff --git a/src/ArduinoJson/Data/ValueSetter.hpp b/src/ArduinoJson/Data/ValueSetter.hpp deleted file mode 100644 index 266df298..00000000 --- a/src/ArduinoJson/Data/ValueSetter.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#pragma once - -#include "../JsonBuffer.hpp" -#include "../JsonVariant.hpp" -#include "../StringTraits/StringTraits.hpp" -#include "../TypeTraits/EnableIf.hpp" - -namespace ArduinoJson { -namespace Internals { - -template -struct ValueSetter { - template - static bool set(JsonBuffer*, TDestination& destination, TSourceRef source) { - destination = source; - return true; - } -}; - -template -struct ValueSetter::should_duplicate>::type> { - template - static bool set(JsonBuffer* buffer, TDestination& destination, - TSourceRef source) { - const char* copy = buffer->strdup(source); - if (!copy) return false; - destination = copy; - return true; - } -}; - -template -struct ValueSetter::should_duplicate>::type> { - template - static bool set(JsonBuffer*, TDestination& destination, TSourceRef source) { - // unsigned char* -> char* - destination = reinterpret_cast(source); - return true; - } -}; -} -} diff --git a/src/ArduinoJson/JsonArray.hpp b/src/ArduinoJson/JsonArray.hpp index 8ce21d7c..3c3ff36b 100644 --- a/src/ArduinoJson/JsonArray.hpp +++ b/src/ArduinoJson/JsonArray.hpp @@ -7,7 +7,7 @@ #include "Data/JsonBufferAllocated.hpp" #include "Data/List.hpp" #include "Data/ReferenceType.hpp" -#include "Data/ValueSetter.hpp" +#include "Data/ValueSaver.hpp" #include "JsonVariant.hpp" #include "Serialization/JsonPrintable.hpp" #include "StringTraits/StringTraits.hpp" @@ -56,19 +56,17 @@ class JsonArray : public Internals::JsonPrintable, // // bool add(TValue); // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf::value, bool>::type add( - const T &value) { + bool add(const T &value) { return add_impl(value); } // // bool add(TValue); - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - bool add(const T *value) { - return add_impl(value); + bool add(T *value) { + return add_impl(value); } // // bool add(TValue value, uint8_t decimals); @@ -81,21 +79,19 @@ class JsonArray : public Internals::JsonPrintable, // Sets the value at specified index. // - // bool add(size_t index, TValue); + // bool add(size_t index, const TValue&); // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf::value, bool>::type set( - size_t index, const T &value) { + bool set(size_t index, const T &value) { return set_impl(index, value); } // // bool add(size_t index, TValue); - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - bool set(size_t index, const T *value) { - return set_impl(index, value); + bool set(size_t index, T *value) { + return set_impl(index, value); } // // bool set(size_t index, TValue value, uint8_t decimals); @@ -208,14 +204,14 @@ class JsonArray : public Internals::JsonPrintable, bool set_impl(size_t index, TValueRef value) { iterator it = begin() += index; if (it == end()) return false; - return Internals::ValueSetter::set(_buffer, *it, value); + return Internals::ValueSaver::save(_buffer, *it, value); } template bool add_impl(TValueRef value) { iterator it = Internals::List::add(); if (it == end()) return false; - return Internals::ValueSetter::set(_buffer, *it, value); + return Internals::ValueSaver::save(_buffer, *it, value); } }; diff --git a/src/ArduinoJson/JsonArraySubscript.hpp b/src/ArduinoJson/JsonArraySubscript.hpp index 06d33094..da9807fb 100644 --- a/src/ArduinoJson/JsonArraySubscript.hpp +++ b/src/ArduinoJson/JsonArraySubscript.hpp @@ -25,10 +25,9 @@ class JsonArraySubscript : public JsonVariantBase { // Replaces the value // - // operator=(TValue) + // operator=(const TValue&) // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template FORCE_INLINE JsonArraySubscript& operator=(const T& src) { _array.set(_index, src); @@ -36,9 +35,9 @@ class JsonArraySubscript : public JsonVariantBase { } // // operator=(TValue) - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - FORCE_INLINE JsonArraySubscript& operator=(const T* src) { + FORCE_INLINE JsonArraySubscript& operator=(T* src) { _array.set(_index, src); return *this; } @@ -59,19 +58,18 @@ class JsonArraySubscript : public JsonVariantBase { // Replaces the value // - // bool set(TValue) + // bool set(const TValue&) // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template FORCE_INLINE bool set(const TValue& value) { return _array.set(_index, value); } // // bool set(TValue) - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - FORCE_INLINE bool set(const TValue* value) { + FORCE_INLINE bool set(TValue* value) { return _array.set(_index, value); } // diff --git a/src/ArduinoJson/JsonObject.hpp b/src/ArduinoJson/JsonObject.hpp index 5dff1090..8bd8105b 100644 --- a/src/ArduinoJson/JsonObject.hpp +++ b/src/ArduinoJson/JsonObject.hpp @@ -7,7 +7,7 @@ #include "Data/JsonBufferAllocated.hpp" #include "Data/List.hpp" #include "Data/ReferenceType.hpp" -#include "Data/ValueSetter.hpp" +#include "Data/ValueSaver.hpp" #include "JsonPair.hpp" #include "Serialization/JsonPrintable.hpp" #include "StringTraits/StringTraits.hpp" @@ -50,17 +50,15 @@ class JsonObject : public Internals::JsonPrintable, // JsonObjectSubscript operator[](TKey) // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - JsonObjectSubscript >::type - operator[](const TString& key) { + JsonObjectSubscript operator[](const TString& key) { return JsonObjectSubscript(*this, key); } // // JsonObjectSubscript operator[](TKey) - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, char[], const char[N], const FlashStringHelper* template - JsonObjectSubscript operator[](const TString* key) { - return JsonObjectSubscript(*this, key); + JsonObjectSubscript operator[](TString* key) { + return JsonObjectSubscript(*this, key); } // Gets the value associated with the specified key. @@ -68,10 +66,8 @@ class JsonObject : public Internals::JsonPrintable, // const JsonObjectSubscript operator[](TKey) const; // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf< - !TypeTraits::IsArray::value, - const JsonObjectSubscript >::type - operator[](const TString& key) const { + const JsonObjectSubscript operator[]( + const TString& key) const { return JsonObjectSubscript(*const_cast(this), key); } @@ -79,10 +75,8 @@ class JsonObject : public Internals::JsonPrintable, // const JsonObjectSubscript operator[](TKey) const; // TKey = const char*, const char[N], const FlashStringHelper* template - const JsonObjectSubscript operator[]( - const TString* key) const { - return JsonObjectSubscript(*const_cast(this), - key); + const JsonObjectSubscript operator[](TString* key) const { + return JsonObjectSubscript(*const_cast(this), key); } // Sets the specified key with the specified value. @@ -90,43 +84,35 @@ class JsonObject : public Internals::JsonPrintable, // bool set(TKey, TValue); // TKey = const std::string&, const String& // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf::value && - !TypeTraits::IsArray::value, - bool>::type - set(const TString& key, const TValue& value) { + bool set(const TString& key, const TValue& value) { return set_impl(key, value); } // // bool set(TKey, TValue); // TKey = const std::string&, const String& - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - typename TypeTraits::EnableIf::value, - bool>::type - set(const TString& key, const TValue* value) { - return set_impl(key, value); + bool set(const TString& key, TValue* value) { + return set_impl(key, value); } // - // bool set(TKey, TValue); - // TKey = const char*, const char[N], const FlashStringHelper* + // bool set(TKey, const TValue&); + // TKey = char*, const char*, const FlashStringHelper* // TValue = bool, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf::value, bool>::type - set(const TString* key, const TValue& value) { - return set_impl(key, value); + bool set(TString* key, const TValue& value) { + return set_impl(key, value); } // // bool set(TKey, TValue); - // TKey = const char*, const char[N], const FlashStringHelper* - // TValue = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template - bool set(const TString* key, const TValue* value) { - return set_impl(key, value); + bool set(TString* key, TValue* value) { + return set_impl(key, value); } // // bool set(TKey, TValue, uint8_t decimals); @@ -134,8 +120,7 @@ class JsonObject : public Internals::JsonPrintable, // TValue = float, double template DEPRECATED("Second argument is not supported anymore") - typename TypeTraits::EnableIf::value && - !TypeTraits::IsArray::value, + typename TypeTraits::EnableIf::value, bool>::type set(const TString& key, TValue value, uint8_t) { return set_impl(key, @@ -143,41 +128,35 @@ class JsonObject : public Internals::JsonPrintable, } // // bool set(TKey, TValue, uint8_t decimals); - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, const FlashStringHelper* // TValue = float, double template DEPRECATED("Second argument is not supported anymore") typename TypeTraits::EnableIf::value, bool>::type - set(const TString* key, TValue value, uint8_t) { - return set_impl(key, - JsonVariant(value)); + set(TString* key, TValue value, uint8_t) { + return set_impl(key, JsonVariant(value)); } // Gets the value associated with the specified key. // - // TValue get(TKey); + // TValue get(TKey) const; // TKey = const std::string&, const String& // TValue = bool, char, long, int, short, float, double, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf< - !TypeTraits::IsArray::value, - typename Internals::JsonVariantAs::type>::type - get(const TString& key) const { + typename Internals::JsonVariantAs::type get( + const TString& key) const { return get_impl(key); } // - // TValue get(TKey); - // TKey = const char*, const char[N], const FlashStringHelper* + // TValue get(TKey) const; + // TKey = char*, const char*, const FlashStringHelper* // TValue = bool, char, long, int, short, float, double, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename Internals::JsonVariantAs::type get( - const TString* key) const { - return get_impl(key); + typename Internals::JsonVariantAs::type get(TString* key) const { + return get_impl(key); } // Checks the type of the value associated with the specified key. @@ -186,23 +165,19 @@ class JsonObject : public Internals::JsonPrintable, // bool is(TKey) const; // TKey = const std::string&, const String& // TValue = bool, char, long, int, short, float, double, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - typename TypeTraits::EnableIf::value, - bool>::type - is(const TString& key) const { + bool is(const TString& key) const { return is_impl(key); } // // bool is(TKey) const; - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, const FlashStringHelper* // TValue = bool, char, long, int, short, float, double, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template - bool is(const TString* key) const { - return is_impl(key); + bool is(TString* key) const { + return is_impl(key); } // Creates and adds a JsonArray. @@ -210,16 +185,14 @@ class JsonObject : public Internals::JsonPrintable, // JsonArray& createNestedArray(TKey); // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - JsonArray&>::type - createNestedArray(const TString& key) { + JsonArray& createNestedArray(const TString& key) { return createNestedArray_impl(key); } // JsonArray& createNestedArray(TKey); - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, char[], const char[], const FlashStringHelper* template - JsonArray& createNestedArray(const TString* key) { - return createNestedArray_impl(key); + JsonArray& createNestedArray(TString* key) { + return createNestedArray_impl(key); } // Creates and adds a JsonObject. @@ -227,17 +200,15 @@ class JsonObject : public Internals::JsonPrintable, // JsonObject& createNestedObject(TKey); // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - JsonObject&>::type - createNestedObject(const TString& key) { + JsonObject& createNestedObject(const TString& key) { return createNestedObject_impl(key); } // // JsonObject& createNestedObject(TKey); - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, char[], const char[], const FlashStringHelper* template - JsonObject& createNestedObject(const TString* key) { - return createNestedObject_impl(key); + JsonObject& createNestedObject(TString* key) { + return createNestedObject_impl(key); } // Tells weither the specified key is present and associated with a value. @@ -245,17 +216,15 @@ class JsonObject : public Internals::JsonPrintable, // bool containsKey(TKey); // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - bool>::type - containsKey(const TString& key) const { + bool containsKey(const TString& key) const { return findKey(key) != end(); } // // bool containsKey(TKey); - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, char[], const char[], const FlashStringHelper* template - bool containsKey(const TString* key) const { - return findKey(key) != end(); + bool containsKey(TString* key) const { + return findKey(key) != end(); } // Removes the specified key and the associated value. @@ -263,17 +232,15 @@ class JsonObject : public Internals::JsonPrintable, // void remove(TKey); // TKey = const std::string&, const String& template - typename TypeTraits::EnableIf::value, - void>::type - remove(const TString& key) { + void remove(const TString& key) { remove(findKey(key)); } // // void remove(TKey); - // TKey = const char*, const char[N], const FlashStringHelper* + // TKey = char*, const char*, char[], const char[], const FlashStringHelper* template - void remove(const TString* key) { - remove(findKey(key)); + void remove(TString* key) { + remove(findKey(key)); } // // void remove(iterator) @@ -318,10 +285,10 @@ class JsonObject : public Internals::JsonPrintable, if (it == end()) return false; bool key_ok = - Internals::ValueSetter::set(_buffer, it->key, key); + Internals::ValueSaver::save(_buffer, it->key, key); if (!key_ok) return false; } - return Internals::ValueSetter::set(_buffer, it->value, value); + return Internals::ValueSaver::save(_buffer, it->value, value); } template diff --git a/src/ArduinoJson/JsonObjectSubscript.hpp b/src/ArduinoJson/JsonObjectSubscript.hpp index 1657cf77..57544e65 100644 --- a/src/ArduinoJson/JsonObjectSubscript.hpp +++ b/src/ArduinoJson/JsonObjectSubscript.hpp @@ -31,10 +31,9 @@ class JsonObjectSubscript // Set the specified value // - // operator=(TValue); + // operator=(const TValue&); // TValue = bool, char, long, int, short, float, double, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template FORCE_INLINE typename TypeTraits::EnableIf::value, @@ -45,7 +44,7 @@ class JsonObjectSubscript } // // operator=(TValue); - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char*, const FlashStringHelper* template FORCE_INLINE this_type& operator=(const TValue* src) { _object.set(_key, src); @@ -68,10 +67,9 @@ class JsonObjectSubscript // Sets the specified value. // - // bool set(TValue); + // bool set(const TValue&); // TValue = bool, char, long, int, short, float, double, RawJson, JsonVariant, - // const std::string&, const String&, - // const JsonArray&, const JsonObject& + // std::string, String, JsonArray, JsonObject template FORCE_INLINE typename TypeTraits::EnableIf::value, @@ -81,7 +79,7 @@ class JsonObjectSubscript } // // bool set(TValue); - // TValue = const char*, const char[N], const FlashStringHelper* + // TValue = char*, const char, const FlashStringHelper* template FORCE_INLINE bool set(const TValue* value) { return _object.set(_key, value); diff --git a/src/ArduinoJson/Polyfills/attributes.hpp b/src/ArduinoJson/Polyfills/attributes.hpp index 2c4e7e6c..b49091dd 100644 --- a/src/ArduinoJson/Polyfills/attributes.hpp +++ b/src/ArduinoJson/Polyfills/attributes.hpp @@ -6,7 +6,7 @@ #ifdef _MSC_VER // Visual Studio -#define FORCE_INLINE __forceinline +#define FORCE_INLINE // __forceinline causes C4714 when returning std::string #define NO_INLINE __declspec(noinline) #define DEPRECATED(msg) __declspec(deprecated(msg)) diff --git a/src/ArduinoJson/StringTraits/CharPointer.hpp b/src/ArduinoJson/StringTraits/CharPointer.hpp index b41e47da..9231d6c4 100644 --- a/src/ArduinoJson/StringTraits/CharPointer.hpp +++ b/src/ArduinoJson/StringTraits/CharPointer.hpp @@ -33,6 +33,7 @@ struct CharPointerTraits { return strcmp(reinterpret_cast(str), expected) == 0; } + // TODO: remove template static char* duplicate(const TChar* str, Buffer* buffer) { if (!str) return NULL; @@ -44,12 +45,46 @@ struct CharPointerTraits { static const bool has_append = false; static const bool has_equals = true; - static const bool should_duplicate = false; }; +// const char*, const unsigned char*, const signed char* template struct StringTraits::value>::type> - : CharPointerTraits {}; + TypeTraits::IsChar::value && + TypeTraits::IsConst::value>::type> + : CharPointerTraits { + // Just save the pointer + template + static typename TypeTraits::EnableIf::value, + bool>::type + save(const TChar* source, Destination& dest, Buffer*) { + dest = reinterpret_cast(source); + return true; + } +}; + +// char*, unsigned char*, signed char* +template +struct StringTraits::value && + !TypeTraits::IsConst::value>::type> + : CharPointerTraits { + // Make a copy of the string + template + static typename TypeTraits::EnableIf::value, + bool>::type + save(const TChar* source, Destination& dest, Buffer* buffer) { + if (source) { + size_t size = strlen(reinterpret_cast(source)) + 1; + void* dup = buffer->alloc(size); + if (!dup) return false; + memcpy(dup, source, size); + dest = reinterpret_cast(dup); + } else { + dest = reinterpret_cast(source); + } + return true; + } +}; } } diff --git a/src/ArduinoJson/StringTraits/FlashString.hpp b/src/ArduinoJson/StringTraits/FlashString.hpp index 2530ceee..d706f35a 100644 --- a/src/ArduinoJson/StringTraits/FlashString.hpp +++ b/src/ArduinoJson/StringTraits/FlashString.hpp @@ -34,6 +34,7 @@ struct StringTraits { return strcmp_P(expected, (const char*)str) == 0; } + // TODO: remove template static char* duplicate(const __FlashStringHelper* str, Buffer* buffer) { if (!str) return NULL; @@ -43,9 +44,22 @@ struct StringTraits { return static_cast(dup); } + template + static bool save(const __FlashStringHelper* source, Destination& dest, + Buffer* buffer) { + if (source) { + size_t size = strlen_P((const char*)source) + 1; + void* dup = buffer->alloc(size); + if (dup != NULL) memcpy_P(dup, (const char*)source, size); + dest = reinterpret_cast(dup); + } else { + dest = reinterpret_cast(source); + } + return true; + } + static const bool has_append = false; static const bool has_equals = true; - static const bool should_duplicate = true; }; } } diff --git a/src/ArduinoJson/StringTraits/StdString.hpp b/src/ArduinoJson/StringTraits/StdString.hpp index d7b14b20..719f7647 100644 --- a/src/ArduinoJson/StringTraits/StdString.hpp +++ b/src/ArduinoJson/StringTraits/StdString.hpp @@ -19,6 +19,7 @@ namespace Internals { template struct StdStringTraits { + // TODO: remove template static char* duplicate(const TString& str, Buffer* buffer) { if (!str.c_str()) return NULL; // <- Arduino string can return NULL @@ -28,6 +29,21 @@ struct StdStringTraits { return static_cast(dup); } + template + static bool save(const TString& str, Destination& dest, Buffer* buffer) { + // Arduino's String::c_str() can return NULL + if (str.c_str()) { + size_t size = str.length() + 1; + void* dup = buffer->alloc(size); + if (!dup) return false; + memcpy(dup, str.c_str(), size); + dest = reinterpret_cast(dup); + } else { + dest = str.c_str(); + } + return true; + } + struct Reader : CharPointerTraits::Reader { Reader(const TString& str) : CharPointerTraits::Reader(str.c_str()) {} }; @@ -46,7 +62,6 @@ struct StdStringTraits { static const bool has_append = true; static const bool has_equals = true; - static const bool should_duplicate = true; }; #if ARDUINOJSON_ENABLE_ARDUINO_STRING diff --git a/src/ArduinoJson/StringTraits/StringTraits.hpp b/src/ArduinoJson/StringTraits/StringTraits.hpp index eec04dc5..568a4221 100644 --- a/src/ArduinoJson/StringTraits/StringTraits.hpp +++ b/src/ArduinoJson/StringTraits/StringTraits.hpp @@ -9,6 +9,7 @@ #include "../TypeTraits/EnableIf.hpp" #include "../TypeTraits/IsBaseOf.hpp" #include "../TypeTraits/IsChar.hpp" +#include "../TypeTraits/IsConst.hpp" #include "../TypeTraits/RemoveReference.hpp" namespace ArduinoJson { diff --git a/test/JsonArray/CMakeLists.txt b/test/JsonArray/CMakeLists.txt index 7d48a1ac..ec0e5206 100644 --- a/test/JsonArray/CMakeLists.txt +++ b/test/JsonArray/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(JsonArrayTests printTo.cpp remove.cpp set.cpp + size.cpp subscript.cpp ) diff --git a/test/JsonArray/add.cpp b/test/JsonArray/add.cpp index c344457c..1a39833f 100644 --- a/test/JsonArray/add.cpp +++ b/test/JsonArray/add.cpp @@ -9,11 +9,6 @@ TEST_CASE("JsonArray::add()") { DynamicJsonBuffer _jsonBuffer; JsonArray& _array = _jsonBuffer.createArray(); - SECTION("SizeIncreased_WhenValuesAreAdded") { - _array.add("hello"); - REQUIRE(1U == _array.size()); - } - SECTION("int") { _array.add(123); REQUIRE(123 == _array[0].as()); @@ -38,7 +33,7 @@ TEST_CASE("JsonArray::add()") { SECTION("const char*") { const char* str = "hello"; _array.add(str); - REQUIRE(str == _array[0].as()); + REQUIRE(str == _array[0].as()); REQUIRE(_array[0].is()); REQUIRE_FALSE(_array[0].is()); } @@ -82,4 +77,22 @@ TEST_CASE("JsonArray::add()") { REQUIRE(str == _array[0]); } + + SECTION("should not duplicate const char*") { + _array.add("world"); + const size_t expectedSize = JSON_ARRAY_SIZE(1); + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate char*") { + _array.add(const_cast("world")); + const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate std::string") { + _array.add(std::string("world")); + const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; + REQUIRE(expectedSize == _jsonBuffer.size()); + } } diff --git a/test/JsonArray/set.cpp b/test/JsonArray/set.cpp index 77e737d1..901f9054 100644 --- a/test/JsonArray/set.cpp +++ b/test/JsonArray/set.cpp @@ -12,11 +12,6 @@ TEST_CASE("JsonArray::set()") { JsonArray& _array = _jsonBuffer.createArray(); _array.add(0); - SECTION("SizeIsUnchanged") { - _array.set(0, "hello"); - REQUIRE(1U == _array.size()); - } - SECTION("int") { _array.set(0, 123); REQUIRE(123 == _array[0].as()); @@ -82,4 +77,22 @@ TEST_CASE("JsonArray::set()") { REQUIRE_THAT(_array[0].as(), Equals("hello")); } + + SECTION("should not duplicate const char*") { + _array.set(0, "world"); + const size_t expectedSize = JSON_ARRAY_SIZE(1); + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate char*") { + _array.set(0, const_cast("world")); + const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate std::string") { + _array.set(0, std::string("world")); + const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; + REQUIRE(expectedSize == _jsonBuffer.size()); + } } diff --git a/test/JsonArray/size.cpp b/test/JsonArray/size.cpp new file mode 100644 index 00000000..c45fe30e --- /dev/null +++ b/test/JsonArray/size.cpp @@ -0,0 +1,35 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include + +TEST_CASE("JsonArray::size()") { + DynamicJsonBuffer _jsonBuffer; + JsonArray& _array = _jsonBuffer.createArray(); + + SECTION("increases after add()") { + _array.add("hello"); + REQUIRE(1U == _array.size()); + + _array.add("world"); + REQUIRE(2U == _array.size()); + } + + SECTION("remains the same after set()") { + _array.add("hello"); + REQUIRE(1U == _array.size()); + + _array.set(0, "hello"); + REQUIRE(1U == _array.size()); + } + + SECTION("remains the same after assigment") { + _array.add("hello"); + REQUIRE(1U == _array.size()); + + _array[0] = "hello"; + REQUIRE(1U == _array.size()); + } +} diff --git a/test/JsonArray/subscript.cpp b/test/JsonArray/subscript.cpp index f1551c15..69893c53 100644 --- a/test/JsonArray/subscript.cpp +++ b/test/JsonArray/subscript.cpp @@ -11,11 +11,6 @@ TEST_CASE("JsonArray::operator[]") { JsonArray& _array = _jsonBuffer.createArray(); _array.add(0); - SECTION("SizeIsUnchanged") { - _array[0] = "hello"; - REQUIRE(1U == _array.size()); - } - SECTION("int") { _array[0] = 123; REQUIRE(123 == _array[0].as()); @@ -103,4 +98,22 @@ TEST_CASE("JsonArray::operator[]") { REQUIRE(str == _array[0]); } + + SECTION("should not duplicate const char*") { + _array[0] = "world"; + const size_t expectedSize = JSON_ARRAY_SIZE(1); + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate char*") { + _array[0] = const_cast("world"); + const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate std::string") { + _array[0] = std::string("world"); + const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6; + REQUIRE(expectedSize == _jsonBuffer.size()); + } } diff --git a/test/JsonObject/CMakeLists.txt b/test/JsonObject/CMakeLists.txt index a1b07969..93e8f0de 100644 --- a/test/JsonObject/CMakeLists.txt +++ b/test/JsonObject/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable(JsonObjectTests printTo.cpp remove.cpp set.cpp + size.cpp subscript.cpp ) diff --git a/test/JsonObject/set.cpp b/test/JsonObject/set.cpp index b70de49d..d5ae48b2 100644 --- a/test/JsonObject/set.cpp +++ b/test/JsonObject/set.cpp @@ -10,17 +10,6 @@ TEST_CASE("JsonObject::set()") { DynamicJsonBuffer jb; JsonObject& _object = jb.createObject(); - SECTION("SizeIncreased_WhenValuesAreAdded") { - _object.set("hello", 42); - REQUIRE(1 == _object.size()); - } - - SECTION("SizeUntouched_WhenSameValueIsAdded") { - _object["hello"] = 1; - _object["hello"] = 2; - REQUIRE(1 == _object.size()); - } - SECTION("int") { _object.set("hello", 123); @@ -91,17 +80,59 @@ TEST_CASE("JsonObject::set()") { REQUIRE(42 == _object["a"]); } - SECTION("ShouldReturnTrue_WhenAllocationSucceeds") { + SECTION("returns true when allocation succeeds") { StaticJsonBuffer jsonBuffer; JsonObject& obj = jsonBuffer.createObject(); REQUIRE(true == obj.set(std::string("hello"), std::string("world"))); } - SECTION("ShouldReturnFalse_WhenAllocationFails") { + SECTION("returns false when allocation fails") { StaticJsonBuffer jsonBuffer; JsonObject& obj = jsonBuffer.createObject(); REQUIRE(false == obj.set(std::string("hello"), std::string("world"))); } + + SECTION("should not duplicate const char*") { + _object.set("hello", "world"); + const size_t expectedSize = JSON_OBJECT_SIZE(1); + REQUIRE(expectedSize == jb.size()); + } + + SECTION("should duplicate char* value") { + _object.set("hello", const_cast("world")); + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 6; + REQUIRE(expectedSize == jb.size()); + } + + SECTION("should duplicate char* key") { + _object.set(const_cast("hello"), "world"); + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 6; + REQUIRE(expectedSize == jb.size()); + } + + SECTION("should duplicate char* key&value") { + _object.set(const_cast("hello"), const_cast("world")); + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 12; + REQUIRE(expectedSize <= jb.size()); + } + + SECTION("should duplicate std::string value") { + _object.set("hello", std::string("world")); + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 6; + REQUIRE(expectedSize == jb.size()); + } + + SECTION("should duplicate std::string key") { + _object.set(std::string("hello"), "world"); + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 6; + REQUIRE(expectedSize == jb.size()); + } + + SECTION("should duplicate std::string key&value") { + _object.set(std::string("hello"), std::string("world")); + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 12; + REQUIRE(expectedSize <= jb.size()); + } } diff --git a/test/JsonObject/size.cpp b/test/JsonObject/size.cpp new file mode 100644 index 00000000..eae88834 --- /dev/null +++ b/test/JsonObject/size.cpp @@ -0,0 +1,23 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include +#include + +TEST_CASE("JsonObject::size()") { + DynamicJsonBuffer jb; + JsonObject& _object = jb.createObject(); + + SECTION("increases when values are added") { + _object.set("hello", 42); + REQUIRE(1 == _object.size()); + } + + SECTION("doesn't increase when the smae key is added twice") { + _object["hello"] = 1; + _object["hello"] = 2; + REQUIRE(1 == _object.size()); + } +} diff --git a/test/JsonObject/subscript.cpp b/test/JsonObject/subscript.cpp index 23710570..d08e8c77 100644 --- a/test/JsonObject/subscript.cpp +++ b/test/JsonObject/subscript.cpp @@ -9,17 +9,6 @@ TEST_CASE("JsonObject::operator[]") { DynamicJsonBuffer _jsonBuffer; JsonObject& _object = _jsonBuffer.createObject(); - SECTION("SizeIncreased_WhenValuesAreAdded") { - _object["hello"] = 1; - REQUIRE(1 == _object.size()); - } - - SECTION("SizeUntouched_WhenSameValueIsAdded") { - _object["hello"] = 1; - _object["hello"] = 2; - REQUIRE(1 == _object.size()); - } - SECTION("int") { _object["hello"] = 123; @@ -113,9 +102,51 @@ TEST_CASE("JsonObject::operator[]") { REQUIRE(42 == _object["a"]); } - SECTION("KeyAsCharArray") { // issue #423 + SECTION("char key[]") { // issue #423 char key[] = "hello"; _object[key] = 42; REQUIRE(42 == _object[key]); } + + SECTION("should not duplicate const char*") { + _object["hello"] = "world"; + const size_t expectedSize = JSON_OBJECT_SIZE(1); + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate char* value") { + _object["hello"] = const_cast("world"); + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 6; + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate char* key") { + _object[const_cast("hello")] = "world"; + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 6; + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate char* key&value") { + _object[const_cast("hello")] = const_cast("world"); + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 12; + REQUIRE(expectedSize <= _jsonBuffer.size()); + } + + SECTION("should duplicate std::string value") { + _object["hello"] = std::string("world"); + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 6; + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate std::string key") { + _object[std::string("hello")] = "world"; + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 6; + REQUIRE(expectedSize == _jsonBuffer.size()); + } + + SECTION("should duplicate std::string key&value") { + _object[std::string("hello")] = std::string("world"); + const size_t expectedSize = JSON_OBJECT_SIZE(1) + 12; + REQUIRE(expectedSize <= _jsonBuffer.size()); + } } diff --git a/test/Misc/TypeTraits.cpp b/test/Misc/TypeTraits.cpp index 1619591a..6f170eb0 100644 --- a/test/Misc/TypeTraits.cpp +++ b/test/Misc/TypeTraits.cpp @@ -36,4 +36,9 @@ TEST_CASE("TypeTraits") { REQUIRE((IsString::value)); REQUIRE_FALSE((IsString::value)); } + + SECTION("IsConst") { + REQUIRE_FALSE((IsConst::value)); + REQUIRE((IsConst::value)); + } }