Copyright 2013 -> 2014
[folly.git] / folly / Conv.cpp
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #define FOLLY_CONV_INTERNAL
17 #include "folly/Conv.h"
18
19 namespace folly {
20 namespace detail {
21
22 extern const char digit1[101] =
23   "00000000001111111111222222222233333333334444444444"
24   "55555555556666666666777777777788888888889999999999";
25 extern const char digit2[101] =
26   "01234567890123456789012345678901234567890123456789"
27   "01234567890123456789012345678901234567890123456789";
28
29 template <> const char *const MaxString<bool>::value = "true";
30 template <> const char *const MaxString<uint8_t>::value = "255";
31 template <> const char *const MaxString<uint16_t>::value = "65535";
32 template <> const char *const MaxString<uint32_t>::value = "4294967295";
33 #if __SIZEOF_LONG__ == 4
34 template <> const char *const MaxString<unsigned long>::value =
35   "4294967295";
36 #else
37 template <> const char *const MaxString<unsigned long>::value =
38   "18446744073709551615";
39 #endif
40 static_assert(sizeof(unsigned long) >= 4,
41               "Wrong value for MaxString<unsigned long>::value,"
42               " please update.");
43 template <> const char *const MaxString<unsigned long long>::value =
44   "18446744073709551615";
45 static_assert(sizeof(unsigned long long) >= 8,
46               "Wrong value for MaxString<unsigned long long>::value"
47               ", please update.");
48
49 /* Test for GCC >= 3.6.0 */
50 #if __GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 6))
51 template <> const char *const MaxString<__uint128_t>::value =
52   "340282366920938463463374607431768211455";
53 #endif
54
55 inline bool bool_str_cmp(const char** b, size_t len, const char* value) {
56   // Can't use strncasecmp, since we want to ensure that the full value matches
57   const char* p = *b;
58   const char* e = *b + len;
59   const char* v = value;
60   while (*v != '\0') {
61     if (p == e || tolower(*p) != *v) { // value is already lowercase
62       return false;
63     }
64     ++p;
65     ++v;
66   }
67
68   *b = p;
69   return true;
70 }
71
72 bool str_to_bool(StringPiece* src) {
73   auto b = src->begin(), e = src->end();
74   for (;; ++b) {
75     FOLLY_RANGE_CHECK(b < e,
76                       "No non-whitespace characters found in input string");
77     if (!isspace(*b)) break;
78   }
79
80   bool result;
81   size_t len = e - b;
82   switch (*b) {
83     case '0':
84     case '1': {
85       // Attempt to parse the value as an integer
86       StringPiece tmp(*src);
87       uint8_t value = to<uint8_t>(&tmp);
88       // Only accept 0 or 1
89       FOLLY_RANGE_CHECK(value <= 1,
90                         "Integer overflow when parsing bool: must be 0 or 1");
91       b = tmp.begin();
92       result = (value == 1);
93       break;
94     }
95     case 'y':
96     case 'Y':
97       result = true;
98       if (!bool_str_cmp(&b, len, "yes")) {
99         ++b;  // accept the single 'y' character
100       }
101       break;
102     case 'n':
103     case 'N':
104       result = false;
105       if (!bool_str_cmp(&b, len, "no")) {
106         ++b;
107       }
108       break;
109     case 't':
110     case 'T':
111       result = true;
112       if (!bool_str_cmp(&b, len, "true")) {
113         ++b;
114       }
115       break;
116     case 'f':
117     case 'F':
118       result = false;
119       if (!bool_str_cmp(&b, len, "false")) {
120         ++b;
121       }
122       break;
123     case 'o':
124     case 'O':
125       if (bool_str_cmp(&b, len, "on")) {
126         result = true;
127       } else if (bool_str_cmp(&b, len, "off")) {
128         result = false;
129       } else {
130         FOLLY_RANGE_CHECK(false, "Invalid value for bool");
131       }
132       break;
133     default:
134       FOLLY_RANGE_CHECK(false, "Invalid value for bool");
135   }
136
137   src->assign(b, e);
138   return result;
139 }
140
141 } // namespace detail
142 } // namespace folly