Kaynağa Gözat

Use `float` instead of `double` to reduce the size of `JsonVariant` (issue #134)

Benoit Blanchon 10 yıl önce
ebeveyn
işleme
c0cf9c3fcc

+ 1 - 0
CHANGELOG.md

@@ -5,6 +5,7 @@ v5.0.5
 ------
 ------
 
 
 * Add overload `JsonObjectSuscript::set(value, decimals)` (issue #143)
 * Add overload `JsonObjectSuscript::set(value, decimals)` (issue #143)
+* Use `float` instead of `double` to reduce the size of `JsonVariant` (issue #134)
 
 
 v5.0.4
 v5.0.4
 ------
 ------

+ 1 - 1
README.md

@@ -63,7 +63,7 @@ data.add(2.302038, 6);   // if not specified, 2 digits are printed
 root.printTo(Serial);
 root.printTo(Serial);
 // This prints:
 // This prints:
 // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
 // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
-``
+```
 
 
 
 
 Documentation
 Documentation

+ 1 - 0
include/ArduinoJson/Arduino/Print.hpp

@@ -20,6 +20,7 @@ class Print {
 
 
   size_t print(const char[]);
   size_t print(const char[]);
   size_t print(double, int = 2);
   size_t print(double, int = 2);
+  size_t print(int);
   size_t print(long);
   size_t print(long);
   size_t println();
   size_t println();
 };
 };

+ 1 - 0
include/ArduinoJson/Arduino/String.hpp

@@ -16,6 +16,7 @@ class String : public std::string {
   String(const char *cstr = "") : std::string(cstr) {}
   String(const char *cstr = "") : std::string(cstr) {}
   String(const String &str) : std::string(str) {}
   String(const String &str) : std::string(str) {}
   explicit String(long);
   explicit String(long);
+  explicit String(int);
   explicit String(double, unsigned char decimalPlaces = 2);
   explicit String(double, unsigned char decimalPlaces = 2);
 };
 };
 
 

+ 20 - 0
include/ArduinoJson/Internals/JsonFloat.hpp

@@ -0,0 +1,20 @@
+// Copyright Benoit Blanchon 2014-2015
+// MIT License
+//
+// Arduino JSON library
+// https://github.com/bblanchon/ArduinoJson
+
+#pragma once
+
+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
+typedef double JsonFloat;
+#endif
+}
+}

+ 13 - 0
include/ArduinoJson/Internals/JsonInteger.hpp

@@ -0,0 +1,13 @@
+// Copyright Benoit Blanchon 2014-2015
+// MIT License
+//
+// Arduino JSON library
+// https://github.com/bblanchon/ArduinoJson
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+typedef long JsonInteger;
+}
+}

+ 8 - 6
include/ArduinoJson/Internals/JsonVariantContent.hpp

@@ -6,6 +6,9 @@
 
 
 #pragma once
 #pragma once
 
 
+#include "JsonFloat.hpp"
+#include "JsonInteger.hpp"
+
 namespace ArduinoJson {
 namespace ArduinoJson {
 
 
 // Forward declarations
 // Forward declarations
@@ -13,15 +16,14 @@ class JsonArray;
 class JsonObject;
 class JsonObject;
 
 
 namespace Internals {
 namespace Internals {
-
 // A union that defines the actual content of a JsonVariant.
 // A union that defines the actual content of a JsonVariant.
 // The enum JsonVariantType determines which member is in use.
 // The enum JsonVariantType determines which member is in use.
 union JsonVariantContent {
 union JsonVariantContent {
-  double asDouble;       // asDouble is also used for float
-  long asLong;           // asLong is also used for bool, char, short and int
-  const char* asString;  // asString can be null
-  JsonArray* asArray;    // asArray cannot be null
-  JsonObject* asObject;  // asObject cannot be null
+  JsonFloat asFloat;      // used for double and float
+  JsonInteger asInteger;  // used for bool, char, short, int and longs
+  const char* asString;   // asString can be null
+  JsonArray* asArray;     // asArray cannot be null
+  JsonObject* asObject;   // asObject cannot be null
 };
 };
 }
 }
 }
 }

+ 5 - 5
include/ArduinoJson/Internals/JsonVariantType.hpp

@@ -19,17 +19,17 @@ enum JsonVariantType {
   JSON_UNPARSED,   // the JsonVariant contains an unparsed string
   JSON_UNPARSED,   // the JsonVariant contains an unparsed string
   JSON_STRING,     // the JsonVariant stores a const char*
   JSON_STRING,     // the JsonVariant stores a const char*
   JSON_BOOLEAN,    // the JsonVariant stores a bool
   JSON_BOOLEAN,    // the JsonVariant stores a bool
-  JSON_LONG,       // the JsonVariant stores a long
+  JSON_INTEGER,    // the JsonVariant stores an integer
   JSON_ARRAY,      // the JsonVariant stores a pointer to a JsonArray
   JSON_ARRAY,      // the JsonVariant stores a pointer to a JsonArray
   JSON_OBJECT,     // the JsonVariant stores a pointer to a JsonObject
   JSON_OBJECT,     // the JsonVariant stores a pointer to a JsonObject
 
 
-  // The following values are reserved for double values
+  // The following values are reserved for float values
   // Multiple values are used for double, depending on the number of decimal
   // Multiple values are used for double, depending on the number of decimal
   // digits that must be printed in the JSON output.
   // digits that must be printed in the JSON output.
   // This little trick allow to save one extra member in JsonVariant
   // This little trick allow to save one extra member in JsonVariant
-  JSON_DOUBLE_0_DECIMALS
-  // JSON_DOUBLE_1_DECIMAL
-  // JSON_DOUBLE_2_DECIMALS
+  JSON_FLOAT_0_DECIMALS
+  // JSON_FLOAT_1_DECIMAL
+  // JSON_FLOAT_2_DECIMALS
   // ...
   // ...
 };
 };
 }
 }

+ 4 - 2
include/ArduinoJson/Internals/JsonWriter.hpp

@@ -9,6 +9,8 @@
 #include "../Arduino/Print.hpp"
 #include "../Arduino/Print.hpp"
 #include "Encoding.hpp"
 #include "Encoding.hpp"
 #include "ForceInline.hpp"
 #include "ForceInline.hpp"
+#include "JsonFloat.hpp"
+#include "JsonInteger.hpp"
 
 
 namespace ArduinoJson {
 namespace ArduinoJson {
 namespace Internals {
 namespace Internals {
@@ -60,9 +62,9 @@ class JsonWriter {
     }
     }
   }
   }
 
 
-  void writeLong(long value) { _length += _sink.print(value); }
+  void writeInteger(JsonInteger value) { _length += _sink.print(value); }
 
 
-  void writeDouble(double value, uint8_t decimals) {
+  void writeFloat(JsonFloat value, uint8_t decimals) {
     _length += _sink.print(value, decimals);
     _length += _sink.print(value, decimals);
   }
   }
 
 

+ 3 - 3
include/ArduinoJson/Internals/StaticStringBuilder.hpp

@@ -14,7 +14,7 @@ namespace Internals {
 // A Print implementation that allows to write in a char[]
 // A Print implementation that allows to write in a char[]
 class StaticStringBuilder : public Print {
 class StaticStringBuilder : public Print {
  public:
  public:
-  StaticStringBuilder(char *buf, int size)
+  StaticStringBuilder(char *buf, size_t size)
       : buffer(buf), capacity(size - 1), length(0) {
       : buffer(buf), capacity(size - 1), length(0) {
     buffer[0] = '\0';
     buffer[0] = '\0';
   }
   }
@@ -23,8 +23,8 @@ class StaticStringBuilder : public Print {
 
 
  private:
  private:
   char *buffer;
   char *buffer;
-  int capacity;
-  int length;
+  size_t capacity;
+  size_t length;
 };
 };
 }
 }
 }
 }

+ 3 - 0
include/ArduinoJson/JsonVariant.hpp

@@ -83,6 +83,9 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
   static T invalid();
   static T invalid();
 
 
  private:
  private:
+  Internals::JsonFloat asFloat() const;
+  Internals::JsonInteger asInteger() const;
+
   // The current type of the variant
   // The current type of the variant
   Internals::JsonVariantType _type;
   Internals::JsonVariantType _type;
 
 

+ 52 - 39
include/ArduinoJson/JsonVariant.ipp

@@ -11,8 +11,9 @@
 namespace ArduinoJson {
 namespace ArduinoJson {
 
 
 inline JsonVariant::JsonVariant(bool value) {
 inline JsonVariant::JsonVariant(bool value) {
-  _type = Internals::JSON_BOOLEAN;
-  _content.asLong = value;
+  using namespace Internals;
+  _type = JSON_BOOLEAN;
+  _content.asInteger = static_cast<JsonInteger>(value);
 }
 }
 
 
 inline JsonVariant::JsonVariant(const char *value) {
 inline JsonVariant::JsonVariant(const char *value) {
@@ -26,15 +27,15 @@ inline JsonVariant::JsonVariant(Internals::Unparsed value) {
 }
 }
 
 
 inline JsonVariant::JsonVariant(double value, uint8_t decimals) {
 inline JsonVariant::JsonVariant(double value, uint8_t decimals) {
-  _type = static_cast<Internals::JsonVariantType>(
-      Internals::JSON_DOUBLE_0_DECIMALS + decimals);
-  _content.asDouble = value;
+  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) {
 inline JsonVariant::JsonVariant(float value, uint8_t decimals) {
-  _type = static_cast<Internals::JsonVariantType>(
-      Internals::JSON_DOUBLE_0_DECIMALS + decimals);
-  _content.asDouble = value;
+  using namespace Internals;
+  _type = static_cast<JsonVariantType>(JSON_FLOAT_0_DECIMALS + decimals);
+  _content.asFloat = static_cast<JsonFloat>(value);
 }
 }
 
 
 inline JsonVariant::JsonVariant(JsonArray &array) {
 inline JsonVariant::JsonVariant(JsonArray &array) {
@@ -48,51 +49,53 @@ inline JsonVariant::JsonVariant(JsonObject &object) {
 }
 }
 
 
 inline JsonVariant::JsonVariant(signed char value) {
 inline JsonVariant::JsonVariant(signed char value) {
-  _type = Internals::JSON_LONG;
-  _content.asLong = value;
+  using namespace Internals;
+  _type = JSON_INTEGER;
+  _content.asInteger = static_cast<JsonInteger>(value);
 }
 }
 
 
 inline JsonVariant::JsonVariant(signed int value) {
 inline JsonVariant::JsonVariant(signed int value) {
-  _type = Internals::JSON_LONG;
-  _content.asLong = value;
+  using namespace Internals;
+  _type = JSON_INTEGER;
+  _content.asInteger = static_cast<JsonInteger>(value);
 }
 }
 
 
 inline JsonVariant::JsonVariant(signed long value) {
 inline JsonVariant::JsonVariant(signed long value) {
-  _type = Internals::JSON_LONG;
-  _content.asLong = value;
+  using namespace Internals;
+  _type = JSON_INTEGER;
+  _content.asInteger = static_cast<JsonInteger>(value);
 }
 }
 
 
 inline JsonVariant::JsonVariant(signed short value) {
 inline JsonVariant::JsonVariant(signed short value) {
-  _type = Internals::JSON_LONG;
-  _content.asLong = value;
+  using namespace Internals;
+  _type = JSON_INTEGER;
+  _content.asInteger = static_cast<JsonInteger>(value);
 }
 }
 
 
 inline JsonVariant::JsonVariant(unsigned char value) {
 inline JsonVariant::JsonVariant(unsigned char value) {
-  _type = Internals::JSON_LONG;
-  _content.asLong = value;
+  using namespace Internals;
+  _type = JSON_INTEGER;
+  _content.asInteger = static_cast<JsonInteger>(value);
 }
 }
 
 
 inline JsonVariant::JsonVariant(unsigned int value) {
 inline JsonVariant::JsonVariant(unsigned int value) {
-  _type = Internals::JSON_LONG;
-  _content.asLong = value;
+  using namespace Internals;
+  _type = JSON_INTEGER;
+  _content.asInteger = static_cast<JsonInteger>(value);
 }
 }
 
 
 inline JsonVariant::JsonVariant(unsigned long value) {
 inline JsonVariant::JsonVariant(unsigned long value) {
-  _type = Internals::JSON_LONG;
-  _content.asLong = value;
+  using namespace Internals;
+  _type = JSON_INTEGER;
+  _content.asInteger = static_cast<JsonInteger>(value);
 }
 }
 
 
 inline JsonVariant::JsonVariant(unsigned short value) {
 inline JsonVariant::JsonVariant(unsigned short value) {
-  _type = Internals::JSON_LONG;
-  _content.asLong = value;
+  using namespace Internals;
+  _type = JSON_INTEGER;
+  _content.asInteger = static_cast<JsonInteger>(value);
 }
 }
 
 
-template <>
-double JsonVariant::as<double>() const;
-
-template <>
-long JsonVariant::as<long>() const;
-
 template <>
 template <>
 String JsonVariant::as<String>() const;
 String JsonVariant::as<String>() const;
 
 
@@ -101,47 +104,57 @@ const char *JsonVariant::as<const char *>() const;
 
 
 template <>
 template <>
 inline bool JsonVariant::as<bool>() const {
 inline bool JsonVariant::as<bool>() const {
-  return as<long>() != 0;
+  return asInteger() != 0;
 }
 }
 
 
 template <>
 template <>
 inline signed char JsonVariant::as<signed char>() const {
 inline signed char JsonVariant::as<signed char>() const {
-  return static_cast<signed char>(as<long>());
+  return static_cast<signed char>(asInteger());
 }
 }
 
 
 template <>
 template <>
 inline unsigned char JsonVariant::as<unsigned char>() const {
 inline unsigned char JsonVariant::as<unsigned char>() const {
-  return static_cast<unsigned char>(as<long>());
+  return static_cast<unsigned char>(asInteger());
 }
 }
 
 
 template <>
 template <>
 inline signed short JsonVariant::as<signed short>() const {
 inline signed short JsonVariant::as<signed short>() const {
-  return static_cast<signed short>(as<long>());
+  return static_cast<signed short>(asInteger());
 }
 }
 
 
 template <>
 template <>
 inline unsigned short JsonVariant::as<unsigned short>() const {
 inline unsigned short JsonVariant::as<unsigned short>() const {
-  return static_cast<unsigned short>(as<long>());
+  return static_cast<unsigned short>(asInteger());
 }
 }
 
 
 template <>
 template <>
 inline signed int JsonVariant::as<signed int>() const {
 inline signed int JsonVariant::as<signed int>() const {
-  return static_cast<signed int>(as<long>());
+  return static_cast<signed int>(asInteger());
 }
 }
 
 
 template <>
 template <>
 inline unsigned int JsonVariant::as<unsigned int>() const {
 inline unsigned int JsonVariant::as<unsigned int>() const {
-  return static_cast<unsigned int>(as<long>());
+  return static_cast<unsigned int>(asInteger());
 }
 }
 
 
 template <>
 template <>
 inline unsigned long JsonVariant::as<unsigned long>() const {
 inline unsigned long JsonVariant::as<unsigned long>() const {
-  return static_cast<unsigned long>(as<long>());
+  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 <>
 template <>
 inline float JsonVariant::as<float>() const {
 inline float JsonVariant::as<float>() const {
-  return static_cast<float>(as<double>());
+  return static_cast<float>(asFloat());
 }
 }
 
 
 template <typename T>
 template <typename T>

+ 6 - 0
src/Arduino/Print.cpp

@@ -60,6 +60,12 @@ size_t Print::print(long value) {
   return print(tmp);
   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'); }
 size_t Print::println() { return write('\r') + write('\n'); }
 
 
 #endif
 #endif

+ 6 - 0
src/Arduino/String.cpp

@@ -22,4 +22,10 @@ String::String(long value) {
   *this = tmp;
   *this = tmp;
 }
 }
 
 
+String::String(int value) {
+  char tmp[32];
+  sprintf(tmp, "%d", value);
+  *this = tmp;
+}
+
 #endif
 #endif

+ 46 - 25
src/JsonVariant.cpp

@@ -16,6 +16,29 @@ using namespace ArduinoJson::Internals;
 
 
 namespace ArduinoJson {
 namespace ArduinoJson {
 
 
+template <typename TFloat>
+static TFloat parse(const char *);
+
+template <>
+FORCE_INLINE float parse<float>(const char *s) {
+  return static_cast<float>(strtod(s, NULL));
+}
+
+template <>
+FORCE_INLINE double parse<double>(const char *s) {
+  return strtod(s, NULL);
+}
+
+template <>
+FORCE_INLINE long parse<long>(const char *s) {
+  return strtol(s, NULL, 10);
+}
+
+template <>
+FORCE_INLINE int parse<int>(const char *s) {
+  return atoi(s);
+}
+
 template <>
 template <>
 const char *JsonVariant::as<const char *>() const {
 const char *JsonVariant::as<const char *>() const {
   if (_type == JSON_UNPARSED && _content.asString &&
   if (_type == JSON_UNPARSED && _content.asString &&
@@ -25,29 +48,27 @@ const char *JsonVariant::as<const char *>() const {
   return NULL;
   return NULL;
 }
 }
 
 
-template <>
-double JsonVariant::as<double>() const {
-  if (_type >= JSON_DOUBLE_0_DECIMALS) return _content.asDouble;
+JsonFloat JsonVariant::asFloat() const {
+  if (_type >= JSON_FLOAT_0_DECIMALS) return _content.asFloat;
 
 
-  if (_type == JSON_LONG || _type == JSON_BOOLEAN)
-    return static_cast<double>(_content.asLong);
+  if (_type == JSON_INTEGER || _type == JSON_BOOLEAN)
+    return static_cast<JsonFloat>(_content.asInteger);
 
 
   if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString)
   if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString)
-    return strtod(_content.asString, NULL);
+    return parse<JsonFloat>(_content.asString);
 
 
   return 0.0;
   return 0.0;
 }
 }
 
 
-template <>
-long JsonVariant::as<long>() const {
-  if (_type == JSON_LONG || _type == JSON_BOOLEAN) return _content.asLong;
+JsonInteger JsonVariant::asInteger() const {
+  if (_type == JSON_INTEGER || _type == JSON_BOOLEAN) return _content.asInteger;
 
 
-  if (_type >= JSON_DOUBLE_0_DECIMALS)
-    return static_cast<long>(_content.asDouble);
+  if (_type >= JSON_FLOAT_0_DECIMALS)
+    return static_cast<JsonInteger>(_content.asFloat);
 
 
   if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString) {
   if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString) {
     if (!strcmp("true", _content.asString)) return 1;
     if (!strcmp("true", _content.asString)) return 1;
-    return strtol(_content.asString, NULL, 10);
+    return parse<JsonInteger>(_content.asString);
   }
   }
 
 
   return 0L;
   return 0L;
@@ -59,12 +80,12 @@ String JsonVariant::as<String>() const {
       _content.asString != NULL)
       _content.asString != NULL)
     return String(_content.asString);
     return String(_content.asString);
 
 
-  if (_type == JSON_LONG || _type == JSON_BOOLEAN)
-    return String(_content.asLong);
+  if (_type == JSON_INTEGER || _type == JSON_BOOLEAN)
+    return String(_content.asInteger);
 
 
-  if (_type >= JSON_DOUBLE_0_DECIMALS) {
-    uint8_t decimals = static_cast<uint8_t>(_type - JSON_DOUBLE_0_DECIMALS);
-    return String(_content.asDouble, decimals);
+  if (_type >= JSON_FLOAT_0_DECIMALS) {
+    uint8_t decimals = static_cast<uint8_t>(_type - JSON_FLOAT_0_DECIMALS);
+    return String(_content.asFloat, decimals);
   }
   }
 
 
   String s;
   String s;
@@ -74,7 +95,7 @@ String JsonVariant::as<String>() const {
 
 
 template <>
 template <>
 bool JsonVariant::is<signed long>() const {
 bool JsonVariant::is<signed long>() const {
-  if (_type == JSON_LONG) return true;
+  if (_type == JSON_INTEGER) return true;
 
 
   if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
   if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
 
 
@@ -87,7 +108,7 @@ bool JsonVariant::is<signed long>() const {
 
 
 template <>
 template <>
 bool JsonVariant::is<double>() const {
 bool JsonVariant::is<double>() const {
-  if (_type >= JSON_DOUBLE_0_DECIMALS) return true;
+  if (_type >= JSON_FLOAT_0_DECIMALS) return true;
 
 
   if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
   if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
 
 
@@ -111,15 +132,15 @@ void JsonVariant::writeTo(JsonWriter &writer) const {
   else if (_type == JSON_UNPARSED)
   else if (_type == JSON_UNPARSED)
     writer.writeRaw(_content.asString);
     writer.writeRaw(_content.asString);
 
 
-  else if (_type == JSON_LONG)
-    writer.writeLong(_content.asLong);
+  else if (_type == JSON_INTEGER)
+    writer.writeInteger(_content.asInteger);
 
 
   else if (_type == JSON_BOOLEAN)
   else if (_type == JSON_BOOLEAN)
-    writer.writeBoolean(_content.asLong != 0);
+    writer.writeBoolean(_content.asInteger != 0);
 
 
-  else if (_type >= JSON_DOUBLE_0_DECIMALS) {
-    uint8_t decimals = static_cast<uint8_t>(_type - JSON_DOUBLE_0_DECIMALS);
-    writer.writeDouble(_content.asDouble, decimals);
+  else if (_type >= JSON_FLOAT_0_DECIMALS) {
+    uint8_t decimals = static_cast<uint8_t>(_type - JSON_FLOAT_0_DECIMALS);
+    writer.writeFloat(_content.asFloat, decimals);
   }
   }
 }
 }
 }
 }