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

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

cpp: added missing return statements, changed the way facets work for the moment (we return by value instead of by reference which means we can avoid that ugly leaking hack

  • Property mode set to 100644
File size: 13.0 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 <cerrno>
33#include <cstring>
34#include <internal/locale.hpp>
35#include <internal/locale/numpunct.hpp>
36#include <ios>
37#include <iterator>
38#include <limits>
39
40namespace std
41{
42 /**
43 * 22.4.2.1, class template num_get:
44 */
45
46 template<class Char, class InputIterator = istreambuf_iterator<Char>>
47 class num_get: public locale::facet
48 {
49 public:
50 using char_type = Char;
51 using iter_type = InputIterator;
52
53 explicit num_get(size_t refs = 0)
54 { /* DUMMY BODY */ }
55
56 iter_type get(iter_type in, iter_type end, ios_base& base,
57 ios_base::iostate& err, bool& v) const
58 {
59 return do_get(in, end, base, err, v);
60 }
61
62 iter_type get(iter_type in, iter_type end, ios_base& base,
63 ios_base::iostate& err, long& v) const
64 {
65 return do_get(in, end, base, err, v);
66 }
67
68 iter_type get(iter_type in, iter_type end, ios_base& base,
69 ios_base::iostate& err, long long& v) const
70 {
71 return do_get(in, end, base, err, v);
72 }
73
74 iter_type get(iter_type in, iter_type end, ios_base& base,
75 ios_base::iostate& err, unsigned short& v) const
76 {
77 return do_get(in, end, base, err, v);
78 }
79
80 iter_type get(iter_type in, iter_type end, ios_base& base,
81 ios_base::iostate& err, unsigned int& v) const
82 {
83 return do_get(in, end, base, err, v);
84 }
85
86 iter_type get(iter_type in, iter_type end, ios_base& base,
87 ios_base::iostate& err, unsigned long& v) const
88 {
89 return do_get(in, end, base, err, v);
90 }
91
92 iter_type get(iter_type in, iter_type end, ios_base& base,
93 ios_base::iostate& err, unsigned long long& v) const
94 {
95 return do_get(in, end, base, err, v);
96 }
97
98 iter_type get(iter_type in, iter_type end, ios_base& base,
99 ios_base::iostate& err, float& v) const
100 {
101 return do_get(in, end, base, err, v);
102 }
103
104 iter_type get(iter_type in, iter_type end, ios_base& base,
105 ios_base::iostate& err, double& v) const
106 {
107 return do_get(in, end, base, err, v);
108 }
109
110 iter_type get(iter_type in, iter_type end, ios_base& base,
111 ios_base::iostate& err, long double& v) const
112 {
113 return do_get(in, end, base, err, v);
114 }
115
116 iter_type get(iter_type in, iter_type end, ios_base& base,
117 ios_base::iostate& err, void*& v) const
118 {
119 return do_get(in, end, base, err, v);
120 }
121
122 static locale::id id;
123
124 ~num_get()
125 { /* DUMMY BODY */ }
126
127 protected:
128 iter_type do_get(iter_type in, iter_type end, ios_base& base,
129 ios_base::iostate& err, bool& v) const
130 {
131 if (in == end)
132 {
133 err = ios_base::eofbit;
134 return in;
135 }
136
137 if ((base.flags() & ios_base::boolalpha) == 0)
138 {
139 int8_t tmp{};
140 in = get_integral_<int64_t>(in, end, base, err, tmp);
141
142 if (tmp == 0)
143 v = false;
144 else if (tmp == 1)
145 v = true;
146 else
147 {
148 v = true;
149 err = ios_base::failbit;
150 }
151 }
152 else
153 {
154 /**
155 * We track both truename() and falsename()
156 * at the same time, once either is matched
157 * or the input is too big without a match
158 * or the input ends the conversion ends
159 * and the result is deduced.
160 */
161
162 auto loc = base.getloc();
163 const auto& nt = use_facet<numpunct<char_type>>(loc);
164
165 auto true_target = nt.truename();
166 auto false_target = nt.falsename();
167
168 if (true_target == "" || false_target == "")
169 {
170 v = (err == ios_base::failbit);
171 return in;
172 }
173
174 auto true_str = true_target;
175 auto false_str = false_target;
176
177 size_t i{};
178 while (true)
179 {
180 if (true_str.size() <= i && false_str.size() <= i)
181 break;
182 auto c = *in++;
183
184 if (i < true_str.size())
185 true_str[i] = c;
186 if (i < false_str.size())
187 false_str[i] = c;
188 ++i;
189
190 if (in == end || *in == '\n')
191 {
192 err = ios_base::eofbit;
193 break;
194 }
195 }
196
197 if (i == true_str.size() && true_str == true_target)
198 {
199 v = true;
200
201 if (++in == end)
202 err = ios_base::eofbit;
203 else
204 err = ios_base::goodbit;
205 }
206 else if (i == false_str.size() && false_str == false_target)
207 {
208 v = false;
209
210 if (in == end)
211 err = (ios_base::failbit | ios_base::eofbit);
212 else
213 err = ios_base::failbit;
214 }
215 else
216 err = ios_base::failbit;
217 }
218
219 return in;
220 }
221
222 iter_type do_get(iter_type in, iter_type end, ios_base& base,
223 ios_base::iostate& err, long& v) const
224 {
225 return get_integral_<int64_t>(in, end, base, err, v);
226 }
227
228 iter_type do_get(iter_type in, iter_type end, ios_base& base,
229 ios_base::iostate& err, long long& v) const
230 {
231 return get_integral_<int64_t>(in, end, base, err, v);
232 }
233
234 iter_type do_get(iter_type in, iter_type end, ios_base& base,
235 ios_base::iostate& err, unsigned short& v) const
236 {
237 return get_integral_<uint64_t>(in, end, base, err, v);
238 }
239
240 iter_type do_get(iter_type in, iter_type end, ios_base& base,
241 ios_base::iostate& err, unsigned int& v) const
242 {
243 return get_integral_<uint64_t>(in, end, base, err, v);
244 }
245
246 iter_type do_get(iter_type in, iter_type end, ios_base& base,
247 ios_base::iostate& err, unsigned long& v) const
248 {
249 return get_integral_<uint64_t>(in, end, base, err, v);
250 }
251
252 iter_type do_get(iter_type in, iter_type end, ios_base& base,
253 ios_base::iostate& err, unsigned long long& v) const
254 {
255 return get_integral_<uint64_t>(in, end, base, err, v);
256 }
257
258 iter_type do_get(iter_type in, iter_type end, ios_base& base,
259 ios_base::iostate& err, float& v) const
260 {
261 // TODO: implement
262 return in;
263 }
264
265 iter_type do_get(iter_type in, iter_type end, ios_base& base,
266 ios_base::iostate& err, double& v) const
267 {
268 // TODO: implement
269 return in;
270 }
271
272 iter_type do_get(iter_type in, iter_type end, ios_base& base,
273 ios_base::iostate& err, long double& v) const
274 {
275 // TODO: implement
276 return in;
277 }
278
279 iter_type do_get(iter_type in, iter_type end, ios_base& base,
280 ios_base::iostate& err, void*& v) const
281 {
282 // TODO: implement
283 return in;
284 }
285
286 private:
287 template<class BaseType, class T>
288 iter_type get_integral_(iter_type in, iter_type end, ios_base& base,
289 ios_base::iostate& err, T& v) const
290 {
291 BaseType res{};
292 unsigned int num_base{10};
293
294 auto basefield = (base.flags() & ios_base::basefield);
295 if (basefield == ios_base::oct)
296 num_base = 8;
297 else if (basefield == ios_base::hex)
298 num_base = 16;
299
300 auto size = fill_buffer_integral_(in, end, base);
301 if (size > 0)
302 {
303 int ret{};
304 if constexpr (is_signed<BaseType>::value)
305 ret = std::hel::str_int64_t(base.buffer_, nullptr, num_base, false, &res);
306 else
307 ret = std::hel::str_uint64_t(base.buffer_, nullptr, num_base, false, &res);
308
309 if (ret != EOK)
310 {
311 err |= ios_base::failbit;
312 v = 0;
313 }
314 else if (res > static_cast<BaseType>(numeric_limits<T>::max()))
315 {
316 err |= ios_base::failbit;
317 v = numeric_limits<T>::max();
318 }
319 else if (res < static_cast<BaseType>(numeric_limits<T>::min()))
320 {
321 err |= ios_base::failbit;
322 v = numeric_limits<T>::min();
323 }
324 else
325 v = static_cast<T>(res);
326 }
327 else
328 {
329 err |= ios_base::failbit;
330 v = 0;
331 }
332
333 return in;
334 }
335
336 size_t fill_buffer_integral_(iter_type& in, iter_type end, ios_base& base) const
337 {
338 if (in == end)
339 return 0;
340
341 auto loc = base.getloc();
342 const auto& ct = use_facet<ctype<char_type>>(loc);
343 auto hex = ((base.flags() & ios_base::hex) != 0);
344
345 size_t i{};
346 if (*in == '+' || *in == '-')
347 base.buffer_[i++] = *in++;
348
349 while (in != end && i < ios_base::buffer_size_ - 1)
350 {
351 auto c = *in;
352 if (ct.is(ctype_base::digit, c) || (hex &&
353 ((c >= ct.widen('A') && c <= ct.widen('F')) ||
354 (c >= ct.widen('a') && c <= ct.widen('f')))))
355 {
356 ++in;
357 base.buffer_[i++] = c;
358 }
359 else
360 break;
361 }
362 base.buffer_[i] = char_type{};
363
364 return i;
365 }
366 };
367}
368
369#endif
Note: See TracBrowser for help on using the repository browser.