diff options
author | mikhnenko <mikhnenko@yandex-team.com> | 2023-10-16 00:07:25 +0300 |
---|---|---|
committer | mikhnenko <mikhnenko@yandex-team.com> | 2023-10-16 00:31:43 +0300 |
commit | 6851965da19965a2680cfea6815b486fb14e739d (patch) | |
tree | b0ca5fe8b2ae7dc1407f134786ee8d2d67065520 /contrib/libs/cxxsupp/libcxx/include/__format | |
parent | 70f009564b5c4b41a3e14d7d1efd6aef5880034c (diff) | |
download | ydb-6851965da19965a2680cfea6815b486fb14e739d.tar.gz |
Upd libc++ to 18 May 4ac0589122830fc6d90e0ea091300c0b979a42dc
Diffstat (limited to 'contrib/libs/cxxsupp/libcxx/include/__format')
7 files changed, 584 insertions, 168 deletions
diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/buffer.h b/contrib/libs/cxxsupp/libcxx/include/__format/buffer.h index e5c3b9fda28..14926e32c66 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/buffer.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/buffer.h @@ -11,12 +11,16 @@ #define _LIBCPP___FORMAT_BUFFER_H #include <__algorithm/copy_n.h> +#include <__algorithm/max.h> +#include <__algorithm/min.h> #include <__algorithm/unwrap_iter.h> #include <__config> #include <__format/enable_insertable.h> +#include <__format/format_to_n_result.h> #include <__format/formatter.h> // for __char_type TODO FMT Move the concept? #include <__iterator/back_insert_iterator.h> #include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> #include <__iterator/wrap_iter.h> #include <__utility/move.h> @@ -28,6 +32,9 @@ # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER > 17 @@ -267,10 +274,97 @@ private: size_t __size_{0}; }; +/// The base of a buffer that counts and limits the number of insertions. +template <class _OutIt, __formatter::__char_type _CharT, bool> + requires(output_iterator<_OutIt, const _CharT&>) +struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base { + using _Size = iter_difference_t<_OutIt>; + +public: + _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __n) + : __writer_(_VSTD::move(__out_it)), __n_(_VSTD::max(_Size(0), __n)) {} + + _LIBCPP_HIDE_FROM_ABI void flush(_CharT* __ptr, size_t __size) { + if (_Size(__size_) <= __n_) + __writer_.flush(__ptr, _VSTD::min(_Size(__size), __n_ - __size_)); + __size_ += __size; + } + +protected: + __internal_storage<_CharT> __storage_; + __output_buffer<_CharT> __output_{__storage_.begin(), __storage_.capacity(), this}; + typename __writer_selector<_OutIt, _CharT>::type __writer_; + + _Size __n_; + _Size __size_{0}; +}; + +/// The base of a buffer that counts and limits the number of insertions. +/// +/// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true. +/// +/// This class limits the size available the the direct writer so it will not +/// exceed the maximum number of code units. +template <class _OutIt, __formatter::__char_type _CharT> + requires(output_iterator<_OutIt, const _CharT&>) +class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> { + using _Size = iter_difference_t<_OutIt>; + +public: + _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __n) + : __output_(_VSTD::__unwrap_iter(__out_it), __n, this), __writer_(_VSTD::move(__out_it)) { + if (__n <= 0) [[unlikely]] + __output_.reset(__storage_.begin(), __storage_.capacity()); + } + + _LIBCPP_HIDE_FROM_ABI void flush(_CharT* __ptr, size_t __size) { + // A flush to the direct writer happens in two occasions: + // - The format function has written the maximum number of allowed code + // units. At this point it's no longer valid to write to this writer. So + // switch to the internal storage. This internal storage doesn't need to + // be written anywhere so the flush for that storage writes no output. + // - The format_to_n function is finished. In this case there's no need to + // switch the buffer, but for simplicity the buffers are still switched. + // When the __n <= 0 the constructor already switched the buffers. + if (__size_ == 0 && __ptr != __storage_.begin()) { + __writer_.flush(__ptr, __size); + __output_.reset(__storage_.begin(), __storage_.capacity()); + } + + __size_ += __size; + } + +protected: + __internal_storage<_CharT> __storage_; + __output_buffer<_CharT> __output_; + __writer_direct<_OutIt, _CharT> __writer_; + + _Size __size_{0}; +}; + +/// The buffer that counts and limits the number of insertions. +template <class _OutIt, __formatter::__char_type _CharT> + requires(output_iterator<_OutIt, const _CharT&>) +struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final + : public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> { + using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>; + using _Size = iter_difference_t<_OutIt>; + +public: + _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __n) : _Base(_VSTD::move(__out_it), __n) {} + _LIBCPP_HIDE_FROM_ABI auto make_output_iterator() { return this->__output_.make_output_iterator(); } + + _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> result() && { + this->__output_.flush(); + return {_VSTD::move(this->__writer_).out(), this->__size_}; + } +}; } // namespace __format #endif //_LIBCPP_STD_VER > 17 _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___FORMAT_BUFFER_H diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/concepts.h b/contrib/libs/cxxsupp/libcxx/include/__format/concepts.h new file mode 100644 index 00000000000..8df6493b0ae --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/include/__format/concepts.h @@ -0,0 +1,53 @@ +// -*- 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_CONCEPTS_H +#define _LIBCPP___FORMAT_CONCEPTS_H + +#include <__concepts/same_as.h> +#include <__concepts/semiregular.h> +#include <__config> +#include <__format/format_fwd.h> +#include <__format/format_parse_context.h> +#include <type_traits> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +// The output iterator isn't specified. A formatter should accept any +// output_iterator. This iterator is a minimal iterator to test the concept. +// (Note testing for (w)format_context would be a valid choice, but requires +// selecting the proper one depending on the type of _CharT.) +template <class _CharT> +using __fmt_iter_for = _CharT*; + +// The concept is based on P2286R6 +// It lacks the const of __cf as required by, the not yet accepted, LWG-3636. +// The current formatters can't be easily adapted, but that is WIP. +// TODO FMT properly implement this concepts once accepted. +template <class _Tp, class _CharT> +concept __formattable = (semiregular<formatter<remove_cvref_t<_Tp>, _CharT>>) && + requires(formatter<remove_cvref_t<_Tp>, _CharT> __f, + formatter<remove_cvref_t<_Tp>, _CharT> __cf, _Tp __t, + basic_format_context<__fmt_iter_for<_CharT>, _CharT> __fc, + basic_format_parse_context<_CharT> __pc) { + { __f.parse(__pc) } -> same_as<typename basic_format_parse_context<_CharT>::iterator>; + { __cf.format(__t, __fc) } -> same_as<__fmt_iter_for<_CharT>>; + }; + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_CONCEPTS_H diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/format_arg.h b/contrib/libs/cxxsupp/libcxx/include/__format/format_arg.h index 845a20f3c72..3c61446378b 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/format_arg.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/format_arg.h @@ -35,6 +35,14 @@ namespace __format { /// /// @note The 128-bit types are unconditionally in the list to avoid the values /// of the enums to depend on the availability of 128-bit integers. +/// +/// @note The value is stored as a 5-bit value in the __packed_arg_t_bits. This +/// limits the maximum number of elements to 32. +/// When modifying update the test +/// test/libcxx/utilities/format/format.arguments/format.arg/arg_t.compile.pass.cpp +/// It could be packed in 4-bits but that means a new type directly becomes an +/// ABI break. The packed type is 64-bit so this reduces the maximum number of +/// packed elements from 16 to 12. enum class _LIBCPP_ENUM_VIS __arg_t : uint8_t { __none, __boolean, @@ -53,58 +61,151 @@ enum class _LIBCPP_ENUM_VIS __arg_t : uint8_t { __ptr, __handle }; + +inline constexpr unsigned __packed_arg_t_bits = 5; +inline constexpr uint8_t __packed_arg_t_mask = 0x1f; + +inline constexpr unsigned __packed_types_storage_bits = 64; +inline constexpr unsigned __packed_types_max = __packed_types_storage_bits / __packed_arg_t_bits; + +_LIBCPP_HIDE_FROM_ABI +constexpr bool __use_packed_format_arg_store(size_t __size) { return __size <= __packed_types_max; } + +_LIBCPP_HIDE_FROM_ABI +constexpr __arg_t __get_packed_type(uint64_t __types, size_t __id) { + _LIBCPP_ASSERT(__id <= __packed_types_max, ""); + + if (__id > 0) + __types >>= __id * __packed_arg_t_bits; + + return static_cast<__format::__arg_t>(__types & __packed_arg_t_mask); +} + } // namespace __format template <class _Visitor, class _Context> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT decltype(auto) -visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT decltype(auto) visit_format_arg(_Visitor&& __vis, + basic_format_arg<_Context> __arg) { switch (__arg.__type_) { case __format::__arg_t::__none: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), monostate{}); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__monostate_); case __format::__arg_t::__boolean: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__boolean); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__boolean_); case __format::__arg_t::__char_type: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__char_type); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__char_type_); case __format::__arg_t::__int: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__int); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__int_); case __format::__arg_t::__long_long: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__long_long); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__long_long_); case __format::__arg_t::__i128: -#ifndef _LIBCPP_HAS_NO_INT128 - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__i128); -#else +# ifndef _LIBCPP_HAS_NO_INT128 + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__i128_); +# else __libcpp_unreachable(); -#endif +# endif case __format::__arg_t::__unsigned: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__unsigned); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__unsigned_); case __format::__arg_t::__unsigned_long_long: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), - __arg.__unsigned_long_long); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__unsigned_long_long_); case __format::__arg_t::__u128: -#ifndef _LIBCPP_HAS_NO_INT128 - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__u128); -#else - __libcpp_unreachable(); -#endif +# ifndef _LIBCPP_HAS_NO_INT128 + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__u128_); +# else + __libcpp_unreachable(); +# endif case __format::__arg_t::__float: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__float); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__float_); case __format::__arg_t::__double: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__double); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__double_); case __format::__arg_t::__long_double: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__long_double); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__long_double_); case __format::__arg_t::__const_char_type_ptr: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), - __arg.__const_char_type_ptr); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__const_char_type_ptr_); case __format::__arg_t::__string_view: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__string_view); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__string_view_); case __format::__arg_t::__ptr: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__ptr); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__ptr_); case __format::__arg_t::__handle: - return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__handle); + return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), + typename basic_format_arg<_Context>::handle{__arg.__value_.__handle_}); } + __libcpp_unreachable(); } +/// Contains the values used in basic_format_arg. +/// +/// This is a separate type so it's possible to store the values and types in +/// separate arrays. +template <class _Context> +class __basic_format_arg_value { + using _CharT = typename _Context::char_type; + +public: + /// Contains the implementation for basic_format_arg::handle. + struct __handle { + template <class _Tp> + _LIBCPP_HIDE_FROM_ABI explicit __handle(const _Tp& __v) noexcept + : __ptr_(_VSTD::addressof(__v)), + __format_([](basic_format_parse_context<_CharT>& __parse_ctx, _Context& __ctx, const void* __ptr) { + using _Formatter = typename _Context::template formatter_type<_Tp>; + using _Qp = conditional_t<requires { _Formatter().format(declval<const _Tp&>(), declval<_Context&>()); }, + const _Tp, _Tp>; + _Formatter __f; + __parse_ctx.advance_to(__f.parse(__parse_ctx)); + __ctx.advance_to(__f.format(*const_cast<_Qp*>(static_cast<const _Tp*>(__ptr)), __ctx)); + }) {} + + const void* __ptr_; + void (*__format_)(basic_format_parse_context<_CharT>&, _Context&, const void*); + }; + + union { + monostate __monostate_; + bool __boolean_; + _CharT __char_type_; + int __int_; + unsigned __unsigned_; + long long __long_long_; + unsigned long long __unsigned_long_long_; +# ifndef _LIBCPP_HAS_NO_INT128 + __int128_t __i128_; + __uint128_t __u128_; +# endif + float __float_; + double __double_; + long double __long_double_; + const _CharT* __const_char_type_ptr_; + basic_string_view<_CharT> __string_view_; + const void* __ptr_; + __handle __handle_; + }; + + // These constructors contain the exact storage type used. If adjustments are + // required, these will be done in __create_format_arg. + + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value() noexcept : __monostate_() {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(bool __value) noexcept : __boolean_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(_CharT __value) noexcept : __char_type_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(int __value) noexcept : __int_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(unsigned __value) noexcept : __unsigned_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(long long __value) noexcept : __long_long_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(unsigned long long __value) noexcept + : __unsigned_long_long_(__value) {} +# ifndef _LIBCPP_HAS_NO_INT128 + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__int128_t __value) noexcept : __i128_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__uint128_t __value) noexcept : __u128_(__value) {} +# endif + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(float __value) noexcept : __float_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(double __value) noexcept : __double_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(long double __value) noexcept : __long_double_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(const _CharT* __value) noexcept : __const_char_type_ptr_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(basic_string_view<_CharT> __value) noexcept + : __string_view_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(const void* __value) noexcept : __ptr_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__handle __value) noexcept : __handle_(__value) {} +}; + template <class _Context> class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_arg { public: @@ -131,146 +232,28 @@ private: // .format(declval<const T&>(), declval<Context&>()) // shall be well-formed when treated as an unevaluated operand. - template <class _Ctx, class... _Args> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT friend __format_arg_store<_Ctx, _Args...> - make_format_args(const _Args&...); - - template <class _Visitor, class _Ctx> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT friend decltype(auto) - visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx> __arg); - - union { - bool __boolean; - char_type __char_type; - int __int; - unsigned __unsigned; - long long __long_long; - unsigned long long __unsigned_long_long; -#ifndef _LIBCPP_HAS_NO_INT128 - __int128_t __i128; - __uint128_t __u128; -#endif - float __float; - double __double; - long double __long_double; - const char_type* __const_char_type_ptr; - basic_string_view<char_type> __string_view; - const void* __ptr; - handle __handle; - }; +public: + __basic_format_arg_value<_Context> __value_; __format::__arg_t __type_; - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(const bool& __v) noexcept - : __boolean(__v), __type_(__format::__arg_t::__boolean) {} - - template <class _Tp> - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(const _Tp& __v) noexcept - requires(same_as<_Tp, char_type> || - (same_as<_Tp, char> && same_as<char_type, wchar_t>)) - : __char_type(__v), __type_(__format::__arg_t::__char_type) {} - - template <__libcpp_signed_integer _Tp> - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(const _Tp& __v) noexcept { - if constexpr (sizeof(_Tp) <= sizeof(int)) { - __int = static_cast<int>(__v); - __type_ = __format::__arg_t::__int; - } else if constexpr (sizeof(_Tp) <= sizeof(long long)) { - __long_long = static_cast<long long>(__v); - __type_ = __format::__arg_t::__long_long; - } -#ifndef _LIBCPP_HAS_NO_INT128 - else if constexpr (sizeof(_Tp) == sizeof(__int128_t)) { - __i128 = __v; - __type_ = __format::__arg_t::__i128; - } -#endif - else - static_assert(sizeof(_Tp) == 0, "An unsupported signed integer was used"); - } - - template <__libcpp_unsigned_integer _Tp> - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(const _Tp& __v) noexcept { - if constexpr (sizeof(_Tp) <= sizeof(unsigned)) { - __unsigned = static_cast<unsigned>(__v); - __type_ = __format::__arg_t::__unsigned; - } else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) { - __unsigned_long_long = static_cast<unsigned long long>(__v); - __type_ = __format::__arg_t::__unsigned_long_long; - } -#ifndef _LIBCPP_HAS_NO_INT128 - else if constexpr (sizeof(_Tp) == sizeof(__int128_t)) { - __u128 = __v; - __type_ = __format::__arg_t::__u128; - } -#endif - else - static_assert(sizeof(_Tp) == 0, - "An unsupported unsigned integer was used"); - } - - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(float __v) noexcept - : __float(__v), __type_(__format::__arg_t::__float) {} - - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(double __v) noexcept - : __double(__v), __type_(__format::__arg_t::__double) {} - - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(long double __v) noexcept - : __long_double(__v), __type_(__format::__arg_t::__long_double) {} - - // Note not a 'noexcept' function. - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(const char_type* __s) - : __const_char_type_ptr(__s), - __type_(__format::__arg_t::__const_char_type_ptr) { - _LIBCPP_ASSERT(__s, "Used a nullptr argument to initialize a C-string"); - } - - template <class _Traits> - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg( - basic_string_view<char_type, _Traits> __s) noexcept - : __string_view{__s.data(), __s.size()}, - __type_(__format::__arg_t::__string_view) {} - - template <class _Traits, class _Allocator> - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg( - const basic_string<char_type, _Traits, _Allocator>& __s) noexcept - : __string_view{__s.data(), __s.size()}, - __type_(__format::__arg_t::__string_view) {} - - _LIBCPP_HIDE_FROM_ABI - explicit basic_format_arg(nullptr_t) noexcept - : __ptr(nullptr), __type_(__format::__arg_t::__ptr) {} - - 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 <__libcpp_not_integral _Tp> - _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(const _Tp& __v) noexcept - : __handle(__v), __type_(__format::__arg_t::__handle) {} + _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(__format::__arg_t __type, + __basic_format_arg_value<_Context> __value) noexcept + : __value_(__value), __type_(__type) {} }; 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_); + __handle_.__format_(__parse_ctx, __ctx, __handle_.__ptr_); } + _LIBCPP_HIDE_FROM_ABI explicit handle(typename __basic_format_arg_value<_Context>::__handle __handle) noexcept + : __handle_(__handle) {} + 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)); - }) {} + typename __basic_format_arg_value<_Context>::__handle __handle_; }; #endif //_LIBCPP_STD_VER > 17 diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/format_arg_store.h b/contrib/libs/cxxsupp/libcxx/include/__format/format_arg_store.h new file mode 100644 index 00000000000..4a3fcd4ff33 --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/include/__format/format_arg_store.h @@ -0,0 +1,251 @@ +// -*- 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_FORMAT_ARG_STORE_H +#define _LIBCPP___FORMAT_FORMAT_ARG_STORE_H + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#include <__config> +#include <__format/concepts.h> +#include <__format/format_arg.h> +#include <__iterator/data.h> +#include <__iterator/size.h> +#include <cstring> +#include <string> +#include <string_view> +#include <type_traits> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +namespace __format { + +/// \returns The @c __arg_t based on the type of the formatting argument. +/// +/// \pre \c __formattable<_Tp, typename _Context::char_type> +template <class _Context, class _Tp> +consteval __arg_t __determine_arg_t(); + +// Boolean +template <class, same_as<bool> _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__boolean; +} + +// Char +template <class _Context, same_as<typename _Context::char_type> _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__char_type; +} +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <class _Context, class _CharT> + requires(same_as<typename _Context::char_type, wchar_t> && same_as<_CharT, char>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__char_type; +} +# endif + +// Signed integers +template <class, __libcpp_signed_integer _Tp> +consteval __arg_t __determine_arg_t() { + if constexpr (sizeof(_Tp) <= sizeof(int)) + return __arg_t::__int; + else if constexpr (sizeof(_Tp) <= sizeof(long long)) + return __arg_t::__long_long; +# ifndef _LIBCPP_HAS_NO_INT128 + else if constexpr (sizeof(_Tp) == sizeof(__int128_t)) + return __arg_t::__i128; +# endif + else + static_assert(sizeof(_Tp) == 0, "an unsupported signed integer was used"); +} + +// Unsigned integers +template <class, __libcpp_unsigned_integer _Tp> +consteval __arg_t __determine_arg_t() { + if constexpr (sizeof(_Tp) <= sizeof(unsigned)) + return __arg_t::__unsigned; + else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) + return __arg_t::__unsigned_long_long; +# ifndef _LIBCPP_HAS_NO_INT128 + else if constexpr (sizeof(_Tp) == sizeof(__uint128_t)) + return __arg_t::__u128; +# endif + else + static_assert(sizeof(_Tp) == 0, "an unsupported unsigned integer was used"); +} + +// Floating-point +template <class, same_as<float> _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__float; +} +template <class, same_as<double> _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__double; +} +template <class, same_as<long double> _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__long_double; +} + +// Char pointer +template <class _Context, class _Tp> + requires(same_as<typename _Context::char_type*, _Tp> || same_as<const typename _Context::char_type*, _Tp>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__const_char_type_ptr; +} + +// Char array +template <class _Context, class _Tp> + requires(is_array_v<_Tp> && same_as<_Tp, typename _Context::char_type[extent_v<_Tp>]>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__string_view; +} + +// String view +template <class _Context, class _Tp> + requires(same_as<typename _Context::char_type, typename _Tp::value_type> && + same_as<_Tp, basic_string_view<typename _Tp::value_type, typename _Tp::traits_type>>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__string_view; +} + +// String +template <class _Context, class _Tp> + requires( + same_as<typename _Context::char_type, typename _Tp::value_type> && + same_as<_Tp, basic_string<typename _Tp::value_type, typename _Tp::traits_type, typename _Tp::allocator_type>>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__string_view; +} + +// Pointers +template <class, class _Ptr> + requires(same_as<_Ptr, void*> || same_as<_Ptr, const void*> || same_as<_Ptr, nullptr_t>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__ptr; +} + +// Handle +// +// Note this version can't be constrained avoiding ambiguous overloads. +// That means it can be instantiated by disabled formatters. To solve this, a +// constrained version for not formattable formatters is added. That overload +// is marked as deleted to fail creating a storage type for disabled formatters. +template <class _Context, class _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__handle; +} + +template <class _Context, class _Tp> + requires(!__formattable<_Tp, typename _Context::char_type>) +consteval __arg_t __determine_arg_t() = delete; + +template <class _Context, class _Tp> +_LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp&& __value) noexcept { + constexpr __arg_t __arg = __determine_arg_t<_Context, remove_cvref_t<_Tp>>(); + static_assert(__arg != __arg_t::__none); + + // Not all types can be used to directly initialize the + // __basic_format_arg_value. First handle all types needing adjustment, the + // final else requires no adjustment. + if constexpr (__arg == __arg_t::__char_type) + // On some platforms initializing a wchar_t from a char is a narrowing + // conversion. + return basic_format_arg<_Context>{__arg, static_cast<typename _Context::char_type>(__value)}; + else if constexpr (__arg == __arg_t::__int) + return basic_format_arg<_Context>{__arg, static_cast<int>(__value)}; + else if constexpr (__arg == __arg_t::__long_long) + return basic_format_arg<_Context>{__arg, static_cast<long long>(__value)}; + else if constexpr (__arg == __arg_t::__unsigned) + return basic_format_arg<_Context>{__arg, static_cast<unsigned>(__value)}; + else if constexpr (__arg == __arg_t::__unsigned_long_long) + return basic_format_arg<_Context>{__arg, static_cast<unsigned long long>(__value)}; + else if constexpr (__arg == __arg_t::__string_view) + // When the _Traits or _Allocator are different an implicit conversion will + // fail. + // + // Note since the input can be an array use the non-member functions to + // extract the constructor arguments. + return basic_format_arg<_Context>{ + __arg, basic_string_view<typename _Context::char_type>{_VSTD::data(__value), _VSTD::size(__value)}}; + else if constexpr (__arg == __arg_t::__ptr) + return basic_format_arg<_Context>{__arg, static_cast<const void*>(__value)}; + else if constexpr (__arg == __arg_t::__handle) + return basic_format_arg<_Context>{ + __arg, typename __basic_format_arg_value<_Context>::__handle{_VSTD::forward<_Tp>(__value)}}; + else + return basic_format_arg<_Context>{__arg, __value}; +} + +template <class _Context, class... _Args> +_LIBCPP_HIDE_FROM_ABI void __create_packed_storage(uint64_t& __types, __basic_format_arg_value<_Context>* __values, + _Args&&... __args) noexcept { + int __shift = 0; + ( + [&] { + basic_format_arg<_Context> __arg = __create_format_arg<_Context>(_VSTD::forward<_Args>(__args)); + if (__shift != 0) + __types |= static_cast<uint64_t>(__arg.__type_) << __shift; + else + // Assigns the initial value. + __types = static_cast<uint64_t>(__arg.__type_); + __shift += __packed_arg_t_bits; + *__values++ = __arg.__value_; + }(), + ...); +} + +template <class _Context, class... _Args> +_LIBCPP_HIDE_FROM_ABI void __store_basic_format_arg(basic_format_arg<_Context>* __data, _Args&&... __args) noexcept { + ([&] { *__data++ = __create_format_arg<_Context>(_VSTD::forward<_Args>(__args)); }(), ...); +} + +template <class _Context, size_t N> +struct __packed_format_arg_store { + __basic_format_arg_value<_Context> __values_[N]; + uint64_t __types_; +}; + +template <class _Context, size_t N> +struct __unpacked_format_arg_store { + basic_format_arg<_Context> __args_[N]; +}; + +} // namespace __format + +template <class _Context, class... _Args> +struct _LIBCPP_TEMPLATE_VIS __format_arg_store { + _LIBCPP_HIDE_FROM_ABI + __format_arg_store(_Args&&... __args) noexcept { + if constexpr (sizeof...(_Args) != 0) { + if constexpr (__format::__use_packed_format_arg_store(sizeof...(_Args))) + __format::__create_packed_storage(__storage.__types_, __storage.__values_, _VSTD::forward<_Args>(__args)...); + else + __format::__store_basic_format_arg<_Context>(__storage.__args_, _VSTD::forward<_Args>(__args)...); + } + } + + using _Storage = conditional_t<__format::__use_packed_format_arg_store(sizeof...(_Args)), + __format::__packed_format_arg_store<_Context, sizeof...(_Args)>, + __format::__unpacked_format_arg_store<_Context, sizeof...(_Args)>>; + + _Storage __storage; +}; + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMAT_ARG_STORE_H diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/format_args.h b/contrib/libs/cxxsupp/libcxx/include/__format/format_args.h index 40dde984006..d90dc50acbd 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/format_args.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/format_args.h @@ -12,8 +12,11 @@ #include <__availability> #include <__config> +#include <__format/format_arg.h> +#include <__format/format_arg_store.h> #include <__format/format_fwd.h> #include <cstddef> +#include <cstdint> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -26,29 +29,47 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Context> class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_args { public: - // TODO FMT Implement [format.args]/5 - // [Note 1: Implementations are encouraged to optimize the representation of - // basic_format_args for small number of formatting arguments by storing - // indices of type alternatives separately from values and packing the - // former. - end note] - // Note: Change __format_arg_store to use a built-in array. _LIBCPP_HIDE_FROM_ABI basic_format_args() noexcept = default; template <class... _Args> - _LIBCPP_HIDE_FROM_ABI basic_format_args( - const __format_arg_store<_Context, _Args...>& __store) noexcept - : __size_(sizeof...(_Args)), __data_(__store.__args.data()) {} + _LIBCPP_HIDE_FROM_ABI basic_format_args(const __format_arg_store<_Context, _Args...>& __store) noexcept + : __size_(sizeof...(_Args)) { + if constexpr (sizeof...(_Args) != 0) { + if constexpr (__format::__use_packed_format_arg_store(sizeof...(_Args))) { + __values_ = __store.__storage.__values_; + __types_ = __store.__storage.__types_; + } else + __args_ = __store.__storage.__args_; + } + } _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> get(size_t __id) const noexcept { - return __id < __size_ ? __data_[__id] : basic_format_arg<_Context>{}; + if (__id >= __size_) + return basic_format_arg<_Context>{}; + + if (__format::__use_packed_format_arg_store(__size_)) + return basic_format_arg<_Context>{__format::__get_packed_type(__types_, __id), __values_[__id]}; + + return __args_[__id]; } _LIBCPP_HIDE_FROM_ABI size_t __size() const noexcept { return __size_; } private: size_t __size_{0}; - const basic_format_arg<_Context>* __data_{nullptr}; + // [format.args]/5 + // [Note 1: Implementations are encouraged to optimize the representation of + // basic_format_args for small number of formatting arguments by storing + // indices of type alternatives separately from values and packing the + // former. - end note] + union { + struct { + const __basic_format_arg_value<_Context>* __values_; + uint64_t __types_; + }; + const basic_format_arg<_Context>* __args_; + }; }; #endif //_LIBCPP_STD_VER > 17 diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/format_fwd.h b/contrib/libs/cxxsupp/libcxx/include/__format/format_fwd.h index 0f2e9085f88..f7c72e21211 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/format_fwd.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/format_fwd.h @@ -12,6 +12,7 @@ #include <__availability> #include <__config> +#include <__iterator/concepts.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -24,8 +25,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Context> class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_arg; -template <class _Context, class... _Args> -struct _LIBCPP_TEMPLATE_VIS __format_arg_store; +template <class _OutIt, class _CharT> + requires output_iterator<_OutIt, const _CharT&> +class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_context; template <class _Tp, class _CharT = char> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter; diff --git a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_string.h b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_string.h index e78b43b8ca7..c687e3fd483 100644 --- a/contrib/libs/cxxsupp/libcxx/include/__format/formatter_string.h +++ b/contrib/libs/cxxsupp/libcxx/include/__format/formatter_string.h @@ -101,6 +101,18 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT } }; +// Formatter char[]. +template <__formatter::__char_type _CharT, size_t _Size> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<_CharT[_Size], _CharT> + : public __format_spec::__formatter_string<_CharT> { + static_assert(!is_const_v<_CharT>); + using _Base = __format_spec::__formatter_string<_CharT>; + + _LIBCPP_HIDE_FROM_ABI auto format(_CharT __str[_Size], auto& __ctx) -> decltype(__ctx.out()) { + return _Base::format(basic_string_view<_CharT>(__str, _Size), __ctx); + } +}; + // Formatter const char[]. template <__formatter::__char_type _CharT, size_t _Size> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT |