1 // Tencent is pleased to support the open source community by making RapidJSON available.
2 //
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // http://opensource.org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14 
15 #include "unittest.h"
16 #include "rapidjson/internal/itoa.h"
17 
18 #ifdef __GNUC__
19 RAPIDJSON_DIAG_PUSH
20 RAPIDJSON_DIAG_OFF(type-limits)
21 #endif
22 
23 using namespace rapidjson::internal;
24 
25 template <typename T>
26 struct Traits {
27 };
28 
29 template <>
30 struct Traits<uint32_t> {
31     enum { kBufferSize = 11 };
32     enum { kMaxDigit = 10 };
NegateTraits33     static uint32_t Negate(uint32_t x) { return x; };
34 };
35 
36 template <>
37 struct Traits<int32_t> {
38     enum { kBufferSize = 12 };
39     enum { kMaxDigit = 10 };
NegateTraits40     static int32_t Negate(int32_t x) { return -x; };
41 };
42 
43 template <>
44 struct Traits<uint64_t> {
45     enum { kBufferSize = 21 };
46     enum { kMaxDigit = 20 };
NegateTraits47     static uint64_t Negate(uint64_t x) { return x; };
48 };
49 
50 template <>
51 struct Traits<int64_t> {
52     enum { kBufferSize = 22 };
53     enum { kMaxDigit = 20 };
NegateTraits54     static int64_t Negate(int64_t x) { return -x; };
55 };
56 
57 template <typename T>
VerifyValue(T value,void (* f)(T,char *),char * (* g)(T,char *))58 static void VerifyValue(T value, void(*f)(T, char*), char* (*g)(T, char*)) {
59     char buffer1[Traits<T>::kBufferSize];
60     char buffer2[Traits<T>::kBufferSize];
61 
62     f(value, buffer1);
63     *g(value, buffer2) = '\0';
64 
65 
66     EXPECT_STREQ(buffer1, buffer2);
67 }
68 
69 template <typename T>
Verify(void (* f)(T,char *),char * (* g)(T,char *))70 static void Verify(void(*f)(T, char*), char* (*g)(T, char*)) {
71     // Boundary cases
72     VerifyValue<T>(0, f, g);
73     VerifyValue<T>(std::numeric_limits<T>::min(), f, g);
74     VerifyValue<T>(std::numeric_limits<T>::max(), f, g);
75 
76     // 2^n - 1, 2^n, 10^n - 1, 10^n until overflow
77     for (uint32_t power = 2; power <= 10; power += 8) {
78         T i = 1, last;
79         do {
80             VerifyValue<T>(i - 1, f, g);
81             VerifyValue<T>(i, f, g);
82             if (std::numeric_limits<T>::min() < 0) {
83                 VerifyValue<T>(Traits<T>::Negate(i), f, g);
84                 VerifyValue<T>(Traits<T>::Negate(i + 1), f, g);
85             }
86             last = i;
87             i *= power;
88         } while (last < i);
89     }
90 }
91 
u32toa_naive(uint32_t value,char * buffer)92 static void u32toa_naive(uint32_t value, char* buffer) {
93     char temp[10];
94     char *p = temp;
95     do {
96         *p++ = char(value % 10) + '0';
97         value /= 10;
98     } while (value > 0);
99 
100     do {
101         *buffer++ = *--p;
102     } while (p != temp);
103 
104     *buffer = '\0';
105 }
106 
i32toa_naive(int32_t value,char * buffer)107 static void i32toa_naive(int32_t value, char* buffer) {
108     uint32_t u = static_cast<uint32_t>(value);
109     if (value < 0) {
110         *buffer++ = '-';
111         u = ~u + 1;
112     }
113     u32toa_naive(u, buffer);
114 }
115 
u64toa_naive(uint64_t value,char * buffer)116 static void u64toa_naive(uint64_t value, char* buffer) {
117     char temp[20];
118     char *p = temp;
119     do {
120         *p++ = char(value % 10) + '0';
121         value /= 10;
122     } while (value > 0);
123 
124     do {
125         *buffer++ = *--p;
126     } while (p != temp);
127 
128     *buffer = '\0';
129 }
130 
i64toa_naive(int64_t value,char * buffer)131 static void i64toa_naive(int64_t value, char* buffer) {
132     uint64_t u = static_cast<uint64_t>(value);
133     if (value < 0) {
134         *buffer++ = '-';
135         u = ~u + 1;
136     }
137     u64toa_naive(u, buffer);
138 }
139 
TEST(itoa,u32toa)140 TEST(itoa, u32toa) {
141     Verify(u32toa_naive, u32toa);
142 }
143 
TEST(itoa,i32toa)144 TEST(itoa, i32toa) {
145     Verify(i32toa_naive, i32toa);
146 }
147 
TEST(itoa,u64toa)148 TEST(itoa, u64toa) {
149     Verify(u64toa_naive, u64toa);
150 }
151 
TEST(itoa,i64toa)152 TEST(itoa, i64toa) {
153     Verify(i64toa_naive, i64toa);
154 }
155 
156 #ifdef __GNUC__
157 RAPIDJSON_DIAG_POP
158 #endif
159