Skip to content

Commit

Permalink
Merge branch 'master' of github.com:bblanchon/ArduinoJson into issue2…
Browse files Browse the repository at this point in the history
…76-4
  • Loading branch information
bblanchon committed Jul 28, 2016
2 parents 0ab2163 + a498abc commit f9a5587
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 16 deletions.
13 changes: 9 additions & 4 deletions CHANGELOG.md
Expand Up @@ -6,6 +6,11 @@ HEAD

* Removed class IndentedPrint

v5.6.4
------

* Fixed error in float serialization (issue #324)

v5.6.3
------

Expand Down Expand Up @@ -116,7 +121,7 @@ v5.0.3
v5.0.2
------

* Fixed segmentation fault in `parseObject(String)` and `parseArray(String)`, when the
* Fixed segmentation fault in `parseObject(String)` and `parseArray(String)`, when the
`StaticJsonBuffer` is too small to hold a copy of the string
* Fixed Clang warning "register specifier is deprecated" (issue #102)
* Fixed GCC warning "declaration shadows a member" (issue #103)
Expand Down Expand Up @@ -232,14 +237,14 @@ v3.1

Old generator API:

JsonObject<3> root;
JsonObject<3> root;
root.add("sensor", "gps");
root.add("time", 1351824120);
root.add("data", array);

New generator API:

JsonObject<3> root;
JsonObject<3> root;
root["sensor"] = "gps";
root["time"] = 1351824120;
root["data"] = array;
Expand Down Expand Up @@ -296,7 +301,7 @@ v1.1
* Example: changed `char* json` into `char[] json` so that the bytes are not write protected
* Fixed parsing bug when the JSON contains multi-dimensional arrays

v1.0
v1.0
----

Initial release
2 changes: 1 addition & 1 deletion appveyor.yml
@@ -1,4 +1,4 @@
version: 5.6.3.{build}
version: 5.6.4.{build}
environment:
matrix:
- CMAKE_GENERATOR: Visual Studio 14 2015
Expand Down
39 changes: 30 additions & 9 deletions include/ArduinoJson/Internals/TextWriter.hpp
Expand Up @@ -7,6 +7,8 @@

#pragma once

#include <stdint.h>

#include "../Polyfills/attributes.hpp"
#include "../Polyfills/math.hpp"
#include "../Polyfills/normalize.hpp"
Expand Down Expand Up @@ -60,7 +62,7 @@ class TextWriter {
}
}

void writeFloat(JsonFloat value, int digits = 2) {
void writeFloat(JsonFloat value, uint8_t digits = 2) {
if (Polyfills::isNaN(value)) return writeRaw("NaN");

if (value < 0.0) {
Expand All @@ -77,6 +79,9 @@ class TextWriter {
powersOf10 = 0;
}

// Round up last digit (so that print(1.999, 2) prints as "2.00")
value += getRoundingBias(digits);

// Extract the integer part of the value and print it
JsonUInt int_part = static_cast<JsonUInt>(value);
JsonFloat remainder = value - static_cast<JsonFloat>(int_part);
Expand All @@ -94,9 +99,6 @@ class TextWriter {
char currentDigit = char(remainder);
remainder -= static_cast<JsonFloat>(currentDigit);

// Round up last digit (so that print(1.999, 2) prints as "2.00")
if (digits == 0 && remainder >= 0.5) currentDigit++;

// Print
writeRaw(char('0' + currentDigit));
}
Expand All @@ -114,16 +116,15 @@ class TextWriter {

void writeInteger(JsonUInt value) {
char buffer[22];
char *ptr = buffer + sizeof(buffer) - 1;

int i = 0;
*ptr = 0;
do {
buffer[i++] = static_cast<char>(value % 10 + '0');
*--ptr = static_cast<char>(value % 10 + '0');
value /= 10;
} while (value);

while (i > 0) {
writeRaw(buffer[--i]);
}
writeRaw(ptr);
}

void writeRaw(const char *s) {
Expand All @@ -139,6 +140,26 @@ class TextWriter {

private:
TextWriter &operator=(const TextWriter &); // cannot be assigned

static JsonFloat getLastDigit(uint8_t digits) {
// Designed as a compromise between code size and speed
switch (digits) {
case 0:
return 1e-0;
case 1:
return 1e-1;
case 2:
return 1e-2;
case 3:
return 1e-3;
default:
return getLastDigit(uint8_t(digits - 4)) * 1e-4;
}
}

FORCE_INLINE static JsonFloat getRoundingBias(uint8_t digits) {
return 0.5 * getLastDigit(digits);
}
};
}
}
2 changes: 1 addition & 1 deletion library.json
Expand Up @@ -6,7 +6,7 @@
"type": "git",
"url": "https://github.com/bblanchon/ArduinoJson.git"
},
"version": "5.6.3",
"version": "5.6.4",
"authors": {
"name": "Benoit Blanchon",
"url": "http://blog.benoitblanchon.fr"
Expand Down
2 changes: 1 addition & 1 deletion library.properties
@@ -1,5 +1,5 @@
name=ArduinoJson
version=5.6.3
version=5.6.4
author=Benoit Blanchon <blog.benoitblanchon.fr>
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
sentence=An efficient and elegant JSON library for Arduino.
Expand Down
113 changes: 113 additions & 0 deletions test/JsonWriter_WriteFloat_Tests.cpp
@@ -0,0 +1,113 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!

#include <gtest/gtest.h>
#include <limits>

#include <ArduinoJson/Internals/JsonWriter.hpp>
#include <ArduinoJson/Internals/StaticStringBuilder.hpp>

using namespace ArduinoJson::Internals;

class JsonWriter_WriteFloat_Tests : public testing::Test {
protected:
void whenInputIs(double input, uint8_t digits = 2) {
StaticStringBuilder sb(buffer, sizeof(buffer));
JsonWriter<StaticStringBuilder> writer(sb);
writer.writeFloat(input, digits);
returnValue = writer.bytesWritten();
}

void outputMustBe(const char *expected) {
EXPECT_STREQ(expected, buffer);
EXPECT_EQ(strlen(expected), returnValue);
}

private:
char buffer[1024];
size_t returnValue;
};

TEST_F(JsonWriter_WriteFloat_Tests, NaN) {
whenInputIs(std::numeric_limits<double>::signaling_NaN());
outputMustBe("NaN");
}

TEST_F(JsonWriter_WriteFloat_Tests, PositiveInfinity) {
whenInputIs(std::numeric_limits<double>::infinity());
outputMustBe("Infinity");
}

TEST_F(JsonWriter_WriteFloat_Tests, NegativeInfinity) {
whenInputIs(-std::numeric_limits<double>::infinity());
outputMustBe("-Infinity");
}

TEST_F(JsonWriter_WriteFloat_Tests, Zero) {
whenInputIs(0);
outputMustBe("0.00");
}

TEST_F(JsonWriter_WriteFloat_Tests, ZeroDigits_Rounding) {
whenInputIs(9.5, 0);
outputMustBe("10");
}

TEST_F(JsonWriter_WriteFloat_Tests, ZeroDigits_NoRounding) {
whenInputIs(9.4, 0);
outputMustBe("9");
}

TEST_F(JsonWriter_WriteFloat_Tests, OneDigit_Rounding) {
whenInputIs(9.95, 1);
outputMustBe("10.0");
}

TEST_F(JsonWriter_WriteFloat_Tests, OneDigit_NoRounding) {
whenInputIs(9.94, 1);
outputMustBe("9.9");
}

TEST_F(JsonWriter_WriteFloat_Tests, TwoDigits_Rounding) {
whenInputIs(9.995, 2);
outputMustBe("10.00");
}

TEST_F(JsonWriter_WriteFloat_Tests, TwoDigits_NoRounding) {
whenInputIs(9.994, 2);
outputMustBe("9.99");
}

TEST_F(JsonWriter_WriteFloat_Tests, ThreeDigits_Rounding) {
whenInputIs(9.9995, 3);
outputMustBe("10.000");
}

TEST_F(JsonWriter_WriteFloat_Tests, ThreeDigits_NoRounding) {
whenInputIs(9.9994, 3);
outputMustBe("9.999");
}

TEST_F(JsonWriter_WriteFloat_Tests, FourDigits_Rounding) {
whenInputIs(9.99995, 4);
outputMustBe("10.0000");
}

TEST_F(JsonWriter_WriteFloat_Tests, FourDigits_NoRounding) {
whenInputIs(9.99994, 4);
outputMustBe("9.9999");
}

TEST_F(JsonWriter_WriteFloat_Tests, FiveDigits_Rounding) {
whenInputIs(9.999995, 5);
outputMustBe("10.00000");
}

TEST_F(JsonWriter_WriteFloat_Tests, FiveDigits_NoRounding) {
whenInputIs(9.999994, 5);
outputMustBe("9.99999");
}

0 comments on commit f9a5587

Please sign in to comment.