1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef _LIBCPP___LOCALE_DIR_NUM_H
10#define _LIBCPP___LOCALE_DIR_NUM_H
11
12#include <__algorithm/copy.h>
13#include <__algorithm/find.h>
14#include <__algorithm/reverse.h>
15#include <__algorithm/simd_utils.h>
16#include <__charconv/to_chars_integral.h>
17#include <__charconv/traits.h>
18#include <__config>
19#include <__iterator/istreambuf_iterator.h>
20#include <__iterator/ostreambuf_iterator.h>
21#include <__locale_dir/check_grouping.h>
22#include <__locale_dir/get_c_locale.h>
23#include <__locale_dir/pad_and_output.h>
24#include <__locale_dir/scan_keyword.h>
25#include <__memory/unique_ptr.h>
26#include <__system_error/errc.h>
27#include <__type_traits/is_signed.h>
28#include <cerrno>
29#include <ios>
30#include <streambuf>
31
32#if _LIBCPP_HAS_LOCALIZATION
33
34# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
35# pragma GCC system_header
36# endif
37
38// TODO: Properly qualify calls now that the locale base API defines functions instead of macros
39// NOLINTBEGIN(libcpp-robust-against-adl)
40
41_LIBCPP_PUSH_MACROS
42# include <__undef_macros>
43
44_LIBCPP_BEGIN_NAMESPACE_STD
45
46struct _LIBCPP_EXPORTED_FROM_ABI __num_get_base {
47 static const int __num_get_buf_sz = 40;
48
49 static int __get_base(ios_base&);
50 static const char __src[33]; // "0123456789abcdefABCDEFxX+-pPiInN"
51 // count of leading characters in __src used for parsing integers ("012..X+-")
52 static inline const size_t __int_chr_cnt = 26;
53 // count of leading characters in __src used for parsing floating-point values ("012..-pP")
54 static inline const size_t __fp_chr_cnt = 28;
55};
56
57template <class _CharT>
58struct __num_get : protected __num_get_base {
59 static string __stage2_float_prep(ios_base& __iob, _CharT* __atoms, _CharT& __decimal_point, _CharT& __thousands_sep);
60
61 static int __stage2_float_loop(
62 _CharT __ct,
63 bool& __in_units,
64 char& __exp,
65 char* __a,
66 char*& __a_end,
67 _CharT __decimal_point,
68 _CharT __thousands_sep,
69 const string& __grouping,
70 unsigned* __g,
71 unsigned*& __g_end,
72 unsigned& __dc,
73 _CharT* __atoms);
74
75 [[__deprecated__("This exists only for ABI compatibility")]] static string
76 __stage2_int_prep(ios_base& __iob, _CharT* __atoms, _CharT& __thousands_sep);
77
78 [[__deprecated__("This exists only for ABI compatibility")]] static int __stage2_int_loop(
79 _CharT __ct,
80 int __base,
81 char* __a,
82 char*& __a_end,
83 unsigned& __dc,
84 _CharT __thousands_sep,
85 const string& __grouping,
86 unsigned* __g,
87 unsigned*& __g_end,
88 _CharT* __atoms);
89
90 _LIBCPP_HIDE_FROM_ABI static ptrdiff_t __atoms_offset(const _CharT* __atoms, _CharT __val) {
91 // TODO: Remove the manual vectorization once https://llvm.org/PR168551 is resolved
92# if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS
93 if constexpr (is_same<_CharT, char>::value) {
94 // TODO(LLVM 24): This can be removed, since -Wpsabi doesn't warn on [[gnu::always_inline]] functions anymore.
95 _LIBCPP_DIAGNOSTIC_PUSH
96 _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi")
97 using __vec = __simd_vector<char, 32>;
98 __vec __chars = std::__broadcast<__vec>(__val);
99 __vec __cmp = std::__partial_load<__vec, __int_chr_cnt>(__atoms);
100 auto __res = __chars == __cmp;
101 if (std::__none_of(vec: __res))
102 return __int_chr_cnt;
103 return std::min(a: __int_chr_cnt, b: std::__find_first_set(vec: __res));
104 _LIBCPP_DIAGNOSTIC_POP
105 }
106# endif
107 return std::find(__atoms, __atoms + __int_chr_cnt, __val) - __atoms;
108 }
109
110 _LIBCPP_HIDE_FROM_ABI const _CharT* __do_widen(ios_base& __iob, _CharT* __atoms) const {
111 return __do_widen_p(__iob, __atoms);
112 }
113
114private:
115 template <typename _Tp>
116 _LIBCPP_HIDE_FROM_ABI const _Tp* __do_widen_p(ios_base& __iob, _Tp* __atoms) const {
117 locale __loc = __iob.getloc();
118 use_facet<ctype<_Tp> >(__loc).widen(__src, __src + __int_chr_cnt, __atoms);
119 return __atoms;
120 }
121
122 _LIBCPP_HIDE_FROM_ABI const char* __do_widen_p(ios_base& __iob, char* __atoms) const {
123 (void)__iob;
124 (void)__atoms;
125 return __src;
126 }
127};
128
129template <class _CharT>
130string __num_get<_CharT>::__stage2_float_prep(
131 ios_base& __iob, _CharT* __atoms, _CharT& __decimal_point, _CharT& __thousands_sep) {
132 locale __loc = __iob.getloc();
133 std::use_facet<ctype<_CharT> >(__loc).widen(__src, __src + __fp_chr_cnt, __atoms);
134 const numpunct<_CharT>& __np = std::use_facet<numpunct<_CharT> >(__loc);
135 __decimal_point = __np.decimal_point();
136 __thousands_sep = __np.thousands_sep();
137 return __np.grouping();
138}
139
140template <class _CharT>
141int __num_get<_CharT>::__stage2_float_loop(
142 _CharT __ct,
143 bool& __in_units,
144 char& __exp,
145 char* __a,
146 char*& __a_end,
147 _CharT __decimal_point,
148 _CharT __thousands_sep,
149 const string& __grouping,
150 unsigned* __g,
151 unsigned*& __g_end,
152 unsigned& __dc,
153 _CharT* __atoms) {
154 if (__ct == __decimal_point) {
155 if (!__in_units)
156 return -1;
157 __in_units = false;
158 *__a_end++ = '.';
159 if (__grouping.size() != 0 && __g_end - __g < __num_get_buf_sz)
160 *__g_end++ = __dc;
161 return 0;
162 }
163 if (__ct == __thousands_sep && __grouping.size() != 0) {
164 if (!__in_units)
165 return -1;
166 if (__g_end - __g < __num_get_buf_sz) {
167 *__g_end++ = __dc;
168 __dc = 0;
169 }
170 return 0;
171 }
172 ptrdiff_t __f = std::find(__atoms, __atoms + __num_get_base::__fp_chr_cnt, __ct) - __atoms;
173 if (__f >= static_cast<ptrdiff_t>(__num_get_base::__fp_chr_cnt))
174 return -1;
175 char __x = __src[__f];
176 if (__x == '-' || __x == '+') {
177 if (__a_end == __a || (std::toupper(c: __a_end[-1]) == std::toupper(c: __exp))) {
178 *__a_end++ = __x;
179 return 0;
180 }
181 return -1;
182 }
183 if (__x == 'x' || __x == 'X')
184 __exp = 'P';
185 else if (std::toupper(c: __x) == __exp) {
186 __exp = std::tolower(c: __exp);
187 if (__in_units) {
188 __in_units = false;
189 if (__grouping.size() != 0 && __g_end - __g < __num_get_buf_sz)
190 *__g_end++ = __dc;
191 }
192 }
193 *__a_end++ = __x;
194 if (__f >= 22)
195 return 0;
196 ++__dc;
197 return 0;
198}
199
200extern template struct _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __num_get<char>;
201# if _LIBCPP_HAS_WIDE_CHARACTERS
202extern template struct _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __num_get<wchar_t>;
203# endif
204
205template <class _Tp>
206_LIBCPP_HIDE_FROM_ABI _Tp __do_strtod(const char* __a, char** __p2);
207
208template <>
209inline _LIBCPP_HIDE_FROM_ABI float __do_strtod<float>(const char* __a, char** __p2) {
210 return __locale::__strtof(nptr: __a, endptr: __p2, _LIBCPP_GET_C_LOCALE);
211}
212
213template <>
214inline _LIBCPP_HIDE_FROM_ABI double __do_strtod<double>(const char* __a, char** __p2) {
215 return __locale::__strtod(nptr: __a, endptr: __p2, _LIBCPP_GET_C_LOCALE);
216}
217
218template <>
219inline _LIBCPP_HIDE_FROM_ABI long double __do_strtod<long double>(const char* __a, char** __p2) {
220 return __locale::__strtold(nptr: __a, endptr: __p2, _LIBCPP_GET_C_LOCALE);
221}
222
223template <class _Tp>
224_LIBCPP_HIDE_FROM_ABI _Tp __num_get_float(const char* __a, const char* __a_end, ios_base::iostate& __err) {
225 if (__a != __a_end) {
226 __libcpp_remove_reference_t<decltype(errno)> __save_errno = errno;
227 errno = 0;
228 char* __p2;
229 _Tp __ld = std::__do_strtod<_Tp>(__a, &__p2);
230 __libcpp_remove_reference_t<decltype(errno)> __current_errno = errno;
231 if (__current_errno == 0)
232 errno = __save_errno;
233 if (__p2 != __a_end) {
234 __err = ios_base::failbit;
235 return 0;
236 } else if (__current_errno == ERANGE)
237 __err = ios_base::failbit;
238 return __ld;
239 }
240 __err = ios_base::failbit;
241 return 0;
242}
243
244template <class _CharT, class _InputIterator = istreambuf_iterator<_CharT> >
245class num_get : public locale::facet, private __num_get<_CharT> {
246public:
247 typedef _CharT char_type;
248 typedef _InputIterator iter_type;
249
250 _LIBCPP_HIDE_FROM_ABI explicit num_get(size_t __refs = 0) : locale::facet(__refs) {}
251
252 _LIBCPP_HIDE_FROM_ABI iter_type
253 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, bool& __v) const {
254 return do_get(__b, __e, __iob, __err, __v);
255 }
256
257 _LIBCPP_HIDE_FROM_ABI iter_type
258 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long& __v) const {
259 return do_get(__b, __e, __iob, __err, __v);
260 }
261
262 _LIBCPP_HIDE_FROM_ABI iter_type
263 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long long& __v) const {
264 return do_get(__b, __e, __iob, __err, __v);
265 }
266
267 _LIBCPP_HIDE_FROM_ABI iter_type
268 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned short& __v) const {
269 return do_get(__b, __e, __iob, __err, __v);
270 }
271
272 _LIBCPP_HIDE_FROM_ABI iter_type
273 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned int& __v) const {
274 return do_get(__b, __e, __iob, __err, __v);
275 }
276
277 _LIBCPP_HIDE_FROM_ABI iter_type
278 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long& __v) const {
279 return do_get(__b, __e, __iob, __err, __v);
280 }
281
282 _LIBCPP_HIDE_FROM_ABI iter_type
283 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long long& __v) const {
284 return do_get(__b, __e, __iob, __err, __v);
285 }
286
287 _LIBCPP_HIDE_FROM_ABI iter_type
288 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, float& __v) const {
289 return do_get(__b, __e, __iob, __err, __v);
290 }
291
292 _LIBCPP_HIDE_FROM_ABI iter_type
293 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, double& __v) const {
294 return do_get(__b, __e, __iob, __err, __v);
295 }
296
297 _LIBCPP_HIDE_FROM_ABI iter_type
298 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long double& __v) const {
299 return do_get(__b, __e, __iob, __err, __v);
300 }
301
302 _LIBCPP_HIDE_FROM_ABI iter_type
303 get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, void*& __v) const {
304 return do_get(__b, __e, __iob, __err, __v);
305 }
306
307 static locale::id id;
308
309protected:
310 _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~num_get() override {}
311
312 template <class _Fp>
313 _LIBCPP_HIDE_FROM_ABI iter_type
314 __do_get_floating_point(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Fp& __v) const {
315 // Stage 1, nothing to do
316 // Stage 2
317 char_type __atoms[__num_get_base::__fp_chr_cnt];
318 char_type __decimal_point;
319 char_type __thousands_sep;
320 string __grouping = this->__stage2_float_prep(__iob, __atoms, __decimal_point, __thousands_sep);
321 string __buf;
322 __buf.resize(n: __buf.capacity());
323 char* __a = &__buf[0];
324 char* __a_end = __a;
325 unsigned __g[__num_get_base::__num_get_buf_sz];
326 unsigned* __g_end = __g;
327 unsigned __dc = 0;
328 bool __in_units = true;
329 char __exp = 'E';
330 bool __is_leading_parsed = false;
331 for (; __b != __e; ++__b) {
332 if (__a_end == __a + __buf.size()) {
333 size_t __tmp = __buf.size();
334 __buf.resize(n: 2 * __buf.size());
335 __buf.resize(n: __buf.capacity());
336 __a = &__buf[0];
337 __a_end = __a + __tmp;
338 }
339 if (this->__stage2_float_loop(
340 *__b,
341 __in_units,
342 __exp,
343 __a,
344 __a_end,
345 __decimal_point,
346 __thousands_sep,
347 __grouping,
348 __g,
349 __g_end,
350 __dc,
351 __atoms))
352 break;
353
354 // the leading character excluding the sign must be a decimal digit
355 if (!__is_leading_parsed) {
356 if (__a_end - __a >= 1 && __a[0] != '-' && __a[0] != '+') {
357 if (('0' <= __a[0] && __a[0] <= '9') || __a[0] == '.')
358 __is_leading_parsed = true;
359 else
360 break;
361 } else if (__a_end - __a >= 2 && (__a[0] == '-' || __a[0] == '+')) {
362 if (('0' <= __a[1] && __a[1] <= '9') || __a[1] == '.')
363 __is_leading_parsed = true;
364 else
365 break;
366 }
367 }
368 }
369 if (__grouping.size() != 0 && __in_units && __g_end - __g < __num_get_base::__num_get_buf_sz)
370 *__g_end++ = __dc;
371 // Stage 3
372 __v = std::__num_get_float<_Fp>(__a, __a_end, __err);
373 // Digit grouping checked
374 __check_grouping(__grouping, __g, __g_end, __err);
375 // EOF checked
376 if (__b == __e)
377 __err |= ios_base::eofbit;
378 return __b;
379 }
380
381 template <class _MaybeSigned>
382 iter_type __do_get_integral(
383 iter_type __first, iter_type __last, ios_base& __iob, ios_base::iostate& __err, _MaybeSigned& __v) const {
384 using _Unsigned = __make_unsigned_t<_MaybeSigned>;
385
386 // Stage 1
387 int __base = this->__get_base(__iob);
388
389 // Stages 2 & 3
390 // These are combined into a single step where we parse the characters and calculate the value in one go instead of
391 // storing the relevant characters first (in an allocated buffer) and parse the characters after we extracted them.
392 // This makes the whole process significantly faster, since we avoid potential allocations and copies.
393
394 const auto& __numpunct = use_facet<numpunct<_CharT> >(__iob.getloc());
395 char_type __thousands_sep = __numpunct.thousands_sep();
396 string __grouping = __numpunct.grouping();
397
398 char_type __atoms_buffer[__num_get_base::__int_chr_cnt];
399 const char_type* __atoms = this->__do_widen(__iob, __atoms_buffer);
400 unsigned __g[__num_get_base::__num_get_buf_sz];
401 unsigned* __g_end = __g;
402 unsigned __dc = 0;
403
404 if (__first == __last) {
405 __err |= ios_base::eofbit | ios_base::failbit;
406 __v = 0;
407 return __first;
408 }
409
410 while (!__grouping.empty() && *__first == __thousands_sep) {
411 ++__first;
412 if (__g_end - __g < this->__num_get_buf_sz)
413 *__g_end++ = 0;
414 }
415
416 bool __negate = false;
417 // __c == '+' || __c == '-'
418 if (auto __c = *__first; __c == __atoms[24] || __c == __atoms[25]) {
419 __negate = __c == __atoms[25];
420 ++__first;
421 }
422
423 if (__first == __last) {
424 __err |= ios_base::eofbit | ios_base::failbit;
425 __v = 0;
426 return __first;
427 }
428
429 bool __parsed_num = false;
430
431 // If we don't have a pre-set base, figure it out and swallow any prefix
432 if (__base == 0) {
433 auto __c = *__first;
434 // __c == '0'
435 if (__c == __atoms[0]) {
436 ++__first;
437 if (__first == __last) {
438 __err |= ios_base::eofbit;
439 __v = 0;
440 return __first;
441 }
442 // __c2 == 'x' || __c2 == 'X'
443 if (auto __c2 = *__first; __c2 == __atoms[22] || __c2 == __atoms[23]) {
444 __base = 16;
445 ++__first;
446 } else {
447 __base = 8;
448 __parsed_num = true; // We only swallowed '0', so we've started to parse a number
449 }
450 } else {
451 __base = 10;
452 }
453
454 // If the base has been specified explicitly, try to swallow the appropriate prefix. We only need to do something
455 // special for hex, since decimal has no prefix and octal's prefix is '0', which doesn't change the value that
456 // we'll parse if we don't swallow it.
457 } else if (__base == 16) {
458 // Try to swallow '0x'
459
460 // *__first == '0'
461 if (*__first == __atoms[0]) {
462 ++__first;
463 if (__first == __last) {
464 __err |= ios_base::eofbit;
465 __v = 0;
466 return __first;
467 }
468 // __c == 'x' || __c == 'X'
469 if (auto __c = *__first; __c == __atoms[22] || __c == __atoms[23])
470 ++__first;
471 else
472 __parsed_num = true; // We only swallowed '0', so we've started to parse a number
473 }
474 }
475
476 // Calculate the actual number
477 _Unsigned __val = 0;
478 bool __overflowed = false;
479 for (; __first != __last; ++__first) {
480 auto __c = *__first;
481 if (!__grouping.empty() && __c == __thousands_sep) {
482 if (__g_end - __g < this->__num_get_buf_sz) {
483 *__g_end++ = __dc;
484 __dc = 0;
485 }
486 continue;
487 }
488 auto __offset = this->__atoms_offset(__atoms, __c);
489 if (__offset >= 22) // Not a valid integer character
490 break;
491
492 if (__base == 16 && __offset >= 16)
493 __offset -= 6;
494 if (__offset >= __base)
495 break;
496 // __val = (__val * __base) + __offset
497 __overflowed |= __builtin_mul_overflow(__val, __base, std::addressof(__val)) ||
498 __builtin_add_overflow(__val, __offset, std::addressof(__val));
499 __parsed_num = true;
500 ++__dc;
501 }
502
503 if (!__parsed_num) {
504 __err |= ios_base::failbit;
505 __v = 0;
506 } else if (__overflowed) {
507 __err |= ios_base::failbit;
508 __v = is_signed<_MaybeSigned>::value && __negate
509 ? numeric_limits<_MaybeSigned>::min()
510 : numeric_limits<_MaybeSigned>::max();
511 } else if (!__negate) {
512 if (__val > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max())) {
513 __err |= ios_base::failbit;
514 __v = numeric_limits<_MaybeSigned>::max();
515 } else {
516 __v = __val;
517 }
518 } else if (is_signed<_MaybeSigned>::value) {
519 if (__val > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) {
520 __err |= ios_base::failbit;
521 __v = numeric_limits<_MaybeSigned>::min();
522 } else if (__val == static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) {
523 __v = numeric_limits<_MaybeSigned>::min();
524 } else {
525 __v = -__val;
526 }
527 } else {
528 __v = -__val;
529 }
530
531 if (__grouping.size() != 0 && __g_end - __g < __num_get_base::__num_get_buf_sz)
532 *__g_end++ = __dc;
533
534 // Digit grouping checked
535 __check_grouping(__grouping, __g, __g_end, __err);
536 // EOF checked
537 if (__first == __last)
538 __err |= ios_base::eofbit;
539 return __first;
540 }
541
542 virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, bool& __v) const;
543
544 virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long& __v) const {
545 return this->__do_get_integral(__b, __e, __iob, __err, __v);
546 }
547
548 virtual iter_type
549 do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long long& __v) const {
550 return this->__do_get_integral(__b, __e, __iob, __err, __v);
551 }
552
553 virtual iter_type
554 do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned short& __v) const {
555 return this->__do_get_integral(__b, __e, __iob, __err, __v);
556 }
557
558 virtual iter_type
559 do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned int& __v) const {
560 return this->__do_get_integral(__b, __e, __iob, __err, __v);
561 }
562
563 virtual iter_type
564 do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long& __v) const {
565 return this->__do_get_integral(__b, __e, __iob, __err, __v);
566 }
567
568 virtual iter_type
569 do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long long& __v) const {
570 return this->__do_get_integral(__b, __e, __iob, __err, __v);
571 }
572
573 virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, float& __v) const {
574 return this->__do_get_floating_point(__b, __e, __iob, __err, __v);
575 }
576
577 virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, double& __v) const {
578 return this->__do_get_floating_point(__b, __e, __iob, __err, __v);
579 }
580
581 virtual iter_type
582 do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long double& __v) const {
583 return this->__do_get_floating_point(__b, __e, __iob, __err, __v);
584 }
585
586 virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, void*& __v) const;
587};
588
589template <class _CharT, class _InputIterator>
590locale::id num_get<_CharT, _InputIterator>::id;
591
592template <class _CharT, class _InputIterator>
593_InputIterator num_get<_CharT, _InputIterator>::do_get(
594 iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, bool& __v) const {
595 if ((__iob.flags() & ios_base::boolalpha) == 0) {
596 long __lv = -1;
597 __b = do_get(__b, __e, __iob, __err, __lv);
598 switch (__lv) {
599 case 0:
600 __v = false;
601 break;
602 case 1:
603 __v = true;
604 break;
605 default:
606 __v = true;
607 __err = ios_base::failbit;
608 break;
609 }
610 return __b;
611 }
612 const ctype<_CharT>& __ct = std::use_facet<ctype<_CharT> >(__iob.getloc());
613 const numpunct<_CharT>& __np = std::use_facet<numpunct<_CharT> >(__iob.getloc());
614 typedef typename numpunct<_CharT>::string_type string_type;
615 const string_type __names[2] = {__np.truename(), __np.falsename()};
616 const string_type* __i = std::__scan_keyword(__b, __e, __names, __names + 2, __ct, __err);
617 __v = __i == __names;
618 return __b;
619}
620
621template <class _CharT, class _InputIterator>
622_InputIterator num_get<_CharT, _InputIterator>::do_get(
623 iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, void*& __v) const {
624 auto __flags = __iob.flags();
625 __iob.flags(fmtfl: (__flags & ~ios_base::basefield & ~ios_base::uppercase) | ios_base::hex);
626 uintptr_t __ptr;
627 auto __res = __do_get_integral(__b, __e, __iob, __err, __ptr);
628 __iob.flags(fmtfl: __flags);
629 __v = reinterpret_cast<void*>(__ptr);
630 return __res;
631}
632
633extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS num_get<char>;
634# if _LIBCPP_HAS_WIDE_CHARACTERS
635extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS num_get<wchar_t>;
636# endif
637
638struct _LIBCPP_EXPORTED_FROM_ABI __num_put_base {
639protected:
640 static void __format_int(char* __fmt, const char* __len, bool __signd, ios_base::fmtflags __flags);
641 static bool __format_float(char* __fmt, const char* __len, ios_base::fmtflags __flags);
642 static char* __identify_padding(char* __nb, char* __ne, const ios_base& __iob);
643};
644
645template <class _CharT>
646struct __num_put : protected __num_put_base {
647 static void __widen_and_group_int(
648 char* __nb, char* __np, char* __ne, _CharT* __ob, _CharT*& __op, _CharT*& __oe, const locale& __loc);
649 static void __widen_and_group_float(
650 char* __nb, char* __np, char* __ne, _CharT* __ob, _CharT*& __op, _CharT*& __oe, const locale& __loc);
651};
652
653template <class _CharT>
654void __num_put<_CharT>::__widen_and_group_int(
655 char* __nb, char* __np, char* __ne, _CharT* __ob, _CharT*& __op, _CharT*& __oe, const locale& __loc) {
656 const ctype<_CharT>& __ct = std::use_facet<ctype<_CharT> >(__loc);
657 const numpunct<_CharT>& __npt = std::use_facet<numpunct<_CharT> >(__loc);
658 string __grouping = __npt.grouping();
659 if (__grouping.empty()) {
660 __ct.widen(__nb, __ne, __ob);
661 __oe = __ob + (__ne - __nb);
662 } else {
663 __oe = __ob;
664 char* __nf = __nb;
665 if (*__nf == '-' || *__nf == '+')
666 *__oe++ = __ct.widen(*__nf++);
667 if (__ne - __nf >= 2 && __nf[0] == '0' && (__nf[1] == 'x' || __nf[1] == 'X')) {
668 *__oe++ = __ct.widen(*__nf++);
669 *__oe++ = __ct.widen(*__nf++);
670 }
671 std::reverse(first: __nf, last: __ne);
672 _CharT __thousands_sep = __npt.thousands_sep();
673 unsigned __dc = 0;
674 unsigned __dg = 0;
675 for (char* __p = __nf; __p < __ne; ++__p) {
676 if (static_cast<unsigned>(__grouping[__dg]) > 0 && __dc == static_cast<unsigned>(__grouping[__dg])) {
677 *__oe++ = __thousands_sep;
678 __dc = 0;
679 if (__dg < __grouping.size() - 1)
680 ++__dg;
681 }
682 *__oe++ = __ct.widen(*__p);
683 ++__dc;
684 }
685 std::reverse(__ob + (__nf - __nb), __oe);
686 }
687 if (__np == __ne)
688 __op = __oe;
689 else
690 __op = __ob + (__np - __nb);
691}
692
693_LIBCPP_HIDE_FROM_ABI inline bool __isdigit(char __c) { return __c >= '0' && __c <= '9'; }
694
695_LIBCPP_HIDE_FROM_ABI inline bool __isxdigit(char __c) {
696 auto __lower = __c | 0x20;
697 return std::__isdigit(__c) || (__lower >= 'a' && __lower <= 'f');
698}
699
700template <class _CharT>
701void __num_put<_CharT>::__widen_and_group_float(
702 char* __nb, char* __np, char* __ne, _CharT* __ob, _CharT*& __op, _CharT*& __oe, const locale& __loc) {
703 const ctype<_CharT>& __ct = std::use_facet<ctype<_CharT> >(__loc);
704 const numpunct<_CharT>& __npt = std::use_facet<numpunct<_CharT> >(__loc);
705 string __grouping = __npt.grouping();
706 __oe = __ob;
707 char* __nf = __nb;
708 if (*__nf == '-' || *__nf == '+')
709 *__oe++ = __ct.widen(*__nf++);
710 char* __ns;
711 if (__ne - __nf >= 2 && __nf[0] == '0' && (__nf[1] == 'x' || __nf[1] == 'X')) {
712 *__oe++ = __ct.widen(*__nf++);
713 *__oe++ = __ct.widen(*__nf++);
714 for (__ns = __nf; __ns < __ne; ++__ns)
715 if (!std::__isxdigit(c: *__ns))
716 break;
717 } else {
718 for (__ns = __nf; __ns < __ne; ++__ns)
719 if (!std::__isdigit(c: *__ns))
720 break;
721 }
722 if (__grouping.empty()) {
723 __ct.widen(__nf, __ns, __oe);
724 __oe += __ns - __nf;
725 } else {
726 std::reverse(first: __nf, last: __ns);
727 _CharT __thousands_sep = __npt.thousands_sep();
728 unsigned __dc = 0;
729 unsigned __dg = 0;
730 for (char* __p = __nf; __p < __ns; ++__p) {
731 if (__grouping[__dg] > 0 && __dc == static_cast<unsigned>(__grouping[__dg])) {
732 *__oe++ = __thousands_sep;
733 __dc = 0;
734 if (__dg < __grouping.size() - 1)
735 ++__dg;
736 }
737 *__oe++ = __ct.widen(*__p);
738 ++__dc;
739 }
740 std::reverse(__ob + (__nf - __nb), __oe);
741 }
742 for (__nf = __ns; __nf < __ne; ++__nf) {
743 if (*__nf == '.') {
744 *__oe++ = __npt.decimal_point();
745 ++__nf;
746 break;
747 } else
748 *__oe++ = __ct.widen(*__nf);
749 }
750 __ct.widen(__nf, __ne, __oe);
751 __oe += __ne - __nf;
752 if (__np == __ne)
753 __op = __oe;
754 else
755 __op = __ob + (__np - __nb);
756}
757
758extern template struct _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __num_put<char>;
759# if _LIBCPP_HAS_WIDE_CHARACTERS
760extern template struct _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __num_put<wchar_t>;
761# endif
762
763template <class _CharT, class _OutputIterator = ostreambuf_iterator<_CharT> >
764class num_put : public locale::facet, private __num_put<_CharT> {
765public:
766 typedef _CharT char_type;
767 typedef _OutputIterator iter_type;
768
769 _LIBCPP_HIDE_FROM_ABI explicit num_put(size_t __refs = 0) : locale::facet(__refs) {}
770
771 _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, bool __v) const {
772 return do_put(__s, __iob, __fl, __v);
773 }
774
775 _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, long __v) const {
776 return do_put(__s, __iob, __fl, __v);
777 }
778
779 _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, long long __v) const {
780 return do_put(__s, __iob, __fl, __v);
781 }
782
783 _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long __v) const {
784 return do_put(__s, __iob, __fl, __v);
785 }
786
787 _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long long __v) const {
788 return do_put(__s, __iob, __fl, __v);
789 }
790
791 _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, double __v) const {
792 return do_put(__s, __iob, __fl, __v);
793 }
794
795 _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, long double __v) const {
796 return do_put(__s, __iob, __fl, __v);
797 }
798
799 _LIBCPP_HIDE_FROM_ABI iter_type put(iter_type __s, ios_base& __iob, char_type __fl, const void* __v) const {
800 return do_put(__s, __iob, __fl, __v);
801 }
802
803 static locale::id id;
804
805protected:
806 _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~num_put() override {}
807
808 virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, bool __v) const;
809 virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, long __v) const;
810 virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, long long __v) const;
811 virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long) const;
812 virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long long) const;
813 virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, double __v) const;
814 virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, long double __v) const;
815 virtual iter_type do_put(iter_type __s, ios_base& __iob, char_type __fl, const void* __v) const;
816
817 template <class _Integral>
818 _LIBCPP_HIDE_FROM_ABI inline _OutputIterator
819 __do_put_integral(iter_type __s, ios_base& __iob, char_type __fl, _Integral __v) const;
820
821 template <class _Float>
822 _LIBCPP_HIDE_FROM_ABI inline _OutputIterator
823 __do_put_floating_point(iter_type __s, ios_base& __iob, char_type __fl, _Float __v, char const* __len) const;
824};
825
826template <class _CharT, class _OutputIterator>
827locale::id num_put<_CharT, _OutputIterator>::id;
828
829template <class _CharT, class _OutputIterator>
830_OutputIterator
831num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, bool __v) const {
832 if ((__iob.flags() & ios_base::boolalpha) == 0)
833 return do_put(__s, __iob, __fl, (unsigned long)__v);
834 const numpunct<char_type>& __np = std::use_facet<numpunct<char_type> >(__iob.getloc());
835 typedef typename numpunct<char_type>::string_type string_type;
836 string_type __nm = __v ? __np.truename() : __np.falsename();
837 return std::copy(__nm.begin(), __nm.end(), __s);
838}
839
840template <class _CharT, class _OutputIterator>
841template <class _Integral>
842_LIBCPP_HIDE_FROM_ABI inline _OutputIterator num_put<_CharT, _OutputIterator>::__do_put_integral(
843 iter_type __s, ios_base& __iob, char_type __fl, _Integral __v) const {
844 // Stage 1 - Get number in narrow char
845
846 // Worst case is octal, with showbase enabled. Note that octal is always
847 // printed as an unsigned value.
848 using _Unsigned = typename make_unsigned<_Integral>::type;
849 _LIBCPP_CONSTEXPR const unsigned __buffer_size =
850 (numeric_limits<_Unsigned>::digits / 3) // 1 char per 3 bits
851 + ((numeric_limits<_Unsigned>::digits % 3) != 0) // round up
852 + 2; // base prefix + terminating null character
853
854 char __char_buffer[__buffer_size];
855 char* __buffer_ptr = __char_buffer;
856
857 auto __flags = __iob.flags();
858
859 auto __basefield = (__flags & ios_base::basefield);
860
861 // Extract base
862 int __base = 10;
863 if (__basefield == ios_base::oct)
864 __base = 8;
865 else if (__basefield == ios_base::hex)
866 __base = 16;
867
868 // Print '-' and make the argument unsigned
869 auto __uval = std::__to_unsigned_like(__v);
870 if (__basefield != ios_base::oct && __basefield != ios_base::hex && __v < 0) {
871 *__buffer_ptr++ = '-';
872 __uval = std::__complement(__uval);
873 }
874
875 // Maybe add '+' prefix
876 if (std::is_signed<_Integral>::value && (__flags & ios_base::showpos) && __basefield != ios_base::oct &&
877 __basefield != ios_base::hex && __v >= 0)
878 *__buffer_ptr++ = '+';
879
880 // Add base prefix
881 if (__v != 0 && __flags & ios_base::showbase) {
882 if (__basefield == ios_base::oct) {
883 *__buffer_ptr++ = '0';
884 } else if (__basefield == ios_base::hex) {
885 *__buffer_ptr++ = '0';
886 *__buffer_ptr++ = (__flags & ios_base::uppercase ? 'X' : 'x');
887 }
888 }
889
890 auto __res = std::__to_chars_integral(__buffer_ptr, __char_buffer + __buffer_size, __uval, __base);
891 _LIBCPP_ASSERT_INTERNAL(__res.__ec == std::errc(0), "to_chars: invalid maximum buffer size computed?");
892
893 // Make letters uppercase
894 if (__flags & ios_base::hex && __flags & ios_base::uppercase) {
895 for (; __buffer_ptr != __res.__ptr; ++__buffer_ptr)
896 *__buffer_ptr = std::__hex_to_upper(c: *__buffer_ptr);
897 }
898
899 char* __np = this->__identify_padding(__char_buffer, __res.__ptr, __iob);
900 // Stage 2 - Widen __nar while adding thousands separators
901 char_type __o[2 * (__buffer_size - 1) - 1];
902 char_type* __op; // pad here
903 char_type* __oe; // end of output
904 this->__widen_and_group_int(__char_buffer, __np, __res.__ptr, __o, __op, __oe, __iob.getloc());
905 // [__o, __oe) contains thousands_sep'd wide number
906 // Stage 3 & 4
907 return std::__pad_and_output(__s, __o, __op, __oe, __iob, __fl);
908}
909
910template <class _CharT, class _OutputIterator>
911_OutputIterator
912num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, long __v) const {
913 return this->__do_put_integral(__s, __iob, __fl, __v);
914}
915
916template <class _CharT, class _OutputIterator>
917_OutputIterator
918num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, long long __v) const {
919 return this->__do_put_integral(__s, __iob, __fl, __v);
920}
921
922template <class _CharT, class _OutputIterator>
923_OutputIterator
924num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long __v) const {
925 return this->__do_put_integral(__s, __iob, __fl, __v);
926}
927
928template <class _CharT, class _OutputIterator>
929_OutputIterator
930num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, unsigned long long __v) const {
931 return this->__do_put_integral(__s, __iob, __fl, __v);
932}
933
934template <class _CharT, class _OutputIterator>
935template <class _Float>
936_LIBCPP_HIDE_FROM_ABI inline _OutputIterator num_put<_CharT, _OutputIterator>::__do_put_floating_point(
937 iter_type __s, ios_base& __iob, char_type __fl, _Float __v, char const* __len) const {
938 // Stage 1 - Get number in narrow char
939 char __fmt[8] = {'%', 0};
940 bool __specify_precision = this->__format_float(__fmt + 1, __len, __iob.flags());
941 const unsigned __nbuf = 30;
942 char __nar[__nbuf];
943 char* __nb = __nar;
944 int __nc;
945 _LIBCPP_DIAGNOSTIC_PUSH
946 _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
947 _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
948 if (__specify_precision)
949 __nc = __locale::__snprintf(s: __nb, n: __nbuf, _LIBCPP_GET_C_LOCALE, format: __fmt, (int)__iob.precision(), __v);
950 else
951 __nc = __locale::__snprintf(s: __nb, n: __nbuf, _LIBCPP_GET_C_LOCALE, format: __fmt, __v);
952 unique_ptr<char, void (*)(void*)> __nbh(nullptr, free);
953 if (__nc > static_cast<int>(__nbuf - 1)) {
954 if (__specify_precision)
955 __nc = __locale::__asprintf(s: &__nb, _LIBCPP_GET_C_LOCALE, format: __fmt, (int)__iob.precision(), __v);
956 else
957 __nc = __locale::__asprintf(s: &__nb, _LIBCPP_GET_C_LOCALE, format: __fmt, __v);
958 if (__nc == -1)
959 std::__throw_bad_alloc();
960 __nbh.reset(p: __nb);
961 }
962 _LIBCPP_DIAGNOSTIC_POP
963 char* __ne = __nb + __nc;
964 char* __np = this->__identify_padding(__nb, __ne, __iob);
965 // Stage 2 - Widen __nar while adding thousands separators
966 char_type __o[2 * (__nbuf - 1) - 1];
967 char_type* __ob = __o;
968 unique_ptr<char_type, void (*)(void*)> __obh(0, free);
969 if (__nb != __nar) {
970 __ob = (char_type*)malloc(size: 2 * static_cast<size_t>(__nc) * sizeof(char_type));
971 if (__ob == 0)
972 std::__throw_bad_alloc();
973 __obh.reset(__ob);
974 }
975 char_type* __op; // pad here
976 char_type* __oe; // end of output
977 this->__widen_and_group_float(__nb, __np, __ne, __ob, __op, __oe, __iob.getloc());
978 // [__o, __oe) contains thousands_sep'd wide number
979 // Stage 3 & 4
980 __s = std::__pad_and_output(__s, __ob, __op, __oe, __iob, __fl);
981 return __s;
982}
983
984template <class _CharT, class _OutputIterator>
985_OutputIterator
986num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, double __v) const {
987 return this->__do_put_floating_point(__s, __iob, __fl, __v, "");
988}
989
990template <class _CharT, class _OutputIterator>
991_OutputIterator
992num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, long double __v) const {
993 return this->__do_put_floating_point(__s, __iob, __fl, __v, "L");
994}
995
996template <class _CharT, class _OutputIterator>
997_OutputIterator
998num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_type __fl, const void* __v) const {
999 auto __flags = __iob.flags();
1000 __iob.flags(fmtfl: (__flags & ~ios_base::basefield & ~ios_base::uppercase) | ios_base::hex | ios_base::showbase);
1001 auto __res = __do_put_integral(__s, __iob, __fl, reinterpret_cast<uintptr_t>(__v));
1002 __iob.flags(fmtfl: __flags);
1003 return __res;
1004}
1005
1006extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS num_put<char>;
1007# if _LIBCPP_HAS_WIDE_CHARACTERS
1008extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS num_put<wchar_t>;
1009# endif
1010
1011_LIBCPP_END_NAMESPACE_STD
1012
1013_LIBCPP_POP_MACROS
1014
1015// NOLINTEND(libcpp-robust-against-adl)
1016
1017#endif // _LIBCPP_HAS_LOCALIZATION
1018
1019#endif // _LIBCPP___LOCALE_DIR_NUM_H
1020