瀏覽代碼

Added support of `long long` (issue #171)
Moved all build settings to `ArduinoJson/Configuration.hpp`
Added AppVeyor settings in source tree

Benoit Blanchon 10 年之前
父節點
當前提交
8733f95e51
共有 53 個文件被更改,包括 935 次插入859 次删除
  1. 2 1
      .clang-format
  2. 9 0
      CHANGELOG.md
  3. 16 0
      appveyor.yml
  4. 61 5
      include/ArduinoJson/Arduino/Print.hpp
  5. 79 0
      include/ArduinoJson/Configuration.hpp
  6. 5 5
      include/ArduinoJson/Internals/JsonFloat.hpp
  7. 9 0
      include/ArduinoJson/Internals/JsonInteger.hpp
  8. 4 3
      include/ArduinoJson/Internals/JsonPrintable.hpp
  9. 51 0
      include/ArduinoJson/Internals/Parse.hpp
  10. 5 1
      include/ArduinoJson/Internals/StreamPrintAdapter.hpp
  11. 79 34
      include/ArduinoJson/JsonArray.hpp
  12. 24 143
      include/ArduinoJson/JsonArray.ipp
  13. 19 8
      include/ArduinoJson/JsonArraySubscript.hpp
  14. 3 4
      include/ArduinoJson/JsonBuffer.hpp
  15. 53 52
      include/ArduinoJson/JsonObject.hpp
  16. 41 152
      include/ArduinoJson/JsonObject.ipp
  17. 7 5
      include/ArduinoJson/JsonObjectKey.hpp
  18. 22 12
      include/ArduinoJson/JsonObjectSubscript.hpp
  19. 1 1
      include/ArduinoJson/JsonPair.hpp
  20. 0 83
      include/ArduinoJson/JsonSubscriptBase.hpp
  21. 122 12
      include/ArduinoJson/JsonVariant.hpp
  22. 21 122
      include/ArduinoJson/JsonVariant.ipp
  23. 5 24
      include/ArduinoJson/JsonVariantBase.hpp
  24. 22 0
      include/ArduinoJson/TypeTraits/EnableIf.hpp
  25. 21 0
      include/ArduinoJson/TypeTraits/IsFloatingPoint.hpp
  26. 41 0
      include/ArduinoJson/TypeTraits/IsIntegral.hpp
  27. 24 0
      include/ArduinoJson/TypeTraits/IsReference.hpp
  28. 24 0
      include/ArduinoJson/TypeTraits/IsSame.hpp
  29. 23 0
      include/ArduinoJson/TypeTraits/RemoveConst.hpp
  30. 23 0
      include/ArduinoJson/TypeTraits/RemoveReference.hpp
  31. 0 72
      src/Arduino/Print.cpp
  32. 0 14
      src/JsonArray.cpp
  33. 1 29
      src/JsonObject.cpp
  34. 2 41
      src/JsonVariant.cpp
  35. 6 1
      test/CMakeLists.txt
  36. 0 1
      test/GbathreeBug.cpp
  37. 3 1
      test/Issue90.cpp
  38. 0 1
      test/JsonArray_Add_Tests.cpp
  39. 0 1
      test/JsonArray_Basic_Tests.cpp
  40. 15 0
      test/JsonArray_PrintTo_Tests.cpp
  41. 0 1
      test/JsonArray_Set_Tests.cpp
  42. 11 2
      test/JsonArray_Subscript_Tests.cpp
  43. 0 1
      test/JsonObject_Iterator_Tests.cpp
  44. 3 2
      test/JsonObject_PrintTo_Tests.cpp
  45. 0 1
      test/JsonObject_Set_Tests.cpp
  46. 0 1
      test/JsonObject_Subscript_Tests.cpp
  47. 15 2
      test/JsonVariant_As_Tests.cpp
  48. 0 1
      test/JsonVariant_Comparison_Tests.cpp
  49. 0 1
      test/JsonVariant_Is_Tests.cpp
  50. 12 0
      test/JsonVariant_PrintTo_Tests.cpp
  51. 51 17
      test/JsonVariant_Storage_Tests.cpp
  52. 0 1
      test/JsonVariant_Undefined_Tests.cpp
  53. 0 1
      test/StdStream.cpp

+ 2 - 1
.clang-format

@@ -1,3 +1,4 @@
 # http://clang.llvm.org/docs/ClangFormatStyleOptions.html
 
-BasedOnStyle: Google
+BasedOnStyle: Google
+Standard: Cpp03

+ 9 - 0
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
 ------
 

+ 16 - 0
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 . 

+ 61 - 5
include/ArduinoJson/Arduino/Print.hpp

@@ -9,8 +9,19 @@
 
 #ifndef ARDUINO
 
+#include "../Internals/JsonFloat.hpp"
+#include "../Internals/JsonInteger.hpp"
+
 #include <stddef.h>
 #include <stdint.h>
+#include <stdio.h>
+
+#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<char>(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

+ 79 - 0
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

+ 5 - 5
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
 }
 }

+ 9 - 0
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
 }
 }

+ 4 - 3
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<const T *>(this); }
 };
 
-#ifdef ARDUINOJSON_ENABLE_STD_STREAM
+#if ARDUINOJSON_ENABLE_STD_STREAM
 template <typename T>
 inline std::ostream &operator<<(std::ostream &os, const JsonPrintable<T> &v) {
   return v.printTo(os);

+ 51 - 0
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 <stdlib.h>
+
+namespace ArduinoJson {
+namespace Internals {
+template <typename TFloat>
+TFloat parse(const char *);
+
+template <>
+inline float parse<float>(const char *s) {
+  return static_cast<float>(strtod(s, NULL));
+}
+
+template <>
+inline double parse<double>(const char *s) {
+  return strtod(s, NULL);
+}
+
+template <>
+inline long parse<long>(const char *s) {
+  return strtol(s, NULL, 10);
+}
+
+template <>
+inline int parse<int>(const char *s) {
+  return atoi(s);
+}
+
+#if ARDUINOJSON_USE_LONG_LONG
+template <>
+inline long long parse<long long>(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
+}
+}

+ 5 - 1
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 <ostream>
+
 namespace ArduinoJson {
 namespace Internals {
 

+ 79 - 34
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<JsonArray>,
                   public Internals::List<JsonVariant>,
                   public Internals::JsonBufferAllocated {
  public:
+  // A meta-function that returns true if type T can be used in
+  // JsonArray::set()
+  template <typename T>
+  struct CanSet {
+    static const bool value = JsonVariant::IsConstructibleFrom<T>::value ||
+                              TypeTraits::IsSame<T, String &>::value ||
+                              TypeTraits::IsSame<T, const String &>::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<JsonArray>,
   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 <typename T>
+  FORCE_INLINE bool add(
+      T value,
+      typename TypeTraits::EnableIf<
+          CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type * = 0) {
+    return addNode<T>(value);
+  }
+  // bool add(const String&)
+  // bool add(const JsonVariant&);
+  // bool add(JsonArray&);
+  // bool add(JsonObject&);
   template <typename T>
-  FORCE_INLINE bool add(const T &value);
+  FORCE_INLINE bool add(
+      const T &value,
+      typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) {
+    return addNode<T &>(const_cast<T &>(value));
+  }
+  // bool add(float value, uint8_t decimals);
+  // bool add(double value, uint8_t decimals);
+  template <typename T>
+  FORCE_INLINE bool add(
+      T value, uint8_t decimals,
+      typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value>::type
+          * = 0) {
+    return addNode<JsonVariant>(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 <typename T>
+  FORCE_INLINE bool set(
+      size_t index, T value,
+      typename TypeTraits::EnableIf<
+          CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type * = 0) {
+    return setNodeAt<T>(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 <typename T>
+  FORCE_INLINE bool set(
+      size_t index, const T &value,
+      typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) {
+    return setNodeAt<T &>(index, const_cast<T &>(value));
+  }
+  // bool set(size_t index, float value, uint8_t decimals = 2);
+  // bool set(size_t index, double value, uint8_t decimals = 2);
   template <typename T>
-  FORCE_INLINE void set(size_t index, const T &value);
+  FORCE_INLINE bool set(
+      size_t index, T value, uint8_t decimals,
+      typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value>::type
+          * = 0) {
+    return setNodeAt<const JsonVariant &>(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<JsonArray>,
   node_type *getNodeAt(size_t index) const;
 
   template <typename TValue>
-  void setNodeAt(size_t index, TValue value);
+  bool setNodeAt(size_t index, TValue value);
 
   template <typename TValue>
   bool addNode(TValue);
 
   template <typename T>
-  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;

+ 24 - 143
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<bool>(value); }
-
-inline bool JsonArray::add(float value, uint8_t decimals) {
-  return addNode<const JsonVariant &>(JsonVariant(value, decimals));
-}
-
-inline bool JsonArray::add(double value, uint8_t decimals) {
-  return addNode<const JsonVariant &>(JsonVariant(value, decimals));
-}
-
-inline bool JsonArray::add(signed char value) {
-  return addNode<signed char>(value);
-}
-
-inline bool JsonArray::add(signed long value) {
-  return addNode<signed long>(value);
-}
-
-inline bool JsonArray::add(signed int value) {
-  return addNode<signed int>(value);
-}
-
-inline bool JsonArray::add(signed short value) {
-  return addNode<signed short>(value);
-}
-
-inline bool JsonArray::add(unsigned char value) {
-  return addNode<unsigned char>(value);
-}
-
-inline bool JsonArray::add(unsigned long value) {
-  return addNode<unsigned long>(value);
-}
-
-inline bool JsonArray::add(unsigned int value) {
-  return addNode<unsigned int>(value);
-}
-
-inline bool JsonArray::add(unsigned short value) {
-  return addNode<unsigned short>(value);
-}
-
-inline bool JsonArray::add(const char *value) {
-  return addNode<const char *>(value);
-}
-
-inline bool JsonArray::add(const String &value) {
-  return addNode<const String &>(value);
-}
-
-inline bool JsonArray::add(JsonArray &array) {
-  return addNode<JsonArray &>(array);
-}
-
-inline bool JsonArray::add(JsonObject &object) {
-  return addNode<JsonObject &>(object);
-}
-
-template <typename T>
-inline bool JsonArray::add(const T &variant) {
-  return addNode<const JsonVariant &>(variant);
-}
-
 template <typename TValue>
 inline bool JsonArray::addNode(TValue value) {
   node_type *node = addNewNode();
-  if (node == NULL) return false;
-  setNodeValue<TValue>(node, value);
-  return true;
-}
-
-inline void JsonArray::set(size_t index, bool value) {
-  return setNodeAt<bool>(index, value);
-}
-
-inline void JsonArray::set(size_t index, float value, uint8_t decimals) {
-  return setNodeAt<const JsonVariant &>(index, JsonVariant(value, decimals));
-}
-
-inline void JsonArray::set(size_t index, double value, uint8_t decimals) {
-  return setNodeAt<const JsonVariant &>(index, JsonVariant(value, decimals));
-}
-
-inline void JsonArray::set(size_t index, signed char value) {
-  return setNodeAt<signed char>(index, value);
-}
-
-inline void JsonArray::set(size_t index, signed long value) {
-  return setNodeAt<signed long>(index, value);
-}
-
-inline void JsonArray::set(size_t index, signed int value) {
-  return setNodeAt<signed int>(index, value);
-}
-
-inline void JsonArray::set(size_t index, signed short value) {
-  return setNodeAt<signed short>(index, value);
-}
-
-inline void JsonArray::set(size_t index, unsigned char value) {
-  return setNodeAt<unsigned char>(index, value);
-}
-
-inline void JsonArray::set(size_t index, unsigned long value) {
-  return setNodeAt<unsigned long>(index, value);
-}
-
-inline void JsonArray::set(size_t index, unsigned int value) {
-  return setNodeAt<unsigned int>(index, value);
-}
-
-inline void JsonArray::set(size_t index, unsigned short value) {
-  return setNodeAt<unsigned short>(index, value);
-}
-
-inline void JsonArray::set(size_t index, const char *value) {
-  return setNodeAt<const char *>(index, value);
-}
-
-inline void JsonArray::set(size_t index, const String &value) {
-  return setNodeAt<const String &>(index, value);
-}
-
-inline void JsonArray::set(size_t index, JsonArray &array) {
-  return setNodeAt<JsonArray &>(index, array);
-}
-
-inline void JsonArray::set(size_t index, JsonObject &object) {
-  return setNodeAt<JsonObject &>(index, object);
-}
-
-template <typename T>
-inline void JsonArray::set(size_t index, const T &variant) {
-  return setNodeAt<const JsonVariant &>(index, variant);
+  return node != NULL && setNodeValue<TValue>(node, value);
 }
 
 template <typename TValue>
-inline void JsonArray::setNodeAt(size_t index, TValue value) {
+inline bool JsonArray::setNodeAt(size_t index, TValue value) {
   node_type *node = getNodeAt(index);
-  if (node == NULL) return;
-  setNodeValue<TValue>(node, value);
+  return node != NULL && setNodeValue<TValue>(node, value);
 }
 
 template <typename TValue>
-inline void JsonArray::setNodeValue(node_type *node, TValue value) {
+inline bool JsonArray::setNodeValue(node_type *node, TValue value) {
   node->content = value;
+  return true;
 }
 
 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<JsonArray const &>() {
   return JsonArray::invalid();
 }
 
-template <>
-inline JsonArray &JsonVariant::as<JsonArray &>() const {
+inline JsonArray &JsonVariant::asArray() const {
   if (_type == Internals::JSON_ARRAY) return *_content.asArray;
   return JsonArray::invalid();
 }
 
-template <>
-inline const JsonArray &JsonVariant::as<const JsonArray &>() 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<const JsonVariant &>(key, array);
+  return array;
 }
 }

+ 19 - 8
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<JsonArraySubscript> {
+class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
  public:
   FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index)
       : _array(array), _index(index) {}
 
-  using JsonSubscriptBase<JsonArraySubscript>::operator=;
-
   JsonArraySubscript& operator=(const JsonArraySubscript& src) {
-    return assign<const JsonVariant&>(src);
+    _array.set<const JsonVariant&>(_index, src);
+    return *this;
+  }
+
+  template <typename T>
+  typename TypeTraits::EnableIf<JsonArray::CanSet<T&>::value,
+                                JsonArraySubscript>::type&
+  operator=(const T& src) {
+    _array.set<T&>(_index, const_cast<T&>(src));
+    return *this;
   }
 
   template <typename T>
-  JsonArraySubscript& operator=(const T& src) {
-    return assign<const JsonVariant&>(src);
+  typename TypeTraits::EnableIf<JsonArray::CanSet<T>::value,
+                                JsonArraySubscript>::type&
+  operator=(T src) {
+    _array.set<T>(_index, src);
+    return *this;
   }
 
   FORCE_INLINE bool success() const { return _index < _array.size(); }
@@ -59,7 +70,7 @@ class JsonArraySubscript : public JsonSubscriptBase<JsonArraySubscript> {
   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);

+ 3 - 4
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
   }
 

+ 53 - 52
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<JsonObject>,
                    public Internals::List<JsonPair>,
                    public Internals::JsonBufferAllocated {
  public:
+  // A meta-function that returns true if type T can be used in
+  // JsonObject::set()
+  template <typename T>
+  struct CanSet {
+    static const bool value = JsonVariant::IsConstructibleFrom<T>::value ||
+                              TypeTraits::IsSame<T, String&>::value ||
+                              TypeTraits::IsSame<T, const String&>::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<JsonObject>,
   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 <typename T>
-  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<T>::value && !TypeTraits::IsReference<T>::value>::type* = 0) {
+    return setNodeAt<T>(key, value);
+  }
+  // bool set(Key, String&);
+  // bool set(Key, JsonArray&);
+  // bool set(Key, JsonObject&);
+  // bool set(Key, JsonVariant&);
   template <typename T>
-  FORCE_INLINE bool set(const String& key, const T& value);
+  FORCE_INLINE bool set(
+      JsonObjectKey key, const T& value,
+      typename TypeTraits::EnableIf<CanSet<T&>::value>::type* = 0) {
+    return setNodeAt<T&>(key, const_cast<T&>(value));
+  }
+  // bool set(Key, float value, uint8_t decimals);
+  // bool set(Key, double value, uint8_t decimals);
+  template <typename TValue>
+  FORCE_INLINE bool set(
+      JsonObjectKey key, TValue value, uint8_t decimals,
+      typename TypeTraits::EnableIf<
+          TypeTraits::IsFloatingPoint<TValue>::value>::type* = 0) {
+    return setNodeAt<const JsonVariant&>(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<JsonObject>,
 
   // 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<JsonObject>,
 
  private:
   // Returns the list node that matches the specified key.
-  node_type* getNodeAt(JsonObjectKey key) const;
-
-  node_type* getOrCreateNodeAt(JsonObjectKey key);
+  node_type* getNodeAt(const char* key) const;
 
-  template <typename TKey, typename TValue>
-  FORCE_INLINE bool setNodeAt(TKey key, TValue value);
-
-  template <typename TKey>
-  JsonArray& createArrayAt(TKey key);
-
-  template <typename TKey>
-  JsonObject& createObjectAt(TKey key);
+  node_type* getOrCreateNodeAt(const char* key);
 
   template <typename T>
-  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 <typename T>
-  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;

+ 41 - 152
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 <typename T>
 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<T>() : JsonVariant::invalid<T>();
 }
 
 template <typename T>
 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<T>() : 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<const char *>(key);
-}
-
-inline JsonArray &JsonObject::createNestedArray(const String &key) {
-  return createArrayAt<const String &>(key);
-}
-
-inline JsonObject &JsonObject::createNestedObject(const char *key) {
-  return createObjectAt<const char *>(key);
-}
-
-inline JsonObject &JsonObject::createNestedObject(const String &key) {
-  return createObjectAt<const String &>(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<const char *, bool>(key, value);
-}
-inline bool JsonObject::set(const char *key, float value, uint8_t decimals) {
-  return setNodeAt<const char *, const JsonVariant &>(
-      key, JsonVariant(value, decimals));
-}
-inline bool JsonObject::set(const char *key, double value, uint8_t decimals) {
-  return setNodeAt<const char *, const JsonVariant &>(
-      key, JsonVariant(value, decimals));
-}
-inline bool JsonObject::set(const char *key, signed char value) {
-  return setNodeAt<const char *, signed char>(key, value);
-}
-inline bool JsonObject::set(const char *key, signed long value) {
-  return setNodeAt<const char *, signed long>(key, value);
-}
-inline bool JsonObject::set(const char *key, signed int value) {
-  return setNodeAt<const char *, signed int>(key, value);
-}
-inline bool JsonObject::set(const char *key, signed short value) {
-  return setNodeAt<const char *, signed short>(key, value);
-}
-inline bool JsonObject::set(const char *key, unsigned char value) {
-  return setNodeAt<const char *, unsigned char>(key, value);
-}
-inline bool JsonObject::set(const char *key, unsigned long value) {
-  return setNodeAt<const char *, unsigned long>(key, value);
-}
-inline bool JsonObject::set(const char *key, unsigned int value) {
-  return setNodeAt<const char *, unsigned int>(key, value);
-}
-inline bool JsonObject::set(const char *key, unsigned short value) {
-  return setNodeAt<const char *, unsigned short>(key, value);
-}
-inline bool JsonObject::set(const char *key, const char *value) {
-  return setNodeAt<const char *, const char *>(key, value);
-}
-inline bool JsonObject::set(const char *key, const String &value) {
-  return setNodeAt<const char *, const String &>(key, value);
-}
-inline bool JsonObject::set(const char *key, JsonArray &array) {
-  return setNodeAt<const char *, JsonArray &>(key, array);
-}
-inline bool JsonObject::set(const char *key, JsonObject &object) {
-  return setNodeAt<const char *, JsonObject &>(key, object);
-}
-inline bool JsonObject::set(const char *key, const JsonVariant &value) {
-  return setNodeAt<const char *, const JsonVariant &>(key, value);
-}
 template <typename T>
-inline bool JsonObject::set(const char *key, const T &value) {
-  return setNodeAt<const char *, JsonVariant>(key, value);
-}
-inline bool JsonObject::set(const String &key, bool value) {
-  return setNodeAt<const String &, bool>(key, value);
-}
-inline bool JsonObject::set(const String &key, float value, uint8_t decimals) {
-  return setNodeAt<const String &, const JsonVariant &>(
-      key, JsonVariant(value, decimals));
-}
-inline bool JsonObject::set(const String &key, double value, uint8_t decimals) {
-  return setNodeAt<const String &, const JsonVariant &>(
-      key, JsonVariant(value, decimals));
-}
-inline bool JsonObject::set(const String &key, signed char value) {
-  return setNodeAt<const String &, signed char>(key, value);
-}
-inline bool JsonObject::set(const String &key, signed long value) {
-  return setNodeAt<const String &, signed long>(key, value);
-}
-inline bool JsonObject::set(const String &key, signed int value) {
-  return setNodeAt<const String &, signed int>(key, value);
-}
-inline bool JsonObject::set(const String &key, signed short value) {
-  return setNodeAt<const String &, signed short>(key, value);
-}
-inline bool JsonObject::set(const String &key, unsigned char value) {
-  return setNodeAt<const String &, unsigned char>(key, value);
-}
-inline bool JsonObject::set(const String &key, unsigned long value) {
-  return setNodeAt<const String &, unsigned long>(key, value);
-}
-inline bool JsonObject::set(const String &key, unsigned int value) {
-  return setNodeAt<const String &, unsigned int>(key, value);
-}
-inline bool JsonObject::set(const String &key, unsigned short value) {
-  return setNodeAt<const String &, unsigned short>(key, value);
-}
-inline bool JsonObject::set(const String &key, const char *value) {
-  return setNodeAt<const String &, const char *>(key, value);
-}
-inline bool JsonObject::set(const String &key, const String &value) {
-  return setNodeAt<const String &, const String &>(key, value);
-}
-inline bool JsonObject::set(const String &key, JsonArray &array) {
-  return setNodeAt<const String &, JsonArray &>(key, array);
-}
-inline bool JsonObject::set(const String &key, JsonObject &object) {
-  return setNodeAt<const String &, JsonObject &>(key, object);
-}
-inline bool JsonObject::set(const String &key, const JsonVariant &value) {
-  return setNodeAt<const String &, const JsonVariant &>(key, value);
-}
-template <typename T>
-inline bool JsonObject::set(const String &key, const T &value) {
-  return setNodeAt<const String &, JsonVariant>(key, value);
-}
-
-template <typename TKey, typename TValue>
-inline bool JsonObject::setNodeAt(TKey key, TValue value) {
-  node_type *node = getOrCreateNodeAt(key);
-  if (!node) return false;
-  setNodeKey<TKey>(node, key);
-  setNodeValue<TValue>(node, 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<T>(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 void JsonObject::setNodeKey(node_type *node, const char *key) {
-  node->content.key = key;
+template <typename TValue>
+inline bool JsonObject::setNodeValue(node_type *node, TValue value) {
+  node->content.value = value;
+  return true;
 }
 
 template <>
-inline void JsonObject::setNodeKey(node_type *node, const String &key) {
-  node->content.key = _buffer->strdup(key);
-}
-
-template <typename TValue>
-inline void JsonObject::setNodeValue(node_type *node, TValue value) {
-  node->content.value = value;
+inline bool JsonObject::setNodeValue(node_type *node, String &value) {
+  node->content.value = _buffer->strdup(value);
+  return node->content.value;
 }
 
 template <>
-inline void JsonObject::setNodeValue(node_type *node, const String &value) {
+inline bool JsonObject::setNodeValue(node_type *node, const String &value) {
   node->content.value = _buffer->strdup(value);
+  return node->content.value;
 }
 
 template <typename TImplem>
@@ -227,15 +109,22 @@ inline JsonObject &JsonVariant::invalid<JsonObject &>() {
   return JsonObject::invalid();
 }
 
-template <>
-inline JsonObject &JsonVariant::as<JsonObject &>() const {
+inline JsonObject &JsonVariant::asObject() const {
   if (_type == Internals::JSON_OBJECT) return *_content.asObject;
   return JsonObject::invalid();
 }
 
-template <>
-inline const JsonObject &JsonVariant::as<const JsonObject &>() 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<const JsonVariant &>(key, array);
+  return array;
+}
+
+inline JsonObject &JsonArray::createNestedObject() {
+  if (!_buffer) return JsonObject::invalid();
+  JsonObject &object = _buffer->createObject();
+  add(object);
+  return object;
 }
 }

+ 7 - 5
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;
 };
 }

+ 22 - 12
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 <typename TKey>
-class JsonObjectSubscript
-    : public JsonSubscriptBase<JsonObjectSubscript<TKey> > {
+class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript<TKey> > {
  public:
   FORCE_INLINE JsonObjectSubscript(JsonObject& object, TKey key)
       : _object(object), _key(key) {}
 
-  using JsonSubscriptBase<JsonObjectSubscript<TKey> >::operator=;
-
   JsonObjectSubscript<TKey>& operator=(const JsonObjectSubscript<TKey>& src) {
-    return JsonSubscriptBase<JsonObjectSubscript<TKey> >::template assign<
-        JsonVariant>(src);
+    _object.set<const JsonVariant&>(_key, src);
+    return *this;
   }
 
   template <typename T>
-  JsonObjectSubscript<TKey>& operator=(const T& src) {
-    return JsonSubscriptBase<JsonObjectSubscript<TKey> >::template assign<
-        JsonVariant>(src);
+  typename TypeTraits::EnableIf<JsonObject::CanSet<T&>::value,
+                                JsonObjectSubscript<TKey> >::type&
+  operator=(const T& src) {
+    _object.set<T&>(_key, const_cast<T&>(src));
+    return *this;
+  }
+
+  template <typename T>
+  typename TypeTraits::EnableIf<JsonObject::CanSet<T>::value,
+                                JsonObjectSubscript<TKey> >::type&
+  operator=(T src) {
+    _object.set<T>(_key, src);
+    return *this;
   }
 
   FORCE_INLINE bool success() const { return _object.containsKey(_key); }
@@ -52,7 +61,7 @@ class JsonObjectSubscript
 
   template <typename TValue>
   FORCE_INLINE bool set(TValue value) {
-    return _object.set(_key, value);
+    return _object.set<TValue>(_key, value);
   }
 
   template <typename TValue>
@@ -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<const String&>& source) {
   return source.printTo(os);
@@ -82,6 +91,7 @@ inline std::ostream& operator<<(
   return source.printTo(os);
 }
 #endif
+
 }  // namespace ArduinoJson
 
 #ifdef _MSC_VER

+ 1 - 1
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;
 };
 }

+ 0 - 83
include/ArduinoJson/JsonSubscriptBase.hpp

@@ -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 <typename TImpl>
-class JsonSubscriptBase : public JsonVariantBase<TImpl> {
- public:
-  FORCE_INLINE TImpl& operator=(bool value) { return assign<bool>(value); }
-
-  FORCE_INLINE TImpl& operator=(float value) { return assign<float>(value); }
-
-  FORCE_INLINE TImpl& operator=(double value) { return assign<double>(value); }
-
-  FORCE_INLINE TImpl& operator=(signed char value) {
-    return assign<signed char>(value);
-  }
-
-  FORCE_INLINE TImpl& operator=(signed long value) {
-    return assign<signed long>(value);
-  }
-
-  FORCE_INLINE TImpl& operator=(signed int value) {
-    return assign<signed int>(value);
-  }
-
-  FORCE_INLINE TImpl& operator=(signed short value) {
-    return assign<signed short>(value);
-  }
-
-  FORCE_INLINE TImpl& operator=(unsigned char value) {
-    return assign<unsigned char>(value);
-  }
-
-  FORCE_INLINE TImpl& operator=(unsigned long value) {
-    return assign<unsigned long>(value);
-  }
-
-  FORCE_INLINE TImpl& operator=(unsigned int value) {
-    return assign<unsigned int>(value);
-  }
-
-  FORCE_INLINE TImpl& operator=(unsigned short value) {
-    return assign<unsigned short>(value);
-  }
-
-  FORCE_INLINE TImpl& operator=(const char* value) {
-    return assign<const char*>(value);
-  }
-
-  FORCE_INLINE TImpl& operator=(const String& value) {
-    return assign<const String&>(value);
-  }
-
-  FORCE_INLINE TImpl& operator=(JsonArray& array) {
-    return assign<JsonArray&>(array);
-  }
-
-  FORCE_INLINE TImpl& operator=(JsonObject& object) {
-    return assign<JsonObject&>(object);
-  }
-
-  FORCE_INLINE TImpl& operator=(JsonVariant value) {
-    return assign<const JsonVariant&>(value);
-  }
-
- protected:
-  template <typename TValue>
-  FORCE_INLINE TImpl& assign(TValue value) {
-    TImpl* that = static_cast<TImpl*>(this);
-    that->template set<TValue>(value);
-    return *that;
-  }
-};
-}

+ 122 - 12
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<JsonVariant> {
  public:
+  template <typename T>
+  struct IsConstructibleFrom;
+
   // Creates an uninitialized JsonVariant
   FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
 
@@ -41,18 +50,31 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   // 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 <typename T>
+  FORCE_INLINE JsonVariant(
+      T value, uint8_t decimals = 2,
+      typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value>::type
+          * = 0) {
+    using namespace Internals;
+    _type = static_cast<JsonVariantType>(JSON_FLOAT_0_DECIMALS + decimals);
+    _content.asFloat = static_cast<JsonFloat>(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 <typename T>
+  FORCE_INLINE JsonVariant(
+      T value,
+      typename TypeTraits::EnableIf<TypeTraits::IsIntegral<T>::value>::type * =
+          0) {
+    using namespace Internals;
+    _type = JSON_INTEGER;
+    _content.asInteger = static_cast<JsonInteger>(value);
+  }
 
   // Create a JsonVariant containing a string.
   FORCE_INLINE JsonVariant(const char *value);
@@ -67,9 +89,70 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   FORCE_INLINE JsonVariant(JsonObject &object);
 
   // Get the variant as the specified type.
-  // See cast operators for details.
+  // short as<short>() const;
+  // int as<int>() const;
+  // long as<long>() const;
+  template <typename T>
+  const typename TypeTraits::EnableIf<TypeTraits::IsIntegral<T>::value, T>::type
+  as() const {
+    return static_cast<T>(asInteger());
+  }
+  // double as<double>() const;
+  // float as<float>() const;
+  template <typename T>
+  const typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value,
+                                      T>::type
+  as() const {
+    return static_cast<T>(asFloat());
+  }
+  // const String as<String>() const;
+  template <typename T>
+  const typename TypeTraits::EnableIf<TypeTraits::IsSame<T, String>::value,
+                                      T>::type
+  as() const {
+    return toString();
+  }
+  // const char* as<const char*>() const;
+  // const char* as<char*>() const;
   template <typename T>
-  T as() const;
+  typename TypeTraits::EnableIf<TypeTraits::IsSame<T, const char *>::value,
+                                const char *>::type
+  as() const {
+    return asString();
+  }
+  // const bool as<bool>() const
+  template <typename T>
+  const typename TypeTraits::EnableIf<TypeTraits::IsSame<T, bool>::value,
+                                      T>::type
+  as() const {
+    return asInteger() != 0;
+  }
+  // JsonArray& as<JsonArray> const;
+  // JsonArray& as<JsonArray&> const;
+  // JsonArray& as<const JsonArray&> const;
+  template <typename T>
+  typename TypeTraits::EnableIf<
+      TypeTraits::IsSame<
+          typename TypeTraits::RemoveConst<
+              typename TypeTraits::RemoveReference<T>::type>::type,
+          JsonArray>::value,
+      JsonArray &>::type
+  as() const {
+    return asArray();
+  }
+  // JsonObject& as<JsonObject> const;
+  // JsonObject& as<JsonObject&> const;
+  // JsonObject& as<const JsonObject&> const;
+  template <typename T>
+  typename TypeTraits::EnableIf<
+      TypeTraits::IsSame<
+          typename TypeTraits::RemoveConst<
+              typename TypeTraits::RemoveReference<T>::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<JsonVariant> {
   template <typename T>
   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 <typename T>
+struct JsonVariant::IsConstructibleFrom {
+  static const bool value =
+      TypeTraits::IsIntegral<T>::value ||
+      TypeTraits::IsFloatingPoint<T>::value ||
+      TypeTraits::IsSame<T, bool>::value ||
+      TypeTraits::IsSame<T, char *>::value ||
+      TypeTraits::IsSame<T, const char *>::value ||
+      TypeTraits::IsSame<T, JsonArray &>::value ||
+      TypeTraits::IsSame<T, const JsonArray &>::value ||
+      TypeTraits::IsSame<T, JsonArraySubscript &>::value ||
+      TypeTraits::IsSame<T, const JsonArraySubscript &>::value ||
+      TypeTraits::IsSame<T, JsonObject &>::value ||
+      TypeTraits::IsSame<T, const JsonObject &>::value ||
+      TypeTraits::IsSame<T, JsonObjectSubscript<const char *> &>::value ||
+      TypeTraits::IsSame<T, const JsonObjectSubscript<const char *> &>::value ||
+      TypeTraits::IsSame<T, JsonObjectSubscript<String> &>::value ||
+      TypeTraits::IsSame<T, const JsonObjectSubscript<String> &>::value ||
+      TypeTraits::IsSame<T, JsonVariant &>::value ||
+      TypeTraits::IsSame<T, const JsonVariant &>::value;
+};
 }
 
 // Include inline implementations

+ 21 - 122
include/ArduinoJson/JsonVariant.ipp

@@ -7,7 +7,11 @@
 
 #pragma once
 
+#include "Configuration.hpp"
 #include "JsonVariant.hpp"
+#include "Internals/Parse.hpp"
+
+#include <string.h>
 
 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<JsonVariantType>(JSON_FLOAT_0_DECIMALS + decimals);
-  _content.asFloat = static_cast<JsonFloat>(value);
-}
-
-inline JsonVariant::JsonVariant(float value, uint8_t decimals) {
-  using namespace Internals;
-  _type = static_cast<JsonVariantType>(JSON_FLOAT_0_DECIMALS + decimals);
-  _content.asFloat = static_cast<JsonFloat>(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<JsonInteger>(value);
-}
-
-inline JsonVariant::JsonVariant(signed int value) {
-  using namespace Internals;
-  _type = JSON_INTEGER;
-  _content.asInteger = static_cast<JsonInteger>(value);
-}
-
-inline JsonVariant::JsonVariant(signed long value) {
-  using namespace Internals;
-  _type = JSON_INTEGER;
-  _content.asInteger = static_cast<JsonInteger>(value);
-}
-
-inline JsonVariant::JsonVariant(signed short value) {
-  using namespace Internals;
-  _type = JSON_INTEGER;
-  _content.asInteger = static_cast<JsonInteger>(value);
-}
-
-inline JsonVariant::JsonVariant(unsigned char value) {
-  using namespace Internals;
-  _type = JSON_INTEGER;
-  _content.asInteger = static_cast<JsonInteger>(value);
-}
-
-inline JsonVariant::JsonVariant(unsigned int value) {
-  using namespace Internals;
-  _type = JSON_INTEGER;
-  _content.asInteger = static_cast<JsonInteger>(value);
-}
-
-inline JsonVariant::JsonVariant(unsigned long value) {
-  using namespace Internals;
-  _type = JSON_INTEGER;
-  _content.asInteger = static_cast<JsonInteger>(value);
-}
-
-inline JsonVariant::JsonVariant(unsigned short value) {
-  using namespace Internals;
-  _type = JSON_INTEGER;
-  _content.asInteger = static_cast<JsonInteger>(value);
-}
-
-template <>
-String JsonVariant::as<String>() const;
-
-template <>
-const char *JsonVariant::as<const char *>() const;
-
-template <>
-inline bool JsonVariant::as<bool>() const {
-  return asInteger() != 0;
-}
-
-template <>
-inline signed char JsonVariant::as<signed char>() const {
-  return static_cast<signed char>(asInteger());
-}
-
-template <>
-inline unsigned char JsonVariant::as<unsigned char>() const {
-  return static_cast<unsigned char>(asInteger());
-}
-
-template <>
-inline signed short JsonVariant::as<signed short>() const {
-  return static_cast<signed short>(asInteger());
-}
-
-template <>
-inline unsigned short JsonVariant::as<unsigned short>() const {
-  return static_cast<unsigned short>(asInteger());
-}
-
-template <>
-inline signed int JsonVariant::as<signed int>() const {
-  return static_cast<signed int>(asInteger());
-}
-
-template <>
-inline unsigned int JsonVariant::as<unsigned int>() const {
-  return static_cast<unsigned int>(asInteger());
-}
-
-template <>
-inline unsigned long JsonVariant::as<unsigned long>() const {
-  return static_cast<unsigned long>(asInteger());
-}
-
-template <>
-inline signed long JsonVariant::as<signed long>() const {
-  return static_cast<unsigned long>(asInteger());
-}
-
-template <>
-inline double JsonVariant::as<double>() const {
-  return static_cast<double>(asFloat());
-}
-
-template <>
-inline float JsonVariant::as<float>() const {
-  return static_cast<float>(asFloat());
-}
-
 template <typename T>
 inline T JsonVariant::invalid() {
   return T();
@@ -242,7 +125,23 @@ inline bool JsonVariant::is<unsigned short>() const {
   return is<signed long>();
 }
 
-#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<Internals::JsonInteger>(_content.asFloat);
+
+  if ((_type == Internals::JSON_STRING || _type == Internals::JSON_UNPARSED) &&
+      _content.asString) {
+    if (!strcmp("true", _content.asString)) return 1;
+    return Internals::parse<Internals::JsonInteger>(_content.asString);
+  }
+
+  return 0L;
+}
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
 inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) {
   return source.printTo(os);
 }

+ 5 - 24
include/ArduinoJson/JsonVariantBase.hpp

@@ -20,31 +20,7 @@ class JsonObjectSubscript;
 template <typename TImpl>
 class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
  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<bool>(); }
-
-  // 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<double>(); }
-  FORCE_INLINE operator float() const { return as<float>(); }
-
-  // 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<signed long>(); }
-  FORCE_INLINE operator signed char() const { return as<signed char>(); }
-  FORCE_INLINE operator signed int() const { return as<signed int>(); }
-  FORCE_INLINE operator signed short() const { return as<signed short>(); }
-  FORCE_INLINE operator unsigned char() const { return as<unsigned char>(); }
-  FORCE_INLINE operator unsigned int() const { return as<unsigned int>(); }
-  FORCE_INLINE operator unsigned long() const { return as<unsigned long>(); }
-  FORCE_INLINE operator unsigned short() const { return as<unsigned short>(); }
-
-  // Gets the variant as a string.
-  // Returns NULL if variant is not a string.
-  FORCE_INLINE operator const char *() const { return as<const char *>(); }
   FORCE_INLINE const char *asString() const { return as<const char *>(); }
-  FORCE_INLINE operator String() const { return as<String>(); }
 
   // 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<TImpl> {
   FORCE_INLINE operator JsonObject &() const { return as<JsonObject &>(); }
   FORCE_INLINE JsonObject &asObject() const { return as<JsonObject &>(); }
 
+  template <typename T>
+  FORCE_INLINE operator T() const {
+    return as<T>();
+  }
+
   template <typename T>
   FORCE_INLINE const T as() const {
     return impl()->template as<T>();

+ 22 - 0
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 <bool Condition, typename T = void>
+struct EnableIf {};
+
+template <typename T>
+struct EnableIf<true, T> {
+  typedef T type;
+};
+}
+}

+ 21 - 0
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 <typename T>
+struct IsFloatingPoint {
+  static const bool value = IsSame<T, float>::value || IsSame<T, double>::value;
+};
+}
+}

+ 41 - 0
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 <stdint.h>
+
+namespace ArduinoJson {
+namespace TypeTraits {
+
+// A meta-function that returns true if T is an integral type.
+template <typename T>
+struct IsIntegral {
+  static const bool value = TypeTraits::IsSame<T, signed char>::value ||
+                            TypeTraits::IsSame<T, unsigned char>::value ||
+                            TypeTraits::IsSame<T, signed short>::value ||
+                            TypeTraits::IsSame<T, unsigned short>::value ||
+                            TypeTraits::IsSame<T, signed int>::value ||
+                            TypeTraits::IsSame<T, unsigned int>::value ||
+                            TypeTraits::IsSame<T, signed long>::value ||
+                            TypeTraits::IsSame<T, unsigned long>::value ||
+#if ARDUINOJSON_USE_LONG_LONG
+                            TypeTraits::IsSame<T, long long>::value ||
+                            TypeTraits::IsSame<T, unsigned long long>::value ||
+#endif
+
+#if ARDUINOJSON_USE_INT64
+                            TypeTraits::IsSame<T, __int64>::value ||
+                            TypeTraits::IsSame<T, unsigned __int64>::value ||
+#endif
+                            TypeTraits::IsSame<T, char>::value;
+};
+}
+}

+ 24 - 0
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 <typename T>
+struct IsReference {
+  static const bool value = false;
+};
+
+template <typename T>
+struct IsReference<T&> {
+  static const bool value = true;
+};
+}
+}

+ 24 - 0
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 <typename T, typename U>
+struct IsSame {
+  static const bool value = false;
+};
+
+template <typename T>
+struct IsSame<T, T> {
+  static const bool value = true;
+};
+}
+}

+ 23 - 0
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 <typename T>
+struct RemoveConst {
+  typedef T type;
+};
+template <typename T>
+struct RemoveConst<const T> {
+  typedef T type;
+};
+}
+}

+ 23 - 0
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 <typename T>
+struct RemoveReference {
+  typedef T type;
+};
+template <typename T>
+struct RemoveReference<T&> {
+  typedef T type;
+};
+}
+}

+ 0 - 72
src/Arduino/Print.cpp

@@ -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 <math.h>   // for isnan() and isinf()
-#include <stdio.h>  // 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 <float.h>
-#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

+ 0 - 14
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 {

+ 1 - 29
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 <typename TKey>
-JsonArray &JsonObject::createArrayAt(TKey key) {
-  if (!_buffer) return JsonArray::invalid();
-  JsonArray &array = _buffer->createArray();
-  setNodeAt<TKey, const JsonVariant &>(key, array);
-  return array;
-}
-template JsonArray &JsonObject::createArrayAt<const char *>(const char *);
-template JsonArray &JsonObject::createArrayAt<const String &>(const String &);
-
-template <typename TKey>
-JsonObject &JsonObject::createObjectAt(TKey key) {
-  if (!_buffer) return JsonObject::invalid();
-  JsonObject &array = _buffer->createObject();
-  setNodeAt<TKey, const JsonVariant &>(key, array);
-  return array;
-}
-template JsonObject &JsonObject::createObjectAt<const char *>(const char *);
-template JsonObject &JsonObject::createObjectAt<const String &>(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;
   }

+ 2 - 41
src/JsonVariant.cpp

@@ -17,31 +17,7 @@ using namespace ArduinoJson::Internals;
 
 namespace ArduinoJson {
 
-template <typename TFloat>
-static TFloat parse(const char *);
-
-template <>
-float parse<float>(const char *s) {
-  return static_cast<float>(strtod(s, NULL));
-}
-
-template <>
-double parse<double>(const char *s) {
-  return strtod(s, NULL);
-}
-
-template <>
-long parse<long>(const char *s) {
-  return strtol(s, NULL, 10);
-}
-
-template <>
-int parse<int>(const char *s) {
-  return atoi(s);
-}
-
-template <>
-const char *JsonVariant::as<const char *>() 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<JsonInteger>(_content.asFloat);
-
-  if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString) {
-    if (!strcmp("true", _content.asString)) return 1;
-    return parse<JsonInteger>(_content.asString);
-  }
-
-  return 0L;
-}
-
-template <>
-String JsonVariant::as<String>() const {
+String JsonVariant::toString() const {
   String s;
   if ((_type == JSON_STRING || _type == JSON_UNPARSED) &&
       _content.asString != NULL)

+ 6 - 1
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)

+ 0 - 1
test/GbathreeBug.cpp

@@ -6,7 +6,6 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
 class GbathreeBug : public testing::Test {

+ 3 - 1
test/Issue90.cpp

@@ -7,7 +7,9 @@
 
 #include <gtest/gtest.h>
 #include <limits.h>  // for LONG_MAX
-#define ARDUINOJSON_ENABLE_STD_STREAM
+
+#define ARDUINOJSON_USE_LONG_LONG 0
+#define ARDUINOJSON_USE_INT64 0
 #include <ArduinoJson.h>
 
 #define SUITE Issue90

+ 0 - 1
test/JsonArray_Add_Tests.cpp

@@ -6,7 +6,6 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
 class JsonArray_Add_Tests : public ::testing::Test {

+ 0 - 1
test/JsonArray_Basic_Tests.cpp

@@ -6,7 +6,6 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
 #define TEST_(name) TEST(JsonArray_Basic_Tests, name)

+ 15 - 0
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);
 

+ 0 - 1
test/JsonArray_Set_Tests.cpp

@@ -6,7 +6,6 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
 class JsonArray_Set_Tests : public ::testing::Test {

+ 11 - 2
test/JsonArray_Subscript_Tests.cpp

@@ -5,9 +5,9 @@
 // https://github.com/bblanchon/ArduinoJson
 // If you like this project, please add a star!
 
-#include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
+#include <gtest/gtest.h>
+#include <stdint.h>
 
 class JsonArray_Subscript_Tests : public ::testing::Test {
  protected:
@@ -33,6 +33,15 @@ TEST_(StoreInteger) {
   EXPECT_FALSE(_array[0].is<double>());
 }
 
+#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
+TEST_(StoreLongLong) {
+  _array[0] = 9223372036854775807;
+  EXPECT_EQ(9223372036854775807, _array[0].as<long long>());
+  EXPECT_TRUE(_array[0].is<int>());
+  EXPECT_FALSE(_array[0].is<double>());
+}
+#endif
+
 TEST_(StoreDouble) {
   _array[0] = 123.45;
   EXPECT_EQ(123.45, _array[0].as<double>());

+ 0 - 1
test/JsonObject_Iterator_Tests.cpp

@@ -6,7 +6,6 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
 class JsonObject_Iterator_Test : public testing::Test {

+ 3 - 2
test/JsonObject_PrintTo_Tests.cpp

@@ -5,8 +5,8 @@
 // https://github.com/bblanchon/ArduinoJson
 // If you like this project, please add a star!
 
-#include <gtest/gtest.h>
 #include <ArduinoJson.h>
+#include <gtest/gtest.h>
 
 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) {

+ 0 - 1
test/JsonObject_Set_Tests.cpp

@@ -6,7 +6,6 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
 class JsonObject_Set_Tests : public ::testing::Test {

+ 0 - 1
test/JsonObject_Subscript_Tests.cpp

@@ -6,7 +6,6 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
 class JsonObject_Subscript_Tests : public ::testing::Test {

+ 15 - 2
test/JsonVariant_As_Tests.cpp

@@ -5,10 +5,11 @@
 // https://github.com/bblanchon/ArduinoJson
 // If you like this project, please add a star!
 
-#include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
+#include <gtest/gtest.h>
+#include <stdint.h>
+
 static const char* null = 0;
 
 TEST(JsonVariant_As_Tests, DoubleAsBool) {
@@ -136,6 +137,18 @@ TEST(JsonVariant_As_Tests, NumberStringAsLong) {
   ASSERT_EQ(42L, variant.as<long>());
 }
 
+#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
+TEST(JsonVariant_As_Tests, NumberStringAsInt64Negative) {
+  JsonVariant variant = "-9223372036854775808";
+  ASSERT_EQ(-9223372036854775807 - 1, variant.as<long long>());
+}
+
+TEST(JsonVariant_As_Tests, NumberStringAsInt64Positive) {
+  JsonVariant variant = "9223372036854775807";
+  ASSERT_EQ(9223372036854775807, variant.as<long long>());
+}
+#endif
+
 TEST(JsonVariant_As_Tests, RandomStringAsBool) {
   JsonVariant variant = "hello";
   ASSERT_FALSE(variant.as<bool>());

+ 0 - 1
test/JsonVariant_Comparison_Tests.cpp

@@ -6,7 +6,6 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson/JsonVariant.hpp>
 
 using namespace ArduinoJson;

+ 0 - 1
test/JsonVariant_Is_Tests.cpp

@@ -6,7 +6,6 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
 #define SUITE JsonVariant_Is_Tests

+ 12 - 0
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

+ 51 - 17
test/JsonVariant_Storage_Tests.cpp

@@ -6,40 +6,74 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
+#include <stdint.h>
+#include <limits>
 #include <ArduinoJson.h>
 
 class JsonVariant_Storage_Tests : public ::testing::Test {
  protected:
   template <typename T>
   void testValue(T expected) {
-    _actual = expected;
-    EXPECT_EQ(expected, _actual.as<T>());
+    JsonVariant variant = expected;
+    EXPECT_EQ(expected, variant.as<T>());
   }
 
   template <typename T>
   void testReference(T &expected) {
-    _actual = expected;
-    EXPECT_EQ(expected, _actual.as<T &>());
+    JsonVariant variant = expected;
+    EXPECT_EQ(expected, variant.as<T &>());
   }
 
- private:
-  JsonVariant _actual;
+  template <typename T>
+  void testNumericType() {
+    T min = std::numeric_limits<T>::min();
+    T max = std::numeric_limits<T>::max();
+
+    JsonVariant variantMin(min);
+    JsonVariant variantMax(max);
+
+    EXPECT_EQ(min, variantMin.as<T>());
+    EXPECT_EQ(max, variantMax.as<T>());
+  }
 };
 
-TEST_F(JsonVariant_Storage_Tests, Double) { testValue<double>(123.45); }
-TEST_F(JsonVariant_Storage_Tests, False) { testValue<bool>(false); }
-TEST_F(JsonVariant_Storage_Tests, Float) { testValue<float>(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<const char *>(NULL); }
-TEST_F(JsonVariant_Storage_Tests, SChar) { testValue<signed char>(123); }
-TEST_F(JsonVariant_Storage_Tests, SInt) { testValue<signed int>(123); }
-TEST_F(JsonVariant_Storage_Tests, SLong) { testValue<signed long>(123L); }
-TEST_F(JsonVariant_Storage_Tests, SShort) { testValue<signed short>(123); }
 TEST_F(JsonVariant_Storage_Tests, String) { testValue<const char *>("hello"); }
+
+TEST_F(JsonVariant_Storage_Tests, False) { testValue<bool>(false); }
 TEST_F(JsonVariant_Storage_Tests, True) { testValue<bool>(true); }
-TEST_F(JsonVariant_Storage_Tests, UChar) { testValue<unsigned char>(123); }
-TEST_F(JsonVariant_Storage_Tests, UInt) { testValue<unsigned int>(123U); }
-TEST_F(JsonVariant_Storage_Tests, ULong) { testValue<unsigned long>(123UL); }
-TEST_F(JsonVariant_Storage_Tests, UShort) { testValue<unsigned short>(123); }
+
+TEST_F(JsonVariant_Storage_Tests, Double) { testNumericType<double>(); }
+TEST_F(JsonVariant_Storage_Tests, Float) { testNumericType<float>(); }
+TEST_F(JsonVariant_Storage_Tests, SChar) { testNumericType<signed char>(); }
+TEST_F(JsonVariant_Storage_Tests, SInt) { testNumericType<signed int>(); }
+TEST_F(JsonVariant_Storage_Tests, SLong) { testNumericType<signed long>(); }
+TEST_F(JsonVariant_Storage_Tests, SShort) { testNumericType<signed short>(); }
+TEST_F(JsonVariant_Storage_Tests, UChar) { testNumericType<unsigned char>(); }
+TEST_F(JsonVariant_Storage_Tests, UInt) { testNumericType<unsigned int>(); }
+TEST_F(JsonVariant_Storage_Tests, ULong) { testNumericType<unsigned long>(); }
+TEST_F(JsonVariant_Storage_Tests, UShort) { testNumericType<unsigned short>(); }
+#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
+TEST_F(JsonVariant_Storage_Tests, LongLong) { testNumericType<unsigned long long>(); }
+TEST_F(JsonVariant_Storage_Tests, ULongLong) { testNumericType<unsigned long long>(); }
+#endif
+
+TEST_F(JsonVariant_Storage_Tests, Int8) { testNumericType<int8_t>(); }
+TEST_F(JsonVariant_Storage_Tests, Uint8) { testNumericType<uint8_t>(); }
+TEST_F(JsonVariant_Storage_Tests, Int16) { testNumericType<int16_t>(); }
+TEST_F(JsonVariant_Storage_Tests, Uint16) { testNumericType<uint16_t>(); }
+TEST_F(JsonVariant_Storage_Tests, Int32) { testNumericType<int32_t>(); }
+TEST_F(JsonVariant_Storage_Tests, Uint32) { testNumericType<uint32_t>(); }
+#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
+TEST_F(JsonVariant_Storage_Tests, Int64) { testNumericType<int64_t>(); }
+TEST_F(JsonVariant_Storage_Tests, Uint64) { testNumericType<uint64_t>(); }
+#endif
 
 TEST_F(JsonVariant_Storage_Tests, CanStoreObject) {
   DynamicJsonBuffer jsonBuffer;

+ 0 - 1
test/JsonVariant_Undefined_Tests.cpp

@@ -6,7 +6,6 @@
 // If you like this project, please add a star!
 
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
 class JsonVariant_Undefined_Tests : public ::testing::Test {

+ 0 - 1
test/StdStream.cpp

@@ -7,7 +7,6 @@
 
 #include <sstream>
 #include <gtest/gtest.h>
-#define ARDUINOJSON_ENABLE_STD_STREAM
 #include <ArduinoJson.h>
 
 TEST(StdStream, JsonVariantFalse) {