Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-03 08:13:29

0001 // -*- C++ -*-
0002 //===----------------------------------------------------------------------===//
0003 //
0004 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0005 // See https://llvm.org/LICENSE.txt for license information.
0006 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0007 //
0008 //===----------------------------------------------------------------------===//
0009 
0010 #ifndef _LIBCPP___CXX03___FORMAT_FORMATTER_INTEGRAL_H
0011 #define _LIBCPP___CXX03___FORMAT_FORMATTER_INTEGRAL_H
0012 
0013 #include <__cxx03/__charconv/to_chars_integral.h>
0014 #include <__cxx03/__charconv/to_chars_result.h>
0015 #include <__cxx03/__charconv/traits.h>
0016 #include <__cxx03/__concepts/arithmetic.h>
0017 #include <__cxx03/__concepts/same_as.h>
0018 #include <__cxx03/__config>
0019 #include <__cxx03/__format/concepts.h>
0020 #include <__cxx03/__format/format_error.h>
0021 #include <__cxx03/__format/formatter_output.h>
0022 #include <__cxx03/__format/parser_std_format_spec.h>
0023 #include <__cxx03/__iterator/concepts.h>
0024 #include <__cxx03/__iterator/iterator_traits.h>
0025 #include <__cxx03/__memory/pointer_traits.h>
0026 #include <__cxx03/__system_error/errc.h>
0027 #include <__cxx03/__type_traits/make_unsigned.h>
0028 #include <__cxx03/__utility/unreachable.h>
0029 #include <__cxx03/array>
0030 #include <__cxx03/limits>
0031 #include <__cxx03/string>
0032 #include <__cxx03/string_view>
0033 
0034 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
0035 #  include <__cxx03/__locale>
0036 #endif
0037 
0038 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0039 #  pragma GCC system_header
0040 #endif
0041 
0042 _LIBCPP_PUSH_MACROS
0043 #include <__cxx03/__undef_macros>
0044 
0045 _LIBCPP_BEGIN_NAMESPACE_STD
0046 
0047 #if _LIBCPP_STD_VER >= 20
0048 
0049 namespace __formatter {
0050 
0051 //
0052 // Generic
0053 //
0054 
0055 template <contiguous_iterator _Iterator>
0056   requires same_as<char, iter_value_t<_Iterator>>
0057 _LIBCPP_HIDE_FROM_ABI inline _Iterator __insert_sign(_Iterator __buf, bool __negative, __format_spec::__sign __sign) {
0058   if (__negative)
0059     *__buf++ = '-';
0060   else
0061     switch (__sign) {
0062     case __format_spec::__sign::__default:
0063     case __format_spec::__sign::__minus:
0064       // No sign added.
0065       break;
0066     case __format_spec::__sign::__plus:
0067       *__buf++ = '+';
0068       break;
0069     case __format_spec::__sign::__space:
0070       *__buf++ = ' ';
0071       break;
0072     }
0073 
0074   return __buf;
0075 }
0076 
0077 /**
0078  * Determines the required grouping based on the size of the input.
0079  *
0080  * The grouping's last element will be repeated. For simplicity this repeating
0081  * is unwrapped based on the length of the input. (When the input is short some
0082  * groups are not processed.)
0083  *
0084  * @returns The size of the groups to write. This means the number of
0085  * separator characters written is size() - 1.
0086  *
0087  * @note Since zero-sized groups cause issues they are silently ignored.
0088  *
0089  * @note The grouping field of the locale is always a @c std::string,
0090  * regardless whether the @c std::numpunct's type is @c char or @c wchar_t.
0091  */
0092 _LIBCPP_HIDE_FROM_ABI inline string __determine_grouping(ptrdiff_t __size, const string& __grouping) {
0093   _LIBCPP_ASSERT_INTERNAL(!__grouping.empty() && __size > __grouping[0],
0094                           "The slow grouping formatting is used while there will be no separators written");
0095   string __r;
0096   auto __end = __grouping.end() - 1;
0097   auto __ptr = __grouping.begin();
0098 
0099   while (true) {
0100     __size -= *__ptr;
0101     if (__size > 0)
0102       __r.push_back(*__ptr);
0103     else {
0104       // __size <= 0 so the value pushed will be <= *__ptr.
0105       __r.push_back(*__ptr + __size);
0106       return __r;
0107     }
0108 
0109     // Proceed to the next group.
0110     if (__ptr != __end) {
0111       do {
0112         ++__ptr;
0113         // Skip grouping with a width of 0.
0114       } while (*__ptr == 0 && __ptr != __end);
0115     }
0116   }
0117 
0118   __libcpp_unreachable();
0119 }
0120 
0121 //
0122 // Char
0123 //
0124 
0125 template <__fmt_char_type _CharT>
0126 _LIBCPP_HIDE_FROM_ABI auto
0127 __format_char(integral auto __value,
0128               output_iterator<const _CharT&> auto __out_it,
0129               __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
0130   using _Tp = decltype(__value);
0131   if constexpr (!same_as<_CharT, _Tp>) {
0132     // cmp_less and cmp_greater can't be used for character types.
0133     if constexpr (signed_integral<_CharT> == signed_integral<_Tp>) {
0134       if (__value < numeric_limits<_CharT>::min() || __value > numeric_limits<_CharT>::max())
0135         std::__throw_format_error("Integral value outside the range of the char type");
0136     } else if constexpr (signed_integral<_CharT>) {
0137       // _CharT is signed _Tp is unsigned
0138       if (__value > static_cast<make_unsigned_t<_CharT>>(numeric_limits<_CharT>::max()))
0139         std::__throw_format_error("Integral value outside the range of the char type");
0140     } else {
0141       // _CharT is unsigned _Tp is signed
0142       if (__value < 0 || static_cast<make_unsigned_t<_Tp>>(__value) > numeric_limits<_CharT>::max())
0143         std::__throw_format_error("Integral value outside the range of the char type");
0144     }
0145   }
0146 
0147   const auto __c = static_cast<_CharT>(__value);
0148   return __formatter::__write(std::addressof(__c), std::addressof(__c) + 1, std::move(__out_it), __specs);
0149 }
0150 
0151 //
0152 // Integer
0153 //
0154 
0155 /** Wrapper around @ref to_chars, returning the output iterator. */
0156 template <contiguous_iterator _Iterator, integral _Tp>
0157   requires same_as<char, iter_value_t<_Iterator>>
0158 _LIBCPP_HIDE_FROM_ABI _Iterator __to_buffer(_Iterator __first, _Iterator __last, _Tp __value, int __base) {
0159   // TODO FMT Evaluate code overhead due to not calling the internal function
0160   // directly. (Should be zero overhead.)
0161   to_chars_result __r = std::to_chars(std::to_address(__first), std::to_address(__last), __value, __base);
0162   _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
0163   auto __diff = __r.ptr - std::to_address(__first);
0164   return __first + __diff;
0165 }
0166 
0167 /**
0168  * Helper to determine the buffer size to output a integer in Base @em x.
0169  *
0170  * There are several overloads for the supported bases. The function uses the
0171  * base as template argument so it can be used in a constant expression.
0172  */
0173 template <unsigned_integral _Tp, size_t _Base>
0174 consteval size_t __buffer_size() noexcept
0175   requires(_Base == 2)
0176 {
0177   return numeric_limits<_Tp>::digits // The number of binary digits.
0178        + 2                           // Reserve space for the '0[Bb]' prefix.
0179        + 1;                          // Reserve space for the sign.
0180 }
0181 
0182 template <unsigned_integral _Tp, size_t _Base>
0183 consteval size_t __buffer_size() noexcept
0184   requires(_Base == 8)
0185 {
0186   return numeric_limits<_Tp>::digits // The number of binary digits.
0187            / 3                       // Adjust to octal.
0188        + 1                           // Turn floor to ceil.
0189        + 1                           // Reserve space for the '0' prefix.
0190        + 1;                          // Reserve space for the sign.
0191 }
0192 
0193 template <unsigned_integral _Tp, size_t _Base>
0194 consteval size_t __buffer_size() noexcept
0195   requires(_Base == 10)
0196 {
0197   return numeric_limits<_Tp>::digits10 // The floored value.
0198        + 1                             // Turn floor to ceil.
0199        + 1;                            // Reserve space for the sign.
0200 }
0201 
0202 template <unsigned_integral _Tp, size_t _Base>
0203 consteval size_t __buffer_size() noexcept
0204   requires(_Base == 16)
0205 {
0206   return numeric_limits<_Tp>::digits // The number of binary digits.
0207            / 4                       // Adjust to hexadecimal.
0208        + 2                           // Reserve space for the '0[Xx]' prefix.
0209        + 1;                          // Reserve space for the sign.
0210 }
0211 
0212 template <class _OutIt, contiguous_iterator _Iterator, class _CharT>
0213   requires same_as<char, iter_value_t<_Iterator>>
0214 _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(
0215     _OutIt __out_it,
0216     _Iterator __begin,
0217     _Iterator __first,
0218     _Iterator __last,
0219     string&& __grouping,
0220     _CharT __sep,
0221     __format_spec::__parsed_specifications<_CharT> __specs) {
0222   int __size = (__first - __begin) +    // [sign][prefix]
0223                (__last - __first) +     // data
0224                (__grouping.size() - 1); // number of separator characters
0225 
0226   __padding_size_result __padding = {0, 0};
0227   if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) {
0228     // Write [sign][prefix].
0229     __out_it = __formatter::__copy(__begin, __first, std::move(__out_it));
0230 
0231     if (__specs.__width_ > __size) {
0232       // Write zero padding.
0233       __padding.__before_ = __specs.__width_ - __size;
0234       __out_it            = __formatter::__fill(std::move(__out_it), __specs.__width_ - __size, _CharT('0'));
0235     }
0236   } else {
0237     if (__specs.__width_ > __size) {
0238       // Determine padding and write padding.
0239       __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_);
0240 
0241       __out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_);
0242     }
0243     // Write [sign][prefix].
0244     __out_it = __formatter::__copy(__begin, __first, std::move(__out_it));
0245   }
0246 
0247   auto __r = __grouping.rbegin();
0248   auto __e = __grouping.rend() - 1;
0249   _LIBCPP_ASSERT_INTERNAL(
0250       __r != __e, "The slow grouping formatting is used while there will be no separators written.");
0251   // The output is divided in small groups of numbers to write:
0252   // - A group before the first separator.
0253   // - A separator and a group, repeated for the number of separators.
0254   // - A group after the last separator.
0255   // This loop achieves that process by testing the termination condition
0256   // midway in the loop.
0257   //
0258   // TODO FMT This loop evaluates the loop invariant `__parser.__type !=
0259   // _Flags::_Type::__hexadecimal_upper_case` for every iteration. (This test
0260   // happens in the __write call.) Benchmark whether making two loops and
0261   // hoisting the invariant is worth the effort.
0262   while (true) {
0263     if (__specs.__std_.__type_ == __format_spec::__type::__hexadecimal_upper_case) {
0264       __last   = __first + *__r;
0265       __out_it = __formatter::__transform(__first, __last, std::move(__out_it), __hex_to_upper);
0266       __first  = __last;
0267     } else {
0268       __out_it = __formatter::__copy(__first, *__r, std::move(__out_it));
0269       __first += *__r;
0270     }
0271 
0272     if (__r == __e)
0273       break;
0274 
0275     ++__r;
0276     *__out_it++ = __sep;
0277   }
0278 
0279   return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_);
0280 }
0281 
0282 template <unsigned_integral _Tp, contiguous_iterator _Iterator, class _CharT, class _FormatContext>
0283   requires same_as<char, iter_value_t<_Iterator>>
0284 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_integer(
0285     _Tp __value,
0286     _FormatContext& __ctx,
0287     __format_spec::__parsed_specifications<_CharT> __specs,
0288     bool __negative,
0289     _Iterator __begin,
0290     _Iterator __end,
0291     const char* __prefix,
0292     int __base) {
0293   _Iterator __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_);
0294   if (__specs.__std_.__alternate_form_ && __prefix)
0295     while (*__prefix)
0296       *__first++ = *__prefix++;
0297 
0298   _Iterator __last = __formatter::__to_buffer(__first, __end, __value, __base);
0299 
0300 #  ifndef _LIBCPP_HAS_NO_LOCALIZATION
0301   if (__specs.__std_.__locale_specific_form_) {
0302     const auto& __np  = std::use_facet<numpunct<_CharT>>(__ctx.locale());
0303     string __grouping = __np.grouping();
0304     ptrdiff_t __size  = __last - __first;
0305     // Writing the grouped form has more overhead than the normal output
0306     // routines. If there will be no separators written the locale-specific
0307     // form is identical to the normal routine. Test whether to grouped form
0308     // is required.
0309     if (!__grouping.empty() && __size > __grouping[0])
0310       return __formatter::__write_using_decimal_separators(
0311           __ctx.out(),
0312           __begin,
0313           __first,
0314           __last,
0315           __formatter::__determine_grouping(__size, __grouping),
0316           __np.thousands_sep(),
0317           __specs);
0318   }
0319 #  endif
0320   auto __out_it = __ctx.out();
0321   if (__specs.__alignment_ != __format_spec::__alignment::__zero_padding)
0322     __first = __begin;
0323   else {
0324     // __buf contains [sign][prefix]data
0325     //                              ^ location of __first
0326     // The zero padding is done like:
0327     // - Write [sign][prefix]
0328     // - Write data right aligned with '0' as fill character.
0329     __out_it                  = __formatter::__copy(__begin, __first, std::move(__out_it));
0330     __specs.__alignment_      = __format_spec::__alignment::__right;
0331     __specs.__fill_.__data[0] = _CharT('0');
0332     int32_t __size            = __first - __begin;
0333 
0334     __specs.__width_ -= std::min(__size, __specs.__width_);
0335   }
0336 
0337   if (__specs.__std_.__type_ != __format_spec::__type::__hexadecimal_upper_case) [[likely]]
0338     return __formatter::__write(__first, __last, __ctx.out(), __specs);
0339 
0340   return __formatter::__write_transformed(__first, __last, __ctx.out(), __specs, __formatter::__hex_to_upper);
0341 }
0342 
0343 template <unsigned_integral _Tp, class _CharT, class _FormatContext>
0344 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
0345 __format_integer(_Tp __value,
0346                  _FormatContext& __ctx,
0347                  __format_spec::__parsed_specifications<_CharT> __specs,
0348                  bool __negative = false) {
0349   switch (__specs.__std_.__type_) {
0350   case __format_spec::__type::__binary_lower_case: {
0351     array<char, __formatter::__buffer_size<decltype(__value), 2>()> __array;
0352     return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0b", 2);
0353   }
0354   case __format_spec::__type::__binary_upper_case: {
0355     array<char, __formatter::__buffer_size<decltype(__value), 2>()> __array;
0356     return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0B", 2);
0357   }
0358   case __format_spec::__type::__octal: {
0359     // Octal is special; if __value == 0 there's no prefix.
0360     array<char, __formatter::__buffer_size<decltype(__value), 8>()> __array;
0361     return __formatter::__format_integer(
0362         __value, __ctx, __specs, __negative, __array.begin(), __array.end(), __value != 0 ? "0" : nullptr, 8);
0363   }
0364   case __format_spec::__type::__default:
0365   case __format_spec::__type::__decimal: {
0366     array<char, __formatter::__buffer_size<decltype(__value), 10>()> __array;
0367     return __formatter::__format_integer(
0368         __value, __ctx, __specs, __negative, __array.begin(), __array.end(), nullptr, 10);
0369   }
0370   case __format_spec::__type::__hexadecimal_lower_case: {
0371     array<char, __formatter::__buffer_size<decltype(__value), 16>()> __array;
0372     return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0x", 16);
0373   }
0374   case __format_spec::__type::__hexadecimal_upper_case: {
0375     array<char, __formatter::__buffer_size<decltype(__value), 16>()> __array;
0376     return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0X", 16);
0377   }
0378   default:
0379     _LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type");
0380     __libcpp_unreachable();
0381   }
0382 }
0383 
0384 template <signed_integral _Tp, class _CharT, class _FormatContext>
0385 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
0386 __format_integer(_Tp __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) {
0387   // Depending on the std-format-spec string the sign and the value
0388   // might not be outputted together:
0389   // - alternate form may insert a prefix string.
0390   // - zero-padding may insert additional '0' characters.
0391   // Therefore the value is processed as a positive unsigned value.
0392   // The function @ref __insert_sign will a '-' when the value was negative.
0393   auto __r        = std::__to_unsigned_like(__value);
0394   bool __negative = __value < 0;
0395   if (__negative)
0396     __r = std::__complement(__r);
0397 
0398   return __formatter::__format_integer(__r, __ctx, __specs, __negative);
0399 }
0400 
0401 //
0402 // Formatter arithmetic (bool)
0403 //
0404 
0405 template <class _CharT>
0406 struct _LIBCPP_TEMPLATE_VIS __bool_strings;
0407 
0408 template <>
0409 struct _LIBCPP_TEMPLATE_VIS __bool_strings<char> {
0410   static constexpr string_view __true{"true"};
0411   static constexpr string_view __false{"false"};
0412 };
0413 
0414 #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
0415 template <>
0416 struct _LIBCPP_TEMPLATE_VIS __bool_strings<wchar_t> {
0417   static constexpr wstring_view __true{L"true"};
0418   static constexpr wstring_view __false{L"false"};
0419 };
0420 #  endif
0421 
0422 template <class _CharT, class _FormatContext>
0423 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
0424 __format_bool(bool __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) {
0425 #  ifndef _LIBCPP_HAS_NO_LOCALIZATION
0426   if (__specs.__std_.__locale_specific_form_) {
0427     const auto& __np           = std::use_facet<numpunct<_CharT>>(__ctx.locale());
0428     basic_string<_CharT> __str = __value ? __np.truename() : __np.falsename();
0429     return __formatter::__write_string_no_precision(basic_string_view<_CharT>{__str}, __ctx.out(), __specs);
0430   }
0431 #  endif
0432   basic_string_view<_CharT> __str =
0433       __value ? __formatter::__bool_strings<_CharT>::__true : __formatter::__bool_strings<_CharT>::__false;
0434   return __formatter::__write(__str.begin(), __str.end(), __ctx.out(), __specs);
0435 }
0436 
0437 } // namespace __formatter
0438 
0439 #endif //_LIBCPP_STD_VER >= 20
0440 
0441 _LIBCPP_END_NAMESPACE_STD
0442 
0443 _LIBCPP_POP_MACROS
0444 
0445 #endif // _LIBCPP___CXX03___FORMAT_FORMATTER_INTEGRAL_H