Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: base/string_number_conversions.cc

Issue 3056029: Move the number conversions from string_util to a new file.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/string_number_conversions.h ('k') | base/string_number_conversions_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/string_number_conversions.h"
6
7 #include <errno.h>
8 #include <stdlib.h>
9
10 #include "base/logging.h"
11 #include "base/third_party/dmg_fp/dmg_fp.h"
12 #include "base/utf_string_conversions.h"
13
14 namespace base {
15
16 namespace {
17
18 template <typename STR, typename INT, typename UINT, bool NEG>
19 struct IntToStringT {
20 // This is to avoid a compiler warning about unary minus on unsigned type.
21 // For example, say you had the following code:
22 // template <typename INT>
23 // INT abs(INT value) { return value < 0 ? -value : value; }
24 // Even though if INT is unsigned, it's impossible for value < 0, so the
25 // unary minus will never be taken, the compiler will still generate a
26 // warning. We do a little specialization dance...
27 template <typename INT2, typename UINT2, bool NEG2>
28 struct ToUnsignedT {};
29
30 template <typename INT2, typename UINT2>
31 struct ToUnsignedT<INT2, UINT2, false> {
32 static UINT2 ToUnsigned(INT2 value) {
33 return static_cast<UINT2>(value);
34 }
35 };
36
37 template <typename INT2, typename UINT2>
38 struct ToUnsignedT<INT2, UINT2, true> {
39 static UINT2 ToUnsigned(INT2 value) {
40 return static_cast<UINT2>(value < 0 ? -value : value);
41 }
42 };
43
44 // This set of templates is very similar to the above templates, but
45 // for testing whether an integer is negative.
46 template <typename INT2, bool NEG2>
47 struct TestNegT {};
48 template <typename INT2>
49 struct TestNegT<INT2, false> {
50 static bool TestNeg(INT2 value) {
51 // value is unsigned, and can never be negative.
52 return false;
53 }
54 };
55 template <typename INT2>
56 struct TestNegT<INT2, true> {
57 static bool TestNeg(INT2 value) {
58 return value < 0;
59 }
60 };
61
62 static STR IntToString(INT value) {
63 // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
64 // So round up to allocate 3 output characters per byte, plus 1 for '-'.
65 const int kOutputBufSize = 3 * sizeof(INT) + 1;
66
67 // Allocate the whole string right away, we will right back to front, and
68 // then return the substr of what we ended up using.
69 STR outbuf(kOutputBufSize, 0);
70
71 bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
72 // Even though is_neg will never be true when INT is parameterized as
73 // unsigned, even the presence of the unary operation causes a warning.
74 UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
75
76 for (typename STR::iterator it = outbuf.end();;) {
77 --it;
78 DCHECK(it != outbuf.begin());
79 *it = static_cast<typename STR::value_type>((res % 10) + '0');
80 res /= 10;
81
82 // We're done..
83 if (res == 0) {
84 if (is_neg) {
85 --it;
86 DCHECK(it != outbuf.begin());
87 *it = static_cast<typename STR::value_type>('-');
88 }
89 return STR(it, outbuf.end());
90 }
91 }
92 NOTREACHED();
93 return STR();
94 }
95 };
96
97 // Generalized string-to-number conversion.
98 //
99 // StringToNumberTraits should provide:
100 // - a typedef for string_type, the STL string type used as input.
101 // - a typedef for value_type, the target numeric type.
102 // - a static function, convert_func, which dispatches to an appropriate
103 // strtol-like function and returns type value_type.
104 // - a static function, valid_func, which validates |input| and returns a bool
105 // indicating whether it is in proper form. This is used to check for
106 // conditions that convert_func tolerates but should result in
107 // StringToNumber returning false. For strtol-like funtions, valid_func
108 // should check for leading whitespace.
109 template<typename StringToNumberTraits>
110 bool StringToNumber(const typename StringToNumberTraits::string_type& input,
111 typename StringToNumberTraits::value_type* output) {
112 typedef StringToNumberTraits traits;
113
114 errno = 0; // Thread-safe? It is on at least Mac, Linux, and Windows.
115 typename traits::string_type::value_type* endptr = NULL;
116 typename traits::value_type value = traits::convert_func(input.c_str(),
117 &endptr);
118 *output = value;
119
120 // Cases to return false:
121 // - If errno is ERANGE, there was an overflow or underflow.
122 // - If the input string is empty, there was nothing to parse.
123 // - If endptr does not point to the end of the string, there are either
124 // characters remaining in the string after a parsed number, or the string
125 // does not begin with a parseable number. endptr is compared to the
126 // expected end given the string's stated length to correctly catch cases
127 // where the string contains embedded NUL characters.
128 // - valid_func determines that the input is not in preferred form.
129 return errno == 0 &&
130 !input.empty() &&
131 input.c_str() + input.length() == endptr &&
132 traits::valid_func(input);
133 }
134
135 static int strtoi(const char *nptr, char **endptr, int base) {
136 long res = strtol(nptr, endptr, base);
137 #if __LP64__
138 // Long is 64-bits, we have to handle under/overflow ourselves.
139 if (res > kint32max) {
140 res = kint32max;
141 errno = ERANGE;
142 } else if (res < kint32min) {
143 res = kint32min;
144 errno = ERANGE;
145 }
146 #endif
147 return static_cast<int>(res);
148 }
149
150 static unsigned int strtoui(const char *nptr, char **endptr, int base) {
151 unsigned long res = strtoul(nptr, endptr, base);
152 #if __LP64__
153 // Long is 64-bits, we have to handle under/overflow ourselves. Test to see
154 // if the result can fit into 32-bits (as signed or unsigned).
155 if (static_cast<int>(static_cast<long>(res)) != static_cast<long>(res) &&
156 static_cast<unsigned int>(res) != res) {
157 res = kuint32max;
158 errno = ERANGE;
159 }
160 #endif
161 return static_cast<unsigned int>(res);
162 }
163
164 class StringToIntTraits {
165 public:
166 typedef std::string string_type;
167 typedef int value_type;
168 static const int kBase = 10;
169 static inline value_type convert_func(const string_type::value_type* str,
170 string_type::value_type** endptr) {
171 return strtoi(str, endptr, kBase);
172 }
173 static inline bool valid_func(const string_type& str) {
174 return !str.empty() && !isspace(str[0]);
175 }
176 };
177
178 class String16ToIntTraits {
179 public:
180 typedef string16 string_type;
181 typedef int value_type;
182 static const int kBase = 10;
183 static inline value_type convert_func(const string_type::value_type* str,
184 string_type::value_type** endptr) {
185 #if defined(WCHAR_T_IS_UTF16)
186 return wcstol(str, endptr, kBase);
187 #elif defined(WCHAR_T_IS_UTF32)
188 std::string ascii_string = UTF16ToUTF8(string16(str));
189 char* ascii_end = NULL;
190 value_type ret = strtoi(ascii_string.c_str(), &ascii_end, kBase);
191 if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
192 *endptr =
193 const_cast<string_type::value_type*>(str) + ascii_string.length();
194 }
195 return ret;
196 #endif
197 }
198 static inline bool valid_func(const string_type& str) {
199 return !str.empty() && !iswspace(str[0]);
200 }
201 };
202
203 class StringToInt64Traits {
204 public:
205 typedef std::string string_type;
206 typedef int64 value_type;
207 static const int kBase = 10;
208 static inline value_type convert_func(const string_type::value_type* str,
209 string_type::value_type** endptr) {
210 #ifdef OS_WIN
211 return _strtoi64(str, endptr, kBase);
212 #else // assume OS_POSIX
213 return strtoll(str, endptr, kBase);
214 #endif
215 }
216 static inline bool valid_func(const string_type& str) {
217 return !str.empty() && !isspace(str[0]);
218 }
219 };
220
221 class String16ToInt64Traits {
222 public:
223 typedef string16 string_type;
224 typedef int64 value_type;
225 static const int kBase = 10;
226 static inline value_type convert_func(const string_type::value_type* str,
227 string_type::value_type** endptr) {
228 #ifdef OS_WIN
229 return _wcstoi64(str, endptr, kBase);
230 #else // assume OS_POSIX
231 std::string ascii_string = UTF16ToUTF8(string16(str));
232 char* ascii_end = NULL;
233 value_type ret = strtoll(ascii_string.c_str(), &ascii_end, kBase);
234 if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
235 *endptr =
236 const_cast<string_type::value_type*>(str) + ascii_string.length();
237 }
238 return ret;
239 #endif
240 }
241 static inline bool valid_func(const string_type& str) {
242 return !str.empty() && !iswspace(str[0]);
243 }
244 };
245
246 // For the HexString variants, use the unsigned variants like strtoul for
247 // convert_func so that input like "0x80000000" doesn't result in an overflow.
248
249 class HexStringToIntTraits {
250 public:
251 typedef std::string string_type;
252 typedef int value_type;
253 static const int kBase = 16;
254 static inline value_type convert_func(const string_type::value_type* str,
255 string_type::value_type** endptr) {
256 return strtoui(str, endptr, kBase);
257 }
258 static inline bool valid_func(const string_type& str) {
259 return !str.empty() && !isspace(str[0]);
260 }
261 };
262
263 class StringToDoubleTraits {
264 public:
265 typedef std::string string_type;
266 typedef double value_type;
267 static inline value_type convert_func(const string_type::value_type* str,
268 string_type::value_type** endptr) {
269 return dmg_fp::strtod(str, endptr);
270 }
271 static inline bool valid_func(const string_type& str) {
272 return !str.empty() && !isspace(str[0]);
273 }
274 };
275
276 template<class CHAR>
277 bool HexDigitToIntT(const CHAR digit, uint8* val) {
278 if (digit >= '0' && digit <= '9')
279 *val = digit - '0';
280 else if (digit >= 'a' && digit <= 'f')
281 *val = 10 + digit - 'a';
282 else if (digit >= 'A' && digit <= 'F')
283 *val = 10 + digit - 'A';
284 else
285 return false;
286 return true;
287 }
288
289 template<typename STR>
290 bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
291 DCHECK(output->size() == 0);
292 size_t count = input.size();
293 if (count == 0 || (count % 2) != 0)
294 return false;
295 for (uintptr_t i = 0; i < count / 2; ++i) {
296 uint8 msb = 0; // most significant 4 bits
297 uint8 lsb = 0; // least significant 4 bits
298 if (!HexDigitToIntT(input[i * 2], &msb) ||
299 !HexDigitToIntT(input[i * 2 + 1], &lsb))
300 return false;
301 output->push_back((msb << 4) | lsb);
302 }
303 return true;
304 }
305
306 } // namespace
307
308 std::string IntToString(int value) {
309 return IntToStringT<std::string, int, unsigned int, true>::
310 IntToString(value);
311 }
312
313 string16 IntToString16(int value) {
314 return IntToStringT<string16, int, unsigned int, true>::
315 IntToString(value);
316 }
317
318 std::string UintToString(unsigned int value) {
319 return IntToStringT<std::string, unsigned int, unsigned int, false>::
320 IntToString(value);
321 }
322
323 string16 UintToString16(unsigned int value) {
324 return IntToStringT<string16, unsigned int, unsigned int, false>::
325 IntToString(value);
326 }
327
328 std::string Int64ToString(int64 value) {
329 return IntToStringT<std::string, int64, uint64, true>::
330 IntToString(value);
331 }
332
333 string16 Int64ToString16(int64 value) {
334 return IntToStringT<string16, int64, uint64, true>::IntToString(value);
335 }
336
337 std::string Uint64ToString(uint64 value) {
338 return IntToStringT<std::string, uint64, uint64, false>::
339 IntToString(value);
340 }
341
342 string16 Uint64ToString16(uint64 value) {
343 return IntToStringT<string16, uint64, uint64, false>::
344 IntToString(value);
345 }
346
347 std::string DoubleToString(double value) {
348 // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
349 char buffer[32];
350 dmg_fp::g_fmt(buffer, value);
351 return std::string(buffer);
352 }
353
354 bool StringToInt(const std::string& input, int* output) {
355 return StringToNumber<StringToIntTraits>(input, output);
356 }
357
358 bool StringToInt(const string16& input, int* output) {
359 return StringToNumber<String16ToIntTraits>(input, output);
360 }
361
362 bool StringToInt64(const std::string& input, int64* output) {
363 return StringToNumber<StringToInt64Traits>(input, output);
364 }
365
366 bool StringToInt64(const string16& input, int64* output) {
367 return StringToNumber<String16ToInt64Traits>(input, output);
368 }
369
370 bool StringToDouble(const std::string& input, double* output) {
371 return StringToNumber<StringToDoubleTraits>(input, output);
372 }
373
374 // Note: if you need to add String16ToDouble, first ask yourself if it's
375 // really necessary. If it is, probably the best implementation here is to
376 // convert to 8-bit and then use the 8-bit version.
377
378 std::string HexEncode(const void* bytes, size_t size) {
379 static const char kHexChars[] = "0123456789ABCDEF";
380
381 // Each input byte creates two output hex characters.
382 std::string ret(size * 2, '\0');
383
384 for (size_t i = 0; i < size; ++i) {
385 char b = reinterpret_cast<const char*>(bytes)[i];
386 ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
387 ret[(i * 2) + 1] = kHexChars[b & 0xf];
388 }
389 return ret;
390 }
391
392 bool HexStringToInt(const std::string& input, int* output) {
393 return StringToNumber<HexStringToIntTraits>(input, output);
394 }
395
396 bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
397 return HexStringToBytesT(input, output);
398 }
399
400 } // namespace base
OLDNEW
« no previous file with comments | « base/string_number_conversions.h ('k') | base/string_number_conversions_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698