1349cc55cSDimitry Andric // -*- C++ -*- 2349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 3349cc55cSDimitry Andric // 4349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7349cc55cSDimitry Andric // 8349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 9349cc55cSDimitry Andric 10349cc55cSDimitry Andric #ifndef _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H 11349cc55cSDimitry Andric #define _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H 12349cc55cSDimitry Andric 1306c3fb27SDimitry Andric #include <__charconv/to_chars_integral.h> 1406c3fb27SDimitry Andric #include <__charconv/to_chars_result.h> 1506c3fb27SDimitry Andric #include <__charconv/traits.h> 1681ad6265SDimitry Andric #include <__concepts/arithmetic.h> 1781ad6265SDimitry Andric #include <__concepts/same_as.h> 18349cc55cSDimitry Andric #include <__config> 19bdd1243dSDimitry Andric #include <__format/concepts.h> 20349cc55cSDimitry Andric #include <__format/format_error.h> 2181ad6265SDimitry Andric #include <__format/formatter_output.h> 22349cc55cSDimitry Andric #include <__format/parser_std_format_spec.h> 23cb14a3feSDimitry Andric #include <__iterator/concepts.h> 24cb14a3feSDimitry Andric #include <__iterator/iterator_traits.h> 25cb14a3feSDimitry Andric #include <__memory/pointer_traits.h> 2606c3fb27SDimitry Andric #include <__system_error/errc.h> 2706c3fb27SDimitry Andric #include <__type_traits/make_unsigned.h> 2881ad6265SDimitry Andric #include <__utility/unreachable.h> 29bdd1243dSDimitry Andric #include <array> 30349cc55cSDimitry Andric #include <limits> 31349cc55cSDimitry Andric #include <string> 3206c3fb27SDimitry Andric #include <string_view> 33349cc55cSDimitry Andric 34349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_LOCALIZATION 35*0fca6ea1SDimitry Andric # include <__locale> 36349cc55cSDimitry Andric #endif 37349cc55cSDimitry Andric 38349cc55cSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 39349cc55cSDimitry Andric # pragma GCC system_header 40349cc55cSDimitry Andric #endif 41349cc55cSDimitry Andric 42349cc55cSDimitry Andric _LIBCPP_PUSH_MACROS 43349cc55cSDimitry Andric #include <__undef_macros> 44349cc55cSDimitry Andric 45349cc55cSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 46349cc55cSDimitry Andric 4706c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20 48349cc55cSDimitry Andric 4981ad6265SDimitry Andric namespace __formatter { 50349cc55cSDimitry Andric 5181ad6265SDimitry Andric // 5281ad6265SDimitry Andric // Generic 5381ad6265SDimitry Andric // 54349cc55cSDimitry Andric 55cb14a3feSDimitry Andric template <contiguous_iterator _Iterator> 56cb14a3feSDimitry Andric requires same_as<char, iter_value_t<_Iterator>> 57cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI inline _Iterator __insert_sign(_Iterator __buf, bool __negative, __format_spec::__sign __sign) { 5881ad6265SDimitry Andric if (__negative) 5981ad6265SDimitry Andric *__buf++ = '-'; 6081ad6265SDimitry Andric else 6181ad6265SDimitry Andric switch (__sign) { 6281ad6265SDimitry Andric case __format_spec::__sign::__default: 6381ad6265SDimitry Andric case __format_spec::__sign::__minus: 6481ad6265SDimitry Andric // No sign added. 6581ad6265SDimitry Andric break; 6681ad6265SDimitry Andric case __format_spec::__sign::__plus: 6781ad6265SDimitry Andric *__buf++ = '+'; 6881ad6265SDimitry Andric break; 6981ad6265SDimitry Andric case __format_spec::__sign::__space: 7081ad6265SDimitry Andric *__buf++ = ' '; 7181ad6265SDimitry Andric break; 72349cc55cSDimitry Andric } 73349cc55cSDimitry Andric 7481ad6265SDimitry Andric return __buf; 75349cc55cSDimitry Andric } 76349cc55cSDimitry Andric 77349cc55cSDimitry Andric /** 78349cc55cSDimitry Andric * Determines the required grouping based on the size of the input. 79349cc55cSDimitry Andric * 80349cc55cSDimitry Andric * The grouping's last element will be repeated. For simplicity this repeating 81349cc55cSDimitry Andric * is unwrapped based on the length of the input. (When the input is short some 82349cc55cSDimitry Andric * groups are not processed.) 83349cc55cSDimitry Andric * 84349cc55cSDimitry Andric * @returns The size of the groups to write. This means the number of 85349cc55cSDimitry Andric * separator characters written is size() - 1. 86349cc55cSDimitry Andric * 87349cc55cSDimitry Andric * @note Since zero-sized groups cause issues they are silently ignored. 88349cc55cSDimitry Andric * 89349cc55cSDimitry Andric * @note The grouping field of the locale is always a @c std::string, 90349cc55cSDimitry Andric * regardless whether the @c std::numpunct's type is @c char or @c wchar_t. 91349cc55cSDimitry Andric */ 9281ad6265SDimitry Andric _LIBCPP_HIDE_FROM_ABI inline string __determine_grouping(ptrdiff_t __size, const string& __grouping) { 931db9f3b2SDimitry Andric _LIBCPP_ASSERT_INTERNAL(!__grouping.empty() && __size > __grouping[0], 941db9f3b2SDimitry Andric "The slow grouping formatting is used while there will be no separators written"); 95349cc55cSDimitry Andric string __r; 96349cc55cSDimitry Andric auto __end = __grouping.end() - 1; 97349cc55cSDimitry Andric auto __ptr = __grouping.begin(); 98349cc55cSDimitry Andric 99349cc55cSDimitry Andric while (true) { 100349cc55cSDimitry Andric __size -= *__ptr; 101349cc55cSDimitry Andric if (__size > 0) 102349cc55cSDimitry Andric __r.push_back(*__ptr); 103349cc55cSDimitry Andric else { 104349cc55cSDimitry Andric // __size <= 0 so the value pushed will be <= *__ptr. 105349cc55cSDimitry Andric __r.push_back(*__ptr + __size); 106349cc55cSDimitry Andric return __r; 107349cc55cSDimitry Andric } 108349cc55cSDimitry Andric 109349cc55cSDimitry Andric // Proceed to the next group. 110349cc55cSDimitry Andric if (__ptr != __end) { 111349cc55cSDimitry Andric do { 112349cc55cSDimitry Andric ++__ptr; 113349cc55cSDimitry Andric // Skip grouping with a width of 0. 114349cc55cSDimitry Andric } while (*__ptr == 0 && __ptr != __end); 115349cc55cSDimitry Andric } 116349cc55cSDimitry Andric } 117349cc55cSDimitry Andric 11881ad6265SDimitry Andric __libcpp_unreachable(); 119349cc55cSDimitry Andric } 120349cc55cSDimitry Andric 12181ad6265SDimitry Andric // 12281ad6265SDimitry Andric // Char 12381ad6265SDimitry Andric // 124349cc55cSDimitry Andric 125bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 126cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto 127cb14a3feSDimitry Andric __format_char(integral auto __value, 12881ad6265SDimitry Andric output_iterator<const _CharT&> auto __out_it, 12981ad6265SDimitry Andric __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { 130349cc55cSDimitry Andric using _Tp = decltype(__value); 131349cc55cSDimitry Andric if constexpr (!same_as<_CharT, _Tp>) { 132349cc55cSDimitry Andric // cmp_less and cmp_greater can't be used for character types. 133349cc55cSDimitry Andric if constexpr (signed_integral<_CharT> == signed_integral<_Tp>) { 13481ad6265SDimitry Andric if (__value < numeric_limits<_CharT>::min() || __value > numeric_limits<_CharT>::max()) 13581ad6265SDimitry Andric std::__throw_format_error("Integral value outside the range of the char type"); 136349cc55cSDimitry Andric } else if constexpr (signed_integral<_CharT>) { 137349cc55cSDimitry Andric // _CharT is signed _Tp is unsigned 13881ad6265SDimitry Andric if (__value > static_cast<make_unsigned_t<_CharT>>(numeric_limits<_CharT>::max())) 13981ad6265SDimitry Andric std::__throw_format_error("Integral value outside the range of the char type"); 140349cc55cSDimitry Andric } else { 141349cc55cSDimitry Andric // _CharT is unsigned _Tp is signed 14281ad6265SDimitry Andric if (__value < 0 || static_cast<make_unsigned_t<_Tp>>(__value) > numeric_limits<_CharT>::max()) 14381ad6265SDimitry Andric std::__throw_format_error("Integral value outside the range of the char type"); 144349cc55cSDimitry Andric } 145349cc55cSDimitry Andric } 146349cc55cSDimitry Andric 147349cc55cSDimitry Andric const auto __c = static_cast<_CharT>(__value); 1485f757f3fSDimitry Andric return __formatter::__write(std::addressof(__c), std::addressof(__c) + 1, std::move(__out_it), __specs); 14981ad6265SDimitry Andric } 15081ad6265SDimitry Andric 15181ad6265SDimitry Andric // 15281ad6265SDimitry Andric // Integer 15381ad6265SDimitry Andric // 15481ad6265SDimitry Andric 155cb14a3feSDimitry Andric /** Wrapper around @ref to_chars, returning the output iterator. */ 156cb14a3feSDimitry Andric template <contiguous_iterator _Iterator, integral _Tp> 157cb14a3feSDimitry Andric requires same_as<char, iter_value_t<_Iterator>> 158cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _Iterator __to_buffer(_Iterator __first, _Iterator __last, _Tp __value, int __base) { 15981ad6265SDimitry Andric // TODO FMT Evaluate code overhead due to not calling the internal function 16081ad6265SDimitry Andric // directly. (Should be zero overhead.) 161cb14a3feSDimitry Andric to_chars_result __r = std::to_chars(std::to_address(__first), std::to_address(__last), __value, __base); 1621db9f3b2SDimitry Andric _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); 163cb14a3feSDimitry Andric auto __diff = __r.ptr - std::to_address(__first); 164cb14a3feSDimitry Andric return __first + __diff; 165349cc55cSDimitry Andric } 166349cc55cSDimitry Andric 167349cc55cSDimitry Andric /** 16881ad6265SDimitry Andric * Helper to determine the buffer size to output a integer in Base @em x. 169349cc55cSDimitry Andric * 17081ad6265SDimitry Andric * There are several overloads for the supported bases. The function uses the 17181ad6265SDimitry Andric * base as template argument so it can be used in a constant expression. 172349cc55cSDimitry Andric */ 17381ad6265SDimitry Andric template <unsigned_integral _Tp, size_t _Base> 17481ad6265SDimitry Andric consteval size_t __buffer_size() noexcept 17581ad6265SDimitry Andric requires(_Base == 2) 17681ad6265SDimitry Andric { 17781ad6265SDimitry Andric return numeric_limits<_Tp>::digits // The number of binary digits. 17881ad6265SDimitry Andric + 2 // Reserve space for the '0[Bb]' prefix. 17981ad6265SDimitry Andric + 1; // Reserve space for the sign. 180349cc55cSDimitry Andric } 181349cc55cSDimitry Andric 18281ad6265SDimitry Andric template <unsigned_integral _Tp, size_t _Base> 18381ad6265SDimitry Andric consteval size_t __buffer_size() noexcept 18481ad6265SDimitry Andric requires(_Base == 8) 18581ad6265SDimitry Andric { 18681ad6265SDimitry Andric return numeric_limits<_Tp>::digits // The number of binary digits. 18781ad6265SDimitry Andric / 3 // Adjust to octal. 18881ad6265SDimitry Andric + 1 // Turn floor to ceil. 18981ad6265SDimitry Andric + 1 // Reserve space for the '0' prefix. 19081ad6265SDimitry Andric + 1; // Reserve space for the sign. 191349cc55cSDimitry Andric } 192349cc55cSDimitry Andric 19381ad6265SDimitry Andric template <unsigned_integral _Tp, size_t _Base> 19481ad6265SDimitry Andric consteval size_t __buffer_size() noexcept 19581ad6265SDimitry Andric requires(_Base == 10) 19681ad6265SDimitry Andric { 19781ad6265SDimitry Andric return numeric_limits<_Tp>::digits10 // The floored value. 19881ad6265SDimitry Andric + 1 // Turn floor to ceil. 19981ad6265SDimitry Andric + 1; // Reserve space for the sign. 200349cc55cSDimitry Andric } 201349cc55cSDimitry Andric 20281ad6265SDimitry Andric template <unsigned_integral _Tp, size_t _Base> 20381ad6265SDimitry Andric consteval size_t __buffer_size() noexcept 20481ad6265SDimitry Andric requires(_Base == 16) 20581ad6265SDimitry Andric { 20681ad6265SDimitry Andric return numeric_limits<_Tp>::digits // The number of binary digits. 20781ad6265SDimitry Andric / 4 // Adjust to hexadecimal. 20881ad6265SDimitry Andric + 2 // Reserve space for the '0[Xx]' prefix. 20981ad6265SDimitry Andric + 1; // Reserve space for the sign. 21081ad6265SDimitry Andric } 21181ad6265SDimitry Andric 212cb14a3feSDimitry Andric template <class _OutIt, contiguous_iterator _Iterator, class _CharT> 213cb14a3feSDimitry Andric requires same_as<char, iter_value_t<_Iterator>> 214cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators( 215cb14a3feSDimitry Andric _OutIt __out_it, 216cb14a3feSDimitry Andric _Iterator __begin, 217cb14a3feSDimitry Andric _Iterator __first, 218cb14a3feSDimitry Andric _Iterator __last, 219cb14a3feSDimitry Andric string&& __grouping, 220cb14a3feSDimitry Andric _CharT __sep, 22106c3fb27SDimitry Andric __format_spec::__parsed_specifications<_CharT> __specs) { 22206c3fb27SDimitry Andric int __size = (__first - __begin) + // [sign][prefix] 22306c3fb27SDimitry Andric (__last - __first) + // data 22406c3fb27SDimitry Andric (__grouping.size() - 1); // number of separator characters 22506c3fb27SDimitry Andric 22606c3fb27SDimitry Andric __padding_size_result __padding = {0, 0}; 22706c3fb27SDimitry Andric if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) { 22806c3fb27SDimitry Andric // Write [sign][prefix]. 2295f757f3fSDimitry Andric __out_it = __formatter::__copy(__begin, __first, std::move(__out_it)); 23006c3fb27SDimitry Andric 23106c3fb27SDimitry Andric if (__specs.__width_ > __size) { 23206c3fb27SDimitry Andric // Write zero padding. 23306c3fb27SDimitry Andric __padding.__before_ = __specs.__width_ - __size; 2345f757f3fSDimitry Andric __out_it = __formatter::__fill(std::move(__out_it), __specs.__width_ - __size, _CharT('0')); 23506c3fb27SDimitry Andric } 23606c3fb27SDimitry Andric } else { 23706c3fb27SDimitry Andric if (__specs.__width_ > __size) { 23806c3fb27SDimitry Andric // Determine padding and write padding. 23906c3fb27SDimitry Andric __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_); 24006c3fb27SDimitry Andric 2415f757f3fSDimitry Andric __out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_); 24206c3fb27SDimitry Andric } 24306c3fb27SDimitry Andric // Write [sign][prefix]. 2445f757f3fSDimitry Andric __out_it = __formatter::__copy(__begin, __first, std::move(__out_it)); 24506c3fb27SDimitry Andric } 24606c3fb27SDimitry Andric 24706c3fb27SDimitry Andric auto __r = __grouping.rbegin(); 24806c3fb27SDimitry Andric auto __e = __grouping.rend() - 1; 2491db9f3b2SDimitry Andric _LIBCPP_ASSERT_INTERNAL( 2501db9f3b2SDimitry Andric __r != __e, "The slow grouping formatting is used while there will be no separators written."); 25106c3fb27SDimitry Andric // The output is divided in small groups of numbers to write: 25206c3fb27SDimitry Andric // - A group before the first separator. 25306c3fb27SDimitry Andric // - A separator and a group, repeated for the number of separators. 25406c3fb27SDimitry Andric // - A group after the last separator. 25506c3fb27SDimitry Andric // This loop achieves that process by testing the termination condition 25606c3fb27SDimitry Andric // midway in the loop. 25706c3fb27SDimitry Andric // 25806c3fb27SDimitry Andric // TODO FMT This loop evaluates the loop invariant `__parser.__type != 25906c3fb27SDimitry Andric // _Flags::_Type::__hexadecimal_upper_case` for every iteration. (This test 26006c3fb27SDimitry Andric // happens in the __write call.) Benchmark whether making two loops and 26106c3fb27SDimitry Andric // hoisting the invariant is worth the effort. 26206c3fb27SDimitry Andric while (true) { 26306c3fb27SDimitry Andric if (__specs.__std_.__type_ == __format_spec::__type::__hexadecimal_upper_case) { 26406c3fb27SDimitry Andric __last = __first + *__r; 2655f757f3fSDimitry Andric __out_it = __formatter::__transform(__first, __last, std::move(__out_it), __hex_to_upper); 26606c3fb27SDimitry Andric __first = __last; 26706c3fb27SDimitry Andric } else { 2685f757f3fSDimitry Andric __out_it = __formatter::__copy(__first, *__r, std::move(__out_it)); 26906c3fb27SDimitry Andric __first += *__r; 27006c3fb27SDimitry Andric } 27106c3fb27SDimitry Andric 27206c3fb27SDimitry Andric if (__r == __e) 27306c3fb27SDimitry Andric break; 27406c3fb27SDimitry Andric 27506c3fb27SDimitry Andric ++__r; 27606c3fb27SDimitry Andric *__out_it++ = __sep; 27706c3fb27SDimitry Andric } 27806c3fb27SDimitry Andric 2795f757f3fSDimitry Andric return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_); 28006c3fb27SDimitry Andric } 28106c3fb27SDimitry Andric 282cb14a3feSDimitry Andric template <unsigned_integral _Tp, contiguous_iterator _Iterator, class _CharT, class _FormatContext> 283cb14a3feSDimitry Andric requires same_as<char, iter_value_t<_Iterator>> 28406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_integer( 28581ad6265SDimitry Andric _Tp __value, 28606c3fb27SDimitry Andric _FormatContext& __ctx, 28781ad6265SDimitry Andric __format_spec::__parsed_specifications<_CharT> __specs, 28881ad6265SDimitry Andric bool __negative, 289cb14a3feSDimitry Andric _Iterator __begin, 290cb14a3feSDimitry Andric _Iterator __end, 29181ad6265SDimitry Andric const char* __prefix, 29206c3fb27SDimitry Andric int __base) { 293cb14a3feSDimitry Andric _Iterator __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_); 29481ad6265SDimitry Andric if (__specs.__std_.__alternate_form_ && __prefix) 295349cc55cSDimitry Andric while (*__prefix) 296349cc55cSDimitry Andric *__first++ = *__prefix++; 297349cc55cSDimitry Andric 298cb14a3feSDimitry Andric _Iterator __last = __formatter::__to_buffer(__first, __end, __value, __base); 29981ad6265SDimitry Andric 300349cc55cSDimitry Andric # ifndef _LIBCPP_HAS_NO_LOCALIZATION 30181ad6265SDimitry Andric if (__specs.__std_.__locale_specific_form_) { 302bdd1243dSDimitry Andric const auto& __np = std::use_facet<numpunct<_CharT>>(__ctx.locale()); 303349cc55cSDimitry Andric string __grouping = __np.grouping(); 304349cc55cSDimitry Andric ptrdiff_t __size = __last - __first; 305349cc55cSDimitry Andric // Writing the grouped form has more overhead than the normal output 306349cc55cSDimitry Andric // routines. If there will be no separators written the locale-specific 307349cc55cSDimitry Andric // form is identical to the normal routine. Test whether to grouped form 308349cc55cSDimitry Andric // is required. 309349cc55cSDimitry Andric if (!__grouping.empty() && __size > __grouping[0]) 31081ad6265SDimitry Andric return __formatter::__write_using_decimal_separators( 31181ad6265SDimitry Andric __ctx.out(), 31281ad6265SDimitry Andric __begin, 31381ad6265SDimitry Andric __first, 31481ad6265SDimitry Andric __last, 31581ad6265SDimitry Andric __formatter::__determine_grouping(__size, __grouping), 31681ad6265SDimitry Andric __np.thousands_sep(), 31781ad6265SDimitry Andric __specs); 318349cc55cSDimitry Andric } 319349cc55cSDimitry Andric # endif 320349cc55cSDimitry Andric auto __out_it = __ctx.out(); 32181ad6265SDimitry Andric if (__specs.__alignment_ != __format_spec::__alignment::__zero_padding) 322349cc55cSDimitry Andric __first = __begin; 323349cc55cSDimitry Andric else { 324349cc55cSDimitry Andric // __buf contains [sign][prefix]data 325349cc55cSDimitry Andric // ^ location of __first 326349cc55cSDimitry Andric // The zero padding is done like: 327349cc55cSDimitry Andric // - Write [sign][prefix] 328349cc55cSDimitry Andric // - Write data right aligned with '0' as fill character. 3295f757f3fSDimitry Andric __out_it = __formatter::__copy(__begin, __first, std::move(__out_it)); 33081ad6265SDimitry Andric __specs.__alignment_ = __format_spec::__alignment::__right; 33106c3fb27SDimitry Andric __specs.__fill_.__data[0] = _CharT('0'); 33281ad6265SDimitry Andric int32_t __size = __first - __begin; 33381ad6265SDimitry Andric 3345f757f3fSDimitry Andric __specs.__width_ -= std::min(__size, __specs.__width_); 335349cc55cSDimitry Andric } 336349cc55cSDimitry Andric 33781ad6265SDimitry Andric if (__specs.__std_.__type_ != __format_spec::__type::__hexadecimal_upper_case) [[likely]] 33881ad6265SDimitry Andric return __formatter::__write(__first, __last, __ctx.out(), __specs); 33981ad6265SDimitry Andric 34081ad6265SDimitry Andric return __formatter::__write_transformed(__first, __last, __ctx.out(), __specs, __formatter::__hex_to_upper); 341349cc55cSDimitry Andric } 342349cc55cSDimitry Andric 34306c3fb27SDimitry Andric template <unsigned_integral _Tp, class _CharT, class _FormatContext> 34406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator 34506c3fb27SDimitry Andric __format_integer(_Tp __value, 34606c3fb27SDimitry Andric _FormatContext& __ctx, 34706c3fb27SDimitry Andric __format_spec::__parsed_specifications<_CharT> __specs, 34806c3fb27SDimitry Andric bool __negative = false) { 34981ad6265SDimitry Andric switch (__specs.__std_.__type_) { 35081ad6265SDimitry Andric case __format_spec::__type::__binary_lower_case: { 35181ad6265SDimitry Andric array<char, __formatter::__buffer_size<decltype(__value), 2>()> __array; 35281ad6265SDimitry Andric return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0b", 2); 353349cc55cSDimitry Andric } 35481ad6265SDimitry Andric case __format_spec::__type::__binary_upper_case: { 35581ad6265SDimitry Andric array<char, __formatter::__buffer_size<decltype(__value), 2>()> __array; 35681ad6265SDimitry Andric return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0B", 2); 357349cc55cSDimitry Andric } 35881ad6265SDimitry Andric case __format_spec::__type::__octal: { 35981ad6265SDimitry Andric // Octal is special; if __value == 0 there's no prefix. 36081ad6265SDimitry Andric array<char, __formatter::__buffer_size<decltype(__value), 8>()> __array; 36181ad6265SDimitry Andric return __formatter::__format_integer( 36281ad6265SDimitry Andric __value, __ctx, __specs, __negative, __array.begin(), __array.end(), __value != 0 ? "0" : nullptr, 8); 36381ad6265SDimitry Andric } 364753f127fSDimitry Andric case __format_spec::__type::__default: 36581ad6265SDimitry Andric case __format_spec::__type::__decimal: { 36681ad6265SDimitry Andric array<char, __formatter::__buffer_size<decltype(__value), 10>()> __array; 36781ad6265SDimitry Andric return __formatter::__format_integer( 36881ad6265SDimitry Andric __value, __ctx, __specs, __negative, __array.begin(), __array.end(), nullptr, 10); 36981ad6265SDimitry Andric } 37081ad6265SDimitry Andric case __format_spec::__type::__hexadecimal_lower_case: { 37181ad6265SDimitry Andric array<char, __formatter::__buffer_size<decltype(__value), 16>()> __array; 37281ad6265SDimitry Andric return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0x", 16); 37381ad6265SDimitry Andric } 37481ad6265SDimitry Andric case __format_spec::__type::__hexadecimal_upper_case: { 37581ad6265SDimitry Andric array<char, __formatter::__buffer_size<decltype(__value), 16>()> __array; 37681ad6265SDimitry Andric return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0X", 16); 37781ad6265SDimitry Andric } 37881ad6265SDimitry Andric default: 3791db9f3b2SDimitry Andric _LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type"); 38081ad6265SDimitry Andric __libcpp_unreachable(); 38181ad6265SDimitry Andric } 382349cc55cSDimitry Andric } 383349cc55cSDimitry Andric 38406c3fb27SDimitry Andric template <signed_integral _Tp, class _CharT, class _FormatContext> 38506c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator 38606c3fb27SDimitry Andric __format_integer(_Tp __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { 38781ad6265SDimitry Andric // Depending on the std-format-spec string the sign and the value 38881ad6265SDimitry Andric // might not be outputted together: 38981ad6265SDimitry Andric // - alternate form may insert a prefix string. 39081ad6265SDimitry Andric // - zero-padding may insert additional '0' characters. 39181ad6265SDimitry Andric // Therefore the value is processed as a positive unsigned value. 39281ad6265SDimitry Andric // The function @ref __insert_sign will a '-' when the value was negative. 39381ad6265SDimitry Andric auto __r = std::__to_unsigned_like(__value); 39481ad6265SDimitry Andric bool __negative = __value < 0; 39581ad6265SDimitry Andric if (__negative) 396bdd1243dSDimitry Andric __r = std::__complement(__r); 39781ad6265SDimitry Andric 39881ad6265SDimitry Andric return __formatter::__format_integer(__r, __ctx, __specs, __negative); 39981ad6265SDimitry Andric } 40081ad6265SDimitry Andric 401349cc55cSDimitry Andric // 40281ad6265SDimitry Andric // Formatter arithmetic (bool) 40381ad6265SDimitry Andric // 404349cc55cSDimitry Andric 40581ad6265SDimitry Andric template <class _CharT> 40681ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __bool_strings; 407349cc55cSDimitry Andric 40881ad6265SDimitry Andric template <> 40981ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __bool_strings<char> { 41081ad6265SDimitry Andric static constexpr string_view __true{"true"}; 41181ad6265SDimitry Andric static constexpr string_view __false{"false"}; 412349cc55cSDimitry Andric }; 413349cc55cSDimitry Andric 41481ad6265SDimitry Andric # ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 41581ad6265SDimitry Andric template <> 41681ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __bool_strings<wchar_t> { 41781ad6265SDimitry Andric static constexpr wstring_view __true{L"true"}; 41881ad6265SDimitry Andric static constexpr wstring_view __false{L"false"}; 41981ad6265SDimitry Andric }; 42081ad6265SDimitry Andric # endif 421349cc55cSDimitry Andric 42206c3fb27SDimitry Andric template <class _CharT, class _FormatContext> 42306c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator 42406c3fb27SDimitry Andric __format_bool(bool __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { 42581ad6265SDimitry Andric # ifndef _LIBCPP_HAS_NO_LOCALIZATION 42681ad6265SDimitry Andric if (__specs.__std_.__locale_specific_form_) { 427bdd1243dSDimitry Andric const auto& __np = std::use_facet<numpunct<_CharT>>(__ctx.locale()); 42881ad6265SDimitry Andric basic_string<_CharT> __str = __value ? __np.truename() : __np.falsename(); 429fcaf7f86SDimitry Andric return __formatter::__write_string_no_precision(basic_string_view<_CharT>{__str}, __ctx.out(), __specs); 43081ad6265SDimitry Andric } 43181ad6265SDimitry Andric # endif 43281ad6265SDimitry Andric basic_string_view<_CharT> __str = 43381ad6265SDimitry Andric __value ? __formatter::__bool_strings<_CharT>::__true : __formatter::__bool_strings<_CharT>::__false; 43481ad6265SDimitry Andric return __formatter::__write(__str.begin(), __str.end(), __ctx.out(), __specs); 43581ad6265SDimitry Andric } 43681ad6265SDimitry Andric 43781ad6265SDimitry Andric } // namespace __formatter 438349cc55cSDimitry Andric 43906c3fb27SDimitry Andric #endif //_LIBCPP_STD_VER >= 20 440349cc55cSDimitry Andric 441349cc55cSDimitry Andric _LIBCPP_END_NAMESPACE_STD 442349cc55cSDimitry Andric 443349cc55cSDimitry Andric _LIBCPP_POP_MACROS 444349cc55cSDimitry Andric 445349cc55cSDimitry Andric #endif // _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H 446