458 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			458 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
// -*- C++ -*-
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#ifndef _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H
 | 
						|
#define _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H
 | 
						|
 | 
						|
#include <__algorithm/copy.h>
 | 
						|
#include <__algorithm/copy_n.h>
 | 
						|
#include <__algorithm/fill_n.h>
 | 
						|
#include <__algorithm/transform.h>
 | 
						|
#include <__assert>
 | 
						|
#include <__config>
 | 
						|
#include <__format/format_error.h>
 | 
						|
#include <__format/format_fwd.h>
 | 
						|
#include <__format/formatter.h>
 | 
						|
#include <__format/parser_std_format_spec.h>
 | 
						|
#include <__utility/unreachable.h>
 | 
						|
#include <array>
 | 
						|
#include <charconv>
 | 
						|
#include <concepts>
 | 
						|
#include <limits>
 | 
						|
#include <string>
 | 
						|
 | 
						|
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
 | 
						|
#include <locale>
 | 
						|
#endif
 | 
						|
 | 
						|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 | 
						|
#  pragma GCC system_header
 | 
						|
#endif
 | 
						|
 | 
						|
_LIBCPP_PUSH_MACROS
 | 
						|
#include <__undef_macros>
 | 
						|
 | 
						|
_LIBCPP_BEGIN_NAMESPACE_STD
 | 
						|
 | 
						|
#if _LIBCPP_STD_VER > 17
 | 
						|
 | 
						|
/**
 | 
						|
 * Integral formatting classes.
 | 
						|
 *
 | 
						|
 * There are two types used here:
 | 
						|
 * * C++-type, the type as used in C++.
 | 
						|
 * * format-type, the output type specified in the std-format-spec.
 | 
						|
 *
 | 
						|
 * Design of the integral formatters consists of several layers.
 | 
						|
 * * @ref __parser_integral The basic std-format-spec parser for all integral
 | 
						|
 *   classes. This parser does the basic sanity checks. It also contains some
 | 
						|
 *   helper functions that are nice to have available for all parsers.
 | 
						|
 * * A C++-type specific parser. These parsers must derive from
 | 
						|
 *   @ref __parser_integral. Their task is to validate whether the parsed
 | 
						|
 *   std-format-spec is valid for the C++-type and selected format-type. After
 | 
						|
 *   validation they need to make sure all members are properly set. For
 | 
						|
 *   example, when the alignment hasn't changed it needs to set the proper
 | 
						|
 *   default alignment for the format-type. The following parsers are available:
 | 
						|
 *   - @ref __parser_integer
 | 
						|
 *   - @ref __parser_char
 | 
						|
 *   - @ref __parser_bool
 | 
						|
 * * A general formatter for all integral types @ref __formatter_integral. This
 | 
						|
 *   formatter can handle all formatting of integers and characters. The class
 | 
						|
 *   derives from the proper formatter.
 | 
						|
 *   Note the boolean string format-type isn't supported in this class.
 | 
						|
 * * A typedef C++-type group combining the @ref __formatter_integral with a
 | 
						|
 *   parser:
 | 
						|
 *   * @ref __formatter_integer
 | 
						|
 *   * @ref __formatter_char
 | 
						|
 *   * @ref __formatter_bool
 | 
						|
 * * Then every C++-type has its own formatter specializations. They inherit
 | 
						|
 *   from the C++-type group typedef. Most specializations need nothing else.
 | 
						|
 *   Others need some additional specializations in this class.
 | 
						|
 */
 | 
						|
namespace __format_spec {
 | 
						|
 | 
						|
/** Wrapper around @ref to_chars, returning the output pointer. */
 | 
						|
template <integral _Tp>
 | 
						|
_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last,
 | 
						|
                                        _Tp __value, int __base) {
 | 
						|
  // TODO FMT Evaluate code overhead due to not calling the internal function
 | 
						|
  // directly. (Should be zero overhead.)
 | 
						|
  to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __base);
 | 
						|
  _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
 | 
						|
  return __r.ptr;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Helper to determine the buffer size to output a integer in Base @em x.
 | 
						|
 *
 | 
						|
 * There are several overloads for the supported bases. The function uses the
 | 
						|
 * base as template argument so it can be used in a constant expression.
 | 
						|
 */
 | 
						|
template <unsigned_integral _Tp, size_t _Base>
 | 
						|
_LIBCPP_HIDE_FROM_ABI constexpr size_t __buffer_size() noexcept
 | 
						|
    requires(_Base == 2) {
 | 
						|
  return numeric_limits<_Tp>::digits // The number of binary digits.
 | 
						|
         + 2                         // Reserve space for the '0[Bb]' prefix.
 | 
						|
         + 1;                        // Reserve space for the sign.
 | 
						|
}
 | 
						|
 | 
						|
template <unsigned_integral _Tp, size_t _Base>
 | 
						|
_LIBCPP_HIDE_FROM_ABI constexpr size_t __buffer_size() noexcept
 | 
						|
    requires(_Base == 8) {
 | 
						|
  return numeric_limits<_Tp>::digits // The number of binary digits.
 | 
						|
             / 3                     // Adjust to octal.
 | 
						|
         + 1                         // Turn floor to ceil.
 | 
						|
         + 1                         // Reserve space for the '0' prefix.
 | 
						|
         + 1;                        // Reserve space for the sign.
 | 
						|
}
 | 
						|
 | 
						|
template <unsigned_integral _Tp, size_t _Base>
 | 
						|
_LIBCPP_HIDE_FROM_ABI constexpr size_t __buffer_size() noexcept
 | 
						|
    requires(_Base == 10) {
 | 
						|
  return numeric_limits<_Tp>::digits10 // The floored value.
 | 
						|
         + 1                           // Turn floor to ceil.
 | 
						|
         + 1;                          // Reserve space for the sign.
 | 
						|
}
 | 
						|
 | 
						|
template <unsigned_integral _Tp, size_t _Base>
 | 
						|
_LIBCPP_HIDE_FROM_ABI constexpr size_t __buffer_size() noexcept
 | 
						|
    requires(_Base == 16) {
 | 
						|
  return numeric_limits<_Tp>::digits // The number of binary digits.
 | 
						|
             / 4                     // Adjust to hexadecimal.
 | 
						|
         + 2                         // Reserve space for the '0[Xx]' prefix.
 | 
						|
         + 1;                        // Reserve space for the sign.
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Determines the required grouping based on the size of the input.
 | 
						|
 *
 | 
						|
 * The grouping's last element will be repeated. For simplicity this repeating
 | 
						|
 * is unwrapped based on the length of the input. (When the input is short some
 | 
						|
 * groups are not processed.)
 | 
						|
 *
 | 
						|
 * @returns The size of the groups to write. This means the number of
 | 
						|
 * separator characters written is size() - 1.
 | 
						|
 *
 | 
						|
 * @note Since zero-sized groups cause issues they are silently ignored.
 | 
						|
 *
 | 
						|
 * @note The grouping field of the locale is always a @c std::string,
 | 
						|
 * regardless whether the @c std::numpunct's type is @c char or @c wchar_t.
 | 
						|
 */
 | 
						|
_LIBCPP_HIDE_FROM_ABI inline string
 | 
						|
__determine_grouping(ptrdiff_t __size, const string& __grouping) {
 | 
						|
  _LIBCPP_ASSERT(!__grouping.empty() && __size > __grouping[0],
 | 
						|
                 "The slow grouping formatting is used while there will be no "
 | 
						|
                 "separators written");
 | 
						|
  string __r;
 | 
						|
  auto __end = __grouping.end() - 1;
 | 
						|
  auto __ptr = __grouping.begin();
 | 
						|
 | 
						|
  while (true) {
 | 
						|
    __size -= *__ptr;
 | 
						|
    if (__size > 0)
 | 
						|
      __r.push_back(*__ptr);
 | 
						|
    else {
 | 
						|
      // __size <= 0 so the value pushed will be <= *__ptr.
 | 
						|
      __r.push_back(*__ptr + __size);
 | 
						|
      return __r;
 | 
						|
    }
 | 
						|
 | 
						|
    // Proceed to the next group.
 | 
						|
    if (__ptr != __end) {
 | 
						|
      do {
 | 
						|
        ++__ptr;
 | 
						|
        // Skip grouping with a width of 0.
 | 
						|
      } while (*__ptr == 0 && __ptr != __end);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  __libcpp_unreachable();
 | 
						|
}
 | 
						|
 | 
						|
template <class _Parser>
 | 
						|
requires __formatter::__char_type<typename _Parser::char_type>
 | 
						|
class _LIBCPP_TEMPLATE_VIS __formatter_integral : public _Parser {
 | 
						|
public:
 | 
						|
  using _CharT = typename _Parser::char_type;
 | 
						|
 | 
						|
  template <integral _Tp>
 | 
						|
  _LIBCPP_HIDE_FROM_ABI auto format(_Tp __value, auto& __ctx)
 | 
						|
      -> decltype(__ctx.out()) {
 | 
						|
    if (this->__width_needs_substitution())
 | 
						|
      this->__substitute_width_arg_id(__ctx.arg(this->__width));
 | 
						|
 | 
						|
    if (this->__type == _Flags::_Type::__char)
 | 
						|
      return __format_as_char(__value, __ctx);
 | 
						|
 | 
						|
    if constexpr (unsigned_integral<_Tp>)
 | 
						|
      return __format_unsigned_integral(__value, false, __ctx);
 | 
						|
    else {
 | 
						|
      // Depending on the std-format-spec string the sign and the value
 | 
						|
      // might not be outputted together:
 | 
						|
      // - alternate form may insert a prefix string.
 | 
						|
      // - zero-padding may insert additional '0' characters.
 | 
						|
      // Therefore the value is processed as a positive unsigned value.
 | 
						|
      // The function @ref __insert_sign will a '-' when the value was negative.
 | 
						|
      auto __r = __to_unsigned_like(__value);
 | 
						|
      bool __negative = __value < 0;
 | 
						|
      if (__negative)
 | 
						|
        __r = __complement(__r);
 | 
						|
 | 
						|
      return __format_unsigned_integral(__r, __negative, __ctx);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
private:
 | 
						|
  /** Generic formatting for format-type c. */
 | 
						|
  _LIBCPP_HIDE_FROM_ABI auto __format_as_char(integral auto __value,
 | 
						|
                                              auto& __ctx)
 | 
						|
      -> decltype(__ctx.out()) {
 | 
						|
    if (this->__alignment == _Flags::_Alignment::__default)
 | 
						|
      this->__alignment = _Flags::_Alignment::__right;
 | 
						|
 | 
						|
    using _Tp = decltype(__value);
 | 
						|
    if constexpr (!same_as<_CharT, _Tp>) {
 | 
						|
      // cmp_less and cmp_greater can't be used for character types.
 | 
						|
      if constexpr (signed_integral<_CharT> == signed_integral<_Tp>) {
 | 
						|
        if (__value < numeric_limits<_CharT>::min() ||
 | 
						|
            __value > numeric_limits<_CharT>::max())
 | 
						|
          __throw_format_error(
 | 
						|
              "Integral value outside the range of the char type");
 | 
						|
      } else if constexpr (signed_integral<_CharT>) {
 | 
						|
        // _CharT is signed _Tp is unsigned
 | 
						|
        if (__value >
 | 
						|
            static_cast<make_unsigned_t<_CharT>>(numeric_limits<_CharT>::max()))
 | 
						|
          __throw_format_error(
 | 
						|
              "Integral value outside the range of the char type");
 | 
						|
      } else {
 | 
						|
        // _CharT is unsigned _Tp is signed
 | 
						|
        if (__value < 0 || static_cast<make_unsigned_t<_Tp>>(__value) >
 | 
						|
                               numeric_limits<_CharT>::max())
 | 
						|
          __throw_format_error(
 | 
						|
              "Integral value outside the range of the char type");
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    const auto __c = static_cast<_CharT>(__value);
 | 
						|
    return __write(_VSTD::addressof(__c), _VSTD::addressof(__c) + 1,
 | 
						|
                   __ctx.out());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Generic formatting for format-type bBdoxX.
 | 
						|
   *
 | 
						|
   * This small wrapper allocates a buffer with the required size. Then calls
 | 
						|
   * the real formatter with the buffer and the prefix for the base.
 | 
						|
   */
 | 
						|
  _LIBCPP_HIDE_FROM_ABI auto
 | 
						|
  __format_unsigned_integral(unsigned_integral auto __value, bool __negative,
 | 
						|
                             auto& __ctx) -> decltype(__ctx.out()) {
 | 
						|
    switch (this->__type) {
 | 
						|
    case _Flags::_Type::__binary_lower_case: {
 | 
						|
      array<char, __buffer_size<decltype(__value), 2>()> __array;
 | 
						|
      return __format_unsigned_integral(__array.begin(), __array.end(), __value,
 | 
						|
                                        __negative, 2, __ctx, "0b");
 | 
						|
    }
 | 
						|
    case _Flags::_Type::__binary_upper_case: {
 | 
						|
      array<char, __buffer_size<decltype(__value), 2>()> __array;
 | 
						|
      return __format_unsigned_integral(__array.begin(), __array.end(), __value,
 | 
						|
                                        __negative, 2, __ctx, "0B");
 | 
						|
    }
 | 
						|
    case _Flags::_Type::__octal: {
 | 
						|
      // Octal is special; if __value == 0 there's no prefix.
 | 
						|
      array<char, __buffer_size<decltype(__value), 8>()> __array;
 | 
						|
      return __format_unsigned_integral(__array.begin(), __array.end(), __value,
 | 
						|
                                        __negative, 8, __ctx,
 | 
						|
                                        __value != 0 ? "0" : nullptr);
 | 
						|
    }
 | 
						|
    case _Flags::_Type::__decimal: {
 | 
						|
      array<char, __buffer_size<decltype(__value), 10>()> __array;
 | 
						|
      return __format_unsigned_integral(__array.begin(), __array.end(), __value,
 | 
						|
                                        __negative, 10, __ctx, nullptr);
 | 
						|
    }
 | 
						|
    case _Flags::_Type::__hexadecimal_lower_case: {
 | 
						|
      array<char, __buffer_size<decltype(__value), 16>()> __array;
 | 
						|
      return __format_unsigned_integral(__array.begin(), __array.end(), __value,
 | 
						|
                                        __negative, 16, __ctx, "0x");
 | 
						|
    }
 | 
						|
    case _Flags::_Type::__hexadecimal_upper_case: {
 | 
						|
      array<char, __buffer_size<decltype(__value), 16>()> __array;
 | 
						|
      return __format_unsigned_integral(__array.begin(), __array.end(), __value,
 | 
						|
                                        __negative, 16, __ctx, "0X");
 | 
						|
    }
 | 
						|
    default:
 | 
						|
      _LIBCPP_ASSERT(false, "The parser should have validated the type");
 | 
						|
      __libcpp_unreachable();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  template <class _Tp>
 | 
						|
  requires(same_as<char, _Tp> || same_as<wchar_t, _Tp>) _LIBCPP_HIDE_FROM_ABI
 | 
						|
      auto __write(const _Tp* __first, const _Tp* __last, auto __out_it)
 | 
						|
          -> decltype(__out_it) {
 | 
						|
 | 
						|
    unsigned __size = __last - __first;
 | 
						|
    if (this->__type != _Flags::_Type::__hexadecimal_upper_case) [[likely]] {
 | 
						|
      if (__size >= this->__width)
 | 
						|
        return _VSTD::copy(__first, __last, _VSTD::move(__out_it));
 | 
						|
 | 
						|
      return __formatter::__write(_VSTD::move(__out_it), __first, __last,
 | 
						|
                                  __size, this->__width, this->__fill,
 | 
						|
                                  this->__alignment);
 | 
						|
    }
 | 
						|
 | 
						|
    // this->__type == _Flags::_Type::__hexadecimal_upper_case
 | 
						|
    // This means all characters in the range [a-f] need to be changed to their
 | 
						|
    // uppercase representation. The transformation is done as transformation
 | 
						|
    // in the output routine instead of before. This avoids another pass over
 | 
						|
    // the data.
 | 
						|
    // TODO FMT See whether it's possible to do this transformation during the
 | 
						|
    // conversion. (This probably requires changing std::to_chars' alphabet.)
 | 
						|
    if (__size >= this->__width)
 | 
						|
      return _VSTD::transform(__first, __last, _VSTD::move(__out_it),
 | 
						|
                              __hex_to_upper);
 | 
						|
 | 
						|
    return __formatter::__write(_VSTD::move(__out_it), __first, __last, __size,
 | 
						|
                                __hex_to_upper, this->__width, this->__fill,
 | 
						|
                                this->__alignment);
 | 
						|
  }
 | 
						|
 | 
						|
  _LIBCPP_HIDE_FROM_ABI auto
 | 
						|
  __format_unsigned_integral(char* __begin, char* __end,
 | 
						|
                             unsigned_integral auto __value, bool __negative,
 | 
						|
                             int __base, auto& __ctx, const char* __prefix)
 | 
						|
      -> decltype(__ctx.out()) {
 | 
						|
    char* __first = __insert_sign(__begin, __negative, this->__sign);
 | 
						|
    if (this->__alternate_form && __prefix)
 | 
						|
      while (*__prefix)
 | 
						|
        *__first++ = *__prefix++;
 | 
						|
 | 
						|
    char* __last = __to_buffer(__first, __end, __value, __base);
 | 
						|
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
 | 
						|
    if (this->__locale_specific_form) {
 | 
						|
      const auto& __np = use_facet<numpunct<_CharT>>(__ctx.locale());
 | 
						|
      string __grouping = __np.grouping();
 | 
						|
      ptrdiff_t __size = __last - __first;
 | 
						|
      // Writing the grouped form has more overhead than the normal output
 | 
						|
      // routines. If there will be no separators written the locale-specific
 | 
						|
      // form is identical to the normal routine. Test whether to grouped form
 | 
						|
      // is required.
 | 
						|
      if (!__grouping.empty() && __size > __grouping[0])
 | 
						|
        return __format_grouping(__ctx.out(), __begin, __first, __last,
 | 
						|
                                 __determine_grouping(__size, __grouping),
 | 
						|
                                 __np.thousands_sep());
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    auto __out_it = __ctx.out();
 | 
						|
    if (this->__alignment != _Flags::_Alignment::__default)
 | 
						|
      __first = __begin;
 | 
						|
    else {
 | 
						|
      // __buf contains [sign][prefix]data
 | 
						|
      //                              ^ location of __first
 | 
						|
      // The zero padding is done like:
 | 
						|
      // - Write [sign][prefix]
 | 
						|
      // - Write data right aligned with '0' as fill character.
 | 
						|
      __out_it = _VSTD::copy(__begin, __first, _VSTD::move(__out_it));
 | 
						|
      this->__alignment = _Flags::_Alignment::__right;
 | 
						|
      this->__fill = _CharT('0');
 | 
						|
      uint32_t __size = __first - __begin;
 | 
						|
      this->__width -= _VSTD::min(__size, this->__width);
 | 
						|
    }
 | 
						|
 | 
						|
    return __write(__first, __last, _VSTD::move(__out_it));
 | 
						|
  }
 | 
						|
 | 
						|
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
 | 
						|
  /** Format's the locale-specific form's groupings. */
 | 
						|
  template <class _OutIt, class _CharT>
 | 
						|
  _LIBCPP_HIDE_FROM_ABI _OutIt
 | 
						|
  __format_grouping(_OutIt __out_it, const char* __begin, const char* __first,
 | 
						|
                    const char* __last, string&& __grouping, _CharT __sep) {
 | 
						|
 | 
						|
    // TODO FMT This function duplicates some functionality of the normal
 | 
						|
    // output routines. Evaluate whether these parts can be efficiently
 | 
						|
    // combined with the existing routines.
 | 
						|
 | 
						|
    unsigned __size = (__first - __begin) +    // [sign][prefix]
 | 
						|
                      (__last - __first) +     // data
 | 
						|
                      (__grouping.size() - 1); // number of separator characters
 | 
						|
 | 
						|
    __formatter::__padding_size_result __padding = {0, 0};
 | 
						|
    if (this->__alignment == _Flags::_Alignment::__default) {
 | 
						|
      // Write [sign][prefix].
 | 
						|
      __out_it = _VSTD::copy(__begin, __first, _VSTD::move(__out_it));
 | 
						|
 | 
						|
      if (this->__width > __size) {
 | 
						|
        // Write zero padding.
 | 
						|
        __padding.__before = this->__width - __size;
 | 
						|
        __out_it = _VSTD::fill_n(_VSTD::move(__out_it), this->__width - __size,
 | 
						|
                                 _CharT('0'));
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      if (this->__width > __size) {
 | 
						|
        // Determine padding and write padding.
 | 
						|
        __padding = __formatter::__padding_size(__size, this->__width,
 | 
						|
                                                this->__alignment);
 | 
						|
 | 
						|
        __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before,
 | 
						|
                                 this->__fill);
 | 
						|
      }
 | 
						|
      // Write [sign][prefix].
 | 
						|
      __out_it = _VSTD::copy(__begin, __first, _VSTD::move(__out_it));
 | 
						|
    }
 | 
						|
 | 
						|
    auto __r = __grouping.rbegin();
 | 
						|
    auto __e = __grouping.rend() - 1;
 | 
						|
    _LIBCPP_ASSERT(__r != __e, "The slow grouping formatting is used while "
 | 
						|
                               "there will be no separators written.");
 | 
						|
    // The output is divided in small groups of numbers to write:
 | 
						|
    // - A group before the first separator.
 | 
						|
    // - A separator and a group, repeated for the number of separators.
 | 
						|
    // - A group after the last separator.
 | 
						|
    // This loop achieves that process by testing the termination condition
 | 
						|
    // midway in the loop.
 | 
						|
    //
 | 
						|
    // TODO FMT This loop evaluates the loop invariant `this->__type !=
 | 
						|
    // _Flags::_Type::__hexadecimal_upper_case` for every iteration. (This test
 | 
						|
    // happens in the __write call.) Benchmark whether making two loops and
 | 
						|
    // hoisting the invariant is worth the effort.
 | 
						|
    while (true) {
 | 
						|
      if (this->__type == _Flags::_Type::__hexadecimal_upper_case) {
 | 
						|
        __last = __first + *__r;
 | 
						|
        __out_it = _VSTD::transform(__first, __last, _VSTD::move(__out_it),
 | 
						|
                                    __hex_to_upper);
 | 
						|
        __first = __last;
 | 
						|
      } else {
 | 
						|
        __out_it = _VSTD::copy_n(__first, *__r, _VSTD::move(__out_it));
 | 
						|
        __first += *__r;
 | 
						|
      }
 | 
						|
 | 
						|
      if (__r == __e)
 | 
						|
        break;
 | 
						|
 | 
						|
      ++__r;
 | 
						|
      *__out_it++ = __sep;
 | 
						|
    }
 | 
						|
 | 
						|
    return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after,
 | 
						|
                         this->__fill);
 | 
						|
  }
 | 
						|
#endif // _LIBCPP_HAS_NO_LOCALIZATION
 | 
						|
};
 | 
						|
 | 
						|
} // namespace __format_spec
 | 
						|
 | 
						|
#endif //_LIBCPP_STD_VER > 17
 | 
						|
 | 
						|
_LIBCPP_END_NAMESPACE_STD
 | 
						|
 | 
						|
_LIBCPP_POP_MACROS
 | 
						|
 | 
						|
#endif // _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H
 |