/src/capnproto/c++/src/kj/string.c++
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors |
2 | | // Licensed under the MIT License: |
3 | | // |
4 | | // Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | // of this software and associated documentation files (the "Software"), to deal |
6 | | // in the Software without restriction, including without limitation the rights |
7 | | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
8 | | // copies of the Software, and to permit persons to whom the Software is |
9 | | // furnished to do so, subject to the following conditions: |
10 | | // |
11 | | // The above copyright notice and this permission notice shall be included in |
12 | | // all copies or substantial portions of the Software. |
13 | | // |
14 | | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 | | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
20 | | // THE SOFTWARE. |
21 | | |
22 | | #include "string.h" |
23 | | #include "debug.h" |
24 | | #include <stdio.h> |
25 | | #include <float.h> |
26 | | #include <errno.h> |
27 | | #include <stdlib.h> |
28 | | #include <stdint.h> |
29 | | #if !defined(_WIN32) |
30 | | #include <string.h> |
31 | | #endif |
32 | | |
33 | | namespace kj { |
34 | | |
35 | | namespace { |
36 | 0 | bool isHex(const char *s) { |
37 | 0 | if (*s == '-') s++; |
38 | 0 | return s[0] == '0' && (s[1] == 'x' || s[1] == 'X'); |
39 | 0 | } |
40 | | |
41 | 0 | long long parseSigned(const StringPtr& s, long long min, long long max) { |
42 | 0 | KJ_REQUIRE(s != nullptr, "String does not contain valid number", s) { return 0; } |
43 | 0 | char *endPtr; |
44 | 0 | errno = 0; |
45 | 0 | auto value = strtoll(s.begin(), &endPtr, isHex(s.cStr()) ? 16 : 10); |
46 | 0 | KJ_REQUIRE(endPtr == s.end(), "String does not contain valid number", s) { return 0; } |
47 | 0 | KJ_REQUIRE(errno != ERANGE, "Value out-of-range", s) { return 0; } |
48 | 0 | KJ_REQUIRE(value >= min && value <= max, "Value out-of-range", value, min, max) { return 0; } |
49 | 0 | return value; |
50 | 0 | } |
51 | | |
52 | 0 | Maybe<long long> tryParseSigned(const StringPtr& s, long long min, long long max) { |
53 | 0 | if (s == nullptr) { return kj::none; } // String does not contain valid number. |
54 | 0 | char *endPtr; |
55 | 0 | errno = 0; |
56 | 0 | auto value = strtoll(s.begin(), &endPtr, isHex(s.cStr()) ? 16 : 10); |
57 | 0 | if (endPtr != s.end() || errno == ERANGE || value < min || max < value) { |
58 | 0 | return kj::none; |
59 | 0 | } |
60 | 0 | return value; |
61 | 0 | } |
62 | | |
63 | 0 | unsigned long long parseUnsigned(const StringPtr& s, unsigned long long max) { |
64 | 0 | KJ_REQUIRE(s != nullptr, "String does not contain valid number", s) { return 0; } |
65 | 0 | char *endPtr; |
66 | 0 | errno = 0; |
67 | 0 | auto value = strtoull(s.begin(), &endPtr, isHex(s.cStr()) ? 16 : 10); |
68 | 0 | KJ_REQUIRE(endPtr == s.end(), "String does not contain valid number", s) { return 0; } |
69 | 0 | KJ_REQUIRE(errno != ERANGE, "Value out-of-range", s) { return 0; } |
70 | 0 | KJ_REQUIRE(value <= max, "Value out-of-range", value, max) { return 0; } |
71 | | //strtoull("-1") does not fail with ERANGE |
72 | 0 | KJ_REQUIRE(s[0] != '-', "Value out-of-range", s) { return 0; } |
73 | 0 | return value; |
74 | 0 | } |
75 | | |
76 | 0 | Maybe<unsigned long long> tryParseUnsigned(const StringPtr& s, unsigned long long max) { |
77 | 0 | if (s == nullptr) { return kj::none; } // String does not contain valid number. |
78 | 0 | char *endPtr; |
79 | 0 | errno = 0; |
80 | 0 | auto value = strtoull(s.begin(), &endPtr, isHex(s.cStr()) ? 16 : 10); |
81 | 0 | if (endPtr != s.end() || errno == ERANGE || max < value || s[0] == '-') { return kj::none; } |
82 | 0 | return value; |
83 | 0 | } |
84 | | |
85 | | template <typename T> |
86 | 0 | T parseInteger(const StringPtr& s) { |
87 | 0 | if (static_cast<T>(minValue) < 0) { |
88 | 0 | long long min = static_cast<T>(minValue); |
89 | 0 | long long max = static_cast<T>(maxValue); |
90 | 0 | return static_cast<T>(parseSigned(s, min, max)); |
91 | 0 | } else { |
92 | 0 | unsigned long long max = static_cast<T>(maxValue); |
93 | 0 | return static_cast<T>(parseUnsigned(s, max)); |
94 | 0 | } |
95 | 0 | } Unexecuted instantiation: string.c++:char kj::(anonymous namespace)::parseInteger<char>(kj::StringPtr const&) Unexecuted instantiation: string.c++:signed char kj::(anonymous namespace)::parseInteger<signed char>(kj::StringPtr const&) Unexecuted instantiation: string.c++:unsigned char kj::(anonymous namespace)::parseInteger<unsigned char>(kj::StringPtr const&) Unexecuted instantiation: string.c++:short kj::(anonymous namespace)::parseInteger<short>(kj::StringPtr const&) Unexecuted instantiation: string.c++:unsigned short kj::(anonymous namespace)::parseInteger<unsigned short>(kj::StringPtr const&) Unexecuted instantiation: string.c++:int kj::(anonymous namespace)::parseInteger<int>(kj::StringPtr const&) Unexecuted instantiation: string.c++:unsigned int kj::(anonymous namespace)::parseInteger<unsigned int>(kj::StringPtr const&) Unexecuted instantiation: string.c++:long kj::(anonymous namespace)::parseInteger<long>(kj::StringPtr const&) Unexecuted instantiation: string.c++:unsigned long kj::(anonymous namespace)::parseInteger<unsigned long>(kj::StringPtr const&) Unexecuted instantiation: string.c++:long long kj::(anonymous namespace)::parseInteger<long long>(kj::StringPtr const&) Unexecuted instantiation: string.c++:unsigned long long kj::(anonymous namespace)::parseInteger<unsigned long long>(kj::StringPtr const&) |
96 | | |
97 | | template <typename T> |
98 | 0 | Maybe<T> tryParseInteger(const StringPtr& s) { |
99 | 0 | if (static_cast<T>(minValue) < 0) { |
100 | 0 | long long min = static_cast<T>(minValue); |
101 | 0 | long long max = static_cast<T>(maxValue); |
102 | 0 | return static_cast<Maybe<T>>(tryParseSigned(s, min, max)); |
103 | 0 | } else { |
104 | 0 | unsigned long long max = static_cast<T>(maxValue); |
105 | 0 | return static_cast<Maybe<T>>(tryParseUnsigned(s, max)); |
106 | 0 | } |
107 | 0 | } Unexecuted instantiation: string.c++:kj::Maybe<char> kj::(anonymous namespace)::tryParseInteger<char>(kj::StringPtr const&) Unexecuted instantiation: string.c++:kj::Maybe<signed char> kj::(anonymous namespace)::tryParseInteger<signed char>(kj::StringPtr const&) Unexecuted instantiation: string.c++:kj::Maybe<unsigned char> kj::(anonymous namespace)::tryParseInteger<unsigned char>(kj::StringPtr const&) Unexecuted instantiation: string.c++:kj::Maybe<short> kj::(anonymous namespace)::tryParseInteger<short>(kj::StringPtr const&) Unexecuted instantiation: string.c++:kj::Maybe<unsigned short> kj::(anonymous namespace)::tryParseInteger<unsigned short>(kj::StringPtr const&) Unexecuted instantiation: string.c++:kj::Maybe<int> kj::(anonymous namespace)::tryParseInteger<int>(kj::StringPtr const&) Unexecuted instantiation: string.c++:kj::Maybe<unsigned int> kj::(anonymous namespace)::tryParseInteger<unsigned int>(kj::StringPtr const&) Unexecuted instantiation: string.c++:kj::Maybe<long> kj::(anonymous namespace)::tryParseInteger<long>(kj::StringPtr const&) Unexecuted instantiation: string.c++:kj::Maybe<unsigned long> kj::(anonymous namespace)::tryParseInteger<unsigned long>(kj::StringPtr const&) Unexecuted instantiation: string.c++:kj::Maybe<long long> kj::(anonymous namespace)::tryParseInteger<long long>(kj::StringPtr const&) Unexecuted instantiation: string.c++:kj::Maybe<unsigned long long> kj::(anonymous namespace)::tryParseInteger<unsigned long long>(kj::StringPtr const&) |
108 | | |
109 | | } // namespace |
110 | | |
111 | | #define PARSE_AS_INTEGER(T) \ |
112 | 0 | template <> T StringPtr::parseAs<T>() const { return parseInteger<T>(*this); } Unexecuted instantiation: char kj::StringPtr::parseAs<char>() const Unexecuted instantiation: signed char kj::StringPtr::parseAs<signed char>() const Unexecuted instantiation: unsigned char kj::StringPtr::parseAs<unsigned char>() const Unexecuted instantiation: short kj::StringPtr::parseAs<short>() const Unexecuted instantiation: unsigned short kj::StringPtr::parseAs<unsigned short>() const Unexecuted instantiation: int kj::StringPtr::parseAs<int>() const Unexecuted instantiation: unsigned int kj::StringPtr::parseAs<unsigned int>() const Unexecuted instantiation: long kj::StringPtr::parseAs<long>() const Unexecuted instantiation: unsigned long kj::StringPtr::parseAs<unsigned long>() const Unexecuted instantiation: long long kj::StringPtr::parseAs<long long>() const Unexecuted instantiation: unsigned long long kj::StringPtr::parseAs<unsigned long long>() const |
113 | | PARSE_AS_INTEGER(char); |
114 | | PARSE_AS_INTEGER(signed char); |
115 | | PARSE_AS_INTEGER(unsigned char); |
116 | | PARSE_AS_INTEGER(short); |
117 | | PARSE_AS_INTEGER(unsigned short); |
118 | | PARSE_AS_INTEGER(int); |
119 | | PARSE_AS_INTEGER(unsigned int); |
120 | | PARSE_AS_INTEGER(long); |
121 | | PARSE_AS_INTEGER(unsigned long); |
122 | | PARSE_AS_INTEGER(long long); |
123 | | PARSE_AS_INTEGER(unsigned long long); |
124 | | #undef PARSE_AS_INTEGER |
125 | | |
126 | | #define TRY_PARSE_AS_INTEGER(T) \ |
127 | 0 | template <> Maybe<T> StringPtr::tryParseAs<T>() const { return tryParseInteger<T>(*this); } Unexecuted instantiation: kj::Maybe<char> kj::StringPtr::tryParseAs<char>() const Unexecuted instantiation: kj::Maybe<signed char> kj::StringPtr::tryParseAs<signed char>() const Unexecuted instantiation: kj::Maybe<unsigned char> kj::StringPtr::tryParseAs<unsigned char>() const Unexecuted instantiation: kj::Maybe<short> kj::StringPtr::tryParseAs<short>() const Unexecuted instantiation: kj::Maybe<unsigned short> kj::StringPtr::tryParseAs<unsigned short>() const Unexecuted instantiation: kj::Maybe<int> kj::StringPtr::tryParseAs<int>() const Unexecuted instantiation: kj::Maybe<unsigned int> kj::StringPtr::tryParseAs<unsigned int>() const Unexecuted instantiation: kj::Maybe<long> kj::StringPtr::tryParseAs<long>() const Unexecuted instantiation: kj::Maybe<unsigned long> kj::StringPtr::tryParseAs<unsigned long>() const Unexecuted instantiation: kj::Maybe<long long> kj::StringPtr::tryParseAs<long long>() const Unexecuted instantiation: kj::Maybe<unsigned long long> kj::StringPtr::tryParseAs<unsigned long long>() const |
128 | | TRY_PARSE_AS_INTEGER(char); |
129 | | TRY_PARSE_AS_INTEGER(signed char); |
130 | | TRY_PARSE_AS_INTEGER(unsigned char); |
131 | | TRY_PARSE_AS_INTEGER(short); |
132 | | TRY_PARSE_AS_INTEGER(unsigned short); |
133 | | TRY_PARSE_AS_INTEGER(int); |
134 | | TRY_PARSE_AS_INTEGER(unsigned int); |
135 | | TRY_PARSE_AS_INTEGER(long); |
136 | | TRY_PARSE_AS_INTEGER(unsigned long); |
137 | | TRY_PARSE_AS_INTEGER(long long); |
138 | | TRY_PARSE_AS_INTEGER(unsigned long long); |
139 | | #undef TRY_PARSE_AS_INTEGER |
140 | | |
141 | 777k | String heapString(size_t size) { |
142 | 777k | char* buffer = _::HeapArrayDisposer::allocate<char>(size + 1); |
143 | 777k | buffer[size] = '\0'; |
144 | 777k | return String(buffer, size, _::HeapArrayDisposer::instance); |
145 | 777k | } |
146 | | |
147 | 12.1k | String heapString(const char* value, size_t size) { |
148 | 12.1k | char* buffer = _::HeapArrayDisposer::allocate<char>(size + 1); |
149 | 12.1k | if (size != 0u) { |
150 | 12.1k | memcpy(buffer, value, size); |
151 | 12.1k | } |
152 | 12.1k | buffer[size] = '\0'; |
153 | 12.1k | return String(buffer, size, _::HeapArrayDisposer::instance); |
154 | 12.1k | } |
155 | | |
156 | | template <typename T> |
157 | 5.98k | static CappedArray<char, sizeof(T) * 2 + 1> hexImpl(T i) { |
158 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). |
159 | 5.98k | CappedArray<char, sizeof(T) * 2 + 1> result; |
160 | 5.98k | uint8_t reverse[sizeof(T) * 2]; |
161 | 5.98k | uint8_t* p = reverse; |
162 | 5.98k | if (i == 0) { |
163 | 388 | *p++ = 0; |
164 | 5.59k | } else { |
165 | 42.9k | while (i > 0) { |
166 | 37.3k | *p++ = i % 16; |
167 | 37.3k | i /= 16; |
168 | 37.3k | } |
169 | 5.59k | } |
170 | | |
171 | 5.98k | char* p2 = result.begin(); |
172 | 43.6k | while (p > reverse) { |
173 | 37.7k | *p2++ = "0123456789abcdef"[*--p]; |
174 | 37.7k | } |
175 | 5.98k | result.setSize(p2 - result.begin()); |
176 | 5.98k | return result; |
177 | 5.98k | } Unexecuted instantiation: string.c++:kj::CappedArray<char, ((sizeof (unsigned char))*(2))+(1)> kj::hexImpl<unsigned char>(unsigned char) Unexecuted instantiation: string.c++:kj::CappedArray<char, ((sizeof (unsigned short))*(2))+(1)> kj::hexImpl<unsigned short>(unsigned short) Unexecuted instantiation: string.c++:kj::CappedArray<char, ((sizeof (unsigned int))*(2))+(1)> kj::hexImpl<unsigned int>(unsigned int) string.c++:kj::CappedArray<char, ((sizeof (unsigned long))*(2))+(1)> kj::hexImpl<unsigned long>(unsigned long) Line | Count | Source | 157 | 5.98k | static CappedArray<char, sizeof(T) * 2 + 1> hexImpl(T i) { | 158 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 159 | 5.98k | CappedArray<char, sizeof(T) * 2 + 1> result; | 160 | 5.98k | uint8_t reverse[sizeof(T) * 2]; | 161 | 5.98k | uint8_t* p = reverse; | 162 | 5.98k | if (i == 0) { | 163 | 388 | *p++ = 0; | 164 | 5.59k | } else { | 165 | 42.9k | while (i > 0) { | 166 | 37.3k | *p++ = i % 16; | 167 | 37.3k | i /= 16; | 168 | 37.3k | } | 169 | 5.59k | } | 170 | | | 171 | 5.98k | char* p2 = result.begin(); | 172 | 43.6k | while (p > reverse) { | 173 | 37.7k | *p2++ = "0123456789abcdef"[*--p]; | 174 | 37.7k | } | 175 | 5.98k | result.setSize(p2 - result.begin()); | 176 | 5.98k | return result; | 177 | 5.98k | } |
Unexecuted instantiation: string.c++:kj::CappedArray<char, ((sizeof (unsigned long long))*(2))+(1)> kj::hexImpl<unsigned long long>(unsigned long long) |
178 | | |
179 | | #define HEXIFY_INT(type) \ |
180 | 0 | CappedArray<char, sizeof(type) * 2 + 1> hex(type i) { \ |
181 | 0 | return hexImpl<type>(i); \ |
182 | 0 | } Unexecuted instantiation: kj::hex(unsigned char) Unexecuted instantiation: kj::hex(unsigned short) Unexecuted instantiation: kj::hex(unsigned int) Unexecuted instantiation: kj::hex(unsigned long) Unexecuted instantiation: kj::hex(unsigned long long) |
183 | | |
184 | | HEXIFY_INT(unsigned char); |
185 | | HEXIFY_INT(unsigned short); |
186 | | HEXIFY_INT(unsigned int); |
187 | | HEXIFY_INT(unsigned long); |
188 | | HEXIFY_INT(unsigned long long); |
189 | | |
190 | | #undef HEXIFY_INT |
191 | | |
192 | | namespace _ { // private |
193 | | |
194 | 388 | StringPtr Stringifier::operator*(decltype(nullptr)) const { |
195 | 388 | return "nullptr"; |
196 | 388 | } |
197 | | |
198 | 38.5k | StringPtr Stringifier::operator*(bool b) const { |
199 | 38.5k | return b ? StringPtr("true") : StringPtr("false"); |
200 | 38.5k | } |
201 | | |
202 | | template <typename T, typename Unsigned> |
203 | 72.5M | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { |
204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). |
205 | 72.5M | CappedArray<char, sizeof(T) * 3 + 2> result; |
206 | 72.5M | bool negative = i < 0; |
207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But |
208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it |
209 | | // unsigned first, then negate it, to avoid ubsan complaining. |
210 | 72.5M | Unsigned u = i; |
211 | 72.5M | if (negative) u = -u; |
212 | 72.5M | uint8_t reverse[sizeof(T) * 3 + 1]; |
213 | 72.5M | uint8_t* p = reverse; |
214 | 72.5M | if (u == 0) { |
215 | 34.6M | *p++ = 0; |
216 | 37.9M | } else { |
217 | 142M | while (u > 0) { |
218 | 104M | *p++ = u % 10; |
219 | 104M | u /= 10; |
220 | 104M | } |
221 | 37.9M | } |
222 | | |
223 | 72.5M | char* p2 = result.begin(); |
224 | 72.5M | if (negative) *p2++ = '-'; |
225 | 211M | while (p > reverse) { |
226 | 139M | *p2++ = '0' + *--p; |
227 | 139M | } |
228 | 72.5M | result.setSize(p2 - result.begin()); |
229 | 72.5M | return result; |
230 | 72.5M | } string.c++:kj::CappedArray<char, ((sizeof (signed char))*(3))+(2)> kj::_::stringifyImpl<signed char, unsigned int>(signed char) Line | Count | Source | 203 | 28.2k | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { | 204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 205 | 28.2k | CappedArray<char, sizeof(T) * 3 + 2> result; | 206 | 28.2k | bool negative = i < 0; | 207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But | 208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it | 209 | | // unsigned first, then negate it, to avoid ubsan complaining. | 210 | 28.2k | Unsigned u = i; | 211 | 28.2k | if (negative) u = -u; | 212 | 28.2k | uint8_t reverse[sizeof(T) * 3 + 1]; | 213 | 28.2k | uint8_t* p = reverse; | 214 | 28.2k | if (u == 0) { | 215 | 12.8k | *p++ = 0; | 216 | 15.4k | } else { | 217 | 47.2k | while (u > 0) { | 218 | 31.8k | *p++ = u % 10; | 219 | 31.8k | u /= 10; | 220 | 31.8k | } | 221 | 15.4k | } | 222 | | | 223 | 28.2k | char* p2 = result.begin(); | 224 | 28.2k | if (negative) *p2++ = '-'; | 225 | 72.9k | while (p > reverse) { | 226 | 44.7k | *p2++ = '0' + *--p; | 227 | 44.7k | } | 228 | 28.2k | result.setSize(p2 - result.begin()); | 229 | 28.2k | return result; | 230 | 28.2k | } |
string.c++:kj::CappedArray<char, ((sizeof (unsigned char))*(3))+(2)> kj::_::stringifyImpl<unsigned char, unsigned int>(unsigned char) Line | Count | Source | 203 | 72.1M | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { | 204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 205 | 72.1M | CappedArray<char, sizeof(T) * 3 + 2> result; | 206 | 72.1M | bool negative = i < 0; | 207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But | 208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it | 209 | | // unsigned first, then negate it, to avoid ubsan complaining. | 210 | 72.1M | Unsigned u = i; | 211 | 72.1M | if (negative) u = -u; | 212 | 72.1M | uint8_t reverse[sizeof(T) * 3 + 1]; | 213 | 72.1M | uint8_t* p = reverse; | 214 | 72.1M | if (u == 0) { | 215 | 34.5M | *p++ = 0; | 216 | 37.6M | } else { | 217 | 140M | while (u > 0) { | 218 | 102M | *p++ = u % 10; | 219 | 102M | u /= 10; | 220 | 102M | } | 221 | 37.6M | } | 222 | | | 223 | 72.1M | char* p2 = result.begin(); | 224 | 72.1M | if (negative) *p2++ = '-'; | 225 | 209M | while (p > reverse) { | 226 | 137M | *p2++ = '0' + *--p; | 227 | 137M | } | 228 | 72.1M | result.setSize(p2 - result.begin()); | 229 | 72.1M | return result; | 230 | 72.1M | } |
string.c++:kj::CappedArray<char, ((sizeof (short))*(3))+(2)> kj::_::stringifyImpl<short, unsigned int>(short) Line | Count | Source | 203 | 27.2k | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { | 204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 205 | 27.2k | CappedArray<char, sizeof(T) * 3 + 2> result; | 206 | 27.2k | bool negative = i < 0; | 207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But | 208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it | 209 | | // unsigned first, then negate it, to avoid ubsan complaining. | 210 | 27.2k | Unsigned u = i; | 211 | 27.2k | if (negative) u = -u; | 212 | 27.2k | uint8_t reverse[sizeof(T) * 3 + 1]; | 213 | 27.2k | uint8_t* p = reverse; | 214 | 27.2k | if (u == 0) { | 215 | 12.5k | *p++ = 0; | 216 | 14.6k | } else { | 217 | 64.5k | while (u > 0) { | 218 | 49.8k | *p++ = u % 10; | 219 | 49.8k | u /= 10; | 220 | 49.8k | } | 221 | 14.6k | } | 222 | | | 223 | 27.2k | char* p2 = result.begin(); | 224 | 27.2k | if (negative) *p2++ = '-'; | 225 | 89.6k | while (p > reverse) { | 226 | 62.3k | *p2++ = '0' + *--p; | 227 | 62.3k | } | 228 | 27.2k | result.setSize(p2 - result.begin()); | 229 | 27.2k | return result; | 230 | 27.2k | } |
string.c++:kj::CappedArray<char, ((sizeof (unsigned short))*(3))+(2)> kj::_::stringifyImpl<unsigned short, unsigned int>(unsigned short) Line | Count | Source | 203 | 23.9k | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { | 204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 205 | 23.9k | CappedArray<char, sizeof(T) * 3 + 2> result; | 206 | 23.9k | bool negative = i < 0; | 207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But | 208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it | 209 | | // unsigned first, then negate it, to avoid ubsan complaining. | 210 | 23.9k | Unsigned u = i; | 211 | 23.9k | if (negative) u = -u; | 212 | 23.9k | uint8_t reverse[sizeof(T) * 3 + 1]; | 213 | 23.9k | uint8_t* p = reverse; | 214 | 23.9k | if (u == 0) { | 215 | 13.3k | *p++ = 0; | 216 | 13.3k | } else { | 217 | 50.2k | while (u > 0) { | 218 | 39.5k | *p++ = u % 10; | 219 | 39.5k | u /= 10; | 220 | 39.5k | } | 221 | 10.6k | } | 222 | | | 223 | 23.9k | char* p2 = result.begin(); | 224 | 23.9k | if (negative) *p2++ = '-'; | 225 | 76.8k | while (p > reverse) { | 226 | 52.8k | *p2++ = '0' + *--p; | 227 | 52.8k | } | 228 | 23.9k | result.setSize(p2 - result.begin()); | 229 | 23.9k | return result; | 230 | 23.9k | } |
string.c++:kj::CappedArray<char, ((sizeof (int))*(3))+(2)> kj::_::stringifyImpl<int, unsigned int>(int) Line | Count | Source | 203 | 199k | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { | 204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 205 | 199k | CappedArray<char, sizeof(T) * 3 + 2> result; | 206 | 199k | bool negative = i < 0; | 207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But | 208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it | 209 | | // unsigned first, then negate it, to avoid ubsan complaining. | 210 | 199k | Unsigned u = i; | 211 | 199k | if (negative) u = -u; | 212 | 199k | uint8_t reverse[sizeof(T) * 3 + 1]; | 213 | 199k | uint8_t* p = reverse; | 214 | 199k | if (u == 0) { | 215 | 11.1k | *p++ = 0; | 216 | 188k | } else { | 217 | 869k | while (u > 0) { | 218 | 681k | *p++ = u % 10; | 219 | 681k | u /= 10; | 220 | 681k | } | 221 | 188k | } | 222 | | | 223 | 199k | char* p2 = result.begin(); | 224 | 199k | if (negative) *p2++ = '-'; | 225 | 891k | while (p > reverse) { | 226 | 692k | *p2++ = '0' + *--p; | 227 | 692k | } | 228 | 199k | result.setSize(p2 - result.begin()); | 229 | 199k | return result; | 230 | 199k | } |
string.c++:kj::CappedArray<char, ((sizeof (unsigned int))*(3))+(2)> kj::_::stringifyImpl<unsigned int, unsigned int>(unsigned int) Line | Count | Source | 203 | 64.9k | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { | 204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 205 | 64.9k | CappedArray<char, sizeof(T) * 3 + 2> result; | 206 | 64.9k | bool negative = i < 0; | 207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But | 208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it | 209 | | // unsigned first, then negate it, to avoid ubsan complaining. | 210 | 64.9k | Unsigned u = i; | 211 | 64.9k | if (negative) u = -u; | 212 | 64.9k | uint8_t reverse[sizeof(T) * 3 + 1]; | 213 | 64.9k | uint8_t* p = reverse; | 214 | 64.9k | if (u == 0) { | 215 | 15.0k | *p++ = 0; | 216 | 49.8k | } else { | 217 | 328k | while (u > 0) { | 218 | 278k | *p++ = u % 10; | 219 | 278k | u /= 10; | 220 | 278k | } | 221 | 49.8k | } | 222 | | | 223 | 64.9k | char* p2 = result.begin(); | 224 | 64.9k | if (negative) *p2++ = '-'; | 225 | 358k | while (p > reverse) { | 226 | 293k | *p2++ = '0' + *--p; | 227 | 293k | } | 228 | 64.9k | result.setSize(p2 - result.begin()); | 229 | 64.9k | return result; | 230 | 64.9k | } |
string.c++:kj::CappedArray<char, ((sizeof (long))*(3))+(2)> kj::_::stringifyImpl<long, unsigned long>(long) Line | Count | Source | 203 | 25.4k | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { | 204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 205 | 25.4k | CappedArray<char, sizeof(T) * 3 + 2> result; | 206 | 25.4k | bool negative = i < 0; | 207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But | 208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it | 209 | | // unsigned first, then negate it, to avoid ubsan complaining. | 210 | 25.4k | Unsigned u = i; | 211 | 25.4k | if (negative) u = -u; | 212 | 25.4k | uint8_t reverse[sizeof(T) * 3 + 1]; | 213 | 25.4k | uint8_t* p = reverse; | 214 | 25.4k | if (u == 0) { | 215 | 10.0k | *p++ = 0; | 216 | 15.3k | } else { | 217 | 227k | while (u > 0) { | 218 | 211k | *p++ = u % 10; | 219 | 211k | u /= 10; | 220 | 211k | } | 221 | 15.3k | } | 222 | | | 223 | 25.4k | char* p2 = result.begin(); | 224 | 25.4k | if (negative) *p2++ = '-'; | 225 | 247k | while (p > reverse) { | 226 | 221k | *p2++ = '0' + *--p; | 227 | 221k | } | 228 | 25.4k | result.setSize(p2 - result.begin()); | 229 | 25.4k | return result; | 230 | 25.4k | } |
string.c++:kj::CappedArray<char, ((sizeof (unsigned long))*(3))+(2)> kj::_::stringifyImpl<unsigned long, unsigned long>(unsigned long) Line | Count | Source | 203 | 26.9k | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { | 204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 205 | 26.9k | CappedArray<char, sizeof(T) * 3 + 2> result; | 206 | 26.9k | bool negative = i < 0; | 207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But | 208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it | 209 | | // unsigned first, then negate it, to avoid ubsan complaining. | 210 | 26.9k | Unsigned u = i; | 211 | 26.9k | if (negative) u = -u; | 212 | 26.9k | uint8_t reverse[sizeof(T) * 3 + 1]; | 213 | 26.9k | uint8_t* p = reverse; | 214 | 26.9k | if (u == 0) { | 215 | 12.7k | *p++ = 0; | 216 | 14.1k | } else { | 217 | 159k | while (u > 0) { | 218 | 145k | *p++ = u % 10; | 219 | 145k | u /= 10; | 220 | 145k | } | 221 | 14.1k | } | 222 | | | 223 | 26.9k | char* p2 = result.begin(); | 224 | 26.9k | if (negative) *p2++ = '-'; | 225 | 185k | while (p > reverse) { | 226 | 158k | *p2++ = '0' + *--p; | 227 | 158k | } | 228 | 26.9k | result.setSize(p2 - result.begin()); | 229 | 26.9k | return result; | 230 | 26.9k | } |
string.c++:kj::CappedArray<char, ((sizeof (long long))*(3))+(2)> kj::_::stringifyImpl<long long, unsigned long long>(long long) Line | Count | Source | 203 | 12.7k | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { | 204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 205 | 12.7k | CappedArray<char, sizeof(T) * 3 + 2> result; | 206 | 12.7k | bool negative = i < 0; | 207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But | 208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it | 209 | | // unsigned first, then negate it, to avoid ubsan complaining. | 210 | 12.7k | Unsigned u = i; | 211 | 12.7k | if (negative) u = -u; | 212 | 12.7k | uint8_t reverse[sizeof(T) * 3 + 1]; | 213 | 12.7k | uint8_t* p = reverse; | 214 | 12.7k | if (u == 0) { | 215 | 0 | *p++ = 0; | 216 | 12.7k | } else { | 217 | 198k | while (u > 0) { | 218 | 185k | *p++ = u % 10; | 219 | 185k | u /= 10; | 220 | 185k | } | 221 | 12.7k | } | 222 | | | 223 | 12.7k | char* p2 = result.begin(); | 224 | 12.7k | if (negative) *p2++ = '-'; | 225 | 198k | while (p > reverse) { | 226 | 185k | *p2++ = '0' + *--p; | 227 | 185k | } | 228 | 12.7k | result.setSize(p2 - result.begin()); | 229 | 12.7k | return result; | 230 | 12.7k | } |
string.c++:kj::CappedArray<char, ((sizeof (unsigned long long))*(3))+(2)> kj::_::stringifyImpl<unsigned long long, unsigned long long>(unsigned long long) Line | Count | Source | 203 | 12.7k | static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) { | 204 | | // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()). | 205 | 12.7k | CappedArray<char, sizeof(T) * 3 + 2> result; | 206 | 12.7k | bool negative = i < 0; | 207 | | // Note that if `i` is the most-negative value, negating it produces the same bit value. But | 208 | | // since it's a signed integer, this is considered an overflow. We therefore must make it | 209 | | // unsigned first, then negate it, to avoid ubsan complaining. | 210 | 12.7k | Unsigned u = i; | 211 | 12.7k | if (negative) u = -u; | 212 | 12.7k | uint8_t reverse[sizeof(T) * 3 + 1]; | 213 | 12.7k | uint8_t* p = reverse; | 214 | 12.7k | if (u == 0) { | 215 | 0 | *p++ = 0; | 216 | 12.7k | } else { | 217 | 256k | while (u > 0) { | 218 | 243k | *p++ = u % 10; | 219 | 243k | u /= 10; | 220 | 243k | } | 221 | 12.7k | } | 222 | | | 223 | 12.7k | char* p2 = result.begin(); | 224 | 12.7k | if (negative) *p2++ = '-'; | 225 | 256k | while (p > reverse) { | 226 | 243k | *p2++ = '0' + *--p; | 227 | 243k | } | 228 | 12.7k | result.setSize(p2 - result.begin()); | 229 | 12.7k | return result; | 230 | 12.7k | } |
|
231 | | |
232 | | #define STRINGIFY_INT(type, unsigned) \ |
233 | 72.5M | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ |
234 | 72.5M | return stringifyImpl<type, unsigned>(i); \ |
235 | 72.5M | } kj::_::Stringifier::operator*(signed char) const Line | Count | Source | 233 | 28.2k | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ | 234 | 28.2k | return stringifyImpl<type, unsigned>(i); \ | 235 | 28.2k | } |
kj::_::Stringifier::operator*(unsigned char) const Line | Count | Source | 233 | 72.1M | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ | 234 | 72.1M | return stringifyImpl<type, unsigned>(i); \ | 235 | 72.1M | } |
kj::_::Stringifier::operator*(short) const Line | Count | Source | 233 | 27.2k | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ | 234 | 27.2k | return stringifyImpl<type, unsigned>(i); \ | 235 | 27.2k | } |
kj::_::Stringifier::operator*(unsigned short) const Line | Count | Source | 233 | 23.9k | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ | 234 | 23.9k | return stringifyImpl<type, unsigned>(i); \ | 235 | 23.9k | } |
kj::_::Stringifier::operator*(int) const Line | Count | Source | 233 | 199k | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ | 234 | 199k | return stringifyImpl<type, unsigned>(i); \ | 235 | 199k | } |
kj::_::Stringifier::operator*(unsigned int) const Line | Count | Source | 233 | 64.9k | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ | 234 | 64.9k | return stringifyImpl<type, unsigned>(i); \ | 235 | 64.9k | } |
kj::_::Stringifier::operator*(long) const Line | Count | Source | 233 | 25.4k | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ | 234 | 25.4k | return stringifyImpl<type, unsigned>(i); \ | 235 | 25.4k | } |
kj::_::Stringifier::operator*(unsigned long) const Line | Count | Source | 233 | 26.9k | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ | 234 | 26.9k | return stringifyImpl<type, unsigned>(i); \ | 235 | 26.9k | } |
kj::_::Stringifier::operator*(long long) const Line | Count | Source | 233 | 12.7k | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ | 234 | 12.7k | return stringifyImpl<type, unsigned>(i); \ | 235 | 12.7k | } |
kj::_::Stringifier::operator*(unsigned long long) const Line | Count | Source | 233 | 12.7k | CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \ | 234 | 12.7k | return stringifyImpl<type, unsigned>(i); \ | 235 | 12.7k | } |
|
236 | | |
237 | | STRINGIFY_INT(signed char, uint); |
238 | | STRINGIFY_INT(unsigned char, uint); |
239 | | STRINGIFY_INT(short, uint); |
240 | | STRINGIFY_INT(unsigned short, uint); |
241 | | STRINGIFY_INT(int, uint); |
242 | | STRINGIFY_INT(unsigned int, uint); |
243 | | STRINGIFY_INT(long, unsigned long); |
244 | | STRINGIFY_INT(unsigned long, unsigned long); |
245 | | STRINGIFY_INT(long long, unsigned long long); |
246 | | STRINGIFY_INT(unsigned long long, unsigned long long); |
247 | | |
248 | | #undef STRINGIFY_INT |
249 | | |
250 | 5.98k | CappedArray<char, sizeof(const void*) * 2 + 1> Stringifier::operator*(const void* i) const { \ |
251 | 5.98k | return hexImpl<uintptr_t>(reinterpret_cast<uintptr_t>(i)); |
252 | 5.98k | } |
253 | | |
254 | | namespace { |
255 | | |
256 | | // ---------------------------------------------------------------------- |
257 | | // DoubleToBuffer() |
258 | | // FloatToBuffer() |
259 | | // Copied from Protocol Buffers, (C) Google, BSD license. |
260 | | // Kenton wrote this code originally. The following commentary is |
261 | | // from the original. |
262 | | // |
263 | | // Description: converts a double or float to a string which, if |
264 | | // passed to NoLocaleStrtod(), will produce the exact same original double |
265 | | // (except in case of NaN; all NaNs are considered the same value). |
266 | | // We try to keep the string short but it's not guaranteed to be as |
267 | | // short as possible. |
268 | | // |
269 | | // DoubleToBuffer() and FloatToBuffer() write the text to the given |
270 | | // buffer and return it. The buffer must be at least |
271 | | // kDoubleToBufferSize bytes for doubles and kFloatToBufferSize |
272 | | // bytes for floats. kFastToBufferSize is also guaranteed to be large |
273 | | // enough to hold either. |
274 | | // |
275 | | // We want to print the value without losing precision, but we also do |
276 | | // not want to print more digits than necessary. This turns out to be |
277 | | // trickier than it sounds. Numbers like 0.2 cannot be represented |
278 | | // exactly in binary. If we print 0.2 with a very large precision, |
279 | | // e.g. "%.50g", we get "0.2000000000000000111022302462515654042363167". |
280 | | // On the other hand, if we set the precision too low, we lose |
281 | | // significant digits when printing numbers that actually need them. |
282 | | // It turns out there is no precision value that does the right thing |
283 | | // for all numbers. |
284 | | // |
285 | | // Our strategy is to first try printing with a precision that is never |
286 | | // over-precise, then parse the result with strtod() to see if it |
287 | | // matches. If not, we print again with a precision that will always |
288 | | // give a precise result, but may use more digits than necessary. |
289 | | // |
290 | | // An arguably better strategy would be to use the algorithm described |
291 | | // in "How to Print Floating-Point Numbers Accurately" by Steele & |
292 | | // White, e.g. as implemented by David M. Gay's dtoa(). It turns out, |
293 | | // however, that the following implementation is about as fast as |
294 | | // DMG's code. Furthermore, DMG's code locks mutexes, which means it |
295 | | // will not scale well on multi-core machines. DMG's code is slightly |
296 | | // more accurate (in that it will never use more digits than |
297 | | // necessary), but this is probably irrelevant for most users. |
298 | | // |
299 | | // Rob Pike and Ken Thompson also have an implementation of dtoa() in |
300 | | // third_party/fmt/fltfmt.cc. Their implementation is similar to this |
301 | | // one in that it makes guesses and then uses strtod() to check them. |
302 | | // Their implementation is faster because they use their own code to |
303 | | // generate the digits in the first place rather than use snprintf(), |
304 | | // thus avoiding format string parsing overhead. However, this makes |
305 | | // it considerably more complicated than the following implementation, |
306 | | // and it is embedded in a larger library. If speed turns out to be |
307 | | // an issue, we could re-implement this in terms of their |
308 | | // implementation. |
309 | | // ---------------------------------------------------------------------- |
310 | | |
311 | | #ifdef _WIN32 |
312 | | // MSVC has only _snprintf, not snprintf. |
313 | | // |
314 | | // MinGW has both snprintf and _snprintf, but they appear to be different |
315 | | // functions. The former is buggy. When invoked like so: |
316 | | // char buffer[32]; |
317 | | // snprintf(buffer, 32, "%.*g\n", FLT_DIG, 1.23e10f); |
318 | | // it prints "1.23000e+10". This is plainly wrong: %g should never print |
319 | | // trailing zeros after the decimal point. For some reason this bug only |
320 | | // occurs with some input values, not all. In any case, _snprintf does the |
321 | | // right thing, so we use it. |
322 | | #define snprintf _snprintf |
323 | | #endif |
324 | | |
325 | 32.9k | inline bool IsNaN(double value) { |
326 | | // NaN is never equal to anything, even itself. |
327 | 32.9k | return value != value; |
328 | 32.9k | } |
329 | | |
330 | | // In practice, doubles should never need more than 24 bytes and floats |
331 | | // should never need more than 14 (including null terminators), but we |
332 | | // overestimate to be safe. |
333 | | static const int kDoubleToBufferSize = 32; |
334 | | static const int kFloatToBufferSize = 24; |
335 | | |
336 | 61.9k | static inline bool IsValidFloatChar(char c) { |
337 | 61.9k | return ('0' <= c && c <= '9') || |
338 | 61.9k | c == 'e' || c == 'E' || |
339 | 61.9k | c == '+' || c == '-'; |
340 | 61.9k | } |
341 | | |
342 | 32.3k | void DelocalizeRadix(char* buffer) { |
343 | | // Fast check: if the buffer has a normal decimal point, assume no |
344 | | // translation is needed. |
345 | 32.3k | if (strchr(buffer, '.') != NULL) return; |
346 | | |
347 | | // Find the first unknown character. |
348 | 61.9k | while (IsValidFloatChar(*buffer)) ++buffer; |
349 | | |
350 | 17.9k | if (*buffer == '\0') { |
351 | | // No radix character found. |
352 | 17.9k | return; |
353 | 17.9k | } |
354 | | |
355 | | // We are now pointing at the locale-specific radix character. Replace it |
356 | | // with '.'. |
357 | 0 | *buffer = '.'; |
358 | 0 | ++buffer; |
359 | |
|
360 | 0 | if (!IsValidFloatChar(*buffer) && *buffer != '\0') { |
361 | | // It appears the radix was a multi-byte character. We need to remove the |
362 | | // extra bytes. |
363 | 0 | char* target = buffer; |
364 | 0 | do { ++buffer; } while (!IsValidFloatChar(*buffer) && *buffer != '\0'); |
365 | 0 | memmove(target, buffer, strlen(buffer) + 1); |
366 | 0 | } |
367 | 0 | } |
368 | | |
369 | 32.3k | void RemovePlus(char* buffer) { |
370 | | // Remove any + characters because they are redundant and ugly. |
371 | | |
372 | 38.2k | for (;;) { |
373 | 38.2k | buffer = strchr(buffer, '+'); |
374 | 38.2k | if (buffer == NULL) { |
375 | 32.3k | return; |
376 | 32.3k | } |
377 | 5.87k | memmove(buffer, buffer + 1, strlen(buffer + 1) + 1); |
378 | 5.87k | } |
379 | 32.3k | } |
380 | | |
381 | | #if _WIN32 |
382 | | void RemoveE0(char* buffer) { |
383 | | // Remove redundant leading 0's after an e, e.g. 1e012. Seems to appear on |
384 | | // Windows. |
385 | | |
386 | | // Find and skip 'e'. |
387 | | char* ptr = strchr(buffer, 'e'); |
388 | | if (ptr == nullptr) return; |
389 | | ++ptr; |
390 | | |
391 | | // Skip '-'. |
392 | | if (*ptr == '-') ++ptr; |
393 | | |
394 | | // Skip '0's. |
395 | | char* ptr2 = ptr; |
396 | | while (*ptr2 == '0') ++ptr2; |
397 | | |
398 | | // If we went past the last digit, back up one. |
399 | | if (*ptr2 < '0' || *ptr2 > '9') --ptr2; |
400 | | |
401 | | // Move bytes backwards. |
402 | | if (ptr2 > ptr) { |
403 | | memmove(ptr, ptr2, strlen(ptr2) + 1); |
404 | | } |
405 | | } |
406 | | #endif |
407 | | |
408 | 14.8k | char* DoubleToBuffer(double value, char* buffer) { |
409 | | // DBL_DIG is 15 for IEEE-754 doubles, which are used on almost all |
410 | | // platforms these days. Just in case some system exists where DBL_DIG |
411 | | // is significantly larger -- and risks overflowing our buffer -- we have |
412 | | // this assert. |
413 | 14.8k | static_assert(DBL_DIG < 20, "DBL_DIG is too big."); |
414 | | |
415 | 14.8k | if (value == inf()) { |
416 | 11 | strcpy(buffer, "inf"); |
417 | 11 | return buffer; |
418 | 14.8k | } else if (value == -inf()) { |
419 | 10 | strcpy(buffer, "-inf"); |
420 | 10 | return buffer; |
421 | 14.8k | } else if (IsNaN(value)) { |
422 | 133 | strcpy(buffer, "nan"); |
423 | 133 | return buffer; |
424 | 133 | } |
425 | | |
426 | 14.7k | int snprintf_result KJ_UNUSED = |
427 | 14.7k | snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG, value); |
428 | | |
429 | | // The snprintf should never overflow because the buffer is significantly |
430 | | // larger than the precision we asked for. |
431 | 14.7k | KJ_DASSERT(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize); |
432 | | |
433 | | // We need to make parsed_value volatile in order to force the compiler to |
434 | | // write it out to the stack. Otherwise, it may keep the value in a |
435 | | // register, and if it does that, it may keep it as a long double instead |
436 | | // of a double. This long double may have extra bits that make it compare |
437 | | // unequal to "value" even though it would be exactly equal if it were |
438 | | // truncated to a double. |
439 | 14.7k | volatile double parsed_value = strtod(buffer, NULL); |
440 | 14.7k | if (parsed_value != value) { |
441 | 518 | int snprintf_result2 KJ_UNUSED = |
442 | 518 | snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG+2, value); |
443 | | |
444 | | // Should never overflow; see above. |
445 | 518 | KJ_DASSERT(snprintf_result2 > 0 && snprintf_result2 < kDoubleToBufferSize); |
446 | 518 | } |
447 | | |
448 | 14.7k | DelocalizeRadix(buffer); |
449 | 14.7k | RemovePlus(buffer); |
450 | | #if _WIN32 |
451 | | RemoveE0(buffer); |
452 | | #endif // _WIN32 |
453 | 14.7k | return buffer; |
454 | 14.8k | } |
455 | | |
456 | 17.6k | bool safe_strtof(const char* str, float* value) { |
457 | 17.6k | char* endptr; |
458 | 17.6k | errno = 0; // errno only gets set on errors |
459 | | #if defined(_WIN32) || defined (__hpux) // has no strtof() |
460 | | *value = static_cast<float>(strtod(str, &endptr)); |
461 | | #else |
462 | 17.6k | *value = strtof(str, &endptr); |
463 | 17.6k | #endif |
464 | 17.6k | return *str != 0 && *endptr == 0 && errno == 0; |
465 | 17.6k | } |
466 | | |
467 | 18.1k | char* FloatToBuffer(float value, char* buffer) { |
468 | | // FLT_DIG is 6 for IEEE-754 floats, which are used on almost all |
469 | | // platforms these days. Just in case some system exists where FLT_DIG |
470 | | // is significantly larger -- and risks overflowing our buffer -- we have |
471 | | // this assert. |
472 | 18.1k | static_assert(FLT_DIG < 10, "FLT_DIG is too big"); |
473 | | |
474 | 18.1k | if (value == inf()) { |
475 | 10 | strcpy(buffer, "inf"); |
476 | 10 | return buffer; |
477 | 18.1k | } else if (value == -inf()) { |
478 | 14 | strcpy(buffer, "-inf"); |
479 | 14 | return buffer; |
480 | 18.1k | } else if (IsNaN(value)) { |
481 | 466 | strcpy(buffer, "nan"); |
482 | 466 | return buffer; |
483 | 466 | } |
484 | | |
485 | 17.6k | int snprintf_result KJ_UNUSED = |
486 | 17.6k | snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG, value); |
487 | | |
488 | | // The snprintf should never overflow because the buffer is significantly |
489 | | // larger than the precision we asked for. |
490 | 17.6k | KJ_DASSERT(snprintf_result > 0 && snprintf_result < kFloatToBufferSize); |
491 | | |
492 | 17.6k | float parsed_value; |
493 | 17.6k | if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) { |
494 | 2.75k | int snprintf_result2 KJ_UNUSED = |
495 | 2.75k | snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG+2, value); |
496 | | |
497 | | // Should never overflow; see above. |
498 | 2.75k | KJ_DASSERT(snprintf_result2 > 0 && snprintf_result2 < kFloatToBufferSize); |
499 | 2.75k | } |
500 | | |
501 | 17.6k | DelocalizeRadix(buffer); |
502 | 17.6k | RemovePlus(buffer); |
503 | | #if _WIN32 |
504 | | RemoveE0(buffer); |
505 | | #endif // _WIN32 |
506 | 17.6k | return buffer; |
507 | 18.1k | } |
508 | | |
509 | | // ---------------------------------------------------------------------- |
510 | | // NoLocaleStrtod() |
511 | | // This code will make you cry. |
512 | | // ---------------------------------------------------------------------- |
513 | | |
514 | | namespace { |
515 | | |
516 | | // Returns a string identical to *input except that the character pointed to |
517 | | // by radix_pos (which should be '.') is replaced with the locale-specific |
518 | | // radix character. |
519 | 0 | kj::String LocalizeRadix(const char* input, const char* radix_pos) { |
520 | | // Determine the locale-specific radix character by calling sprintf() to |
521 | | // print the number 1.5, then stripping off the digits. As far as I can |
522 | | // tell, this is the only portable, thread-safe way to get the C library |
523 | | // to divuldge the locale's radix character. No, localeconv() is NOT |
524 | | // thread-safe. |
525 | 0 | char temp[16]; |
526 | 0 | int size = snprintf(temp, sizeof(temp), "%.1f", 1.5); |
527 | 0 | KJ_ASSERT(temp[0] == '1'); |
528 | 0 | KJ_ASSERT(temp[size-1] == '5'); |
529 | 0 | KJ_ASSERT(size <= 6); |
530 | | |
531 | | // Now replace the '.' in the input with it. |
532 | 0 | return kj::str( |
533 | 0 | kj::arrayPtr(input, radix_pos), |
534 | 0 | kj::arrayPtr(temp + 1, size - 2), |
535 | 0 | kj::StringPtr(radix_pos + 1)); |
536 | 0 | } |
537 | | |
538 | | } // namespace |
539 | | |
540 | 0 | double NoLocaleStrtod(const char* text, char** original_endptr) { |
541 | | // We cannot simply set the locale to "C" temporarily with setlocale() |
542 | | // as this is not thread-safe. Instead, we try to parse in the current |
543 | | // locale first. If parsing stops at a '.' character, then this is a |
544 | | // pretty good hint that we're actually in some other locale in which |
545 | | // '.' is not the radix character. |
546 | |
|
547 | 0 | char* temp_endptr; |
548 | 0 | double result = strtod(text, &temp_endptr); |
549 | 0 | if (original_endptr != NULL) *original_endptr = temp_endptr; |
550 | 0 | if (*temp_endptr != '.') return result; |
551 | | |
552 | | // Parsing halted on a '.'. Perhaps we're in a different locale? Let's |
553 | | // try to replace the '.' with a locale-specific radix character and |
554 | | // try again. |
555 | 0 | kj::String localized = LocalizeRadix(text, temp_endptr); |
556 | 0 | const char* localized_cstr = localized.cStr(); |
557 | 0 | char* localized_endptr; |
558 | 0 | result = strtod(localized_cstr, &localized_endptr); |
559 | 0 | if ((localized_endptr - localized_cstr) > |
560 | 0 | (temp_endptr - text)) { |
561 | | // This attempt got further, so replacing the decimal must have helped. |
562 | | // Update original_endptr to point at the right location. |
563 | 0 | if (original_endptr != NULL) { |
564 | | // size_diff is non-zero if the localized radix has multiple bytes. |
565 | 0 | int size_diff = localized.size() - strlen(text); |
566 | | // const_cast is necessary to match the strtod() interface. |
567 | 0 | *original_endptr = const_cast<char*>( |
568 | 0 | text + (localized_endptr - localized_cstr - size_diff)); |
569 | 0 | } |
570 | 0 | } |
571 | |
|
572 | 0 | return result; |
573 | 0 | } |
574 | | |
575 | | // ---------------------------------------------------------------------- |
576 | | // End of code copied from Protobuf |
577 | | // ---------------------------------------------------------------------- |
578 | | |
579 | | } // namespace |
580 | | |
581 | 18.1k | CappedArray<char, kFloatToBufferSize> Stringifier::operator*(float f) const { |
582 | 18.1k | CappedArray<char, kFloatToBufferSize> result; |
583 | 18.1k | result.setSize(strlen(FloatToBuffer(f, result.begin()))); |
584 | 18.1k | return result; |
585 | 18.1k | } |
586 | | |
587 | 14.8k | CappedArray<char, kDoubleToBufferSize> Stringifier::operator*(double f) const { |
588 | 14.8k | CappedArray<char, kDoubleToBufferSize> result; |
589 | 14.8k | result.setSize(strlen(DoubleToBuffer(f, result.begin()))); |
590 | 14.8k | return result; |
591 | 14.8k | } |
592 | | |
593 | 0 | double parseDouble(const StringPtr& s) { |
594 | 0 | KJ_REQUIRE(s != nullptr, "String does not contain valid number", s) { return 0; } |
595 | 0 | char *endPtr; |
596 | 0 | errno = 0; |
597 | 0 | auto value = _::NoLocaleStrtod(s.begin(), &endPtr); |
598 | 0 | KJ_REQUIRE(endPtr == s.end(), "String does not contain valid floating number", s) { return 0; } |
599 | | #if _WIN32 || __CYGWIN__ || __BIONIC__ |
600 | | // When Windows' strtod() parses "nan", it returns a value with the sign bit set. But, our |
601 | | // preferred canonical value for NaN does not have the sign bit set, and all other platforms |
602 | | // return one without the sign bit set. So, on Windows, detect NaN and return our preferred |
603 | | // version. |
604 | | // |
605 | | // Cygwin seemingly does not try to emulate Linux behavior here, but rather allows Windows' |
606 | | // behavior to leak through. (Conversely, WINE actually produces the Linux behavior despite |
607 | | // trying to behave like Win32...) |
608 | | // |
609 | | // Bionic (Android) failed the unit test and so I added it to the list without investigating |
610 | | // further. |
611 | | if (isNaN(value)) { |
612 | | // NaN |
613 | | return kj::nan(); |
614 | | } |
615 | | #endif |
616 | 0 | return value; |
617 | 0 | } |
618 | | |
619 | 0 | Maybe<double> tryParseDouble(const StringPtr& s) { |
620 | 0 | if(s == nullptr) { return kj::none; } |
621 | 0 | char *endPtr; |
622 | 0 | errno = 0; |
623 | 0 | auto value = _::NoLocaleStrtod(s.begin(), &endPtr); |
624 | 0 | if (endPtr != s.end()) { return kj::none; } |
625 | | #if _WIN32 || __CYGWIN__ || __BIONIC__ |
626 | | if (isNaN(value)) { |
627 | | return kj::nan(); |
628 | | } |
629 | | #endif |
630 | 0 | return value; |
631 | 0 | } |
632 | | |
633 | | } // namespace _ (private) |
634 | | |
635 | 0 | template <> double StringPtr::parseAs<double>() const { return _::parseDouble(*this); } |
636 | 0 | template <> float StringPtr::parseAs<float>() const { return _::parseDouble(*this); } |
637 | | |
638 | 0 | template <> Maybe<double> StringPtr::tryParseAs<double>() const { return _::tryParseDouble(*this); } |
639 | 0 | template <> Maybe<float> StringPtr::tryParseAs<float>() const { return _::tryParseDouble(*this); } |
640 | | |
641 | 0 | Maybe<size_t> StringPtr::find(const StringPtr& other) const { |
642 | 0 | if (other.size() == 0) { |
643 | 0 | return size_t(0); |
644 | 0 | } |
645 | 0 | if (size() == 0) { |
646 | 0 | return kj::none; |
647 | 0 | } |
648 | 0 | if (other.size() > size()) { |
649 | | // We won't find the entirety of other if other is longer than this. |
650 | 0 | return kj::none; |
651 | 0 | } |
652 | | |
653 | 0 | #if !defined(_WIN32) |
654 | 0 | void* found = memmem(begin(), size(), other.begin(), other.size()); |
655 | 0 | if (found == nullptr) { |
656 | 0 | return kj::none; |
657 | 0 | } else { |
658 | 0 | return static_cast<char*>(found)-begin(); |
659 | 0 | } |
660 | | #else |
661 | | // TODO(perf) This is O(len(this)*len(other)), which is very slow on big strings. |
662 | | // |
663 | | // On platforms that don't support memem, we should implement the Two-Way String-Matching |
664 | | // algorithm with linear performance. The Two-Way String-Matching algorithm is described in |
665 | | // Crochemore and Perrin's CACM paper (Crochemore M., Perrin D., 1991, Two-way |
666 | | // string-matching, Journal of the ACM 38(3):651-675). |
667 | | // |
668 | | // * A scan of the original paper can be found at |
669 | | // https://monge.univ-mlv.fr/~mac/Articles-PDF/CP-1991-jacm.pdf. |
670 | | // |
671 | | // * I find Python's implementation notes much easier to understand than the original paoer. |
672 | | // https://github.com/python/cpython/blob/main/Objects/stringlib/stringlib_find_two_way_notes.txt |
673 | | // |
674 | | // * https://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260 has a description of |
675 | | // the algorithm with some C code. |
676 | | for (size_t i = 0; i + other.size() <= size(); ++i) { |
677 | | if (slice(i).startsWith(other)) { |
678 | | return i; |
679 | | } |
680 | | } |
681 | | |
682 | | return kj::none; |
683 | | #endif |
684 | 0 | } |
685 | | |
686 | | } // namespace kj |