Skip to content

Commit c29c018

Browse files
committed
Handle serializing integers larger than 64bits.
BigNum are expected to be rare, so calling `Integer#to_s` while not super fast is fast enough and simpler than checking bounds. Ref: #4
1 parent e53ee31 commit c29c018

File tree

2 files changed

+12
-13
lines changed

2 files changed

+12
-13
lines changed

ext/rapidjson/encoder.hh

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,14 @@ class RubyObjectEncoder {
6060
}
6161

6262
void encode_bignum(VALUE b) {
63-
b = rb_big_norm(b);
64-
if (FIXNUM_P(b)) {
65-
return encode_fixnum(b);
66-
}
67-
68-
bool negative = rb_big_cmp(b, INT2FIX(0)) == INT2FIX(-1);
69-
if (negative) {
70-
long long ll = rb_big2ll(b);
71-
writer.Int64(ll);
72-
} else {
73-
unsigned long long ull = rb_big2ull(b);
74-
writer.Uint64(ull);
75-
}
63+
// Some T_BIGNUM might be small enough to fit in long long or unsigned long long
64+
// but this being the slow path, it's not really worth it.
65+
VALUE str = rb_funcall(b, id_to_s, 0);
66+
Check_Type(str, T_STRING);
67+
68+
// We should be able to use RawNumber here, but it's buggy
69+
// https://github.com/Tencent/rapidjson/issues/852
70+
writer.RawValue(RSTRING_PTR(str), RSTRING_LEN(str), kNumberType);
7671
}
7772

7873
void encode_float(VALUE v) {

test/test_encoder.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ def test_encode_bignum
3333
assert_equal "18446744073709551615", encode(2**64 - 1)
3434
end
3535

36+
def test_encore_arbitrary_size_num
37+
assert_equal "340282366920938463463374607431768211456", encode(2**128)
38+
end
39+
3640
def test_encode_fixnum_exponents
3741
tests = []
3842
0.upto(65) do |exponent|

0 commit comments

Comments
 (0)