source: mainline/uspace/lib/cpp/include/internal/locale/num_get.hpp@ c1e11d32

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c1e11d32 was c1e11d32, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: num_get now properly parses hexadecimal numbers

  • Property mode set to 100644
File size: 12.6 KB
Line 
1/*
2 * Copyright (c) 2017 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_INTERNAL_LOCALE_NUM_GET
30#define LIBCPP_INTERNAL_LOCALE_NUM_GET
31
32#include <internal/locale.hpp>
33#include <internal/locale/numpunct.hpp>
34#include <ios>
35#include <iterator>
36#include <limits>
37
38namespace std
39{
40 /**
41 * 22.4.2.1, class template num_get:
42 */
43
44 template<class Char, class InputIterator = istreambuf_iterator<Char>>
45 class num_get: public locale::facet
46 {
47 public:
48 using char_type = Char;
49 using iter_type = InputIterator;
50
51 explicit num_get(size_t refs = 0)
52 { /* DUMMY BODY */ }
53
54 iter_type get(iter_type in, iter_type end, ios_base& base,
55 ios_base::iostate& err, bool& v) const
56 {
57 return do_get(in, end, base, err, v);
58 }
59
60 iter_type get(iter_type in, iter_type end, ios_base& base,
61 ios_base::iostate& err, long& v) const
62 {
63 return do_get(in, end, base, err, v);
64 }
65
66 iter_type get(iter_type in, iter_type end, ios_base& base,
67 ios_base::iostate& err, long long& v) const
68 {
69 return do_get(in, end, base, err, v);
70 }
71
72 iter_type get(iter_type in, iter_type end, ios_base& base,
73 ios_base::iostate& err, unsigned short& v) const
74 {
75 return do_get(in, end, base, err, v);
76 }
77
78 iter_type get(iter_type in, iter_type end, ios_base& base,
79 ios_base::iostate& err, unsigned int& v) const
80 {
81 return do_get(in, end, base, err, v);
82 }
83
84 iter_type get(iter_type in, iter_type end, ios_base& base,
85 ios_base::iostate& err, unsigned long& v) const
86 {
87 return do_get(in, end, base, err, v);
88 }
89
90 iter_type get(iter_type in, iter_type end, ios_base& base,
91 ios_base::iostate& err, unsigned long long& v) const
92 {
93 return do_get(in, end, base, err, v);
94 }
95
96 iter_type get(iter_type in, iter_type end, ios_base& base,
97 ios_base::iostate& err, float& v) const
98 {
99 return do_get(in, end, base, err, v);
100 }
101
102 iter_type get(iter_type in, iter_type end, ios_base& base,
103 ios_base::iostate& err, double& v) const
104 {
105 return do_get(in, end, base, err, v);
106 }
107
108 iter_type get(iter_type in, iter_type end, ios_base& base,
109 ios_base::iostate& err, long double& v) const
110 {
111 return do_get(in, end, base, err, v);
112 }
113
114 iter_type get(iter_type in, iter_type end, ios_base& base,
115 ios_base::iostate& err, void*& v) const
116 {
117 return do_get(in, end, base, err, v);
118 }
119
120 static locale::id id;
121
122 ~num_get()
123 { /* DUMMY BODY */ }
124
125 protected:
126 iter_type do_get(iter_type in, iter_type end, ios_base& base,
127 ios_base::iostate& err, bool& v) const
128 {
129 if (in == end)
130 {
131 err = ios_base::eofbit;
132 return in;
133 }
134
135 if ((base.flags() & ios_base::boolalpha) == 0)
136 {
137 int8_t tmp{};
138 in = get_integral_<int64_t>(in, end, base, err, tmp);
139
140 if (tmp == 0)
141 v = false;
142 else if (tmp == 1)
143 v = true;
144 else
145 {
146 v = true;
147 err = ios_base::failbit;
148 }
149 }
150 else
151 {
152 /**
153 * We track both truename() and falsename()
154 * at the same time, once either is matched
155 * or the input is too big without a match
156 * or the input ends the conversion ends
157 * and the result is deduced.
158 */
159
160 auto loc = base.getloc();
161 const auto& nt = use_facet<numpunct<char_type>>(loc);
162
163 auto true_target = nt.truename();
164 auto false_target = nt.falsename();
165
166 if (true_target == "" || false_target == "")
167 {
168 v = (err == ios_base::failbit);
169 return in;
170 }
171
172 auto true_str = true_target;
173 auto false_str = false_target;
174
175 size_t i{};
176 while (true)
177 {
178 if (true_str.size() <= i && false_str.size() <= i)
179 break;
180 auto c = *in++;
181
182 if (i < true_str.size())
183 true_str[i] = c;
184 if (i < false_str.size())
185 false_str[i] = c;
186 ++i;
187
188 if (in == end || *in == '\n')
189 {
190 err = ios_base::eofbit;
191 break;
192 }
193 }
194
195 if (i == true_str.size() && true_str == true_target)
196 {
197 v = true;
198
199 if (++in == end)
200 err = ios_base::eofbit;
201 else
202 err = ios_base::goodbit;
203 }
204 else if (i == false_str.size() && false_str == false_target)
205 {
206 v = false;
207
208 if (in == end)
209 err = (ios_base::failbit | ios_base::eofbit);
210 else
211 err = ios_base::failbit;
212 }
213 else
214 err = ios_base::failbit;
215 }
216
217 return in;
218 }
219
220 iter_type do_get(iter_type in, iter_type end, ios_base& base,
221 ios_base::iostate& err, long& v) const
222 {
223 return get_integral_<int64_t>(in, end, base, err, v);
224 }
225
226 iter_type do_get(iter_type in, iter_type end, ios_base& base,
227 ios_base::iostate& err, long long& v) const
228 {
229 return get_integral_<int64_t>(in, end, base, err, v);
230 }
231
232 iter_type do_get(iter_type in, iter_type end, ios_base& base,
233 ios_base::iostate& err, unsigned short& v) const
234 {
235 return get_integral_<uint64_t>(in, end, base, err, v);
236 }
237
238 iter_type do_get(iter_type in, iter_type end, ios_base& base,
239 ios_base::iostate& err, unsigned int& v) const
240 {
241 return get_integral_<uint64_t>(in, end, base, err, v);
242 }
243
244 iter_type do_get(iter_type in, iter_type end, ios_base& base,
245 ios_base::iostate& err, unsigned long& v) const
246 {
247 return get_integral_<uint64_t>(in, end, base, err, v);
248 }
249
250 iter_type do_get(iter_type in, iter_type end, ios_base& base,
251 ios_base::iostate& err, unsigned long long& v) const
252 {
253 return get_integral_<uint64_t>(in, end, base, err, v);
254 }
255
256 iter_type do_get(iter_type in, iter_type end, ios_base& base,
257 ios_base::iostate& err, float& v) const
258 {
259 // TODO: implement
260 }
261
262 iter_type do_get(iter_type in, iter_type end, ios_base& base,
263 ios_base::iostate& err, double& v) const
264 {
265 // TODO: implement
266 }
267
268 iter_type do_get(iter_type in, iter_type end, ios_base& base,
269 ios_base::iostate& err, long double& v) const
270 {
271 // TODO: implement
272 }
273
274 iter_type do_get(iter_type in, iter_type end, ios_base& base,
275 ios_base::iostate& err, void*& v) const
276 {
277 // TODO: implement
278 }
279
280 private:
281 template<class BaseType, class T>
282 iter_type get_integral_(iter_type in, iter_type end, ios_base& base,
283 ios_base::iostate err, T& v) const
284 {
285 BaseType res{};
286 unsigned int num_base{10};
287
288 auto basefield = (base.flags() & ios_base::basefield);
289 if (basefield == ios_base::oct)
290 num_base = 8;
291 else if (basefield == ios_base::hex)
292 num_base = 16;
293
294 auto size = fill_buffer_integral_(in, end, base);
295 if (size > 0)
296 {
297 if constexpr (is_signed<BaseType>::value)
298 str_int64_t(base.buffer_, nullptr, num_base, false, &res);
299 else
300 str_uint64_t(base.buffer_, nullptr, num_base, false, &res);
301
302 if (res > static_cast<BaseType>(numeric_limits<T>::max()))
303 {
304 err |= ios_base::failbit;
305 v = numeric_limits<T>::max();
306 }
307 else if (res < static_cast<BaseType>(numeric_limits<T>::min()))
308 {
309 err |= ios_base::failbit;
310 v = numeric_limits<T>::min();
311 }
312 else
313 v = static_cast<T>(res);
314 }
315 else
316 {
317 err |= ios_base::failbit;
318 v = 0;
319 }
320
321 return in;
322 }
323
324 size_t fill_buffer_integral_(iter_type& in, iter_type end, ios_base& base) const
325 {
326 if (in == end)
327 return 0;
328
329 auto loc = base.getloc();
330 const auto& ct = use_facet<ctype<char_type>>(loc);
331 auto hex = ((base.flags() & ios_base::hex) != 0);
332
333 size_t i{};
334 if (*in == '+' || *in == '-')
335 base.buffer_[i++] = *in++;
336
337 while (in != end && i < ios_base::buffer_size_ - 1)
338 {
339 auto c = *in;
340 if (ct.is(ctype_base::digit, c) || (hex &&
341 ((c >= ct.widen('A') && c <= ct.widen('F')) ||
342 (c >= ct.widen('a') && c <= ct.widen('f')))))
343 {
344 ++in;
345 base.buffer_[i++] = c;
346 }
347 else
348 break;
349 }
350 base.buffer_[i] = char_type{};
351
352 return i;
353 }
354 };
355}
356
357#endif
Note: See TracBrowser for help on using the repository browser.