diff --git a/.clang-format b/.clang-format index 0f553e88..b5681465 100644 --- a/.clang-format +++ b/.clang-format @@ -1,3 +1,4 @@ # http://clang.llvm.org/docs/ClangFormatStyleOptions.html -BasedOnStyle: Google \ No newline at end of file +BasedOnStyle: Google +Standard: Cpp03 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 244b8775..cb0dbbd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ ArduinoJson: change log ======================= +v5.1.0 +------ + +* Added support of `long long` (issue #171) +* Moved all build settings to `ArduinoJson/Configuration.hpp` + +**BREAKING CHANGE**: +If you defined `ARDUINOJSON_ENABLE_STD_STREAM`, you now need to define it to `1`. + v5.0.8 ------ diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..60db62b9 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,16 @@ +version: 5.1.0.{build} +environment: + matrix: + - CMAKE_GENERATOR: Visual Studio 14 2015 + - CMAKE_GENERATOR: Visual Studio 12 2013 + - CMAKE_GENERATOR: Visual Studio 11 2012 + - CMAKE_GENERATOR: Visual Studio 10 2010 + - CMAKE_GENERATOR: MinGW Makefiles +configuration: Debug +before_build: +- set PATH=C:\MinGW\bin;%PATH:C:\Program Files\Git\usr\bin;=% # Workaround for CMake not wanting sh.exe on PATH for MinGW +- cmake -DCMAKE_BUILD_TYPE=%CONFIGURATION% -G "%CMAKE_GENERATOR%" . +build_script: +- cmake --build . --config %CONFIGURATION% +test_script: +- ctest -V . diff --git a/include/ArduinoJson/Arduino/Print.hpp b/include/ArduinoJson/Arduino/Print.hpp index 0a3baa93..3ec2e90a 100644 --- a/include/ArduinoJson/Arduino/Print.hpp +++ b/include/ArduinoJson/Arduino/Print.hpp @@ -9,8 +9,19 @@ #ifndef ARDUINO +#include "../Internals/JsonFloat.hpp" +#include "../Internals/JsonInteger.hpp" + #include #include +#include + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +// snprintf has been added in Visual Studio 2015 +#define ARDUINOJSON_SNPRINTF _snprintf +#else +#define ARDUINOJSON_SNPRINTF snprintf +#endif // This class reproduces Arduino's Print class class Print { @@ -19,11 +30,56 @@ class Print { virtual size_t write(uint8_t) = 0; - size_t print(const char[]); - size_t print(double, int = 2); - size_t print(int); - size_t print(long); - size_t println(); + size_t print(const char* s) { + size_t n = 0; + while (*s) { + n += write(*s++); + } + return n; + } + + size_t print(ArduinoJson::Internals::JsonFloat value, int digits = 2) { + char tmp[32]; + + // https://github.com/arduino/Arduino/blob/db8cbf24c99dc930b9ccff1a43d018c81f178535/hardware/arduino/sam/cores/arduino/Print.cpp#L220 + bool isBigDouble = value > 4294967040.0 || value < -4294967040.0; + + if (isBigDouble) { + // Arduino's implementation prints "ovf" + // We prefer using the scientific notation, since we have sprintf + ARDUINOJSON_SNPRINTF(tmp, sizeof(tmp), "%g", value); + } else { + // Here we have the exact same output as Arduino's implementation + ARDUINOJSON_SNPRINTF(tmp, sizeof(tmp), "%.*f", digits, value); + } + + return print(tmp); + } + + size_t print(ArduinoJson::Internals::JsonInteger value) { + // see http://clc-wiki.net/wiki/K%26R2_solutions:Chapter_3:Exercise_4 + char buffer[22]; + + size_t n = 0; + if (value < 0) { + value = -value; + n += write('-'); + } + uint8_t i = 0; + do { + ArduinoJson::Internals::JsonInteger digit = value % 10; + value /= 10; + buffer[i++] = static_cast(digit >= 0 ? '0' + digit : '0' - digit); + } while (value); + + while (i > 0) { + n += write(buffer[--i]); + } + + return n; + } + + size_t println() { return write('\r') + write('\n'); } }; #else diff --git a/include/ArduinoJson/Configuration.hpp b/include/ArduinoJson/Configuration.hpp new file mode 100644 index 00000000..8956827d --- /dev/null +++ b/include/ArduinoJson/Configuration.hpp @@ -0,0 +1,79 @@ +// 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 + +#ifdef ARDUINO // assume this is an embedded platform + +// store using float instead of double to reduce the memory usage (issue #134) +#ifndef ARDUINOJSON_USE_DOUBLE +#define ARDUINOJSON_USE_DOUBLE 0 +#endif + +// store using a long because it usually match the size of a float. +#ifndef ARDUINOJSON_USE_LONG_LONG +#define ARDUINOJSON_USE_LONG_LONG 0 +#endif +#ifndef ARDUINOJSON_USE_INT64 +#define ARDUINOJSON_USE_INT64 0 +#endif + +// arduino doesn't support STL stream +#ifndef ARDUINOJSON_ENABLE_STD_STREAM +#define ARDUINOJSON_ENABLE_STD_STREAM 0 +#endif + +#ifndef ARDUINOJSON_ENABLE_ALIGNMENT +#ifdef ARDUINO_ARCH_AVR +// alignment isn't needed for 8-bit AVR +#define ARDUINOJSON_ENABLE_ALIGNMENT 0 +#else +// but must processor needs pointer to be align on word size +#define ARDUINOJSON_ENABLE_ALIGNMENT 1 +#endif +#endif + +#else // assume this is a computer + +// on a computer we have plenty of memory so we can use doubles +#ifndef ARDUINOJSON_USE_DOUBLE +#define ARDUINOJSON_USE_DOUBLE 1 +#endif + +// use long long when available +#ifndef ARDUINOJSON_USE_LONG_LONG +#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) +#define ARDUINOJSON_USE_LONG_LONG 1 +#else +#define ARDUINOJSON_USE_LONG_LONG 0 +#endif +#endif + +// use _int64 on old versions of Visual Studio +#ifndef ARDUINOJSON_USE_INT64 +#if defined(_MSC_VER) && _MSC_VER <= 1700 +#define ARDUINOJSON_USE_INT64 1 +#else +#define ARDUINOJSON_USE_INT64 0 +#endif +#endif + +// on a computer, we can assume that the STL is there +#ifndef ARDUINOJSON_ENABLE_STD_STREAM +#define ARDUINOJSON_ENABLE_STD_STREAM 1 +#endif + +#ifndef ARDUINOJSON_ENABLE_ALIGNMENT +// even if not required, most cpu's are faster with aligned pointers +#define ARDUINOJSON_ENABLE_ALIGNMENT 1 +#endif + +#endif + +#if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64 +#error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together +#endif diff --git a/include/ArduinoJson/Internals/JsonFloat.hpp b/include/ArduinoJson/Internals/JsonFloat.hpp index 7af5d3bc..6da18258 100644 --- a/include/ArduinoJson/Internals/JsonFloat.hpp +++ b/include/ArduinoJson/Internals/JsonFloat.hpp @@ -7,15 +7,15 @@ #pragma once +#include "../Configuration.hpp" + namespace ArduinoJson { namespace Internals { -#ifdef ARDUINO -// On embedded platform, we with use float instead of double to keep JsonVariant -// small (issue #134) -typedef float JsonFloat; -#else +#if ARDUINOJSON_USE_DOUBLE typedef double JsonFloat; +#else +typedef float JsonFloat; #endif } } diff --git a/include/ArduinoJson/Internals/JsonInteger.hpp b/include/ArduinoJson/Internals/JsonInteger.hpp index 912107fa..af2879f0 100644 --- a/include/ArduinoJson/Internals/JsonInteger.hpp +++ b/include/ArduinoJson/Internals/JsonInteger.hpp @@ -7,8 +7,17 @@ #pragma once +#include "../Configuration.hpp" + namespace ArduinoJson { namespace Internals { + +#if ARDUINOJSON_USE_LONG_LONG +typedef long long JsonInteger; +#elif ARDUINOJSON_USE_INT64 +typedef __int64 JsonInteger; +#else typedef long JsonInteger; +#endif } } diff --git a/include/ArduinoJson/Internals/JsonPrintable.hpp b/include/ArduinoJson/Internals/JsonPrintable.hpp index 07381c7a..279c6de7 100644 --- a/include/ArduinoJson/Internals/JsonPrintable.hpp +++ b/include/ArduinoJson/Internals/JsonPrintable.hpp @@ -7,6 +7,7 @@ #pragma once +#include "../Configuration.hpp" #include "DummyPrint.hpp" #include "IndentedPrint.hpp" #include "JsonWriter.hpp" @@ -14,7 +15,7 @@ #include "StaticStringBuilder.hpp" #include "DynamicStringBuilder.hpp" -#ifdef ARDUINOJSON_ENABLE_STD_STREAM +#if ARDUINOJSON_ENABLE_STD_STREAM #include "StreamPrintAdapter.hpp" #endif @@ -34,7 +35,7 @@ class JsonPrintable { return writer.bytesWritten(); } -#ifdef ARDUINOJSON_ENABLE_STD_STREAM +#if ARDUINOJSON_ENABLE_STD_STREAM std::ostream &printTo(std::ostream &os) const { StreamPrintAdapter adapter(os); printTo(adapter); @@ -86,7 +87,7 @@ class JsonPrintable { const T &downcast() const { return *static_cast(this); } }; -#ifdef ARDUINOJSON_ENABLE_STD_STREAM +#if ARDUINOJSON_ENABLE_STD_STREAM template inline std::ostream &operator<<(std::ostream &os, const JsonPrintable &v) { return v.printTo(os); diff --git a/include/ArduinoJson/Internals/Parse.hpp b/include/ArduinoJson/Internals/Parse.hpp new file mode 100644 index 00000000..8d8046d4 --- /dev/null +++ b/include/ArduinoJson/Internals/Parse.hpp @@ -0,0 +1,51 @@ +// 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 + +namespace ArduinoJson { +namespace Internals { +template +TFloat parse(const char *); + +template <> +inline float parse(const char *s) { + return static_cast(strtod(s, NULL)); +} + +template <> +inline double parse(const char *s) { + return strtod(s, NULL); +} + +template <> +inline long parse(const char *s) { + return strtol(s, NULL, 10); +} + +template <> +inline int parse(const char *s) { + return atoi(s); +} + +#if ARDUINOJSON_USE_LONG_LONG +template <> +inline long long parse(const char *s) { + return strtoll(s, NULL, 10); +} +#endif + +#if ARDUINOJSON_USE_INT64 +template <> +inline __int64 parse<__int64>(const char *s) { + return _strtoi64(s, NULL, 10); +} +#endif +} +} diff --git a/include/ArduinoJson/Internals/StreamPrintAdapter.hpp b/include/ArduinoJson/Internals/StreamPrintAdapter.hpp index dd579259..68e9fdfb 100644 --- a/include/ArduinoJson/Internals/StreamPrintAdapter.hpp +++ b/include/ArduinoJson/Internals/StreamPrintAdapter.hpp @@ -7,10 +7,14 @@ #pragma once -#ifdef ARDUINOJSON_ENABLE_STD_STREAM +#include "../Configuration.hpp" + +#if ARDUINOJSON_ENABLE_STD_STREAM #include "../Arduino/Print.hpp" +#include + namespace ArduinoJson { namespace Internals { diff --git a/include/ArduinoJson/JsonArray.hpp b/include/ArduinoJson/JsonArray.hpp index 6bb72c04..62c3ec6c 100644 --- a/include/ArduinoJson/JsonArray.hpp +++ b/include/ArduinoJson/JsonArray.hpp @@ -12,6 +12,10 @@ #include "Internals/List.hpp" #include "Internals/ReferenceType.hpp" #include "JsonVariant.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. // Can be very handy to determine the size of a StaticJsonBuffer. @@ -36,6 +40,15 @@ 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(). @@ -49,42 +62,74 @@ class JsonArray : public Internals::JsonPrintable, FORCE_INLINE JsonArraySubscript operator[](size_t index); // Adds the specified value at the end of the array. - FORCE_INLINE bool add(bool value); - FORCE_INLINE bool add(float value, uint8_t decimals = 2); - FORCE_INLINE bool add(double value, uint8_t decimals = 2); - FORCE_INLINE bool add(signed char value); - FORCE_INLINE bool add(signed long value); - FORCE_INLINE bool add(signed int value); - FORCE_INLINE bool add(signed short value); - FORCE_INLINE bool add(unsigned char value); - FORCE_INLINE bool add(unsigned long value); - FORCE_INLINE bool add(unsigned int value); - FORCE_INLINE bool add(unsigned short value); - FORCE_INLINE bool add(const char *value); - FORCE_INLINE bool add(const String &value); - FORCE_INLINE bool add(JsonArray &array); - FORCE_INLINE bool add(JsonObject &object); + // + // bool add(bool); + // bool add(char); + // bool add(long); + // bool add(int); + // bool add(short); + // bool add(float value); + // bool add(double value); + // bool add(const char*); template - FORCE_INLINE bool add(const T &value); + FORCE_INLINE bool add( + T value, + typename TypeTraits::EnableIf< + CanSet::value && !TypeTraits::IsReference::value>::type * = 0) { + return addNode(value); + } + // bool add(const String&) + // bool add(const JsonVariant&); + // bool add(JsonArray&); + // bool add(JsonObject&); + template + FORCE_INLINE bool add( + const T &value, + typename TypeTraits::EnableIf::value>::type * = 0) { + return addNode(const_cast(value)); + } + // bool add(float value, uint8_t decimals); + // bool add(double value, uint8_t decimals); + template + FORCE_INLINE bool add( + T value, uint8_t decimals, + typename TypeTraits::EnableIf::value>::type + * = 0) { + return addNode(JsonVariant(value, decimals)); + } // Sets the value at specified index. - FORCE_INLINE void set(size_t index, bool value); - FORCE_INLINE void set(size_t index, float value, uint8_t decimals = 2); - FORCE_INLINE void set(size_t index, double value, uint8_t decimals = 2); - FORCE_INLINE void set(size_t index, signed char value); - FORCE_INLINE void set(size_t index, signed long value); - FORCE_INLINE void set(size_t index, signed int value); - FORCE_INLINE void set(size_t index, signed short value); - FORCE_INLINE void set(size_t index, unsigned char value); - FORCE_INLINE void set(size_t index, unsigned long value); - FORCE_INLINE void set(size_t index, unsigned int value); - FORCE_INLINE void set(size_t index, unsigned short value); - FORCE_INLINE void set(size_t index, const char *value); - FORCE_INLINE void set(size_t index, const String &value); - FORCE_INLINE void set(size_t index, JsonArray &array); - FORCE_INLINE void set(size_t index, JsonObject &object); + // + // bool set(size_t index, bool value); + // bool set(size_t index, long value); + // bool set(size_t index, int value); + // bool set(size_t index, short value); template - FORCE_INLINE void set(size_t index, const T &value); + FORCE_INLINE 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 String&) + // bool set(size_t index, const JsonVariant&); + // bool set(size_t index, JsonArray&); + // bool set(size_t index, JsonObject&); + template + FORCE_INLINE 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, float value, uint8_t decimals = 2); + // bool set(size_t index, double value, uint8_t decimals = 2); + template + FORCE_INLINE bool set( + size_t index, T value, uint8_t decimals, + typename TypeTraits::EnableIf::value>::type + * = 0) { + return setNodeAt(index, JsonVariant(value, decimals)); + } // Gets the value at the specified index. FORCE_INLINE JsonVariant get(size_t index) const; @@ -120,13 +165,13 @@ class JsonArray : public Internals::JsonPrintable, node_type *getNodeAt(size_t index) const; template - void setNodeAt(size_t index, TValue value); + bool setNodeAt(size_t index, TValue value); template bool addNode(TValue); template - FORCE_INLINE void setNodeValue(node_type *, T value); + FORCE_INLINE bool setNodeValue(node_type *, T value); // The instance returned by JsonArray::invalid() static JsonArray _invalid; diff --git a/include/ArduinoJson/JsonArray.ipp b/include/ArduinoJson/JsonArray.ipp index 991e1a8d..98cd06e4 100644 --- a/include/ArduinoJson/JsonArray.ipp +++ b/include/ArduinoJson/JsonArray.ipp @@ -8,6 +8,7 @@ #pragma once #include "JsonArray.hpp" +#include "JsonObject.hpp" #include "JsonArraySubscript.hpp" namespace ArduinoJson { @@ -20,157 +21,30 @@ inline JsonVariant JsonArray::operator[](size_t index) const { return get(index); } -inline bool JsonArray::add(bool value) { return addNode(value); } - -inline bool JsonArray::add(float value, uint8_t decimals) { - return addNode(JsonVariant(value, decimals)); -} - -inline bool JsonArray::add(double value, uint8_t decimals) { - return addNode(JsonVariant(value, decimals)); -} - -inline bool JsonArray::add(signed char value) { - return addNode(value); -} - -inline bool JsonArray::add(signed long value) { - return addNode(value); -} - -inline bool JsonArray::add(signed int value) { - return addNode(value); -} - -inline bool JsonArray::add(signed short value) { - return addNode(value); -} - -inline bool JsonArray::add(unsigned char value) { - return addNode(value); -} - -inline bool JsonArray::add(unsigned long value) { - return addNode(value); -} - -inline bool JsonArray::add(unsigned int value) { - return addNode(value); -} - -inline bool JsonArray::add(unsigned short value) { - return addNode(value); -} - -inline bool JsonArray::add(const char *value) { - return addNode(value); -} - -inline bool JsonArray::add(const String &value) { - return addNode(value); -} - -inline bool JsonArray::add(JsonArray &array) { - return addNode(array); -} - -inline bool JsonArray::add(JsonObject &object) { - return addNode(object); -} - -template -inline bool JsonArray::add(const T &variant) { - return addNode(variant); -} - template inline bool JsonArray::addNode(TValue value) { node_type *node = addNewNode(); - if (node == NULL) return false; - setNodeValue(node, value); + return node != NULL && setNodeValue(node, value); +} + +template +inline bool JsonArray::setNodeAt(size_t index, TValue value) { + node_type *node = getNodeAt(index); + return node != NULL && setNodeValue(node, value); +} + +template +inline bool JsonArray::setNodeValue(node_type *node, TValue value) { + node->content = value; return true; } -inline void JsonArray::set(size_t index, bool value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, float value, uint8_t decimals) { - return setNodeAt(index, JsonVariant(value, decimals)); -} - -inline void JsonArray::set(size_t index, double value, uint8_t decimals) { - return setNodeAt(index, JsonVariant(value, decimals)); -} - -inline void JsonArray::set(size_t index, signed char value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, signed long value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, signed int value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, signed short value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, unsigned char value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, unsigned long value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, unsigned int value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, unsigned short value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, const char *value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, const String &value) { - return setNodeAt(index, value); -} - -inline void JsonArray::set(size_t index, JsonArray &array) { - return setNodeAt(index, array); -} - -inline void JsonArray::set(size_t index, JsonObject &object) { - return setNodeAt(index, object); -} - -template -inline void JsonArray::set(size_t index, const T &variant) { - return setNodeAt(index, variant); -} - -template -inline void JsonArray::setNodeAt(size_t index, TValue value) { - node_type *node = getNodeAt(index); - if (node == NULL) return; - setNodeValue(node, value); -} - -template -inline void JsonArray::setNodeValue(node_type *node, TValue value) { - node->content = value; -} - template <> -inline void JsonArray::setNodeValue(node_type *node, const String &value) { - node->content = _buffer->strdup(value); +inline bool JsonArray::setNodeValue(node_type *node, String &value) { + const char *copy = _buffer->strdup(value); + if (!copy) return false; + node->content = copy; + return true; } inline JsonVariant JsonArray::get(size_t index) const { @@ -206,15 +80,22 @@ inline JsonArray const &JsonVariant::invalid() { return JsonArray::invalid(); } -template <> -inline JsonArray &JsonVariant::as() const { +inline JsonArray &JsonVariant::asArray() const { if (_type == Internals::JSON_ARRAY) return *_content.asArray; return JsonArray::invalid(); } -template <> -inline const JsonArray &JsonVariant::as() const { - if (_type == Internals::JSON_ARRAY) return *_content.asArray; - return JsonArray::invalid(); +inline JsonArray &JsonArray::createNestedArray() { + if (!_buffer) return JsonArray::invalid(); + JsonArray &array = _buffer->createArray(); + add(array); + return array; +} + +inline JsonArray &JsonObject::createNestedArray(JsonObjectKey key) { + if (!_buffer) return JsonArray::invalid(); + JsonArray &array = _buffer->createArray(); + setNodeAt(key, array); + return array; } } diff --git a/include/ArduinoJson/JsonArraySubscript.hpp b/include/ArduinoJson/JsonArraySubscript.hpp index 4609fb47..8c489680 100644 --- a/include/ArduinoJson/JsonArraySubscript.hpp +++ b/include/ArduinoJson/JsonArraySubscript.hpp @@ -7,7 +7,8 @@ #pragma once -#include "JsonSubscriptBase.hpp" +#include "Configuration.hpp" +#include "JsonVariantBase.hpp" #ifdef _MSC_VER #pragma warning(push) @@ -15,20 +16,30 @@ #endif namespace ArduinoJson { -class JsonArraySubscript : public JsonSubscriptBase { +class JsonArraySubscript : public JsonVariantBase { public: FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index) : _array(array), _index(index) {} - using JsonSubscriptBase::operator=; - JsonArraySubscript& operator=(const JsonArraySubscript& src) { - return assign(src); + _array.set(_index, src); + return *this; } template - JsonArraySubscript& operator=(const T& src) { - return assign(src); + 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); + return *this; } FORCE_INLINE bool success() const { return _index < _array.size(); } @@ -59,7 +70,7 @@ class JsonArraySubscript : public JsonSubscriptBase { const size_t _index; }; -#ifdef ARDUINOJSON_ENABLE_STD_STREAM +#if ARDUINOJSON_ENABLE_STD_STREAM inline std::ostream& operator<<(std::ostream& os, const JsonArraySubscript& source) { return source.printTo(os); diff --git a/include/ArduinoJson/JsonBuffer.hpp b/include/ArduinoJson/JsonBuffer.hpp index 1e1db21a..9055e914 100644 --- a/include/ArduinoJson/JsonBuffer.hpp +++ b/include/ArduinoJson/JsonBuffer.hpp @@ -107,12 +107,11 @@ class JsonBuffer { protected: // Preserve aligment if nessary static FORCE_INLINE size_t round_size_up(size_t bytes) { -#if defined ARDUINO_ARCH_AVR - // alignment isn't needed for 8-bit AVR - return bytes; -#else +#if ARDUINOJSON_ENABLE_ALIGNMENT const size_t x = sizeof(void *) - 1; return (bytes + x) & ~x; +#else + return bytes; #endif } diff --git a/include/ArduinoJson/JsonObject.hpp b/include/ArduinoJson/JsonObject.hpp index f263f487..9742269a 100644 --- a/include/ArduinoJson/JsonObject.hpp +++ b/include/ArduinoJson/JsonObject.hpp @@ -13,6 +13,10 @@ #include "Internals/List.hpp" #include "Internals/ReferenceType.hpp" #include "JsonPair.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. // Can be very handy to determine the size of a StaticJsonBuffer. @@ -36,6 +40,15 @@ 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(). @@ -50,43 +63,40 @@ class JsonObject : public Internals::JsonPrintable, FORCE_INLINE JsonVariant operator[](JsonObjectKey key) const; // Sets the specified key with the specified value. - FORCE_INLINE bool set(const char* key, bool value); - FORCE_INLINE bool set(const char* key, float value, uint8_t decimals = 2); - FORCE_INLINE bool set(const char* key, double value, uint8_t decimals = 2); - FORCE_INLINE bool set(const char* key, signed char value); - FORCE_INLINE bool set(const char* key, signed long value); - FORCE_INLINE bool set(const char* key, signed int value); - FORCE_INLINE bool set(const char* key, signed short value); - FORCE_INLINE bool set(const char* key, unsigned char value); - FORCE_INLINE bool set(const char* key, unsigned long value); - FORCE_INLINE bool set(const char* key, unsigned int value); - FORCE_INLINE bool set(const char* key, unsigned short value); - FORCE_INLINE bool set(const char* key, const char* value); - FORCE_INLINE bool set(const char* key, const String& value); - FORCE_INLINE bool set(const char* key, JsonArray& array); - FORCE_INLINE bool set(const char* key, JsonObject& object); - FORCE_INLINE bool set(const char* key, const JsonVariant& value); + // bool set(TKey key, bool value); + // bool set(TKey key, char value); + // bool set(TKey key, long value); + // bool set(TKey key, int value); + // bool set(TKey key, short value); + // bool set(TKey key, float value); + // bool set(TKey key, double value); + // bool set(TKey key, const char* value); template - FORCE_INLINE bool set(const char* key, const T& value); - - FORCE_INLINE bool set(const String& key, bool value); - FORCE_INLINE bool set(const String& key, float value, uint8_t decimals = 2); - FORCE_INLINE bool set(const String& key, double value, uint8_t decimals = 2); - FORCE_INLINE bool set(const String& key, signed char value); - FORCE_INLINE bool set(const String& key, signed long value); - FORCE_INLINE bool set(const String& key, signed int value); - FORCE_INLINE bool set(const String& key, signed short value); - FORCE_INLINE bool set(const String& key, unsigned char value); - FORCE_INLINE bool set(const String& key, unsigned long value); - FORCE_INLINE bool set(const String& key, unsigned int value); - FORCE_INLINE bool set(const String& key, unsigned short value); - FORCE_INLINE bool set(const String& key, const char* value); - FORCE_INLINE bool set(const String& key, const String& value); - FORCE_INLINE bool set(const String& key, JsonArray& array); - FORCE_INLINE bool set(const String& key, JsonObject& object); - FORCE_INLINE bool set(const String& key, const JsonVariant& value); + FORCE_INLINE 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 - FORCE_INLINE bool set(const String& key, const T& value); + FORCE_INLINE bool set( + JsonObjectKey key, const T& value, + typename TypeTraits::EnableIf::value>::type* = 0) { + return setNodeAt(key, const_cast(value)); + } + // bool set(Key, float value, uint8_t decimals); + // bool set(Key, double value, uint8_t decimals); + template + FORCE_INLINE bool set( + JsonObjectKey key, TValue value, uint8_t decimals, + typename TypeTraits::EnableIf< + TypeTraits::IsFloatingPoint::value>::type* = 0) { + return setNodeAt(key, JsonVariant(value, decimals)); + } // Gets the value associated with the specified key. FORCE_INLINE JsonVariant get(JsonObjectKey) const; @@ -101,13 +111,11 @@ class JsonObject : public Internals::JsonPrintable, // Creates and adds a JsonArray. // This is a shortcut for JsonBuffer::createArray() and JsonObject::add(). - FORCE_INLINE JsonArray& createNestedArray(const char* key); - FORCE_INLINE JsonArray& createNestedArray(const String& key); + FORCE_INLINE JsonArray& createNestedArray(JsonObjectKey key); // Creates and adds a JsonObject. // This is a shortcut for JsonBuffer::createObject() and JsonObject::add(). - FORCE_INLINE JsonObject& createNestedObject(const char* key); - FORCE_INLINE JsonObject& createNestedObject(const String& key); + FORCE_INLINE JsonObject& createNestedObject(JsonObjectKey key); // Tells weither the specified key is present and associated with a value. FORCE_INLINE bool containsKey(JsonObjectKey key) const; @@ -125,24 +133,17 @@ class JsonObject : public Internals::JsonPrintable, private: // Returns the list node that matches the specified key. - node_type* getNodeAt(JsonObjectKey key) const; + node_type* getNodeAt(const char* key) const; - node_type* getOrCreateNodeAt(JsonObjectKey key); - - template - FORCE_INLINE bool setNodeAt(TKey key, TValue value); - - template - JsonArray& createArrayAt(TKey key); - - template - JsonObject& createObjectAt(TKey key); + node_type* getOrCreateNodeAt(const char* key); template - FORCE_INLINE void setNodeKey(node_type*, T key); + FORCE_INLINE bool setNodeAt(JsonObjectKey key, T value); + + FORCE_INLINE bool setNodeKey(node_type*, JsonObjectKey key); template - FORCE_INLINE void setNodeValue(node_type*, T value); + FORCE_INLINE bool setNodeValue(node_type*, T value); // The instance returned by JsonObject::invalid() static JsonObject _invalid; diff --git a/include/ArduinoJson/JsonObject.ipp b/include/ArduinoJson/JsonObject.ipp index 35643e75..094656c5 100644 --- a/include/ArduinoJson/JsonObject.ipp +++ b/include/ArduinoJson/JsonObject.ipp @@ -7,25 +7,26 @@ #pragma once +#include "JsonArray.hpp" #include "JsonObject.hpp" #include "JsonObjectSubscript.hpp" namespace ArduinoJson { inline JsonVariant JsonObject::get(JsonObjectKey key) const { - node_type *node = getNodeAt(key); + node_type *node = getNodeAt(key.c_str()); return node ? node->content.value : JsonVariant(); } template inline T JsonObject::get(JsonObjectKey key) const { - node_type *node = getNodeAt(key); + node_type *node = getNodeAt(key.c_str()); return node ? node->content.value.as() : JsonVariant::invalid(); } template inline bool JsonObject::is(JsonObjectKey key) const { - node_type *node = getNodeAt(key); + node_type *node = getNodeAt(key.c_str()); return node ? node->content.value.is() : false; } @@ -44,165 +45,46 @@ inline JsonVariant JsonObject::operator[](JsonObjectKey key) const { } inline bool JsonObject::containsKey(JsonObjectKey key) const { - return getNodeAt(key) != NULL; -} - -inline JsonArray &JsonObject::createNestedArray(const char *key) { - return createArrayAt(key); -} - -inline JsonArray &JsonObject::createNestedArray(const String &key) { - return createArrayAt(key); -} - -inline JsonObject &JsonObject::createNestedObject(const char *key) { - return createObjectAt(key); -} - -inline JsonObject &JsonObject::createNestedObject(const String &key) { - return createObjectAt(key); + return getNodeAt(key.c_str()) != NULL; } inline void JsonObject::remove(JsonObjectKey key) { - removeNode(getNodeAt(key)); + removeNode(getNodeAt(key.c_str())); } -inline bool JsonObject::set(const char *key, bool value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, float value, uint8_t decimals) { - return setNodeAt( - key, JsonVariant(value, decimals)); -} -inline bool JsonObject::set(const char *key, double value, uint8_t decimals) { - return setNodeAt( - key, JsonVariant(value, decimals)); -} -inline bool JsonObject::set(const char *key, signed char value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, signed long value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, signed int value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, signed short value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, unsigned char value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, unsigned long value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, unsigned int value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, unsigned short value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, const char *value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, const String &value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const char *key, JsonArray &array) { - return setNodeAt(key, array); -} -inline bool JsonObject::set(const char *key, JsonObject &object) { - return setNodeAt(key, object); -} -inline bool JsonObject::set(const char *key, const JsonVariant &value) { - return setNodeAt(key, value); -} template -inline bool JsonObject::set(const char *key, const T &value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, bool value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, float value, uint8_t decimals) { - return setNodeAt( - key, JsonVariant(value, decimals)); -} -inline bool JsonObject::set(const String &key, double value, uint8_t decimals) { - return setNodeAt( - key, JsonVariant(value, decimals)); -} -inline bool JsonObject::set(const String &key, signed char value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, signed long value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, signed int value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, signed short value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, unsigned char value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, unsigned long value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, unsigned int value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, unsigned short value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, const char *value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, const String &value) { - return setNodeAt(key, value); -} -inline bool JsonObject::set(const String &key, JsonArray &array) { - return setNodeAt(key, array); -} -inline bool JsonObject::set(const String &key, JsonObject &object) { - return setNodeAt(key, object); -} -inline bool JsonObject::set(const String &key, const JsonVariant &value) { - return setNodeAt(key, value); -} -template -inline bool JsonObject::set(const String &key, const T &value) { - return setNodeAt(key, value); +inline bool JsonObject::setNodeAt(JsonObjectKey key, T value) { + node_type *node = getNodeAt(key.c_str()); + if (!node) node = addNewNode(); + return node && setNodeKey(node, key) && setNodeValue(node, value); } -template -inline bool JsonObject::setNodeAt(TKey key, TValue value) { - node_type *node = getOrCreateNodeAt(key); - if (!node) return false; - setNodeKey(node, key); - setNodeValue(node, value); +inline bool JsonObject::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(); + } + return true; +} + +template +inline bool JsonObject::setNodeValue(node_type *node, TValue value) { + node->content.value = value; return true; } template <> -inline void JsonObject::setNodeKey(node_type *node, const char *key) { - node->content.key = key; -} - -template <> -inline void JsonObject::setNodeKey(node_type *node, const String &key) { - node->content.key = _buffer->strdup(key); -} - -template -inline void JsonObject::setNodeValue(node_type *node, TValue value) { - node->content.value = value; -} - -template <> -inline void JsonObject::setNodeValue(node_type *node, const String &value) { +inline bool JsonObject::setNodeValue(node_type *node, String &value) { node->content.value = _buffer->strdup(value); + return node->content.value; +} + +template <> +inline bool JsonObject::setNodeValue(node_type *node, const String &value) { + node->content.value = _buffer->strdup(value); + return node->content.value; } template @@ -227,15 +109,22 @@ inline JsonObject &JsonVariant::invalid() { return JsonObject::invalid(); } -template <> -inline JsonObject &JsonVariant::as() const { +inline JsonObject &JsonVariant::asObject() const { if (_type == Internals::JSON_OBJECT) return *_content.asObject; return JsonObject::invalid(); } -template <> -inline const JsonObject &JsonVariant::as() const { - if (_type == Internals::JSON_OBJECT) return *_content.asObject; - return JsonObject::invalid(); +inline JsonObject &JsonObject::createNestedObject(JsonObjectKey key) { + if (!_buffer) return JsonObject::invalid(); + JsonObject &array = _buffer->createObject(); + setNodeAt(key, array); + return array; +} + +inline JsonObject &JsonArray::createNestedObject() { + if (!_buffer) return JsonObject::invalid(); + JsonObject &object = _buffer->createObject(); + add(object); + return object; } } diff --git a/include/ArduinoJson/JsonObjectKey.hpp b/include/ArduinoJson/JsonObjectKey.hpp index b73573da..22876aff 100644 --- a/include/ArduinoJson/JsonObjectKey.hpp +++ b/include/ArduinoJson/JsonObjectKey.hpp @@ -11,15 +11,17 @@ namespace ArduinoJson { +// Represents a key in a JsonObject class JsonObjectKey { public: - JsonObjectKey() {} - JsonObjectKey(const char* key) : _data(key) {} - JsonObjectKey(const String& key) : _data(key.c_str()) {} + JsonObjectKey(const char* key) : _value(key), _needs_copy(false) {} + JsonObjectKey(const String& key) : _value(key.c_str()), _needs_copy(true) {} - operator const char*() const { return _data; } + const char* c_str() const { return _value; } + bool needs_copy() const { return _needs_copy; } private: - const char* _data; + const char* _value; + bool _needs_copy; }; } diff --git a/include/ArduinoJson/JsonObjectSubscript.hpp b/include/ArduinoJson/JsonObjectSubscript.hpp index f46a86b6..3916a917 100644 --- a/include/ArduinoJson/JsonObjectSubscript.hpp +++ b/include/ArduinoJson/JsonObjectSubscript.hpp @@ -7,7 +7,9 @@ #pragma once -#include "JsonSubscriptBase.hpp" +#include "Configuration.hpp" +#include "JsonVariantBase.hpp" +#include "TypeTraits/EnableIf.hpp" #ifdef _MSC_VER #pragma warning(push) @@ -17,23 +19,30 @@ namespace ArduinoJson { template -class JsonObjectSubscript - : public JsonSubscriptBase > { +class JsonObjectSubscript : public JsonVariantBase > { public: FORCE_INLINE JsonObjectSubscript(JsonObject& object, TKey key) : _object(object), _key(key) {} - using JsonSubscriptBase >::operator=; - JsonObjectSubscript& operator=(const JsonObjectSubscript& src) { - return JsonSubscriptBase >::template assign< - JsonVariant>(src); + _object.set(_key, src); + return *this; } template - JsonObjectSubscript& operator=(const T& src) { - return JsonSubscriptBase >::template assign< - JsonVariant>(src); + 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); + return *this; } FORCE_INLINE bool success() const { return _object.containsKey(_key); } @@ -52,7 +61,7 @@ class JsonObjectSubscript template FORCE_INLINE bool set(TValue value) { - return _object.set(_key, value); + return _object.set(_key, value); } template @@ -71,7 +80,7 @@ class JsonObjectSubscript TKey _key; }; -#ifdef ARDUINOJSON_ENABLE_STD_STREAM +#if ARDUINOJSON_ENABLE_STD_STREAM inline std::ostream& operator<<( std::ostream& os, const JsonObjectSubscript& source) { return source.printTo(os); @@ -82,6 +91,7 @@ inline std::ostream& operator<<( return source.printTo(os); } #endif + } // namespace ArduinoJson #ifdef _MSC_VER diff --git a/include/ArduinoJson/JsonPair.hpp b/include/ArduinoJson/JsonPair.hpp index 38b9ed6b..4a201721 100644 --- a/include/ArduinoJson/JsonPair.hpp +++ b/include/ArduinoJson/JsonPair.hpp @@ -14,7 +14,7 @@ namespace ArduinoJson { // A key value pair for JsonObject. struct JsonPair { - JsonObjectKey key; + const char* key; JsonVariant value; }; } diff --git a/include/ArduinoJson/JsonSubscriptBase.hpp b/include/ArduinoJson/JsonSubscriptBase.hpp deleted file mode 100644 index 595d14ca..00000000 --- a/include/ArduinoJson/JsonSubscriptBase.hpp +++ /dev/null @@ -1,83 +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 "JsonVariantBase.hpp" - -namespace ArduinoJson { - -template -class JsonSubscriptBase : public JsonVariantBase { - public: - FORCE_INLINE TImpl& operator=(bool value) { return assign(value); } - - FORCE_INLINE TImpl& operator=(float value) { return assign(value); } - - FORCE_INLINE TImpl& operator=(double value) { return assign(value); } - - FORCE_INLINE TImpl& operator=(signed char value) { - return assign(value); - } - - FORCE_INLINE TImpl& operator=(signed long value) { - return assign(value); - } - - FORCE_INLINE TImpl& operator=(signed int value) { - return assign(value); - } - - FORCE_INLINE TImpl& operator=(signed short value) { - return assign(value); - } - - FORCE_INLINE TImpl& operator=(unsigned char value) { - return assign(value); - } - - FORCE_INLINE TImpl& operator=(unsigned long value) { - return assign(value); - } - - FORCE_INLINE TImpl& operator=(unsigned int value) { - return assign(value); - } - - FORCE_INLINE TImpl& operator=(unsigned short value) { - return assign(value); - } - - FORCE_INLINE TImpl& operator=(const char* value) { - return assign(value); - } - - FORCE_INLINE TImpl& operator=(const String& value) { - return assign(value); - } - - FORCE_INLINE TImpl& operator=(JsonArray& array) { - return assign(array); - } - - FORCE_INLINE TImpl& operator=(JsonObject& object) { - return assign(object); - } - - FORCE_INLINE TImpl& operator=(JsonVariant value) { - return assign(value); - } - - protected: - template - FORCE_INLINE TImpl& assign(TValue value) { - TImpl* that = static_cast(this); - that->template set(value); - return *that; - } -}; -} diff --git a/include/ArduinoJson/JsonVariant.hpp b/include/ArduinoJson/JsonVariant.hpp index d110f59c..6edc25f0 100644 --- a/include/ArduinoJson/JsonVariant.hpp +++ b/include/ArduinoJson/JsonVariant.hpp @@ -15,6 +15,12 @@ #include "Internals/JsonVariantType.hpp" #include "Internals/Unparsed.hpp" #include "JsonVariantBase.hpp" +#include "TypeTraits/EnableIf.hpp" +#include "TypeTraits/IsFloatingPoint.hpp" +#include "TypeTraits/IsIntegral.hpp" +#include "TypeTraits/IsSame.hpp" +#include "TypeTraits/RemoveConst.hpp" +#include "TypeTraits/RemoveReference.hpp" namespace ArduinoJson { @@ -31,6 +37,9 @@ class JsonObject; // - a reference to a JsonArray or JsonObject class JsonVariant : public JsonVariantBase { public: + template + struct IsConstructibleFrom; + // Creates an uninitialized JsonVariant FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {} @@ -41,18 +50,31 @@ class JsonVariant : public JsonVariantBase { // Create a JsonVariant containing a floating point value. // The second argument specifies the number of decimal digits to write in // the JSON string. - FORCE_INLINE JsonVariant(float value, uint8_t decimals = 2); - FORCE_INLINE JsonVariant(double value, uint8_t decimals = 2); + // JsonVariant(double value, uint8_t decimals); + // JsonVariant(float value, uint8_t decimals); + template + FORCE_INLINE JsonVariant( + T value, uint8_t decimals = 2, + typename TypeTraits::EnableIf::value>::type + * = 0) { + using namespace Internals; + _type = static_cast(JSON_FLOAT_0_DECIMALS + decimals); + _content.asFloat = static_cast(value); + } // Create a JsonVariant containing an integer value. - FORCE_INLINE JsonVariant(signed char value); - FORCE_INLINE JsonVariant(signed long value); - FORCE_INLINE JsonVariant(signed int value); - FORCE_INLINE JsonVariant(signed short value); - FORCE_INLINE JsonVariant(unsigned char value); - FORCE_INLINE JsonVariant(unsigned long value); - FORCE_INLINE JsonVariant(unsigned int value); - FORCE_INLINE JsonVariant(unsigned short value); + // JsonVariant(short) + // JsonVariant(int) + // JsonVariant(long) + template + FORCE_INLINE JsonVariant( + T value, + typename TypeTraits::EnableIf::value>::type * = + 0) { + using namespace Internals; + _type = JSON_INTEGER; + _content.asInteger = static_cast(value); + } // Create a JsonVariant containing a string. FORCE_INLINE JsonVariant(const char *value); @@ -67,9 +89,70 @@ class JsonVariant : public JsonVariantBase { FORCE_INLINE JsonVariant(JsonObject &object); // Get the variant as the specified type. - // See cast operators for details. + // short as() const; + // int as() const; + // long as() const; template - T as() const; + const typename TypeTraits::EnableIf::value, T>::type + as() const { + return static_cast(asInteger()); + } + // double as() const; + // float as() const; + template + const typename TypeTraits::EnableIf::value, + T>::type + as() const { + 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 + typename TypeTraits::EnableIf::value, + const char *>::type + as() const { + return asString(); + } + // const bool as() const + template + const typename TypeTraits::EnableIf::value, + T>::type + as() const { + return asInteger() != 0; + } + // JsonArray& as const; + // JsonArray& as const; + // JsonArray& as const; + template + typename TypeTraits::EnableIf< + TypeTraits::IsSame< + typename TypeTraits::RemoveConst< + typename TypeTraits::RemoveReference::type>::type, + JsonArray>::value, + JsonArray &>::type + as() const { + return asArray(); + } + // JsonObject& as const; + // JsonObject& as const; + // JsonObject& as const; + template + typename TypeTraits::EnableIf< + TypeTraits::IsSame< + typename TypeTraits::RemoveConst< + typename TypeTraits::RemoveReference::type>::type, + JsonObject>::value, + JsonObject &>::type + as() const { + return asObject(); + } // Tells weither the variant has the specified type. // Returns true if the variant has type type T, false otherwise. @@ -83,7 +166,12 @@ class JsonVariant : public JsonVariantBase { template static T invalid(); + const char *asString() const; + JsonArray &asArray() const; + JsonObject &asObject() const; + private: + String toString() const; Internals::JsonFloat asFloat() const; Internals::JsonInteger asInteger() const; @@ -101,6 +189,28 @@ 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; +}; } // Include inline implementations diff --git a/include/ArduinoJson/JsonVariant.ipp b/include/ArduinoJson/JsonVariant.ipp index 436cc795..e8582007 100644 --- a/include/ArduinoJson/JsonVariant.ipp +++ b/include/ArduinoJson/JsonVariant.ipp @@ -7,7 +7,11 @@ #pragma once +#include "Configuration.hpp" #include "JsonVariant.hpp" +#include "Internals/Parse.hpp" + +#include namespace ArduinoJson { @@ -27,18 +31,6 @@ inline JsonVariant::JsonVariant(Internals::Unparsed value) { _content.asString = value; } -inline JsonVariant::JsonVariant(double value, uint8_t decimals) { - using namespace Internals; - _type = static_cast(JSON_FLOAT_0_DECIMALS + decimals); - _content.asFloat = static_cast(value); -} - -inline JsonVariant::JsonVariant(float value, uint8_t decimals) { - using namespace Internals; - _type = static_cast(JSON_FLOAT_0_DECIMALS + decimals); - _content.asFloat = static_cast(value); -} - inline JsonVariant::JsonVariant(JsonArray &array) { _type = Internals::JSON_ARRAY; _content.asArray = &array; @@ -49,115 +41,6 @@ inline JsonVariant::JsonVariant(JsonObject &object) { _content.asObject = &object; } -inline JsonVariant::JsonVariant(signed char value) { - using namespace Internals; - _type = JSON_INTEGER; - _content.asInteger = static_cast(value); -} - -inline JsonVariant::JsonVariant(signed int value) { - using namespace Internals; - _type = JSON_INTEGER; - _content.asInteger = static_cast(value); -} - -inline JsonVariant::JsonVariant(signed long value) { - using namespace Internals; - _type = JSON_INTEGER; - _content.asInteger = static_cast(value); -} - -inline JsonVariant::JsonVariant(signed short value) { - using namespace Internals; - _type = JSON_INTEGER; - _content.asInteger = static_cast(value); -} - -inline JsonVariant::JsonVariant(unsigned char value) { - using namespace Internals; - _type = JSON_INTEGER; - _content.asInteger = static_cast(value); -} - -inline JsonVariant::JsonVariant(unsigned int value) { - using namespace Internals; - _type = JSON_INTEGER; - _content.asInteger = static_cast(value); -} - -inline JsonVariant::JsonVariant(unsigned long value) { - using namespace Internals; - _type = JSON_INTEGER; - _content.asInteger = static_cast(value); -} - -inline JsonVariant::JsonVariant(unsigned short value) { - using namespace Internals; - _type = JSON_INTEGER; - _content.asInteger = static_cast(value); -} - -template <> -String JsonVariant::as() const; - -template <> -const char *JsonVariant::as() const; - -template <> -inline bool JsonVariant::as() const { - return asInteger() != 0; -} - -template <> -inline signed char JsonVariant::as() const { - return static_cast(asInteger()); -} - -template <> -inline unsigned char JsonVariant::as() const { - return static_cast(asInteger()); -} - -template <> -inline signed short JsonVariant::as() const { - return static_cast(asInteger()); -} - -template <> -inline unsigned short JsonVariant::as() const { - return static_cast(asInteger()); -} - -template <> -inline signed int JsonVariant::as() const { - return static_cast(asInteger()); -} - -template <> -inline unsigned int JsonVariant::as() const { - return static_cast(asInteger()); -} - -template <> -inline unsigned long JsonVariant::as() const { - return static_cast(asInteger()); -} - -template <> -inline signed long JsonVariant::as() const { - return static_cast(asInteger()); -} - -template <> -inline double JsonVariant::as() const { - return static_cast(asFloat()); -} - -template <> -inline float JsonVariant::as() const { - return static_cast(asFloat()); -} - template inline T JsonVariant::invalid() { return T(); @@ -242,7 +125,23 @@ inline bool JsonVariant::is() const { return is(); } -#ifdef ARDUINOJSON_ENABLE_STD_STREAM +inline Internals::JsonInteger JsonVariant::asInteger() const { + if (_type == Internals::JSON_INTEGER || _type == Internals::JSON_BOOLEAN) + return _content.asInteger; + + if (_type >= Internals::JSON_FLOAT_0_DECIMALS) + return static_cast(_content.asFloat); + + if ((_type == Internals::JSON_STRING || _type == Internals::JSON_UNPARSED) && + _content.asString) { + if (!strcmp("true", _content.asString)) return 1; + return Internals::parse(_content.asString); + } + + return 0L; +} + +#if ARDUINOJSON_ENABLE_STD_STREAM inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) { return source.printTo(os); } diff --git a/include/ArduinoJson/JsonVariantBase.hpp b/include/ArduinoJson/JsonVariantBase.hpp index 95f328e1..b8b6c393 100644 --- a/include/ArduinoJson/JsonVariantBase.hpp +++ b/include/ArduinoJson/JsonVariantBase.hpp @@ -20,31 +20,7 @@ class JsonObjectSubscript; template class JsonVariantBase : public Internals::JsonPrintable { public: - // Gets the variant as a boolean value. - // Returns false if the variant is not a boolean value. - FORCE_INLINE operator bool() const { return as(); } - - // Gets the variant as a floating-point value. - // Returns 0.0 if the variant is not a floating-point value - FORCE_INLINE operator double() const { return as(); } - FORCE_INLINE operator float() const { return as(); } - - // Gets the variant as an integer value. - // Returns 0 if the variant is not an integer value. - FORCE_INLINE operator signed long() const { return as(); } - FORCE_INLINE operator signed char() const { return as(); } - FORCE_INLINE operator signed int() const { return as(); } - FORCE_INLINE operator signed short() const { return as(); } - FORCE_INLINE operator unsigned char() const { return as(); } - FORCE_INLINE operator unsigned int() const { return as(); } - FORCE_INLINE operator unsigned long() const { return as(); } - FORCE_INLINE operator unsigned short() const { return as(); } - - // Gets the variant as a string. - // Returns NULL if variant is not a string. - FORCE_INLINE operator const char *() const { return as(); } FORCE_INLINE const char *asString() const { return as(); } - FORCE_INLINE operator String() const { return as(); } // Gets the variant as an array. // Returns a reference to the JsonArray or JsonArray::invalid() if the @@ -59,6 +35,11 @@ class JsonVariantBase : public Internals::JsonPrintable { FORCE_INLINE operator JsonObject &() const { return as(); } FORCE_INLINE JsonObject &asObject() const { return as(); } + template + FORCE_INLINE operator T() const { + return as(); + } + template FORCE_INLINE const T as() const { return impl()->template as(); diff --git a/include/ArduinoJson/TypeTraits/EnableIf.hpp b/include/ArduinoJson/TypeTraits/EnableIf.hpp new file mode 100644 index 00000000..cedbbf46 --- /dev/null +++ b/include/ArduinoJson/TypeTraits/EnableIf.hpp @@ -0,0 +1,22 @@ +// 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 if Condition is true. +template +struct EnableIf {}; + +template +struct EnableIf { + typedef T type; +}; +} +} diff --git a/include/ArduinoJson/TypeTraits/IsFloatingPoint.hpp b/include/ArduinoJson/TypeTraits/IsFloatingPoint.hpp new file mode 100644 index 00000000..c9fe764d --- /dev/null +++ b/include/ArduinoJson/TypeTraits/IsFloatingPoint.hpp @@ -0,0 +1,21 @@ +// 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 "IsSame.hpp" + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that returns true if T is a floating point type +template +struct IsFloatingPoint { + static const bool value = IsSame::value || IsSame::value; +}; +} +} diff --git a/include/ArduinoJson/TypeTraits/IsIntegral.hpp b/include/ArduinoJson/TypeTraits/IsIntegral.hpp new file mode 100644 index 00000000..53183d5c --- /dev/null +++ b/include/ArduinoJson/TypeTraits/IsIntegral.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 "../Configuration.hpp" +#include "IsSame.hpp" + +#include + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that returns true if T is an integral type. +template +struct IsIntegral { + static const bool 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 || +#if ARDUINOJSON_USE_LONG_LONG + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || +#endif + +#if ARDUINOJSON_USE_INT64 + TypeTraits::IsSame::value || + TypeTraits::IsSame::value || +#endif + TypeTraits::IsSame::value; +}; +} +} diff --git a/include/ArduinoJson/TypeTraits/IsReference.hpp b/include/ArduinoJson/TypeTraits/IsReference.hpp new file mode 100644 index 00000000..51923fea --- /dev/null +++ b/include/ArduinoJson/TypeTraits/IsReference.hpp @@ -0,0 +1,24 @@ +// 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 returns true if T is a reference +template +struct IsReference { + static const bool value = false; +}; + +template +struct IsReference { + static const bool value = true; +}; +} +} diff --git a/include/ArduinoJson/TypeTraits/IsSame.hpp b/include/ArduinoJson/TypeTraits/IsSame.hpp new file mode 100644 index 00000000..c28a89c1 --- /dev/null +++ b/include/ArduinoJson/TypeTraits/IsSame.hpp @@ -0,0 +1,24 @@ +// 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 returns true if types T and U are the same. +template +struct IsSame { + static const bool value = false; +}; + +template +struct IsSame { + static const bool value = true; +}; +} +} diff --git a/include/ArduinoJson/TypeTraits/RemoveConst.hpp b/include/ArduinoJson/TypeTraits/RemoveConst.hpp new file mode 100644 index 00000000..1be9dac5 --- /dev/null +++ b/include/ArduinoJson/TypeTraits/RemoveConst.hpp @@ -0,0 +1,23 @@ +// 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 RemoveConst { + typedef T type; +}; +template +struct RemoveConst { + typedef T type; +}; +} +} diff --git a/include/ArduinoJson/TypeTraits/RemoveReference.hpp b/include/ArduinoJson/TypeTraits/RemoveReference.hpp new file mode 100644 index 00000000..f79a2dc0 --- /dev/null +++ b/include/ArduinoJson/TypeTraits/RemoveReference.hpp @@ -0,0 +1,23 @@ +// 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 reference modifier. +template +struct RemoveReference { + typedef T type; +}; +template +struct RemoveReference { + typedef T type; +}; +} +} diff --git a/src/Arduino/Print.cpp b/src/Arduino/Print.cpp deleted file mode 100644 index e1e84eba..00000000 --- a/src/Arduino/Print.cpp +++ /dev/null @@ -1,72 +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! - -#ifndef ARDUINO - -#include "../../include/ArduinoJson/Arduino/Print.hpp" - -#include // for isnan() and isinf() -#include // for sprintf() - -// only for GCC 4.9+ -#if defined(__GNUC__) && \ - (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) -#pragma GCC diagnostic ignored "-Wfloat-conversion" -#endif - -// Visual Studo 2012 didn't have isnan, nor isinf -#if defined(_MSC_VER) && _MSC_VER <= 1700 -#include -#define isnan(x) _isnan(x) -#define isinf(x) (!_finite(x)) -#endif - -size_t Print::print(const char s[]) { - size_t n = 0; - while (*s) { - n += write(*s++); - } - return n; -} - -size_t Print::print(double value, int digits) { - // https://github.com/arduino/Arduino/blob/db8cbf24c99dc930b9ccff1a43d018c81f178535/hardware/arduino/sam/cores/arduino/Print.cpp#L218 - if (isnan(value)) return print("nan"); - if (isinf(value)) return print("inf"); - - char tmp[32]; - - // https://github.com/arduino/Arduino/blob/db8cbf24c99dc930b9ccff1a43d018c81f178535/hardware/arduino/sam/cores/arduino/Print.cpp#L220 - bool isBigDouble = value > 4294967040.0 || value < -4294967040.0; - - if (isBigDouble) { - // Arduino's implementation prints "ovf" - // We prefer trying to use scientific notation, since we have sprintf - sprintf(tmp, "%g", value); - } else { - // Here we have the exact same output as Arduino's implementation - sprintf(tmp, "%.*f", digits, value); - } - - return print(tmp); -} - -size_t Print::print(long value) { - char tmp[32]; - sprintf(tmp, "%ld", value); - return print(tmp); -} - -size_t Print::print(int value) { - char tmp[32]; - sprintf(tmp, "%d", value); - return print(tmp); -} - -size_t Print::println() { return write('\r') + write('\n'); } - -#endif diff --git a/src/JsonArray.cpp b/src/JsonArray.cpp index 276e66b9..751619c9 100644 --- a/src/JsonArray.cpp +++ b/src/JsonArray.cpp @@ -21,20 +21,6 @@ JsonArray::node_type *JsonArray::getNodeAt(size_t index) const { return node; } -JsonArray &JsonArray::createNestedArray() { - if (!_buffer) return JsonArray::invalid(); - JsonArray &array = _buffer->createArray(); - add(array); - return array; -} - -JsonObject &JsonArray::createNestedObject() { - if (!_buffer) return JsonObject::invalid(); - JsonObject &object = _buffer->createObject(); - add(object); - return object; -} - void JsonArray::removeAt(size_t index) { removeNode(getNodeAt(index)); } void JsonArray::writeTo(JsonWriter &writer) const { diff --git a/src/JsonObject.cpp b/src/JsonObject.cpp index 6a111239..afa939c8 100644 --- a/src/JsonObject.cpp +++ b/src/JsonObject.cpp @@ -18,35 +18,7 @@ using namespace ArduinoJson::Internals; JsonObject JsonObject::_invalid(NULL); -JsonObject::node_type *JsonObject::getOrCreateNodeAt(JsonObjectKey key) { - node_type *existingNode = getNodeAt(key); - if (existingNode) return existingNode; - - node_type *newNode = addNewNode(); - return newNode; -} - -template -JsonArray &JsonObject::createArrayAt(TKey key) { - if (!_buffer) return JsonArray::invalid(); - JsonArray &array = _buffer->createArray(); - setNodeAt(key, array); - return array; -} -template JsonArray &JsonObject::createArrayAt(const char *); -template JsonArray &JsonObject::createArrayAt(const String &); - -template -JsonObject &JsonObject::createObjectAt(TKey key) { - if (!_buffer) return JsonObject::invalid(); - JsonObject &array = _buffer->createObject(); - setNodeAt(key, array); - return array; -} -template JsonObject &JsonObject::createObjectAt(const char *); -template JsonObject &JsonObject::createObjectAt(const String &); - -JsonObject::node_type *JsonObject::getNodeAt(JsonObjectKey key) const { +JsonObject::node_type *JsonObject::getNodeAt(const char *key) const { for (node_type *node = _firstNode; node; node = node->next) { if (!strcmp(node->content.key, key)) return node; } diff --git a/src/JsonVariant.cpp b/src/JsonVariant.cpp index fec047c0..26f23bb7 100644 --- a/src/JsonVariant.cpp +++ b/src/JsonVariant.cpp @@ -17,31 +17,7 @@ using namespace ArduinoJson::Internals; namespace ArduinoJson { -template -static TFloat parse(const char *); - -template <> -float parse(const char *s) { - return static_cast(strtod(s, NULL)); -} - -template <> -double parse(const char *s) { - return strtod(s, NULL); -} - -template <> -long parse(const char *s) { - return strtol(s, NULL, 10); -} - -template <> -int parse(const char *s) { - return atoi(s); -} - -template <> -const char *JsonVariant::as() const { +const char *JsonVariant::asString() const { if (_type == JSON_UNPARSED && _content.asString && !strcmp("null", _content.asString)) return NULL; @@ -61,22 +37,7 @@ JsonFloat JsonVariant::asFloat() const { return 0.0; } -JsonInteger JsonVariant::asInteger() const { - if (_type == JSON_INTEGER || _type == JSON_BOOLEAN) return _content.asInteger; - - if (_type >= JSON_FLOAT_0_DECIMALS) - return static_cast(_content.asFloat); - - if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString) { - if (!strcmp("true", _content.asString)) return 1; - return parse(_content.asString); - } - - return 0L; -} - -template <> -String JsonVariant::as() const { +String JsonVariant::toString() const { String s; if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString != NULL) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 953c1319..5606dae7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,7 +17,11 @@ add_definitions(-DGTEST_HAS_PTHREAD=0) # Workaround for Visual Studio 2012 if (MSVC AND MSVC_VERSION EQUAL 1700) - add_definitions(-D_VARIADIC_MAX=10) + add_definitions(-D_VARIADIC_MAX=10) +endif() + +if (MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() add_executable(ArduinoJsonTests @@ -25,6 +29,7 @@ add_executable(ArduinoJsonTests ${GTEST_DIR}/src/gtest-all.cc ${GTEST_DIR}/src/gtest_main.cc) + target_link_libraries(ArduinoJsonTests ArduinoJson) add_test(ArduinoJsonTests ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ArduinoJsonTests) diff --git a/test/GbathreeBug.cpp b/test/GbathreeBug.cpp index b17e7843..36e65037 100644 --- a/test/GbathreeBug.cpp +++ b/test/GbathreeBug.cpp @@ -6,7 +6,6 @@ // If you like this project, please add a star! #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include class GbathreeBug : public testing::Test { diff --git a/test/Issue90.cpp b/test/Issue90.cpp index 5ce04879..a6e255e4 100644 --- a/test/Issue90.cpp +++ b/test/Issue90.cpp @@ -7,7 +7,9 @@ #include #include // for LONG_MAX -#define ARDUINOJSON_ENABLE_STD_STREAM + +#define ARDUINOJSON_USE_LONG_LONG 0 +#define ARDUINOJSON_USE_INT64 0 #include #define SUITE Issue90 diff --git a/test/JsonArray_Add_Tests.cpp b/test/JsonArray_Add_Tests.cpp index 3c2b20da..3324e1b8 100644 --- a/test/JsonArray_Add_Tests.cpp +++ b/test/JsonArray_Add_Tests.cpp @@ -6,7 +6,6 @@ // If you like this project, please add a star! #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include class JsonArray_Add_Tests : public ::testing::Test { diff --git a/test/JsonArray_Basic_Tests.cpp b/test/JsonArray_Basic_Tests.cpp index 2a9ab427..71f9a83f 100644 --- a/test/JsonArray_Basic_Tests.cpp +++ b/test/JsonArray_Basic_Tests.cpp @@ -6,7 +6,6 @@ // If you like this project, please add a star! #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include #define TEST_(name) TEST(JsonArray_Basic_Tests, name) diff --git a/test/JsonArray_PrintTo_Tests.cpp b/test/JsonArray_PrintTo_Tests.cpp index 0f936709..39cc431e 100644 --- a/test/JsonArray_PrintTo_Tests.cpp +++ b/test/JsonArray_PrintTo_Tests.cpp @@ -64,10 +64,25 @@ TEST_F(JsonArray_PrintTo_Tests, OneDoubleDefaultDigits) { } TEST_F(JsonArray_PrintTo_Tests, OneDoubleFourDigits) { + array.add(3.14159265358979323846, 4); + outputMustBe("[3.1416]"); +} + +TEST_F(JsonArray_PrintTo_Tests, OneDoubleFourDigits_AlternativeSyntax) { array.add(double_with_n_digits(3.14159265358979323846, 4)); outputMustBe("[3.1416]"); } +TEST_F(JsonArray_PrintTo_Tests, OneFloatDefaultDigits) { + array.add(3.14159f); + outputMustBe("[3.14]"); +} + +TEST_F(JsonArray_PrintTo_Tests, OneFloatFourDigits) { + array.add(3.14159f, 4); + outputMustBe("[3.1416]"); +} + TEST_F(JsonArray_PrintTo_Tests, OneInteger) { array.add(1); diff --git a/test/JsonArray_Set_Tests.cpp b/test/JsonArray_Set_Tests.cpp index 2c550ed2..8535d8d5 100644 --- a/test/JsonArray_Set_Tests.cpp +++ b/test/JsonArray_Set_Tests.cpp @@ -6,7 +6,6 @@ // If you like this project, please add a star! #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include class JsonArray_Set_Tests : public ::testing::Test { diff --git a/test/JsonArray_Subscript_Tests.cpp b/test/JsonArray_Subscript_Tests.cpp index 874fc7ca..e2da2c2d 100644 --- a/test/JsonArray_Subscript_Tests.cpp +++ b/test/JsonArray_Subscript_Tests.cpp @@ -5,9 +5,9 @@ // https://github.com/bblanchon/ArduinoJson // If you like this project, please add a star! -#include -#define ARDUINOJSON_ENABLE_STD_STREAM #include +#include +#include class JsonArray_Subscript_Tests : public ::testing::Test { protected: @@ -33,6 +33,15 @@ TEST_(StoreInteger) { EXPECT_FALSE(_array[0].is()); } +#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 +TEST_(StoreLongLong) { + _array[0] = 9223372036854775807; + EXPECT_EQ(9223372036854775807, _array[0].as()); + EXPECT_TRUE(_array[0].is()); + EXPECT_FALSE(_array[0].is()); +} +#endif + TEST_(StoreDouble) { _array[0] = 123.45; EXPECT_EQ(123.45, _array[0].as()); diff --git a/test/JsonObject_Iterator_Tests.cpp b/test/JsonObject_Iterator_Tests.cpp index cff8f2e6..0d35856e 100644 --- a/test/JsonObject_Iterator_Tests.cpp +++ b/test/JsonObject_Iterator_Tests.cpp @@ -6,7 +6,6 @@ // If you like this project, please add a star! #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include class JsonObject_Iterator_Test : public testing::Test { diff --git a/test/JsonObject_PrintTo_Tests.cpp b/test/JsonObject_PrintTo_Tests.cpp index 2c2f631f..f1188f51 100644 --- a/test/JsonObject_PrintTo_Tests.cpp +++ b/test/JsonObject_PrintTo_Tests.cpp @@ -5,8 +5,8 @@ // https://github.com/bblanchon/ArduinoJson // If you like this project, please add a star! -#include #include +#include using namespace ArduinoJson::Internals; @@ -78,7 +78,8 @@ TEST_F(JsonObject_PrintTo_Tests, TwoIntegers) { TEST_F(JsonObject_PrintTo_Tests, TwoDoublesFourDigits) { _object["a"] = double_with_n_digits(3.14159265358979323846, 4); _object.set("b", 2.71828182845904523536, 4); - outputMustBe("{\"a\":3.1416,\"b\":2.7183}"); + _object.set("c", double_with_n_digits(3.14159265358979323846, 3)); + outputMustBe("{\"a\":3.1416,\"b\":2.7183,\"c\":3.142}"); } TEST_F(JsonObject_PrintTo_Tests, TwoDoubleDefaultDigits) { diff --git a/test/JsonObject_Set_Tests.cpp b/test/JsonObject_Set_Tests.cpp index cb86d7c8..282c5f73 100644 --- a/test/JsonObject_Set_Tests.cpp +++ b/test/JsonObject_Set_Tests.cpp @@ -6,7 +6,6 @@ // If you like this project, please add a star! #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include class JsonObject_Set_Tests : public ::testing::Test { diff --git a/test/JsonObject_Subscript_Tests.cpp b/test/JsonObject_Subscript_Tests.cpp index 0708310a..0a2e8068 100644 --- a/test/JsonObject_Subscript_Tests.cpp +++ b/test/JsonObject_Subscript_Tests.cpp @@ -6,7 +6,6 @@ // If you like this project, please add a star! #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include class JsonObject_Subscript_Tests : public ::testing::Test { diff --git a/test/JsonVariant_As_Tests.cpp b/test/JsonVariant_As_Tests.cpp index 386a0aa4..cc980ba3 100644 --- a/test/JsonVariant_As_Tests.cpp +++ b/test/JsonVariant_As_Tests.cpp @@ -5,10 +5,11 @@ // https://github.com/bblanchon/ArduinoJson // If you like this project, please add a star! -#include -#define ARDUINOJSON_ENABLE_STD_STREAM #include +#include +#include + static const char* null = 0; TEST(JsonVariant_As_Tests, DoubleAsBool) { @@ -136,6 +137,18 @@ TEST(JsonVariant_As_Tests, NumberStringAsLong) { ASSERT_EQ(42L, variant.as()); } +#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 +TEST(JsonVariant_As_Tests, NumberStringAsInt64Negative) { + JsonVariant variant = "-9223372036854775808"; + ASSERT_EQ(-9223372036854775807 - 1, variant.as()); +} + +TEST(JsonVariant_As_Tests, NumberStringAsInt64Positive) { + JsonVariant variant = "9223372036854775807"; + ASSERT_EQ(9223372036854775807, variant.as()); +} +#endif + TEST(JsonVariant_As_Tests, RandomStringAsBool) { JsonVariant variant = "hello"; ASSERT_FALSE(variant.as()); diff --git a/test/JsonVariant_Comparison_Tests.cpp b/test/JsonVariant_Comparison_Tests.cpp index 69cdadbe..3f0cef45 100644 --- a/test/JsonVariant_Comparison_Tests.cpp +++ b/test/JsonVariant_Comparison_Tests.cpp @@ -6,7 +6,6 @@ // If you like this project, please add a star! #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include using namespace ArduinoJson; diff --git a/test/JsonVariant_Is_Tests.cpp b/test/JsonVariant_Is_Tests.cpp index 1d616488..8f9e2b91 100644 --- a/test/JsonVariant_Is_Tests.cpp +++ b/test/JsonVariant_Is_Tests.cpp @@ -6,7 +6,6 @@ // If you like this project, please add a star! #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include #define SUITE JsonVariant_Is_Tests diff --git a/test/JsonVariant_PrintTo_Tests.cpp b/test/JsonVariant_PrintTo_Tests.cpp index ed2ca8a4..ed031159 100644 --- a/test/JsonVariant_PrintTo_Tests.cpp +++ b/test/JsonVariant_PrintTo_Tests.cpp @@ -71,3 +71,15 @@ TEST_F(JsonVariant_PrintTo_Tests, OneFalse) { variant = false; outputMustBe("false"); } + +#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 +TEST_F(JsonVariant_PrintTo_Tests, NegativeInt64) { + variant = -9223372036854775807 - 1; + outputMustBe("-9223372036854775808"); +} + +TEST_F(JsonVariant_PrintTo_Tests, PositiveInt64) { + variant = 9223372036854775807; + outputMustBe("9223372036854775807"); +} +#endif diff --git a/test/JsonVariant_Storage_Tests.cpp b/test/JsonVariant_Storage_Tests.cpp index 86623b65..672ddd94 100644 --- a/test/JsonVariant_Storage_Tests.cpp +++ b/test/JsonVariant_Storage_Tests.cpp @@ -6,40 +6,74 @@ // If you like this project, please add a star! #include +#include +#include #include class JsonVariant_Storage_Tests : public ::testing::Test { protected: template void testValue(T expected) { - _actual = expected; - EXPECT_EQ(expected, _actual.as()); + JsonVariant variant = expected; + EXPECT_EQ(expected, variant.as()); } template void testReference(T &expected) { - _actual = expected; - EXPECT_EQ(expected, _actual.as()); + JsonVariant variant = expected; + EXPECT_EQ(expected, variant.as()); } - private: - JsonVariant _actual; + template + void testNumericType() { + T min = std::numeric_limits::min(); + T max = std::numeric_limits::max(); + + JsonVariant variantMin(min); + JsonVariant variantMax(max); + + EXPECT_EQ(min, variantMin.as()); + EXPECT_EQ(max, variantMax.as()); + } }; -TEST_F(JsonVariant_Storage_Tests, Double) { testValue(123.45); } -TEST_F(JsonVariant_Storage_Tests, False) { testValue(false); } -TEST_F(JsonVariant_Storage_Tests, Float) { testValue(123.45f); } +#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 +TEST_F(JsonVariant_Storage_Tests, SizeOfJsonInteger) { + ASSERT_EQ(8, sizeof(Internals::JsonInteger)); +} +#endif + TEST_F(JsonVariant_Storage_Tests, Null) { testValue(NULL); } -TEST_F(JsonVariant_Storage_Tests, SChar) { testValue(123); } -TEST_F(JsonVariant_Storage_Tests, SInt) { testValue(123); } -TEST_F(JsonVariant_Storage_Tests, SLong) { testValue(123L); } -TEST_F(JsonVariant_Storage_Tests, SShort) { testValue(123); } TEST_F(JsonVariant_Storage_Tests, String) { testValue("hello"); } + +TEST_F(JsonVariant_Storage_Tests, False) { testValue(false); } TEST_F(JsonVariant_Storage_Tests, True) { testValue(true); } -TEST_F(JsonVariant_Storage_Tests, UChar) { testValue(123); } -TEST_F(JsonVariant_Storage_Tests, UInt) { testValue(123U); } -TEST_F(JsonVariant_Storage_Tests, ULong) { testValue(123UL); } -TEST_F(JsonVariant_Storage_Tests, UShort) { testValue(123); } + +TEST_F(JsonVariant_Storage_Tests, Double) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, Float) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, SChar) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, SInt) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, SLong) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, SShort) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, UChar) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, UInt) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, ULong) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, UShort) { testNumericType(); } +#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 +TEST_F(JsonVariant_Storage_Tests, LongLong) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, ULongLong) { testNumericType(); } +#endif + +TEST_F(JsonVariant_Storage_Tests, Int8) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, Uint8) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, Int16) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, Uint16) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, Int32) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, Uint32) { testNumericType(); } +#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64 +TEST_F(JsonVariant_Storage_Tests, Int64) { testNumericType(); } +TEST_F(JsonVariant_Storage_Tests, Uint64) { testNumericType(); } +#endif TEST_F(JsonVariant_Storage_Tests, CanStoreObject) { DynamicJsonBuffer jsonBuffer; diff --git a/test/JsonVariant_Undefined_Tests.cpp b/test/JsonVariant_Undefined_Tests.cpp index 9c49c465..8c0e558d 100644 --- a/test/JsonVariant_Undefined_Tests.cpp +++ b/test/JsonVariant_Undefined_Tests.cpp @@ -6,7 +6,6 @@ // If you like this project, please add a star! #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include class JsonVariant_Undefined_Tests : public ::testing::Test { diff --git a/test/StdStream.cpp b/test/StdStream.cpp index 4414cd0e..90356bfd 100644 --- a/test/StdStream.cpp +++ b/test/StdStream.cpp @@ -7,7 +7,6 @@ #include #include -#define ARDUINOJSON_ENABLE_STD_STREAM #include TEST(StdStream, JsonVariantFalse) {