diff options
author | Andrey Khalyavin <halyavin@gmail.com> | 2022-04-30 01:06:30 +0300 |
---|---|---|
committer | Andrey Khalyavin <halyavin@gmail.com> | 2022-04-30 01:06:30 +0300 |
commit | 53508f15464dfda8cefda38389d55e18d55958cc (patch) | |
tree | e2a3fee5d27a1ca195d63924be57e69d933f4cdd | |
parent | 84d0f48167dad0467bd26e32b0d876f0b49d62d8 (diff) | |
download | ydb-53508f15464dfda8cefda38389d55e18d55958cc.tar.gz |
Update libc++ to 4684857a (25 Jan 2022).
Notable changes:
* enable constexpr in std::common_iterator
* add std::basic_format_arg::handle
* disable formatter constructors in default template to make errors compile-time rather than runtime-time
* implement pointer formatter
* implement floating pointer formatter
ref:05aacf96e1ad5fc10a5fdd0238b020bbfda51953
14 files changed, 1206 insertions, 266 deletions
diff --git a/build/ymake.core.conf b/build/ymake.core.conf index 43c2104dc3f..984b1d74f06 100644 --- a/build/ymake.core.conf +++ b/build/ymake.core.conf @@ -9,7 +9,7 @@ FAKEID=3141592653 SANDBOX_FAKEID=${FAKEID}.7600000 -CPP_FAKEID=9392427 +CPP_FAKEID=9403851 GO_FAKEID=9336945 ANDROID_FAKEID=8821472 CLANG_TIDY_FAKEID=8625699 diff --git a/contrib/libs/cxxsupp/libcxx/import b/contrib/libs/cxxsupp/libcxx/import index b8cb8a84e0b..73bee19dbee 100755 --- a/contrib/libs/cxxsupp/libcxx/import +++ b/contrib/libs/cxxsupp/libcxx/import @@ -1,6 +1,6 @@ #!/bin/sh -e -rev=a2afc824 +rev=4684857a output_dir="libcxx-r$rev" if [ -z $1 ] ; then git clone https://github.com/llvm/llvm-project.git --no-checkout "$output_dir/tmp" diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/format_arg.h b/contrib/libs/cxxsupp/libcxx/include/__format/format_arg.h index 59429c13d41..da829d52fbf 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/format_arg.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/format_arg.h @@ -14,7 +14,9 @@ #include <__config> #include <__format/format_error.h> #include <__format/format_fwd.h> +#include <__format/format_parse_context.h> #include <__functional_base> +#include <__memory/addressof.h> #include <__variant/monostate.h> #include <string> #include <string_view> @@ -56,7 +58,8 @@ enum class _LIBCPP_ENUM_VIS __arg_t : uint8_t { __long_double, __const_char_type_ptr, __string_view, - __ptr + __ptr, + __handle }; } // namespace __format @@ -104,6 +107,8 @@ visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__string_view); case __format::__arg_t::__ptr: return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__ptr); + case __format::__arg_t::__handle: + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__handle); } _LIBCPP_UNREACHABLE(); } @@ -111,8 +116,7 @@ visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { template <class _Context> class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_arg { public: - // TODO FMT Define the handle class. - class handle; + class _LIBCPP_TEMPLATE_VIS handle; _LIBCPP_HIDE_FROM_ABI basic_format_arg() noexcept : __type_{__format::__arg_t::__none} {} @@ -161,7 +165,7 @@ private: const char_type* __const_char_type_ptr; basic_string_view<char_type> __string_view; const void* __ptr; - // TODO FMT Add the handle. + handle __handle; }; __format::__arg_t __type_; @@ -245,7 +249,37 @@ private: explicit basic_format_arg(nullptr_t) noexcept : __ptr(nullptr), __type_(__format::__arg_t::__ptr) {} - // TODO FMT Implement the _Tp* constructor. + template <class _Tp> + requires is_void_v<_Tp> _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(_Tp* __p) noexcept + : __ptr(__p), __type_(__format::__arg_t::__ptr) {} + + template <class _Tp> + _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(const _Tp& __v) noexcept + : __handle(__v), __type_(__format::__arg_t::__handle) {} +}; + +template <class _Context> +class _LIBCPP_TEMPLATE_VIS basic_format_arg<_Context>::handle { + friend class basic_format_arg<_Context>; + +public: + _LIBCPP_HIDE_FROM_ABI + void format(basic_format_parse_context<char_type>& __parse_ctx, _Context& __ctx) const { + __format_(__parse_ctx, __ctx, __ptr_); + } + +private: + const void* __ptr_; + void (*__format_)(basic_format_parse_context<char_type>&, _Context&, const void*); + + template <class _Tp> + _LIBCPP_HIDE_FROM_ABI explicit handle(const _Tp& __v) noexcept + : __ptr_(_VSTD::addressof(__v)), + __format_([](basic_format_parse_context<char_type>& __parse_ctx, _Context& __ctx, const void* __ptr) { + typename _Context::template formatter_type<_Tp> __f; + __parse_ctx.advance_to(__f.parse(__parse_ctx)); + __ctx.advance_to(__f.format(*static_cast<const _Tp*>(__ptr), __ctx)); + }) {} }; #endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/formatter.h b/contrib/libs/cxxsupp/libcxx/include/__format/formatter.h index 1adce75a861..38b73bba32f 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/formatter.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/formatter.h @@ -38,26 +38,20 @@ _LIBCPP_BEGIN_NAMESPACE_STD // to support compilers with partial C++20 support. #if !defined(_LIBCPP_HAS_NO_CONCEPTS) -// Currently not implemented specializations throw an exception when used. This -// does not conform to the Standard. However not all Standard defined formatters -// have been implemented yet. Until that time the current behavior is intended. -// TODO FMT Disable the default template. +/// The default formatter template. +/// +/// [format.formatter.spec]/5 +/// If F is a disabled specialization of formatter, these values are false: +/// - is_default_constructible_v<F>, +/// - is_copy_constructible_v<F>, +/// - is_move_constructible_v<F>, +/// - is_copy_assignable<F>, and +/// - is_move_assignable<F>. template <class _Tp, class _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter { - _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI auto parse(auto& __parse_ctx) - -> decltype(__parse_ctx.begin()) { - __throw(); - } - - _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI auto format(_Tp, auto& __ctx) - -> decltype(__ctx.out()) { - __throw(); - } - -private: - _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI void __throw() { - __throw_format_error("Argument type not implemented yet"); - } + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; }; namespace __format_spec { @@ -193,6 +187,34 @@ __write(output_iterator<const _CharT&> auto __out_it, const _CharT* __first, /** * @overload * + * Writes additional zero's for the precision before the exponent. + * This is used when the precision requested in the format string is larger + * than the maximum precision of the floating-point type. These precision + * digits are always 0. + * + * @param __exponent The location of the exponent character. + * @param __num_trailing_zeros The number of 0's to write before the exponent + * character. + */ +template <class _CharT, class _Fill> +_LIBCPP_HIDE_FROM_ABI auto __write(output_iterator<const _CharT&> auto __out_it, const _CharT* __first, + const _CharT* __last, size_t __size, size_t __width, _Fill __fill, + __format_spec::_Flags::_Alignment __alignment, const _CharT* __exponent, + size_t __num_trailing_zeros) -> decltype(__out_it) { + _LIBCPP_ASSERT(__first <= __last, "Not a valid range"); + _LIBCPP_ASSERT(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used"); + + __padding_size_result __padding = __padding_size(__size + __num_trailing_zeros, __width, __alignment); + __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill); + __out_it = _VSTD::copy(__first, __exponent, _VSTD::move(__out_it)); + __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __num_trailing_zeros, _CharT('0')); + __out_it = _VSTD::copy(__exponent, __last, _VSTD::move(__out_it)); + return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill); +} + +/** + * @overload + * * Uses a transformation operation before writing an element. * * TODO FMT Fill will probably change to support Unicode grapheme cluster. diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_bool.h b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_bool.h index fdd1d75355d..1e40bc0a435 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_bool.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_bool.h @@ -102,7 +102,7 @@ using __formatter_bool = __formatter_integral<__parser_bool<_CharT>>; // For each charT, for each cv-unqualified arithmetic type ArithmeticT other // than char, wchar_t, char8_t, char16_t, or char32_t, a specialization -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<bool, _CharT> : public __format_spec::__formatter_bool<_CharT> { using _Base = __format_spec::__formatter_bool<_CharT>; diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_floating_point.h b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_floating_point.h new file mode 100644 index 00000000000..2e710b409de --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_floating_point.h @@ -0,0 +1,717 @@ +// -*- 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_FLOATING_POINT_H +#define _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H + +#include <__algorithm/copy.h> +#include <__algorithm/copy_n.h> +#include <__algorithm/fill_n.h> +#include <__algorithm/find.h> +#include <__algorithm/min.h> +#include <__algorithm/rotate.h> +#include <__algorithm/transform.h> +#include <__concepts/arithmetic.h> +#include <__config> +#include <__debug> +#include <__format/format_error.h> +#include <__format/format_fwd.h> +#include <__format/format_string.h> +#include <__format/formatter.h> +#include <__format/formatter_integral.h> +#include <__format/parser_std_format_spec.h> +#include <__utility/move.h> +#include <charconv> +#include <cmath> + +#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 + +// TODO FMT Remove this once we require compilers with proper C++20 support. +// If the compiler has no concepts support, the format header will be disabled. +// Without concepts support enable_if needs to be used and that too much effort +// to support compilers with partial C++20 support. +# if !defined(_LIBCPP_HAS_NO_CONCEPTS) + +namespace __format_spec { + +template <floating_point _Tp> +_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value) { + to_chars_result __r = _VSTD::to_chars(__first, __last, __value); + _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small"); + return __r.ptr; +} + +template <floating_point _Tp> +_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt) { + to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __fmt); + _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small"); + return __r.ptr; +} + +template <floating_point _Tp> +_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt, int __precision) { + to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __fmt, __precision); + _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small"); + return __r.ptr; +} + +// https://en.cppreference.com/w/cpp/language/types#cite_note-1 +// float min subnormal: +/-0x1p-149 max: +/- 3.402,823,4 10^38 +// double min subnormal: +/-0x1p-1074 max +/- 1.797,693,134,862,315,7 10^308 +// long double (x86) min subnormal: +/-0x1p-16446 max: +/- 1.189,731,495,357,231,765,021 10^4932 +// +// The maximum number of digits required for the integral part is based on the +// maximum's value power of 10. Every power of 10 requires one additional +// decimal digit. +// The maximum number of digits required for the fractional part is based on +// the minimal subnormal hexadecimal output's power of 10. Every division of a +// fraction's binary 1 by 2, requires one additional decimal digit. +// +// The maximum size of a formatted value depends on the selected output format. +// Ignoring the fact the format string can request a precision larger than the +// values maximum required, these values are: +// +// sign 1 code unit +// __max_integral +// radix point 1 code unit +// __max_fractional +// exponent character 1 code unit +// sign 1 code unit +// __max_fractional_value +// ----------------------------------- +// total 4 code units extra required. +// +// TODO FMT Optimize the storage to avoid storing digits that are known to be zero. +// https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/ + +// TODO FMT Add long double specialization when to_chars has proper long double support. +template <class _Tp> +struct __traits; + +template <floating_point _Fp> +static constexpr size_t __float_buffer_size(int __precision) { + using _Traits = __traits<_Fp>; + return 4 + _Traits::__max_integral + __precision + _Traits::__max_fractional_value; +} + +template <> +struct __traits<float> { + static constexpr int __max_integral = 38; + static constexpr int __max_fractional = 149; + static constexpr int __max_fractional_value = 3; + static constexpr size_t __stack_buffer_size = 256; + + static constexpr int __hex_precision_digits = 3; +}; + +template <> +struct __traits<double> { + static constexpr int __max_integral = 308; + static constexpr int __max_fractional = 1074; + static constexpr int __max_fractional_value = 4; + static constexpr size_t __stack_buffer_size = 1024; + + static constexpr int __hex_precision_digits = 4; +}; + +/// Helper class to store the conversion buffer. +/// +/// Depending on the maxium size required for a value, the buffer is allocated +/// on the stack or the heap. +template <floating_point _Fp> +class _LIBCPP_TEMPLATE_VIS __float_buffer { + using _Traits = __traits<_Fp>; + +public: + // TODO FMT Improve this constructor to do a better estimate. + // When using a scientific formatting with a precision of 6 a stack buffer + // will always suffice. At the moment that isn't important since floats and + // doubles use a stack buffer, unless the precision used in the format string + // is large. + // When supporting long doubles the __max_integral part becomes 4932 which + // may be too much for some platforms. For these cases a better estimate is + // required. + explicit _LIBCPP_HIDE_FROM_ABI __float_buffer(int __precision) + : __precision_(__precision != -1 ? __precision : _Traits::__max_fractional) { + + // When the precision is larger than _Traits::__max_fractional the digits in + // the range (_Traits::__max_fractional, precision] will contain the value + // zero. There's no need to request to_chars to write these zeros: + // - When the value is large a temporary heap buffer needs to be allocated. + // - When to_chars writes the values they need to be "copied" to the output: + // - char: std::fill on the output iterator is faster than std::copy. + // - wchar_t: same argument as char, but additional std::copy won't work. + // The input is always a char buffer, so every char in the buffer needs + // to be converted from a char to a wchar_t. + if (__precision_ > _Traits::__max_fractional) { + __num_trailing_zeros_ = __precision_ - _Traits::__max_fractional; + __precision_ = _Traits::__max_fractional; + } + + __size_ = __format_spec::__float_buffer_size<_Fp>(__precision_); + if (__size_ > _Traits::__stack_buffer_size) + // The allocated buffer's contents don't need initialization. + __begin_ = allocator<char>{}.allocate(__size_); + else + __begin_ = __buffer_; + } + + _LIBCPP_HIDE_FROM_ABI ~__float_buffer() { + if (__size_ > _Traits::__stack_buffer_size) + allocator<char>{}.deallocate(__begin_, __size_); + } + _LIBCPP_HIDE_FROM_ABI __float_buffer(const __float_buffer&) = delete; + _LIBCPP_HIDE_FROM_ABI __float_buffer& operator=(const __float_buffer&) = delete; + + _LIBCPP_HIDE_FROM_ABI char* begin() const { return __begin_; } + _LIBCPP_HIDE_FROM_ABI char* end() const { return __begin_ + __size_; } + + _LIBCPP_HIDE_FROM_ABI int __precision() const { return __precision_; } + _LIBCPP_HIDE_FROM_ABI int __num_trailing_zeros() const { return __num_trailing_zeros_; } + _LIBCPP_HIDE_FROM_ABI void __remove_trailing_zeros() { __num_trailing_zeros_ = 0; } + +private: + int __precision_; + int __num_trailing_zeros_{0}; + size_t __size_; + char* __begin_; + char __buffer_[_Traits::__stack_buffer_size]; +}; + +struct __float_result { + /// Points at the beginning of the integral part in the buffer. + /// + /// When there's no sign character this points at the start of the buffer. + char* __integral; + + /// Points at the radix point, when not present it's the same as \ref __last. + char* __radix_point; + + /// Points at the exponent character, when not present it's the same as \ref __last. + char* __exponent; + + /// Points beyond the last written element in the buffer. + char* __last; +}; + +/// Finds the position of the exponent character 'e' at the end of the buffer. +/// +/// Assuming there is an exponent the input will terminate with +/// eSdd and eSdddd (S = sign, d = digit) +/// +/// \returns a pointer to the exponent or __last when not found. +constexpr inline _LIBCPP_HIDE_FROM_ABI char* __find_exponent(char* __first, char* __last) { + ptrdiff_t __size = __last - __first; + if (__size > 4) { + __first = __last - _VSTD::min(__size, ptrdiff_t(6)); + for (; __first != __last - 3; ++__first) { + if (*__first == 'e') + return __first; + } + } + return __last; +} + +template <class _Fp, class _Tp> +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_default(const __float_buffer<_Fp>& __buffer, _Tp __value, + char* __integral) { + __float_result __result; + __result.__integral = __integral; + __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value); + + __result.__exponent = __format_spec::__find_exponent(__result.__integral, __result.__last); + + // Constrains: + // - There's at least one decimal digit before the radix point. + // - The radix point, when present, is placed before the exponent. + __result.__radix_point = _VSTD::find(__result.__integral + 1, __result.__exponent, '.'); + + // When the radix point isn't found its position is the exponent instead of + // __result.__last. + if (__result.__radix_point == __result.__exponent) + __result.__radix_point = __result.__last; + + // clang-format off + _LIBCPP_ASSERT((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last || *__result.__exponent == 'e'), + "Post-condition failure."); + // clang-format on + + return __result; +} + +template <class _Fp, class _Tp> +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_lower_case(const __float_buffer<_Fp>& __buffer, + _Tp __value, int __precision, + char* __integral) { + __float_result __result; + __result.__integral = __integral; + if (__precision == -1) + __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex); + else + __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex, __precision); + + // H = one or more hex-digits + // S = sign + // D = one or more decimal-digits + // When the fractional part is zero and no precision the output is 0p+0 + // else the output is 0.HpSD + // So testing the second position can differentiate between these two cases. + char* __first = __integral + 1; + if (*__first == '.') { + __result.__radix_point = __first; + // One digit is the minimum + // 0.hpSd + // ^-- last + // ^---- integral = end of search + // ^-------- start of search + // 0123456 + // + // Four digits is the maximum + // 0.hpSdddd + // ^-- last + // ^---- integral = end of search + // ^-------- start of search + // 0123456789 + static_assert(__traits<_Fp>::__hex_precision_digits <= 4, "Guard against possible underflow."); + + char* __last = __result.__last - 2; + __first = __last - __traits<_Fp>::__hex_precision_digits; + __result.__exponent = _VSTD::find(__first, __last, 'p'); + } else { + __result.__radix_point = __result.__last; + __result.__exponent = __first; + } + + // clang-format off + _LIBCPP_ASSERT((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent != __result.__last && *__result.__exponent == 'p'), + "Post-condition failure."); + // clang-format on + + return __result; +} + +template <class _Fp, class _Tp> +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_upper_case(const __float_buffer<_Fp>& __buffer, + _Tp __value, int __precision, + char* __integral) { + __float_result __result = + __format_spec::__format_buffer_hexadecimal_lower_case(__buffer, __value, __precision, __integral); + _VSTD::transform(__result.__integral, __result.__exponent, __result.__integral, __hex_to_upper); + *__result.__exponent = 'P'; + return __result; +} + +template <class _Fp, class _Tp> +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_lower_case(const __float_buffer<_Fp>& __buffer, + _Tp __value, int __precision, + char* __integral) { + __float_result __result; + __result.__integral = __integral; + __result.__last = + __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::scientific, __precision); + + char* __first = __integral + 1; + _LIBCPP_ASSERT(__first != __result.__last, "No exponent present"); + if (*__first == '.') { + __result.__radix_point = __first; + __result.__exponent = __format_spec::__find_exponent(__first + 1, __result.__last); + } else { + __result.__radix_point = __result.__last; + __result.__exponent = __first; + } + + // clang-format off + _LIBCPP_ASSERT((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent != __result.__last && *__result.__exponent == 'e'), + "Post-condition failure."); + // clang-format on + return __result; +} + +template <class _Fp, class _Tp> +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_upper_case(const __float_buffer<_Fp>& __buffer, + _Tp __value, int __precision, + char* __integral) { + __float_result __result = + __format_spec::__format_buffer_scientific_lower_case(__buffer, __value, __precision, __integral); + *__result.__exponent = 'E'; + return __result; +} + +template <class _Fp, class _Tp> +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_fixed(const __float_buffer<_Fp>& __buffer, _Tp __value, + int __precision, char* __integral) { + __float_result __result; + __result.__integral = __integral; + __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::fixed, __precision); + + // When there's no precision there's no radix point. + // Else the radix point is placed at __precision + 1 from the end. + // By converting __precision to a bool the subtraction can be done + // unconditionally. + __result.__radix_point = __result.__last - (__precision + bool(__precision)); + __result.__exponent = __result.__last; + + // clang-format off + _LIBCPP_ASSERT((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last), + "Post-condition failure."); + // clang-format on + return __result; +} + +template <class _Fp, class _Tp> +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_lower_case(__float_buffer<_Fp>& __buffer, _Tp __value, + int __precision, char* __integral) { + + __buffer.__remove_trailing_zeros(); + + __float_result __result; + __result.__integral = __integral; + __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::general, __precision); + + char* __first = __integral + 1; + if (__first == __result.__last) { + __result.__radix_point = __result.__last; + __result.__exponent = __result.__last; + } else { + __result.__exponent = __format_spec::__find_exponent(__first, __result.__last); + if (__result.__exponent != __result.__last) + // In scientific mode if there's a radix point it will always be after + // the first digit. (This is the position __first points at). + __result.__radix_point = *__first == '.' ? __first : __result.__last; + else { + // In fixed mode the algorithm truncates trailing spaces and possibly the + // radix point. There's no good guess for the position of the radix point + // therefore scan the output after the first digit. + __result.__radix_point = _VSTD::find(__first, __result.__last, '.'); + } + } + + // clang-format off + _LIBCPP_ASSERT((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last || *__result.__exponent == 'e'), + "Post-condition failure."); + // clang-format on + + return __result; +} + +template <class _Fp, class _Tp> +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_upper_case(__float_buffer<_Fp>& __buffer, _Tp __value, + int __precision, char* __integral) { + __float_result __result = + __format_spec::__format_buffer_general_lower_case(__buffer, __value, __precision, __integral); + if (__result.__exponent != __result.__last) + *__result.__exponent = 'E'; + return __result; +} + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION +template <class _OutIt, class _Fp, class _CharT> +_LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(_OutIt __out_it, const __float_buffer<_Fp>& __buffer, + const __float_result& __result, _VSTD::locale __loc, + size_t __width, _Flags::_Alignment __alignment, + _CharT __fill) { + const auto& __np = use_facet<numpunct<_CharT>>(__loc); + string __grouping = __np.grouping(); + char* __first = __result.__integral; + // When no radix point or exponent are present __last will be __result.__last. + char* __last = _VSTD::min(__result.__radix_point, __result.__exponent); + + ptrdiff_t __digits = __last - __first; + if (!__grouping.empty()) { + if (__digits <= __grouping[0]) + __grouping.clear(); + else + __grouping = __determine_grouping(__digits, __grouping); + } + + size_t __size = __result.__last - __buffer.begin() + // Formatted string + __buffer.__num_trailing_zeros() + // Not yet rendered zeros + __grouping.size() - // Grouping contains one + !__grouping.empty(); // additional character + + __formatter::__padding_size_result __padding = {0, 0}; + bool __zero_padding = __alignment == _Flags::_Alignment::__default; + if (__size < __width) { + if (__zero_padding) { + __alignment = _Flags::_Alignment::__right; + __fill = _CharT('0'); + } + + __padding = __formatter::__padding_size(__size, __width, __alignment); + } + + // sign and (zero padding or alignment) + if (__zero_padding && __first != __buffer.begin()) + *__out_it++ = *__buffer.begin(); + __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill); + if (!__zero_padding && __first != __buffer.begin()) + *__out_it++ = *__buffer.begin(); + + // integral part + if (__grouping.empty()) { + __out_it = _VSTD::copy_n(__first, __digits, _VSTD::move(__out_it)); + } else { + auto __r = __grouping.rbegin(); + auto __e = __grouping.rend() - 1; + _CharT __sep = __np.thousands_sep(); + // 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. + while (true) { + __out_it = _VSTD::copy_n(__first, *__r, _VSTD::move(__out_it)); + __first += *__r; + + if (__r == __e) + break; + + ++__r; + *__out_it++ = __sep; + } + } + + // fractional part + if (__result.__radix_point != __result.__last) { + *__out_it++ = __np.decimal_point(); + __out_it = _VSTD::copy(__result.__radix_point + 1, __result.__exponent, _VSTD::move(__out_it)); + __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __buffer.__num_trailing_zeros(), _CharT('0')); + } + + // exponent + if (__result.__exponent != __result.__last) + __out_it = _VSTD::copy(__result.__exponent, __result.__last, _VSTD::move(__out_it)); + + // alignment + return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill); +} + +# endif // _LIBCPP_HAS_NO_LOCALIZATION + +template <__formatter::__char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __formatter_floating_point : public __parser_floating_point<_CharT> { +public: + template <floating_point _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)); + + bool __negative = _VSTD::signbit(__value); + + if (!_VSTD::isfinite(__value)) [[unlikely]] + return __format_non_finite(__ctx.out(), __negative, _VSTD::isnan(__value)); + + bool __has_precision = this->__has_precision_field(); + if (this->__precision_needs_substitution()) + this->__substitute_precision_arg_id(__ctx.arg(this->__precision)); + + // Depending on the std-format-spec string the sign and the value + // might not be outputted together: + // - zero-padding may insert additional '0' characters. + // Therefore the value is processed as a non negative value. + // The function @ref __insert_sign will insert a '-' when the value was + // negative. + + if (__negative) + __value = _VSTD::copysign(__value, +1.0); + + // TODO FMT _Fp should just be _Tp when to_chars has proper long double support. + using _Fp = conditional_t<same_as<_Tp, long double>, double, _Tp>; + // Force the type of the precision to avoid -1 to become an unsigned value. + __float_buffer<_Fp> __buffer(__has_precision ? int(this->__precision) : -1); + __float_result __result = __format_buffer(__buffer, __value, __negative, __has_precision); + + if (this->__alternate_form && __result.__radix_point == __result.__last) { + *__result.__last++ = '.'; + + // When there is an exponent the point needs to be moved before the + // exponent. When there's no exponent the rotate does nothing. Since + // rotate tests whether the operation is a nop, call it unconditionally. + _VSTD::rotate(__result.__exponent, __result.__last - 1, __result.__last); + __result.__radix_point = __result.__exponent; + + // The radix point is always placed before the exponent. + // - No exponent needs to point to the new last. + // - An exponent needs to move one position to the right. + // So it's safe to increment the value unconditionally. + ++__result.__exponent; + } + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + if (this->__locale_specific_form) + return __format_spec::__format_locale_specific_form(__ctx.out(), __buffer, __result, __ctx.locale(), + this->__width, this->__alignment, this->__fill); +# endif + + ptrdiff_t __size = __result.__last - __buffer.begin(); + int __num_trailing_zeros = __buffer.__num_trailing_zeros(); + if (__size + __num_trailing_zeros >= this->__width) { + if (__num_trailing_zeros && __result.__exponent != __result.__last) + // Insert trailing zeros before exponent character. + return _VSTD::copy(__result.__exponent, __result.__last, + _VSTD::fill_n(_VSTD::copy(__buffer.begin(), __result.__exponent, __ctx.out()), + __num_trailing_zeros, _CharT('0'))); + + return _VSTD::fill_n(_VSTD::copy(__buffer.begin(), __result.__last, __ctx.out()), __num_trailing_zeros, + _CharT('0')); + } + + auto __out_it = __ctx.out(); + char* __first = __buffer.begin(); + if (this->__alignment == _Flags::_Alignment::__default) { + // When there is a sign output it before the padding. Note the __size + // doesn't need any adjustment, regardless whether the sign is written + // here or in __formatter::__write. + if (__first != __result.__integral) + *__out_it++ = *__first++; + // After the sign is written, zero padding is the same a right alignment + // with '0'. + this->__alignment = _Flags::_Alignment::__right; + this->__fill = _CharT('0'); + } + + if (__num_trailing_zeros) + return __formatter::__write(_VSTD::move(__out_it), __first, __result.__last, __size, this->__width, this->__fill, + this->__alignment, __result.__exponent, __num_trailing_zeros); + + return __formatter::__write(_VSTD::move(__out_it), __first, __result.__last, __size, this->__width, this->__fill, + this->__alignment); + } + +private: + template <class _OutIt> + _LIBCPP_HIDE_FROM_ABI _OutIt __format_non_finite(_OutIt __out_it, bool __negative, bool __isnan) { + char __buffer[4]; + char* __last = __insert_sign(__buffer, __negative, this->__sign); + + // to_char can return inf, infinity, nan, and nan(n-char-sequence). + // The format library requires inf and nan. + // All in one expression to avoid dangling references. + __last = _VSTD::copy_n(&("infnanINFNAN"[6 * (this->__type == _Flags::_Type::__float_hexadecimal_upper_case || + this->__type == _Flags::_Type::__scientific_upper_case || + this->__type == _Flags::_Type::__fixed_upper_case || + this->__type == _Flags::_Type::__general_upper_case) + + 3 * __isnan]), + 3, __last); + + // [format.string.std]/13 + // A zero (0) character preceding the width field pads the field with + // leading zeros (following any indication of sign or base) to the field + // width, except when applied to an infinity or NaN. + if (this->__alignment == _Flags::_Alignment::__default) + this->__alignment = _Flags::_Alignment::__right; + + ptrdiff_t __size = __last - __buffer; + if (__size >= this->__width) + return _VSTD::copy_n(__buffer, __size, _VSTD::move(__out_it)); + + return __formatter::__write(_VSTD::move(__out_it), __buffer, __last, __size, this->__width, this->__fill, + this->__alignment); + } + + /// Fills the buffer with the data based on the requested formatting. + /// + /// This function, when needed, turns the characters to upper case and + /// determines the "interesting" locations which are returned to the caller. + /// + /// This means the caller never has to convert the contents of the buffer to + /// upper case or search for radix points and the location of the exponent. + /// This gives a bit of overhead. The original code didn't do that, but due + /// to the number of possible additional work needed to turn this number to + /// the proper output the code was littered with tests for upper cases and + /// searches for radix points and exponents. + /// - When a precision larger than the type's precision is selected + /// additional zero characters need to be written before the exponent. + /// - alternate form needs to add a radix point when not present. + /// - localization needs to do grouping in the integral part. + template <class _Fp, class _Tp> + // TODO FMT _Fp should just be _Tp when to_chars has proper long double support. + _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer(__float_buffer<_Fp>& __buffer, _Tp __value, bool __negative, + bool __has_precision) { + char* __first = __insert_sign(__buffer.begin(), __negative, this->__sign); + switch (this->__type) { + case _Flags::_Type::__default: + return __format_spec::__format_buffer_default(__buffer, __value, __first); + + case _Flags::_Type::__float_hexadecimal_lower_case: + return __format_spec::__format_buffer_hexadecimal_lower_case( + __buffer, __value, __has_precision ? __buffer.__precision() : -1, __first); + + case _Flags::_Type::__float_hexadecimal_upper_case: + return __format_spec::__format_buffer_hexadecimal_upper_case( + __buffer, __value, __has_precision ? __buffer.__precision() : -1, __first); + + case _Flags::_Type::__scientific_lower_case: + return __format_spec::__format_buffer_scientific_lower_case(__buffer, __value, __buffer.__precision(), __first); + + case _Flags::_Type::__scientific_upper_case: + return __format_spec::__format_buffer_scientific_upper_case(__buffer, __value, __buffer.__precision(), __first); + + case _Flags::_Type::__fixed_lower_case: + case _Flags::_Type::__fixed_upper_case: + return __format_spec::__format_buffer_fixed(__buffer, __value, __buffer.__precision(), __first); + + case _Flags::_Type::__general_lower_case: + return __format_spec::__format_buffer_general_lower_case(__buffer, __value, __buffer.__precision(), __first); + + case _Flags::_Type::__general_upper_case: + return __format_spec::__format_buffer_general_upper_case(__buffer, __value, __buffer.__precision(), __first); + + default: + _LIBCPP_ASSERT(false, "The parser should have validated the type"); + _LIBCPP_UNREACHABLE(); + } + } +}; + +} //namespace __format_spec + +template <__formatter::__char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<float, _CharT> + : public __format_spec::__formatter_floating_point<_CharT> {}; +template <__formatter::__char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<double, _CharT> + : public __format_spec::__formatter_floating_point<_CharT> {}; +template <__formatter::__char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<long double, _CharT> + : public __format_spec::__formatter_floating_point<_CharT> {}; + +# endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_integer.h b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_integer.h index 767df36e61e..e1f3d4e3489 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_integer.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_integer.h @@ -81,25 +81,25 @@ using __formatter_integer = __formatter_integral<__parser_integer<_CharT>>; // than char, wchar_t, char8_t, char16_t, or char32_t, a specialization // Signed integral types. -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<signed char, _CharT> : public __format_spec::__formatter_integer<_CharT> {}; -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<short, _CharT> : public __format_spec::__formatter_integer<_CharT> {}; -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<int, _CharT> : public __format_spec::__formatter_integer<_CharT> {}; -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<long, _CharT> : public __format_spec::__formatter_integer<_CharT> {}; -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<long long, _CharT> : public __format_spec::__formatter_integer<_CharT> {}; #ifndef _LIBCPP_HAS_NO_INT128 -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<__int128_t, _CharT> : public __format_spec::__formatter_integer<_CharT> { @@ -119,28 +119,28 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT #endif // Unsigned integral types. -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<unsigned char, _CharT> : public __format_spec::__formatter_integer<_CharT> {}; -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<unsigned short, _CharT> : public __format_spec::__formatter_integer<_CharT> {}; -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<unsigned, _CharT> : public __format_spec::__formatter_integer<_CharT> {}; -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<unsigned long, _CharT> : public __format_spec::__formatter_integer<_CharT> {}; -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<unsigned long long, _CharT> : public __format_spec::__formatter_integer<_CharT> {}; #ifndef _LIBCPP_HAS_NO_INT128 -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<__uint128_t, _CharT> : public __format_spec::__formatter_integer<_CharT> { diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_integral.h b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_integral.h index 73e2fed8c0b..f164ee61097 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_integral.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_integral.h @@ -82,7 +82,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace __format_spec { /** Wrapper around @ref to_chars, returning the output pointer. */ -template <class _Tp> +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 diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_pointer.h b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_pointer.h new file mode 100644 index 00000000000..aa2eb641c6c --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_pointer.h @@ -0,0 +1,91 @@ +// -*- 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_POINTER_H +#define _LIBCPP___FORMAT_FORMATTER_POINTER_H + +#include <__algorithm/copy.h> +#include <__availability> +#include <__config> +#include <__debug> +#include <__format/format_error.h> +#include <__format/format_fwd.h> +#include <__format/formatter.h> +#include <__format/formatter_integral.h> +#include <__format/parser_std_format_spec.h> +#include <__iterator/access.h> +#include <__nullptr> +#include <cstdint> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +// TODO FMT Remove this once we require compilers with proper C++20 support. +// If the compiler has no concepts support, the format header will be disabled. +// Without concepts support enable_if needs to be used and that too much effort +// to support compilers with partial C++20 support. +# if !defined(_LIBCPP_HAS_NO_CONCEPTS) + +namespace __format_spec { + +template <__formatter::__char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __formatter_pointer : public __parser_pointer<_CharT> { +public: + _LIBCPP_HIDE_FROM_ABI auto format(const void* __ptr, auto& __ctx) -> decltype(__ctx.out()) { + _LIBCPP_ASSERT(this->__alignment != _Flags::_Alignment::__default, + "The call to parse should have updated the alignment"); + if (this->__width_needs_substitution()) + this->__substitute_width_arg_id(__ctx.arg(this->__width)); + + // This code looks a lot like the code to format a hexadecimal integral, + // but that code isn't public. Making that code public requires some + // refactoring. + // TODO FMT Remove code duplication. + char __buffer[2 + 2 * sizeof(uintptr_t)]; + __buffer[0] = '0'; + __buffer[1] = 'x'; + char* __last = __to_buffer(__buffer + 2, _VSTD::end(__buffer), reinterpret_cast<uintptr_t>(__ptr), 16); + + unsigned __size = __last - __buffer; + if (__size >= this->__width) + return _VSTD::copy(__buffer, __last, __ctx.out()); + + return __formatter::__write(__ctx.out(), __buffer, __last, __size, this->__width, this->__fill, this->__alignment); + } +}; + +} // namespace __format_spec + +// [format.formatter.spec]/2.4 +// For each charT, the pointer type specializations template<> +// - struct formatter<nullptr_t, charT>; +// - template<> struct formatter<void*, charT>; +// - template<> struct formatter<const void*, charT>; +template <__formatter::__char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<nullptr_t, _CharT> + : public __format_spec::__formatter_pointer<_CharT> {}; +template <__formatter::__char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<void*, _CharT> + : public __format_spec::__formatter_pointer<_CharT> {}; +template <__formatter::__char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<const void*, _CharT> + : public __format_spec::__formatter_pointer<_CharT> {}; + +# endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMATTER_POINTER_H diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_string.h b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_string.h index 75a81f5184a..04950faa4a2 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_string.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_string.h @@ -64,7 +64,7 @@ public: // [format.formatter.spec]/2.2 For each charT, the string type specializations // Formatter const char*. -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<const _CharT*, _CharT> : public __format_spec::__formatter_string<_CharT> { @@ -98,7 +98,7 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT }; // Formatter char*. -template <class _CharT> +template <__formatter::__char_type _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<_CharT*, _CharT> : public formatter<const _CharT*, _CharT> { using _Base = formatter<const _CharT*, _CharT>; @@ -110,7 +110,7 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT }; // Formatter const char[]. -template <class _CharT, size_t _Size> +template <__formatter::__char_type _CharT, size_t _Size> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<const _CharT[_Size], _CharT> : public __format_spec::__formatter_string<_CharT> { @@ -123,7 +123,7 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT }; // Formatter std::string. -template <class _CharT, class _Traits, class _Allocator> +template <__formatter::__char_type _CharT, class _Traits, class _Allocator> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<basic_string<_CharT, _Traits, _Allocator>, _CharT> : public __format_spec::__formatter_string<_CharT> { @@ -138,7 +138,7 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT }; // Formatter std::string_view. -template <class _CharT, class _Traits> +template <__formatter::__char_type _CharT, class _Traits> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<basic_string_view<_CharT, _Traits>, _CharT> : public __format_spec::__formatter_string<_CharT> { using _Base = __format_spec::__formatter_string<_CharT>; diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/parser_std_format_spec.h b/contrib/libs/cxxsupp/libcxx/include/__format/parser_std_format_spec.h index 6eae27d9ad1..9d893e9ced2 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/parser_std_format_spec.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/parser_std_format_spec.h @@ -476,6 +476,21 @@ __parse_type(const _CharT* __begin, _Flags& __flags) { } /** + * Process the parsed alignment and zero-padding state of arithmetic types. + * + * [format.string.std]/13 + * If the 0 character and an align option both appear, the 0 character is + * ignored. + * + * For the formatter a @ref __default alignment means zero-padding. + */ +_LIBCPP_HIDE_FROM_ABI constexpr void __process_arithmetic_alignment(_Flags& __flags) { + __flags.__zero_padding &= __flags.__alignment == _Flags::_Alignment::__default; + if (!__flags.__zero_padding && __flags.__alignment == _Flags::_Alignment::__default) + __flags.__alignment = _Flags::_Alignment::__right; +} + +/** * The parser for the std-format-spec. * * [format.string.std]/1 specifies the std-format-spec: @@ -648,23 +663,9 @@ protected: return __begin; } - /** - * Handles the post-parsing updates for the integer types. - * - * Updates the zero-padding and alignment for integer types. - * - * [format.string.std]/13 - * If the 0 character and an align option both appear, the 0 character is - * ignored. - * - * For the formatter a @ref __default alignment means zero-padding. Update - * the alignment based on parsed format string. - */ + /** Handles the post-parsing updates for the integer types. */ _LIBCPP_HIDE_FROM_ABI constexpr void __handle_integer() noexcept { - this->__zero_padding &= this->__alignment == _Flags::_Alignment::__default; - if (!this->__zero_padding && - this->__alignment == _Flags::_Alignment::__default) - this->__alignment = _Flags::_Alignment::__right; + __process_arithmetic_alignment(static_cast<_Flags&>(*this)); } /** @@ -701,8 +702,232 @@ protected: } }; -// TODO FMT Add a parser for floating-point values. -// TODO FMT Add a parser for pointer values. +/** + * The parser for the std-format-spec. + * + * This implements the parser for the floating-point types. + * + * See @ref __parser_string. + */ +template <class _CharT> +class _LIBCPP_TEMPLATE_VIS __parser_floating_point + : public __parser_width, // provides __width(|as_arg) + public __parser_precision, // provides __precision(|as_arg) + public __parser_fill_align<_CharT>, // provides __fill and uses __flags + public _Flags // provides __flags +{ +public: + using char_type = _CharT; + + /** + * The low-level std-format-spec parse function. + * + * @pre __begin points at the beginning of the std-format-spec. This means + * directly after the ':'. + * @pre The std-format-spec parses the entire input, or the first unmatched + * character is a '}'. + * + * @returns The iterator pointing at the last parsed character. + */ + _LIBCPP_HIDE_FROM_ABI constexpr auto parse(auto& __parse_ctx) + -> decltype(__parse_ctx.begin()) { + auto __it = __parse(__parse_ctx); + __process_arithmetic_alignment(static_cast<_Flags&>(*this)); + __process_display_type(); + return __it; + } +protected: + /** + * The low-level std-format-spec parse function. + * + * @pre __begin points at the beginning of the std-format-spec. This means + * directly after the ':'. + * @pre The std-format-spec parses the entire input, or the first unmatched + * character is a '}'. + * + * @returns The iterator pointing at the last parsed character. + */ + _LIBCPP_HIDE_FROM_ABI constexpr auto __parse(auto& __parse_ctx) + -> decltype(__parse_ctx.begin()) { + auto __begin = __parse_ctx.begin(); + auto __end = __parse_ctx.end(); + if (__begin == __end) + return __begin; + + __begin = __parser_fill_align<_CharT>::__parse(__begin, __end, + static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + __begin = __parse_sign(__begin, static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + __begin = __parse_alternate_form(__begin, static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + __begin = __parse_zero_padding(__begin, static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + __begin = __parser_width::__parse(__begin, __end, __parse_ctx); + if (__begin == __end) + return __begin; + + __begin = __parser_precision::__parse(__begin, __end, __parse_ctx); + if (__begin == __end) + return __begin; + + __begin = + __parse_locale_specific_form(__begin, static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + __begin = __parse_type(__begin, static_cast<_Flags&>(*this)); + + if (__begin != __end && *__begin != _CharT('}')) + __throw_format_error( + "The format-spec should consume the input or end with a '}'"); + + return __begin; + } + + /** Processes the parsed std-format-spec based on the parsed display type. */ + _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type() { + switch (this->__type) { + case _Flags::_Type::__default: + // When no precision specified then it keeps default since that + // formatting differs from the other types. + if (this->__has_precision_field()) + this->__type = _Flags::_Type::__general_lower_case; + break; + case _Flags::_Type::__float_hexadecimal_lower_case: + case _Flags::_Type::__float_hexadecimal_upper_case: + // Precision specific behavior will be handled later. + break; + case _Flags::_Type::__scientific_lower_case: + case _Flags::_Type::__scientific_upper_case: + case _Flags::_Type::__fixed_lower_case: + case _Flags::_Type::__fixed_upper_case: + case _Flags::_Type::__general_lower_case: + case _Flags::_Type::__general_upper_case: + if (!this->__has_precision_field()) { + // Set the default precision for the call to to_chars. + this->__precision = 6; + this->__precision_as_arg = false; + } + break; + + default: + __throw_format_error("The format-spec type has a type not supported for " + "a floating-point argument"); + } + } +}; + +/** + * The parser for the std-format-spec. + * + * This implements the parser for the pointer types. + * + * See @ref __parser_string. + */ +template <class _CharT> +class _LIBCPP_TEMPLATE_VIS __parser_pointer : public __parser_width, // provides __width(|as_arg) + public __parser_fill_align<_CharT>, // provides __fill and uses __flags + public _Flags // provides __flags +{ +public: + using char_type = _CharT; + + _LIBCPP_HIDE_FROM_ABI constexpr __parser_pointer() { + // Implements LWG3612 Inconsistent pointer alignment in std::format. + // The issue's current status is "Tentatively Ready" and libc++ status is + // still experimental. + // + // TODO FMT Validate this with the final resolution of LWG3612. + this->__alignment = _Flags::_Alignment::__right; + } + + /** + * The low-level std-format-spec parse function. + * + * @pre __begin points at the beginning of the std-format-spec. This means + * directly after the ':'. + * @pre The std-format-spec parses the entire input, or the first unmatched + * character is a '}'. + * + * @returns The iterator pointing at the last parsed character. + */ + _LIBCPP_HIDE_FROM_ABI constexpr auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) { + auto __it = __parse(__parse_ctx); + __process_display_type(); + return __it; + } + +protected: + /** + * The low-level std-format-spec parse function. + * + * @pre __begin points at the beginning of the std-format-spec. This means + * directly after the ':'. + * @pre The std-format-spec parses the entire input, or the first unmatched + * character is a '}'. + * + * @returns The iterator pointing at the last parsed character. + */ + _LIBCPP_HIDE_FROM_ABI constexpr auto __parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) { + auto __begin = __parse_ctx.begin(); + auto __end = __parse_ctx.end(); + if (__begin == __end) + return __begin; + + __begin = __parser_fill_align<_CharT>::__parse(__begin, __end, static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + // An integer presentation type isn't defined in the Standard. + // Since a pointer is formatted as an integer it can be argued it's an + // integer presentation type. However there are two LWG-issues asserting it + // isn't an integer presentation type: + // - LWG3612 Inconsistent pointer alignment in std::format + // - LWG3644 std::format does not define "integer presentation type" + // + // There's a paper to make additional clarifications on the status of + // formatting pointers and proposes additional fields to be valid. That + // paper hasn't been reviewed by the Committee yet. + // - P2510 Formatting pointers + // + // The current implementation assumes formatting pointers isn't covered by + // "integer presentation type". + // TODO FMT Apply the LWG-issues/papers after approval/rejection by the Committee. + + __begin = __parser_width::__parse(__begin, __end, __parse_ctx); + if (__begin == __end) + return __begin; + + __begin = __parse_type(__begin, static_cast<_Flags&>(*this)); + + if (__begin != __end && *__begin != _CharT('}')) + __throw_format_error("The format-spec should consume the input or end with a '}'"); + + return __begin; + } + + /** Processes the parsed std-format-spec based on the parsed display type. */ + _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type() { + switch (this->__type) { + case _Flags::_Type::__default: + this->__type = _Flags::_Type::__pointer; + break; + case _Flags::_Type::__pointer: + break; + default: + __throw_format_error("The format-spec type has a type not supported for a pointer argument"); + } + } +}; /** Helper struct returned from @ref __get_string_alignment. */ template <class _CharT> diff --git a/contrib/libs/cxxsupp/libcxx/include/__iterator/common_iterator.h b/contrib/libs/cxxsupp/libcxx/include/__iterator/common_iterator.h index 9a142769e55..df4c7bd18e8 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__iterator/common_iterator.h +++ b/contrib/libs/cxxsupp/libcxx/include/__iterator/common_iterator.h @@ -41,7 +41,7 @@ class common_iterator { : __value(_VSTD::move(__x)) {} public: - const iter_value_t<_Iter>* operator->() const { + constexpr const iter_value_t<_Iter>* operator->() const noexcept { return _VSTD::addressof(__value); } }; @@ -58,7 +58,7 @@ class common_iterator { constructible_from<iter_value_t<_Iter>, iter_reference_t<_Iter>> && move_constructible<iter_value_t<_Iter>>; - const iter_value_t<_Iter>& operator*() const { + constexpr const iter_value_t<_Iter>& operator*() const noexcept { return __value; } }; @@ -75,7 +75,7 @@ public: requires convertible_to<const _I2&, _Iter> && convertible_to<const _S2&, _Sent> constexpr common_iterator(const common_iterator<_I2, _S2>& __other) : __hold_([&]() -> variant<_Iter, _Sent> { - _LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Constructed from valueless iterator."); + _LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Attempted to construct from a valueless common_iterator"); if (__other.__hold_.index() == 0) return variant<_Iter, _Sent>{in_place_index<0>, _VSTD::__unchecked_get<0>(__other.__hold_)}; return variant<_Iter, _Sent>{in_place_index<1>, _VSTD::__unchecked_get<1>(__other.__hold_)}; @@ -85,7 +85,7 @@ public: requires convertible_to<const _I2&, _Iter> && convertible_to<const _S2&, _Sent> && assignable_from<_Iter&, const _I2&> && assignable_from<_Sent&, const _S2&> common_iterator& operator=(const common_iterator<_I2, _S2>& __other) { - _LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Assigned from valueless iterator."); + _LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Attempted to assign from a valueless common_iterator"); auto __idx = __hold_.index(); auto __other_idx = __other.__hold_.index(); @@ -105,18 +105,16 @@ public: return *this; } - decltype(auto) operator*() + constexpr decltype(auto) operator*() { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), - "Cannot dereference sentinel. Common iterator not holding an iterator."); + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), "Attempted to dereference a non-dereferenceable common_iterator"); return *_VSTD::__unchecked_get<_Iter>(__hold_); } - decltype(auto) operator*() const + constexpr decltype(auto) operator*() const requires __dereferenceable<const _Iter> { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), - "Cannot dereference sentinel. Common iterator not holding an iterator."); + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), "Attempted to dereference a non-dereferenceable common_iterator"); return *_VSTD::__unchecked_get<_Iter>(__hold_); } @@ -127,9 +125,7 @@ public: is_reference_v<iter_reference_t<_I2>> || constructible_from<iter_value_t<_I2>, iter_reference_t<_I2>>) { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), - "Cannot dereference sentinel. Common iterator not holding an iterator."); - + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), "Attempted to dereference a non-dereferenceable common_iterator"); if constexpr (is_pointer_v<_Iter> || requires(const _Iter& __i) { __i.operator->(); }) { return _VSTD::__unchecked_get<_Iter>(__hold_); } else if constexpr (is_reference_v<iter_reference_t<_Iter>>) { @@ -141,15 +137,12 @@ public: } common_iterator& operator++() { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), - "Cannot increment sentinel. Common iterator not holding an iterator."); + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), "Attempted to increment a non-dereferenceable common_iterator"); ++_VSTD::__unchecked_get<_Iter>(__hold_); return *this; } decltype(auto) operator++(int) { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), - "Cannot increment sentinel. Common iterator not holding an iterator."); - + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), "Attempted to increment a non-dereferenceable common_iterator"); if constexpr (forward_iterator<_Iter>) { auto __tmp = *this; ++*this; @@ -166,10 +159,9 @@ public: template<class _I2, sentinel_for<_Iter> _S2> requires sentinel_for<_Sent, _I2> - friend bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { - _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() && - !__y.__hold_.valueless_by_exception(), - "One or both common_iterators are valueless. (Cannot compare valueless iterators.)"); + friend constexpr bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { + _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); + _LIBCPP_ASSERT(!__y.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); auto __x_index = __x.__hold_.index(); auto __y_index = __y.__hold_.index(); @@ -185,10 +177,9 @@ public: template<class _I2, sentinel_for<_Iter> _S2> requires sentinel_for<_Sent, _I2> && equality_comparable_with<_Iter, _I2> - friend bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { - _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() && - !__y.__hold_.valueless_by_exception(), - "One or both common_iterators are valueless. (Cannot compare valueless iterators.)"); + friend constexpr bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { + _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); + _LIBCPP_ASSERT(!__y.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); auto __x_index = __x.__hold_.index(); auto __y_index = __y.__hold_.index(); @@ -207,10 +198,9 @@ public: template<sized_sentinel_for<_Iter> _I2, sized_sentinel_for<_Iter> _S2> requires sized_sentinel_for<_Sent, _I2> - friend iter_difference_t<_I2> operator-(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { - _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() && - !__y.__hold_.valueless_by_exception(), - "One or both common_iterators are valueless. (Cannot subtract valueless iterators.)"); + friend constexpr iter_difference_t<_I2> operator-(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { + _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception(), "Attempted to subtract from a valueless common_iterator"); + _LIBCPP_ASSERT(!__y.__hold_.valueless_by_exception(), "Attempted to subtract a valueless common_iterator"); auto __x_index = __x.__hold_.index(); auto __y_index = __y.__hold_.index(); @@ -227,24 +217,21 @@ public: return _VSTD::__unchecked_get<_Sent>(__x.__hold_) - _VSTD::__unchecked_get<_I2>(__y.__hold_); } - friend iter_rvalue_reference_t<_Iter> iter_move(const common_iterator& __i) + friend constexpr iter_rvalue_reference_t<_Iter> iter_move(const common_iterator& __i) noexcept(noexcept(ranges::iter_move(declval<const _Iter&>()))) requires input_iterator<_Iter> { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__i.__hold_), - "Cannot iter_move a sentinel. Common iterator not holding an iterator."); + _LIBCPP_ASSERT(holds_alternative<_Iter>(__i.__hold_), "Attempted to iter_move a non-dereferenceable common_iterator"); return ranges::iter_move( _VSTD::__unchecked_get<_Iter>(__i.__hold_)); } template<indirectly_swappable<_Iter> _I2, class _S2> - friend void iter_swap(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) + friend constexpr void iter_swap(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) noexcept(noexcept(ranges::iter_swap(declval<const _Iter&>(), declval<const _I2&>()))) { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__x.__hold_), - "Cannot swap __y with a sentinel. Common iterator (__x) not holding an iterator."); - _LIBCPP_ASSERT(holds_alternative<_Iter>(__y.__hold_), - "Cannot swap __x with a sentinel. Common iterator (__y) not holding an iterator."); - return ranges::iter_swap( _VSTD::__unchecked_get<_Iter>(__x.__hold_), _VSTD::__unchecked_get<_Iter>(__y.__hold_)); + _LIBCPP_ASSERT(holds_alternative<_Iter>(__x.__hold_), "Attempted to iter_swap a non-dereferenceable common_iterator"); + _LIBCPP_ASSERT(holds_alternative<_I2>(__y.__hold_), "Attempted to iter_swap a non-dereferenceable common_iterator"); + return ranges::iter_swap(_VSTD::__unchecked_get<_Iter>(__x.__hold_), _VSTD::__unchecked_get<_I2>(__y.__hold_)); } }; @@ -271,7 +258,7 @@ struct __arrow_type_or_void { template<class _Iter, class _Sent> requires __common_iter_has_ptr_op<_Iter, _Sent> struct __arrow_type_or_void<_Iter, _Sent> { - using type = decltype(declval<const common_iterator<_Iter, _Sent>>().operator->()); + using type = decltype(declval<const common_iterator<_Iter, _Sent>&>().operator->()); }; template<class _Iter, class _Sent> diff --git a/contrib/libs/cxxsupp/libcxx/include/format b/contrib/libs/cxxsupp/libcxx/include/format index 788b9c299ab..4cf146ead17 100644 --- a/contrib/libs/cxxsupp/libcxx/include/format +++ b/contrib/libs/cxxsupp/libcxx/include/format @@ -14,43 +14,15 @@ namespace std { // [format.context], class template basic_format_context - template<class Out, class charT> - class basic_format_context { - basic_format_args<basic_format_context> args_; // exposition only - Out out_; // exposition only - - public: - using iterator = Out; - using char_type = charT; - template<class T> using formatter_type = formatter<T, charT>; - - basic_format_arg<basic_format_context> arg(size_t id) const; - std::locale locale(); - - iterator out(); - void advance_to(iterator it); - }; + template<class Out, class charT> class basic_format_context; using format_context = basic_format_context<unspecified, char>; using wformat_context = basic_format_context<unspecified, wchar_t>; // [format.args], class template basic_format_args - template<class Context> - class basic_format_args { - size_t size_; // exposition only - const basic_format_arg<Context>* data_; // exposition only - - public: - basic_format_args() noexcept; - - template<class... Args> - basic_format_args(const format-arg-store<Context, Args...>& store) noexcept; - - basic_format_arg<Context> get(size_t i) const noexcept; - }; + template<class Context> class basic_format_args; using format_args = basic_format_args<format_context>; using wformat_args = basic_format_args<wformat_context>; - // [format.functions], formatting functions template<class... Args> string format(string_view fmt, const Args&... args); @@ -90,8 +62,7 @@ namespace std { Out out; iter_difference_t<Out> size; }; - - template<class Out, class... Args> + template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, string_view fmt, const Args&... args); template<class Out, class... Args> @@ -116,99 +87,22 @@ namespace std { size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args); // [format.formatter], formatter - template<> struct formatter<char, char>; - template<> struct formatter<char, wchar_t>; - template<> struct formatter<wchar_t, wchar_t>; - - template<> struct formatter<charT*, charT>; - template<> struct formatter<const charT*, charT>; - template<size_t N> struct formatter<const charT[N], charT>; - template<class traits, class Allocator> - struct formatter<basic_string<charT, traits, Allocator>, charT>; - template<class traits> - struct formatter<basic_string_view<charT, traits>, charT>; + template<class T, class charT = char> struct formatter; // [format.parse.ctx], class template basic_format_parse_context - template<class charT> - class basic_format_parse_context { - public: - using char_type = charT; - using const_iterator = typename basic_string_view<charT>::const_iterator; - using iterator = const_iterator; - - private: - iterator begin_; // exposition only - iterator end_; // exposition only - enum indexing { unknown, manual, automatic }; // exposition only - indexing indexing_; // exposition only - size_t next_arg_id_; // exposition only - size_t num_args_; // exposition only - - public: - constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt, - size_t num_args = 0) noexcept; - basic_format_parse_context(const basic_format_parse_context&) = delete; - basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; - - constexpr const_iterator begin() const noexcept; - constexpr const_iterator end() const noexcept; - constexpr void advance_to(const_iterator it); - - constexpr size_t next_arg_id(); - constexpr void check_arg_id(size_t id); - }; + template<class charT> class basic_format_parse_context; using format_parse_context = basic_format_parse_context<char>; using wformat_parse_context = basic_format_parse_context<wchar_t>; // [format.arguments], arguments // [format.arg], class template basic_format_arg - template<class Context> - class basic_format_arg { - public: - class handle; - - private: - using char_type = typename Context::char_type; // exposition only - - variant<monostate, bool, char_type, - int, unsigned int, long long int, unsigned long long int, - float, double, long double, - const char_type*, basic_string_view<char_type>, - const void*, handle> value; // exposition only - - template<class T> explicit basic_format_arg(const T& v) noexcept; // exposition only - explicit basic_format_arg(float n) noexcept; // exposition only - explicit basic_format_arg(double n) noexcept; // exposition only - explicit basic_format_arg(long double n) noexcept; // exposition only - explicit basic_format_arg(const char_type* s); // exposition only - - template<class traits> - explicit basic_format_arg( - basic_string_view<char_type, traits> s) noexcept; // exposition only - - template<class traits, class Allocator> - explicit basic_format_arg( - const basic_string<char_type, traits, Allocator>& s) noexcept; // exposition only - - explicit basic_format_arg(nullptr_t) noexcept; // exposition only - - template<class T> - explicit basic_format_arg(const T* p) noexcept; // exposition only - - public: - basic_format_arg() noexcept; - - explicit operator bool() const noexcept; - }; + template<class Context> class basic_format_arg; template<class Visitor, class Context> see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg); // [format.arg.store], class template format-arg-store - template<class Context, class... Args> - struct format-arg-store { // exposition only - array<basic_format_arg<Context>, sizeof...(Args)> args; - }; + template<class Context, class... Args> struct format-arg-store; // exposition only template<class Context = format_context, class... Args> format-arg-store<Context, Args...> @@ -218,43 +112,7 @@ namespace std { make_wformat_args(const Args&... args); // [format.error], class format_error - class format_error : public runtime_error { - public: - explicit format_error(const string& what_arg); - explicit format_error(const char* what_arg); - }; - - // [format.parse.ctx], class template basic_format_parse_context - template<class charT> - class basic_format_parse_context { - public: - using char_type = charT; - using const_iterator = typename basic_string_view<charT>::const_iterator; - using iterator = const_iterator; - - private: - iterator begin_; // exposition only - iterator end_; // exposition only - enum indexing { unknown, manual, automatic }; // exposition only - indexing indexing_; // exposition only - size_t next_arg_id_; // exposition only - size_t num_args_; // exposition only - - public: - constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt, - size_t num_args = 0) noexcept; - basic_format_parse_context(const basic_format_parse_context&) = delete; - basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; - - constexpr const_iterator begin() const noexcept; - constexpr const_iterator end() const noexcept; - constexpr void advance_to(const_iterator it); - - constexpr size_t next_arg_id(); - constexpr void check_arg_id(size_t id); - }; - using format_parse_context = basic_format_parse_context<char>; - using wformat_parse_context = basic_format_parse_context<wchar_t>; + class format_error; } */ @@ -277,7 +135,9 @@ namespace std { #include <__format/formatter.h> #include <__format/formatter_bool.h> #include <__format/formatter_char.h> +#include <__format/formatter_floating_point.h> #include <__format/formatter_integer.h> +#include <__format/formatter_pointer.h> #include <__format/formatter_string.h> #include <__format/parser_std_format_spec.h> #include <__variant/monostate.h> @@ -367,6 +227,8 @@ __handle_replacement_field(const _CharT* __begin, const _CharT* __end, [&](auto __arg) { if constexpr (same_as<decltype(__arg), monostate>) __throw_format_error("Argument index out of bounds"); + else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Ctx>::handle>) + __arg.format(__parse_ctx, __ctx); else { formatter<decltype(__arg), _CharT> __formatter; __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); diff --git a/contrib/libs/cxxsupp/libcxx/include/module.modulemap b/contrib/libs/cxxsupp/libcxx/include/module.modulemap index a927f9d0e67..90fae9bb836 100644 --- a/contrib/libs/cxxsupp/libcxx/include/module.modulemap +++ b/contrib/libs/cxxsupp/libcxx/include/module.modulemap @@ -488,25 +488,27 @@ module std [system] { export * module __format { - module format_arg { private header "__format/format_arg.h" } - module format_args { private header "__format/format_args.h" } + module format_arg { private header "__format/format_arg.h" } + module format_args { private header "__format/format_args.h" } module format_context { private header "__format/format_context.h" export optional export locale } - module format_error { private header "__format/format_error.h" } - module format_fwd { private header "__format/format_fwd.h" } - module format_parse_context { private header "__format/format_parse_context.h" } - module format_string { private header "__format/format_string.h" } - module format_to_n_result { private header "__format/format_to_n_result.h" } - module formatter { private header "__format/formatter.h" } - module formatter_bool { private header "__format/formatter_bool.h" } - module formatter_char { private header "__format/formatter_char.h" } - module formatter_integer { private header "__format/formatter_integer.h" } - module formatter_integral { private header "__format/formatter_integral.h" } - module formatter_string { private header "__format/formatter_string.h" } - module parser_std_format_spec { private header "__format/parser_std_format_spec.h" } + module format_error { private header "__format/format_error.h" } + module format_fwd { private header "__format/format_fwd.h" } + module format_parse_context { private header "__format/format_parse_context.h" } + module format_string { private header "__format/format_string.h" } + module format_to_n_result { private header "__format/format_to_n_result.h" } + module formatter { private header "__format/formatter.h" } + module formatter_bool { private header "__format/formatter_bool.h" } + module formatter_char { private header "__format/formatter_char.h" } + module formatter_floating_point { private header "__format/formatter_floating_point.h" } + module formatter_integer { private header "__format/formatter_integer.h" } + module formatter_integral { private header "__format/formatter_integral.h" } + module formatter_pointer { private header "__format/formatter_pointer.h" } + module formatter_string { private header "__format/formatter_string.h" } + module parser_std_format_spec { private header "__format/parser_std_format_spec.h" } } } module forward_list { |