source: mainline/uspace/lib/cpp/include/__bits/locale/num_get.hpp@ c6f23a7

Last change on this file since c6f23a7 was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

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