mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Use float instead of double to reduce the size of JsonVariant (issue #134)
				
					
				
			This commit is contained in:
		| @@ -5,6 +5,7 @@ v5.0.5 | ||||
| ------ | ||||
|  | ||||
| * Add overload `JsonObjectSuscript::set(value, decimals)` (issue #143) | ||||
| * Use `float` instead of `double` to reduce the size of `JsonVariant` (issue #134) | ||||
|  | ||||
| v5.0.4 | ||||
| ------ | ||||
|   | ||||
| @@ -63,7 +63,7 @@ data.add(2.302038, 6);   // if not specified, 2 digits are printed | ||||
| root.printTo(Serial); | ||||
| // This prints: | ||||
| // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]} | ||||
| `` | ||||
| ``` | ||||
|  | ||||
|  | ||||
| Documentation | ||||
|   | ||||
| @@ -20,6 +20,7 @@ class Print { | ||||
|  | ||||
|   size_t print(const char[]); | ||||
|   size_t print(double, int = 2); | ||||
|   size_t print(int); | ||||
|   size_t print(long); | ||||
|   size_t println(); | ||||
| }; | ||||
|   | ||||
| @@ -16,6 +16,7 @@ class String : public std::string { | ||||
|   String(const char *cstr = "") : std::string(cstr) {} | ||||
|   String(const String &str) : std::string(str) {} | ||||
|   explicit String(long); | ||||
|   explicit String(int); | ||||
|   explicit String(double, unsigned char decimalPlaces = 2); | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										20
									
								
								include/ArduinoJson/Internals/JsonFloat.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								include/ArduinoJson/Internals/JsonFloat.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								include/ArduinoJson/Internals/JsonInteger.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								include/ArduinoJson/Internals/JsonInteger.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
| } | ||||
| } | ||||
| @@ -6,6 +6,9 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "JsonFloat.hpp" | ||||
| #include "JsonInteger.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
|  | ||||
| // Forward declarations | ||||
| @@ -13,15 +16,14 @@ class JsonArray; | ||||
| class JsonObject; | ||||
|  | ||||
| namespace Internals { | ||||
|  | ||||
| // A union that defines the actual content of a JsonVariant. | ||||
| // The enum JsonVariantType determines which member is in use. | ||||
| 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 | ||||
| }; | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -19,17 +19,17 @@ enum JsonVariantType { | ||||
|   JSON_UNPARSED,   // the JsonVariant contains an unparsed string | ||||
|   JSON_STRING,     // the JsonVariant stores a const char* | ||||
|   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_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 | ||||
|   // digits that must be printed in the JSON output. | ||||
|   // 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 | ||||
|   // ... | ||||
| }; | ||||
| } | ||||
|   | ||||
| @@ -9,6 +9,8 @@ | ||||
| #include "../Arduino/Print.hpp" | ||||
| #include "Encoding.hpp" | ||||
| #include "ForceInline.hpp" | ||||
| #include "JsonFloat.hpp" | ||||
| #include "JsonInteger.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| 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); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,7 @@ namespace Internals { | ||||
| // A Print implementation that allows to write in a char[] | ||||
| class StaticStringBuilder : public Print { | ||||
|  public: | ||||
|   StaticStringBuilder(char *buf, int size) | ||||
|   StaticStringBuilder(char *buf, size_t size) | ||||
|       : buffer(buf), capacity(size - 1), length(0) { | ||||
|     buffer[0] = '\0'; | ||||
|   } | ||||
| @@ -23,8 +23,8 @@ class StaticStringBuilder : public Print { | ||||
|  | ||||
|  private: | ||||
|   char *buffer; | ||||
|   int capacity; | ||||
|   int length; | ||||
|   size_t capacity; | ||||
|   size_t length; | ||||
| }; | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -83,6 +83,9 @@ class JsonVariant : public JsonVariantBase<JsonVariant> { | ||||
|   static T invalid(); | ||||
|  | ||||
|  private: | ||||
|   Internals::JsonFloat asFloat() const; | ||||
|   Internals::JsonInteger asInteger() const; | ||||
|  | ||||
|   // The current type of the variant | ||||
|   Internals::JsonVariantType _type; | ||||
|  | ||||
|   | ||||
| @@ -11,8 +11,9 @@ | ||||
| namespace ArduinoJson { | ||||
|  | ||||
| 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) { | ||||
| @@ -26,15 +27,15 @@ inline JsonVariant::JsonVariant(Internals::Unparsed value) { | ||||
| } | ||||
|  | ||||
| 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) { | ||||
|   _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) { | ||||
| @@ -48,51 +49,53 @@ inline JsonVariant::JsonVariant(JsonObject &object) { | ||||
| } | ||||
|  | ||||
| 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) { | ||||
|   _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) { | ||||
|   _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) { | ||||
|   _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) { | ||||
|   _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) { | ||||
|   _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) { | ||||
|   _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) { | ||||
|   _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 <> | ||||
| String JsonVariant::as<String>() const; | ||||
|  | ||||
| @@ -101,47 +104,57 @@ const char *JsonVariant::as<const char *>() const; | ||||
|  | ||||
| template <> | ||||
| inline bool JsonVariant::as<bool>() const { | ||||
|   return as<long>() != 0; | ||||
|   return asInteger() != 0; | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline signed char JsonVariant::as<signed char>() const { | ||||
|   return static_cast<signed char>(as<long>()); | ||||
|   return static_cast<signed char>(asInteger()); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline unsigned char JsonVariant::as<unsigned char>() const { | ||||
|   return static_cast<unsigned char>(as<long>()); | ||||
|   return static_cast<unsigned char>(asInteger()); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline signed short JsonVariant::as<signed short>() const { | ||||
|   return static_cast<signed short>(as<long>()); | ||||
|   return static_cast<signed short>(asInteger()); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline unsigned short JsonVariant::as<unsigned short>() const { | ||||
|   return static_cast<unsigned short>(as<long>()); | ||||
|   return static_cast<unsigned short>(asInteger()); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline signed int JsonVariant::as<signed int>() const { | ||||
|   return static_cast<signed int>(as<long>()); | ||||
|   return static_cast<signed int>(asInteger()); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline unsigned int JsonVariant::as<unsigned int>() const { | ||||
|   return static_cast<unsigned int>(as<long>()); | ||||
|   return static_cast<unsigned int>(asInteger()); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| 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 <> | ||||
| inline float JsonVariant::as<float>() const { | ||||
|   return static_cast<float>(as<double>()); | ||||
|   return static_cast<float>(asFloat()); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
|   | ||||
| @@ -60,6 +60,12 @@ size_t Print::print(long 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 | ||||
|   | ||||
| @@ -22,4 +22,10 @@ String::String(long value) { | ||||
|   *this = tmp; | ||||
| } | ||||
|  | ||||
| String::String(int value) { | ||||
|   char tmp[32]; | ||||
|   sprintf(tmp, "%d", value); | ||||
|   *this = tmp; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -16,6 +16,29 @@ using namespace ArduinoJson::Internals; | ||||
|  | ||||
| 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 <> | ||||
| const char *JsonVariant::as<const char *>() const { | ||||
|   if (_type == JSON_UNPARSED && _content.asString && | ||||
| @@ -25,29 +48,27 @@ const char *JsonVariant::as<const char *>() const { | ||||
|   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) | ||||
|     return strtod(_content.asString, NULL); | ||||
|     return parse<JsonFloat>(_content.asString); | ||||
|  | ||||
|   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 (!strcmp("true", _content.asString)) return 1; | ||||
|     return strtol(_content.asString, NULL, 10); | ||||
|     return parse<JsonInteger>(_content.asString); | ||||
|   } | ||||
|  | ||||
|   return 0L; | ||||
| @@ -59,12 +80,12 @@ String JsonVariant::as<String>() const { | ||||
|       _content.asString != NULL) | ||||
|     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; | ||||
| @@ -74,7 +95,7 @@ String JsonVariant::as<String>() const { | ||||
|  | ||||
| template <> | ||||
| 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; | ||||
|  | ||||
| @@ -87,7 +108,7 @@ bool JsonVariant::is<signed long>() const { | ||||
|  | ||||
| template <> | ||||
| 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; | ||||
|  | ||||
| @@ -111,15 +132,15 @@ void JsonVariant::writeTo(JsonWriter &writer) const { | ||||
|   else if (_type == JSON_UNPARSED) | ||||
|     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) | ||||
|     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); | ||||
|   } | ||||
| } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user