summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/json/generator/generator.c5
-rw-r--r--ext/json/vendor/fpconv.c23
-rwxr-xr-xtest/json/json_generator_test.rb53
3 files changed, 48 insertions, 33 deletions
diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c
index 8fcc980d47..9b67629f96 100644
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -1345,12 +1345,11 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
}
/* This implementation writes directly into the buffer. We reserve
- * the 28 characters that fpconv_dtoa states as its maximum.
+ * the 32 characters that fpconv_dtoa states as its maximum.
*/
- fbuffer_inc_capa(buffer, 28);
+ fbuffer_inc_capa(buffer, 32);
char* d = buffer->ptr + buffer->len;
int len = fpconv_dtoa(value, d);
-
/* fpconv_dtoa converts a float to its shortest string representation,
* but it adds a ".0" if this is a plain integer.
*/
diff --git a/ext/json/vendor/fpconv.c b/ext/json/vendor/fpconv.c
index 75efd46f11..e91c7889c2 100644
--- a/ext/json/vendor/fpconv.c
+++ b/ext/json/vendor/fpconv.c
@@ -29,6 +29,10 @@
#include <string.h>
#include <stdint.h>
+#ifdef JSON_DEBUG
+#include <assert.h>
+#endif
+
#define npowers 87
#define steppowers 8
#define firstpower -348 /* 10 ^ -348 */
@@ -320,15 +324,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
{
int exp = absv(K + ndigits - 1);
- int max_trailing_zeros = 7;
-
- if(neg) {
- max_trailing_zeros -= 1;
- }
-
- /* write plain integer */
- if(K >= 0 && (exp < (ndigits + max_trailing_zeros))) {
-
+ if(K >= 0 && exp < 15) {
memcpy(dest, digits, ndigits);
memset(dest + ndigits, '0', K);
@@ -432,10 +428,12 @@ static int filter_special(double fp, char* dest)
*
* Input:
* fp -> the double to convert, dest -> destination buffer.
- * The generated string will never be longer than 28 characters.
- * Make sure to pass a pointer to at least 28 bytes of memory.
+ * The generated string will never be longer than 32 characters.
+ * Make sure to pass a pointer to at least 32 bytes of memory.
* The emitted string will not be null terminated.
*
+ *
+ *
* Output:
* The number of written characters.
*
@@ -474,6 +472,9 @@ static int fpconv_dtoa(double d, char dest[28])
int ndigits = grisu2(d, digits, &K);
str_len += emit_digits(digits, ndigits, dest + str_len, K, neg);
+#ifdef JSON_DEBUG
+ assert(str_len <= 32);
+#endif
return str_len;
}
diff --git a/test/json/json_generator_test.rb b/test/json/json_generator_test.rb
index 6b42de2ad2..4fdfa12b0d 100755
--- a/test/json/json_generator_test.rb
+++ b/test/json/json_generator_test.rb
@@ -825,26 +825,41 @@ class JSONGeneratorTest < Test::Unit::TestCase
assert_equal object.object_id.to_json, JSON.generate(object, strict: true, as_json: :object_id)
end
- def test_json_generate_float
- values = [-1.0, 1.0, 0.0, 12.2, 7.5 / 3.2, 12.0, 100.0, 1000.0]
- expecteds = ["-1.0", "1.0", "0.0", "12.2", "2.34375", "12.0", "100.0", "1000.0"]
-
- if RUBY_ENGINE == "jruby"
- values << 1746861937.7842371
- expecteds << "1.7468619377842371E9"
- else
- values << 1746861937.7842371
- expecteds << "1746861937.7842371"
- end
-
- if RUBY_ENGINE == "ruby"
- values << -2.2471348024634545e-08 << -2.2471348024634545e-09 << -2.2471348024634545e-10
- expecteds << "-0.000000022471348024634545" << "-0.0000000022471348024634545" << "-2.2471348024634546e-10"
- end
+ def assert_float_roundtrip(expected, actual)
+ assert_equal(expected, JSON.generate(actual))
+ assert_equal(actual, JSON.parse(JSON.generate(actual)), "JSON: #{JSON.generate(actual)}")
+ end
- values.zip(expecteds).each do |value, expected|
- assert_equal expected, value.to_json
- end
+ def test_json_generate_float
+ assert_float_roundtrip "-1.0", -1.0
+ assert_float_roundtrip "1.0", 1.0
+ assert_float_roundtrip "0.0", 0.0
+ assert_float_roundtrip "12.2", 12.2
+ assert_float_roundtrip "2.34375", 7.5 / 3.2
+ assert_float_roundtrip "12.0", 12.0
+ assert_float_roundtrip "100.0", 100.0
+ assert_float_roundtrip "1000.0", 1000.0
+
+ if RUBY_ENGINE == "jruby"
+ assert_float_roundtrip "1.7468619377842371E9", 1746861937.7842371
+ else
+ assert_float_roundtrip "1746861937.7842371", 1746861937.7842371
+ end
+
+ if RUBY_ENGINE == "ruby"
+ assert_float_roundtrip "100000000000000.0", 100000000000000.0
+ assert_float_roundtrip "1e+15", 1e+15
+ assert_float_roundtrip "-100000000000000.0", -100000000000000.0
+ assert_float_roundtrip "-1e+15", -1e+15
+ assert_float_roundtrip "1111111111111111.1", 1111111111111111.1
+ assert_float_roundtrip "1.1111111111111112e+16", 11111111111111111.1
+ assert_float_roundtrip "-1111111111111111.1", -1111111111111111.1
+ assert_float_roundtrip "-1.1111111111111112e+16", -11111111111111111.1
+
+ assert_float_roundtrip "-0.000000022471348024634545", -2.2471348024634545e-08
+ assert_float_roundtrip "-0.0000000022471348024634545", -2.2471348024634545e-09
+ assert_float_roundtrip "-2.2471348024634546e-10", -2.2471348024634545e-10
+ end
end
def test_numbers_of_various_sizes