OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2017 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #ifndef WEBRTC_BASE_STRING_TO_NUMBER_H_ | |
12 #define WEBRTC_BASE_STRING_TO_NUMBER_H_ | |
13 | |
14 #include <string> | |
15 #include <limits> | |
16 | |
17 #include "webrtc/base/optional.h" | |
18 | |
19 namespace rtc { | |
20 | |
21 // This file declares two families of functions to parse numbers from strings, | |
22 // one set for integers and one set for floats. The standard C library functions | |
23 // either fail to indicate errors (atoi, etc.) or are a hassle to work with | |
24 // (strtol, sscanf, etc.). The standard C++ library functions (std::stoi, etc.) | |
25 // indicate errors by throwing exceptions, which are disabled in WebRTC. | |
26 // | |
27 // Integers are parsed using one of the following functions: | |
28 // rtc::Optional<int-type> StringToNumber(const char* str, int base = 10); | |
29 // rtc::Optional<int-type> StringToNumber(const std::string& str, | |
30 // int base = 10); | |
31 // | |
32 // These functions parse a value from the beginning of a string into one of the | |
33 // fundamental integer types, or returns an empty Optional if parsing | |
34 // failed. Values outside of the range supported by the type will be | |
35 // rejected. By setting base to 0, one of octal, decimal or hexadecimal will be | |
36 // detected from the string's prefix (0, nothing or 0x, respectively). | |
37 // If non-zero, base can be set to a value between 2 and 36 inclusively. | |
38 // | |
39 // Floating-point values are parsed similarly to integers, but don't support | |
40 // explicitly specifying the base: | |
41 // rtc::Optional<float-type> StringToNumber(const char* str); | |
42 // rtc::Optional<float-type> StringToNumber(const std::string& str); | |
43 | |
44 template <typename T> | |
45 typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, | |
46 rtc::Optional<T>>::type | |
47 StringToNumber(const char* str, int base = 10) { | |
kwiberg-webrtc
2017/02/16 00:27:24
You probably want to static_assert that long long
ossu
2017/02/16 10:19:26
Makes sense. The tests should catch any case where
kwiberg-webrtc
2017/02/16 11:59:42
Yes, but it's easier for a human to see that the s
| |
48 RTC_DCHECK(str); | |
49 char* end = nullptr; | |
50 errno = 0; | |
51 const long long int value = std::strtoll(str, &end, base); | |
52 if (end != str && errno == 0 && value >= std::numeric_limits<T>::min() && | |
53 value <= std::numeric_limits<T>::max()) { | |
54 return rtc::Optional<T>(static_cast<T>(value)); | |
55 } | |
56 return rtc::Optional<T>(); | |
57 } | |
58 | |
59 template <typename T> | |
60 typename std::enable_if<std::is_integral<T>::value && | |
61 std::is_unsigned<T>::value, | |
62 rtc::Optional<T>>::type | |
63 StringToNumber(const char* str, int base = 10) { | |
64 RTC_DCHECK(str); | |
65 // Explicitly discard negative values. std::strtoull parsing causes unsigned | |
66 // wraparound. We cannot just reject values that start with -, though, since | |
67 // -0 is perfectly fine, as is -0000000000000000000000000000000. | |
68 bool is_negative = false; | |
69 for (const char *ptr = str; isspace(*ptr) || *ptr == '-'; ++ptr) { | |
70 if (*ptr == '-') { | |
71 is_negative = true; | |
72 } | |
73 } | |
kwiberg-webrtc
2017/02/16 00:27:23
You allow multiple minus signs---that's probably n
ossu
2017/02/16 10:19:26
I should check, but I'd expect stroull would rejec
kwiberg-webrtc
2017/02/16 11:59:42
Oh, I see. I thought you were discarding the minus
| |
74 char* end = nullptr; | |
75 errno = 0; | |
76 const unsigned long long int value = std::strtoull(str, &end, base); | |
77 if (end != str && errno == 0 && value >= std::numeric_limits<T>::min() && | |
78 value <= std::numeric_limits<T>::max() && (value == 0 || !is_negative)) { | |
79 return rtc::Optional<T>(static_cast<T>(value)); | |
80 } | |
81 return rtc::Optional<T>(); | |
82 } | |
83 | |
84 template <typename T> | |
85 typename std::enable_if<std::is_floating_point<T>::value, | |
86 rtc::Optional<T>>::type | |
87 StringToNumber(const char* str); | |
88 | |
89 template<> | |
90 rtc::Optional<float> StringToNumber<float>(const char* str) { | |
91 char *end = nullptr; | |
92 errno = 0; | |
93 const float value = std::strtof(str, &end); | |
94 if (end != str && errno == 0) { | |
95 return rtc::Optional<float>(value); | |
96 } | |
97 return rtc::Optional<float>(); | |
98 } | |
99 | |
100 template<> | |
101 rtc::Optional<double> StringToNumber<double>(const char* str) { | |
102 char *end = nullptr; | |
103 errno = 0; | |
104 const double value = std::strtod(str, &end); | |
105 if (end != str && errno == 0) { | |
106 return rtc::Optional<double>(value); | |
107 } | |
108 return rtc::Optional<double>(); | |
109 } | |
110 | |
111 template<> | |
112 rtc::Optional<long double> StringToNumber<long double>(const char* str) { | |
113 char *end = nullptr; | |
114 errno = 0; | |
115 const long double value = std::strtold(str, &end); | |
116 if (end != str && errno == 0) { | |
117 return rtc::Optional<long double>(value); | |
118 } | |
119 return rtc::Optional<long double>(); | |
120 } | |
kwiberg-webrtc
2017/02/16 00:27:23
You could probably unify these three if you made a
ossu
2017/02/16 10:19:26
Yeah, that's true. I'll look into that. As-is, the
kwiberg-webrtc
2017/02/16 11:59:42
Sounds good.
| |
121 | |
122 // The std::string overloads only exists if there is a matching const char* | |
123 // version. | |
124 template <typename T> | |
125 auto StringToNumber(const std::string& str, int base) | |
126 -> decltype(StringToNumber<T>(str.c_str(), base)) { | |
127 return StringToNumber<T>(str.c_str(), base); | |
128 } | |
129 | |
130 template <typename T> | |
131 auto StringToNumber(const std::string& str) | |
132 -> decltype(StringToNumber<T>(str.c_str())) { | |
133 return StringToNumber<T>(str.c_str()); | |
134 } | |
kwiberg-webrtc
2017/02/16 00:27:23
Could you ditch this one if you defaulted base to
ossu
2017/02/16 10:19:26
Alas, no, there's no base parameter to the floatin
| |
135 | |
136 } // namespace rtc | |
137 | |
138 #endif // WEBRTC_BASE_STRING_TO_NUMBER_H_ | |
OLD | NEW |