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 }; 33 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 }; 40 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 }; 47 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 }; 54 static int64_t Negate(int64_t x) { return -x; }; 55 }; 56 57 template <typename T> 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> 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 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 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 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 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 140 TEST(itoa, u32toa) { 141 Verify(u32toa_naive, u32toa); 142 } 143 144 TEST(itoa, i32toa) { 145 Verify(i32toa_naive, i32toa); 146 } 147 148 TEST(itoa, u64toa) { 149 Verify(u64toa_naive, u64toa); 150 } 151 152 TEST(itoa, i64toa) { 153 Verify(i64toa_naive, i64toa); 154 } 155 156 #ifdef __GNUC__ 157 RAPIDJSON_DIAG_POP 158 #endif 159