/src/abseil-cpp/absl/flags/marshalling.cc
Line  | Count  | Source  | 
1  |  | //  | 
2  |  | //  Copyright 2019 The Abseil Authors.  | 
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  |  | //      https://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  |  | #include "absl/flags/marshalling.h"  | 
17  |  |  | 
18  |  | #include <stddef.h>  | 
19  |  |  | 
20  |  | #include <cmath>  | 
21  |  | #include <limits>  | 
22  |  | #include <sstream>  | 
23  |  | #include <string>  | 
24  |  | #include <type_traits>  | 
25  |  | #include <vector>  | 
26  |  |  | 
27  |  | #include "absl/base/config.h"  | 
28  |  | #include "absl/base/log_severity.h"  | 
29  |  | #include "absl/base/macros.h"  | 
30  |  | #include "absl/numeric/int128.h"  | 
31  |  | #include "absl/strings/ascii.h"  | 
32  |  | #include "absl/strings/match.h"  | 
33  |  | #include "absl/strings/numbers.h"  | 
34  |  | #include "absl/strings/str_cat.h"  | 
35  |  | #include "absl/strings/str_format.h"  | 
36  |  | #include "absl/strings/str_join.h"  | 
37  |  | #include "absl/strings/str_split.h"  | 
38  |  | #include "absl/strings/string_view.h"  | 
39  |  |  | 
40  |  | namespace absl { | 
41  |  | ABSL_NAMESPACE_BEGIN  | 
42  |  | namespace flags_internal { | 
43  |  |  | 
44  |  | // --------------------------------------------------------------------  | 
45  |  | // AbslParseFlag specializations for boolean type.  | 
46  |  |  | 
47  | 0  | bool AbslParseFlag(absl::string_view text, bool* dst, std::string*) { | 
48  | 0  |   const char* kTrue[] = {"1", "t", "true", "y", "yes"}; | 
49  | 0  |   const char* kFalse[] = {"0", "f", "false", "n", "no"}; | 
50  | 0  |   static_assert(sizeof(kTrue) == sizeof(kFalse), "true_false_equal");  | 
51  |  | 
  | 
52  | 0  |   text = absl::StripAsciiWhitespace(text);  | 
53  |  | 
  | 
54  | 0  |   for (size_t i = 0; i < ABSL_ARRAYSIZE(kTrue); ++i) { | 
55  | 0  |     if (absl::EqualsIgnoreCase(text, kTrue[i])) { | 
56  | 0  |       *dst = true;  | 
57  | 0  |       return true;  | 
58  | 0  |     } else if (absl::EqualsIgnoreCase(text, kFalse[i])) { | 
59  | 0  |       *dst = false;  | 
60  | 0  |       return true;  | 
61  | 0  |     }  | 
62  | 0  |   }  | 
63  | 0  |   return false;  // didn't match a legal input  | 
64  | 0  | }  | 
65  |  |  | 
66  |  | // --------------------------------------------------------------------  | 
67  |  | // AbslParseFlag for integral types.  | 
68  |  |  | 
69  |  | // Return the base to use for parsing text as an integer.  Leading 0x  | 
70  |  | // puts us in base 16.  But leading 0 does not put us in base 8. It  | 
71  |  | // caused too many bugs when we had that behavior.  | 
72  | 0  | static int NumericBase(absl::string_view text) { | 
73  | 0  |   if (text.empty()) return 0;  | 
74  | 0  |   size_t num_start = (text[0] == '-' || text[0] == '+') ? 1 : 0;  | 
75  | 0  |   const bool hex = (text.size() >= num_start + 2 && text[num_start] == '0' &&  | 
76  | 0  |                     (text[num_start + 1] == 'x' || text[num_start + 1] == 'X'));  | 
77  | 0  |   return hex ? 16 : 10;  | 
78  | 0  | }  | 
79  |  |  | 
80  |  | template <typename IntType>  | 
81  | 0  | inline bool ParseFlagImpl(absl::string_view text, IntType& dst) { | 
82  | 0  |   text = absl::StripAsciiWhitespace(text);  | 
83  |  | 
  | 
84  | 0  |   return absl::numbers_internal::safe_strtoi_base(text, &dst,  | 
85  | 0  |                                                   NumericBase(text));  | 
86  | 0  | } Unexecuted instantiation: bool absl::flags_internal::ParseFlagImpl<int>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, int&) Unexecuted instantiation: bool absl::flags_internal::ParseFlagImpl<unsigned int>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned int&) Unexecuted instantiation: bool absl::flags_internal::ParseFlagImpl<long>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, long&) Unexecuted instantiation: bool absl::flags_internal::ParseFlagImpl<unsigned long>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned long&) Unexecuted instantiation: bool absl::flags_internal::ParseFlagImpl<long long>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, long long&) Unexecuted instantiation: bool absl::flags_internal::ParseFlagImpl<unsigned long long>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, unsigned long long&)  | 
87  |  |  | 
88  | 0  | bool AbslParseFlag(absl::string_view text, short* dst, std::string*) { | 
89  | 0  |   int val;  | 
90  | 0  |   if (!ParseFlagImpl(text, val)) return false;  | 
91  | 0  |   if (static_cast<short>(val) != val)  // worked, but number out of range  | 
92  | 0  |     return false;  | 
93  | 0  |   *dst = static_cast<short>(val);  | 
94  | 0  |   return true;  | 
95  | 0  | }  | 
96  |  |  | 
97  | 0  | bool AbslParseFlag(absl::string_view text, unsigned short* dst, std::string*) { | 
98  | 0  |   unsigned int val;  | 
99  | 0  |   if (!ParseFlagImpl(text, val)) return false;  | 
100  | 0  |   if (static_cast<unsigned short>(val) !=  | 
101  | 0  |       val)  // worked, but number out of range  | 
102  | 0  |     return false;  | 
103  | 0  |   *dst = static_cast<unsigned short>(val);  | 
104  | 0  |   return true;  | 
105  | 0  | }  | 
106  |  |  | 
107  | 0  | bool AbslParseFlag(absl::string_view text, int* dst, std::string*) { | 
108  | 0  |   return ParseFlagImpl(text, *dst);  | 
109  | 0  | }  | 
110  |  |  | 
111  | 0  | bool AbslParseFlag(absl::string_view text, unsigned int* dst, std::string*) { | 
112  | 0  |   return ParseFlagImpl(text, *dst);  | 
113  | 0  | }  | 
114  |  |  | 
115  | 0  | bool AbslParseFlag(absl::string_view text, long* dst, std::string*) { | 
116  | 0  |   return ParseFlagImpl(text, *dst);  | 
117  | 0  | }  | 
118  |  |  | 
119  | 0  | bool AbslParseFlag(absl::string_view text, unsigned long* dst, std::string*) { | 
120  | 0  |   return ParseFlagImpl(text, *dst);  | 
121  | 0  | }  | 
122  |  |  | 
123  | 0  | bool AbslParseFlag(absl::string_view text, long long* dst, std::string*) { | 
124  | 0  |   return ParseFlagImpl(text, *dst);  | 
125  | 0  | }  | 
126  |  |  | 
127  |  | bool AbslParseFlag(absl::string_view text, unsigned long long* dst,  | 
128  | 0  |                    std::string*) { | 
129  | 0  |   return ParseFlagImpl(text, *dst);  | 
130  | 0  | }  | 
131  |  |  | 
132  | 0  | bool AbslParseFlag(absl::string_view text, absl::int128* dst, std::string*) { | 
133  | 0  |   text = absl::StripAsciiWhitespace(text);  | 
134  |  |  | 
135  |  |   // check hex  | 
136  | 0  |   int base = NumericBase(text);  | 
137  | 0  |   if (!absl::numbers_internal::safe_strto128_base(text, dst, base)) { | 
138  | 0  |     return false;  | 
139  | 0  |   }  | 
140  |  |  | 
141  | 0  |   return base == 16 ? absl::SimpleHexAtoi(text, dst)  | 
142  | 0  |                     : absl::SimpleAtoi(text, dst);  | 
143  | 0  | }  | 
144  |  |  | 
145  | 0  | bool AbslParseFlag(absl::string_view text, absl::uint128* dst, std::string*) { | 
146  | 0  |   text = absl::StripAsciiWhitespace(text);  | 
147  |  |  | 
148  |  |   // check hex  | 
149  | 0  |   int base = NumericBase(text);  | 
150  | 0  |   if (!absl::numbers_internal::safe_strtou128_base(text, dst, base)) { | 
151  | 0  |     return false;  | 
152  | 0  |   }  | 
153  |  |  | 
154  | 0  |   return base == 16 ? absl::SimpleHexAtoi(text, dst)  | 
155  | 0  |                     : absl::SimpleAtoi(text, dst);  | 
156  | 0  | }  | 
157  |  |  | 
158  |  | // --------------------------------------------------------------------  | 
159  |  | // AbslParseFlag for floating point types.  | 
160  |  |  | 
161  | 0  | bool AbslParseFlag(absl::string_view text, float* dst, std::string*) { | 
162  | 0  |   return absl::SimpleAtof(text, dst);  | 
163  | 0  | }  | 
164  |  |  | 
165  | 0  | bool AbslParseFlag(absl::string_view text, double* dst, std::string*) { | 
166  | 0  |   return absl::SimpleAtod(text, dst);  | 
167  | 0  | }  | 
168  |  |  | 
169  |  | // --------------------------------------------------------------------  | 
170  |  | // AbslParseFlag for strings.  | 
171  |  |  | 
172  | 0  | bool AbslParseFlag(absl::string_view text, std::string* dst, std::string*) { | 
173  | 0  |   dst->assign(text.data(), text.size());  | 
174  | 0  |   return true;  | 
175  | 0  | }  | 
176  |  |  | 
177  |  | // --------------------------------------------------------------------  | 
178  |  | // AbslParseFlag for vector of strings.  | 
179  |  |  | 
180  |  | bool AbslParseFlag(absl::string_view text, std::vector<std::string>* dst,  | 
181  | 0  |                    std::string*) { | 
182  |  |   // An empty flag value corresponds to an empty vector, not a vector  | 
183  |  |   // with a single, empty std::string.  | 
184  | 0  |   if (text.empty()) { | 
185  | 0  |     dst->clear();  | 
186  | 0  |     return true;  | 
187  | 0  |   }  | 
188  | 0  |   *dst = absl::StrSplit(text, ',', absl::AllowEmpty());  | 
189  | 0  |   return true;  | 
190  | 0  | }  | 
191  |  |  | 
192  |  | // --------------------------------------------------------------------  | 
193  |  | // AbslUnparseFlag specializations for various builtin flag types.  | 
194  |  |  | 
195  | 0  | std::string Unparse(bool v) { return v ? "true" : "false"; } | 
196  | 0  | std::string Unparse(short v) { return absl::StrCat(v); } | 
197  | 0  | std::string Unparse(unsigned short v) { return absl::StrCat(v); } | 
198  | 0  | std::string Unparse(int v) { return absl::StrCat(v); } | 
199  | 0  | std::string Unparse(unsigned int v) { return absl::StrCat(v); } | 
200  | 0  | std::string Unparse(long v) { return absl::StrCat(v); } | 
201  | 0  | std::string Unparse(unsigned long v) { return absl::StrCat(v); } | 
202  | 0  | std::string Unparse(long long v) { return absl::StrCat(v); } | 
203  | 0  | std::string Unparse(unsigned long long v) { return absl::StrCat(v); } | 
204  | 0  | std::string Unparse(absl::int128 v) { | 
205  | 0  |   std::stringstream ss;  | 
206  | 0  |   ss << v;  | 
207  | 0  |   return ss.str();  | 
208  | 0  | }  | 
209  | 0  | std::string Unparse(absl::uint128 v) { | 
210  | 0  |   std::stringstream ss;  | 
211  | 0  |   ss << v;  | 
212  | 0  |   return ss.str();  | 
213  | 0  | }  | 
214  |  |  | 
215  |  | template <typename T>  | 
216  | 0  | std::string UnparseFloatingPointVal(T v) { | 
217  |  |   // digits10 is guaranteed to roundtrip correctly in string -> value -> string  | 
218  |  |   // conversions, but may not be enough to represent all the values correctly.  | 
219  | 0  |   std::string digit10_str =  | 
220  | 0  |       absl::StrFormat("%.*g", std::numeric_limits<T>::digits10, v); | 
221  | 0  |   if (std::isnan(v) || std::isinf(v)) return digit10_str;  | 
222  |  |  | 
223  | 0  |   T roundtrip_val = 0;  | 
224  | 0  |   std::string err;  | 
225  | 0  |   if (absl::ParseFlag(digit10_str, &roundtrip_val, &err) &&  | 
226  | 0  |       roundtrip_val == v) { | 
227  | 0  |     return digit10_str;  | 
228  | 0  |   }  | 
229  |  |  | 
230  |  |   // max_digits10 is the number of base-10 digits that are necessary to uniquely  | 
231  |  |   // represent all distinct values.  | 
232  | 0  |   return absl::StrFormat("%.*g", std::numeric_limits<T>::max_digits10, v); | 
233  | 0  | } Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::flags_internal::UnparseFloatingPointVal<float>(float) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > absl::flags_internal::UnparseFloatingPointVal<double>(double)  | 
234  | 0  | std::string Unparse(float v) { return UnparseFloatingPointVal(v); } | 
235  | 0  | std::string Unparse(double v) { return UnparseFloatingPointVal(v); } | 
236  | 0  | std::string AbslUnparseFlag(absl::string_view v) { return std::string(v); } | 
237  | 0  | std::string AbslUnparseFlag(const std::vector<std::string>& v) { | 
238  | 0  |   return absl::StrJoin(v, ",");  | 
239  | 0  | }  | 
240  |  |  | 
241  |  | }  // namespace flags_internal  | 
242  |  |  | 
243  |  | bool AbslParseFlag(absl::string_view text, absl::LogSeverity* dst,  | 
244  | 0  |                    std::string* err) { | 
245  | 0  |   text = absl::StripAsciiWhitespace(text);  | 
246  | 0  |   if (text.empty()) { | 
247  | 0  |     *err = "no value provided";  | 
248  | 0  |     return false;  | 
249  | 0  |   }  | 
250  | 0  |   if (absl::EqualsIgnoreCase(text, "dfatal")) { | 
251  | 0  |     *dst = absl::kLogDebugFatal;  | 
252  | 0  |     return true;  | 
253  | 0  |   }  | 
254  | 0  |   if (absl::EqualsIgnoreCase(text, "klogdebugfatal")) { | 
255  | 0  |     *dst = absl::kLogDebugFatal;  | 
256  | 0  |     return true;  | 
257  | 0  |   }  | 
258  | 0  |   if (text.front() == 'k' || text.front() == 'K') text.remove_prefix(1);  | 
259  | 0  |   if (absl::EqualsIgnoreCase(text, "info")) { | 
260  | 0  |     *dst = absl::LogSeverity::kInfo;  | 
261  | 0  |     return true;  | 
262  | 0  |   }  | 
263  | 0  |   if (absl::EqualsIgnoreCase(text, "warning")) { | 
264  | 0  |     *dst = absl::LogSeverity::kWarning;  | 
265  | 0  |     return true;  | 
266  | 0  |   }  | 
267  | 0  |   if (absl::EqualsIgnoreCase(text, "error")) { | 
268  | 0  |     *dst = absl::LogSeverity::kError;  | 
269  | 0  |     return true;  | 
270  | 0  |   }  | 
271  | 0  |   if (absl::EqualsIgnoreCase(text, "fatal")) { | 
272  | 0  |     *dst = absl::LogSeverity::kFatal;  | 
273  | 0  |     return true;  | 
274  | 0  |   }  | 
275  | 0  |   std::underlying_type<absl::LogSeverity>::type numeric_value;  | 
276  | 0  |   if (absl::ParseFlag(text, &numeric_value, err)) { | 
277  | 0  |     *dst = static_cast<absl::LogSeverity>(numeric_value);  | 
278  | 0  |     return true;  | 
279  | 0  |   }  | 
280  | 0  |   *err =  | 
281  | 0  |       "only integers, absl::LogSeverity enumerators, and DFATAL are accepted";  | 
282  | 0  |   return false;  | 
283  | 0  | }  | 
284  |  |  | 
285  | 0  | std::string AbslUnparseFlag(absl::LogSeverity v) { | 
286  | 0  |   if (v == absl::NormalizeLogSeverity(v)) return absl::LogSeverityName(v);  | 
287  | 0  |   return absl::UnparseFlag(static_cast<int>(v));  | 
288  | 0  | }  | 
289  |  |  | 
290  |  | ABSL_NAMESPACE_END  | 
291  |  | }  // namespace absl  |