mirror of
				https://github.com/jart/cosmopolitan.git
				synced 2025-10-28 11:52:56 +00:00 
			
		
		
		
	Upgrade to 2022-era LLVM LIBCXX
This commit is contained in:
		
							parent
							
								
									2f4ca71f26
								
							
						
					
					
						commit
						8e68384e15
					
				
					 2078 changed files with 165657 additions and 65010 deletions
				
			
		
							
								
								
									
										643
									
								
								third_party/libcxx/__format/buffer.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										643
									
								
								third_party/libcxx/__format/buffer.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,643 @@ | |||
| // -*- 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_BUFFER_H | ||||
| #define _LIBCPP___FORMAT_BUFFER_H | ||||
| 
 | ||||
| #include <__algorithm/copy_n.h> | ||||
| #include <__algorithm/fill_n.h> | ||||
| #include <__algorithm/max.h> | ||||
| #include <__algorithm/min.h> | ||||
| #include <__algorithm/ranges_copy_n.h> | ||||
| #include <__algorithm/transform.h> | ||||
| #include <__algorithm/unwrap_iter.h> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/enable_insertable.h> | ||||
| #include <__format/format_to_n_result.h> | ||||
| #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 <__memory/addressof.h> | ||||
| #include <__memory/allocate_at_least.h> | ||||
| #include <__memory/allocator_traits.h> | ||||
| #include <__memory/construct_at.h> | ||||
| #include <__memory/ranges_construct_at.h> | ||||
| #include <__memory/uninitialized_algorithms.h> | ||||
| #include <__type_traits/add_pointer.h> | ||||
| #include <__type_traits/conditional.h> | ||||
| #include <__utility/exception_guard.h> | ||||
| #include <__utility/move.h> | ||||
| #include <cstddef> | ||||
| #include <string_view> | ||||
| 
 | ||||
| #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 >= 20 | ||||
| 
 | ||||
| namespace __format { | ||||
| 
 | ||||
| /// A "buffer" that handles writing to the proper iterator.
 | ||||
| ///
 | ||||
| /// This helper is used together with the @ref back_insert_iterator to offer
 | ||||
| /// type-erasure for the formatting functions. This reduces the number to
 | ||||
| /// template instantiations.
 | ||||
| template <__fmt_char_type _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS __output_buffer { | ||||
| public: | ||||
|   using value_type = _CharT; | ||||
| 
 | ||||
|   template <class _Tp> | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj) | ||||
|       : __ptr_(__ptr), | ||||
|         __capacity_(__capacity), | ||||
|         __flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }), | ||||
|         __obj_(__obj) {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) { | ||||
|     __ptr_ = __ptr; | ||||
|     __capacity_ = __capacity; | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; } | ||||
| 
 | ||||
|   // Used in std::back_insert_iterator.
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) { | ||||
|     __ptr_[__size_++] = __c; | ||||
| 
 | ||||
|     // Profiling showed flushing after adding is more efficient than flushing
 | ||||
|     // when entering the function.
 | ||||
|     if (__size_ == __capacity_) | ||||
|       __flush(); | ||||
|   } | ||||
| 
 | ||||
|   /// Copies the input __str to the buffer.
 | ||||
|   ///
 | ||||
|   /// Since some of the input is generated by std::to_chars, there needs to be a
 | ||||
|   /// conversion when _CharT is wchar_t.
 | ||||
|   template <__fmt_char_type _InCharT> | ||||
|   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) { | ||||
|     // When the underlying iterator is a simple iterator the __capacity_ is
 | ||||
|     // infinite. For a string or container back_inserter it isn't. This means
 | ||||
|     // adding a large string the the buffer can cause some overhead. In that
 | ||||
|     // case a better approach could be:
 | ||||
|     // - flush the buffer
 | ||||
|     // - container.append(__str.begin(), __str.end());
 | ||||
|     // The same holds true for the fill.
 | ||||
|     // For transform it might be slightly harder, however the use case for
 | ||||
|     // transform is slightly less common; it converts hexadecimal values to
 | ||||
|     // upper case. For integral these strings are short.
 | ||||
|     // TODO FMT Look at the improvements above.
 | ||||
|     size_t __n = __str.size(); | ||||
| 
 | ||||
|     __flush_on_overflow(__n); | ||||
|     if (__n <= __capacity_) { | ||||
|       _VSTD::copy_n(__str.data(), __n, _VSTD::addressof(__ptr_[__size_])); | ||||
|       __size_ += __n; | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     // The output doesn't fit in the internal buffer.
 | ||||
|     // Copy the data in "__capacity_" sized chunks.
 | ||||
|     _LIBCPP_ASSERT(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); | ||||
|     const _InCharT* __first = __str.data(); | ||||
|     do { | ||||
|       size_t __chunk = _VSTD::min(__n, __capacity_); | ||||
|       _VSTD::copy_n(__first, __chunk, _VSTD::addressof(__ptr_[__size_])); | ||||
|       __size_ = __chunk; | ||||
|       __first += __chunk; | ||||
|       __n -= __chunk; | ||||
|       __flush(); | ||||
|     } while (__n); | ||||
|   } | ||||
| 
 | ||||
|   /// A std::transform wrapper.
 | ||||
|   ///
 | ||||
|   /// Like @ref __copy it may need to do type conversion.
 | ||||
|   template <__fmt_char_type _InCharT, class _UnaryOperation> | ||||
|   _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) { | ||||
|     _LIBCPP_ASSERT(__first <= __last, "not a valid range"); | ||||
| 
 | ||||
|     size_t __n = static_cast<size_t>(__last - __first); | ||||
|     __flush_on_overflow(__n); | ||||
|     if (__n <= __capacity_) { | ||||
|       _VSTD::transform(__first, __last, _VSTD::addressof(__ptr_[__size_]), _VSTD::move(__operation)); | ||||
|       __size_ += __n; | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     // The output doesn't fit in the internal buffer.
 | ||||
|     // Transform the data in "__capacity_" sized chunks.
 | ||||
|     _LIBCPP_ASSERT(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); | ||||
|     do { | ||||
|       size_t __chunk = _VSTD::min(__n, __capacity_); | ||||
|       _VSTD::transform(__first, __first + __chunk, _VSTD::addressof(__ptr_[__size_]), __operation); | ||||
|       __size_ = __chunk; | ||||
|       __first += __chunk; | ||||
|       __n -= __chunk; | ||||
|       __flush(); | ||||
|     } while (__n); | ||||
|   } | ||||
| 
 | ||||
|   /// A \c fill_n wrapper.
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) { | ||||
|     __flush_on_overflow(__n); | ||||
|     if (__n <= __capacity_) { | ||||
|       _VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __n, __value); | ||||
|       __size_ += __n; | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     // The output doesn't fit in the internal buffer.
 | ||||
|     // Fill the buffer in "__capacity_" sized chunks.
 | ||||
|     _LIBCPP_ASSERT(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); | ||||
|     do { | ||||
|       size_t __chunk = _VSTD::min(__n, __capacity_); | ||||
|       _VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __chunk, __value); | ||||
|       __size_ = __chunk; | ||||
|       __n -= __chunk; | ||||
|       __flush(); | ||||
|     } while (__n); | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __flush() { | ||||
|     __flush_(__ptr_, __size_, __obj_); | ||||
|     __size_ = 0; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   _CharT* __ptr_; | ||||
|   size_t __capacity_; | ||||
|   size_t __size_{0}; | ||||
|   void (*__flush_)(_CharT*, size_t, void*); | ||||
|   void* __obj_; | ||||
| 
 | ||||
|   /// Flushes the buffer when the output operation would overflow the buffer.
 | ||||
|   ///
 | ||||
|   /// A simple approach for the overflow detection would be something along the
 | ||||
|   /// lines:
 | ||||
|   /// \code
 | ||||
|   /// // The internal buffer is large enough.
 | ||||
|   /// if (__n <= __capacity_) {
 | ||||
|   ///   // Flush when we really would overflow.
 | ||||
|   ///   if (__size_ + __n >= __capacity_)
 | ||||
|   ///     __flush();
 | ||||
|   ///   ...
 | ||||
|   /// }
 | ||||
|   /// \endcode
 | ||||
|   ///
 | ||||
|   /// This approach works for all cases but one:
 | ||||
|   /// A __format_to_n_buffer_base where \ref __enable_direct_output is true.
 | ||||
|   /// In that case the \ref __capacity_ of the buffer changes during the first
 | ||||
|   /// \ref __flush. During that operation the output buffer switches from its
 | ||||
|   /// __writer_ to its __storage_. The \ref __capacity_ of the former depends
 | ||||
|   /// on the value of n, of the latter is a fixed size. For example:
 | ||||
|   /// - a format_to_n call with a 10'000 char buffer,
 | ||||
|   /// - the buffer is filled with 9'500 chars,
 | ||||
|   /// - adding 1'000 elements would overflow the buffer so the buffer gets
 | ||||
|   ///   changed and the \ref __capacity_ decreases from 10'000 to
 | ||||
|   ///   __buffer_size (256 at the time of writing).
 | ||||
|   ///
 | ||||
|   /// This means that the \ref __flush for this class may need to copy a part of
 | ||||
|   /// the internal buffer to the proper output. In this example there will be
 | ||||
|   /// 500 characters that need this copy operation.
 | ||||
|   ///
 | ||||
|   /// Note it would be more efficient to write 500 chars directly and then swap
 | ||||
|   /// the buffers. This would make the code more complex and \ref format_to_n is
 | ||||
|   /// not the most common use case. Therefore the optimization isn't done.
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) { | ||||
|     if (__size_ + __n >= __capacity_) | ||||
|       __flush(); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| /// A storage using an internal buffer.
 | ||||
| ///
 | ||||
| /// This storage is used when writing a single element to the output iterator
 | ||||
| /// is expensive.
 | ||||
| template <__fmt_char_type _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS __internal_storage { | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; } | ||||
| 
 | ||||
|   static constexpr size_t __buffer_size = 256 / sizeof(_CharT); | ||||
| 
 | ||||
| private: | ||||
|   _CharT __buffer_[__buffer_size]; | ||||
| }; | ||||
| 
 | ||||
| /// A storage writing directly to the storage.
 | ||||
| ///
 | ||||
| /// This requires the storage to be a contiguous buffer of \a _CharT.
 | ||||
| /// Since the output is directly written to the underlying storage this class
 | ||||
| /// is just an empty class.
 | ||||
| template <__fmt_char_type _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS __direct_storage {}; | ||||
| 
 | ||||
| template <class _OutIt, class _CharT> | ||||
| concept __enable_direct_output = __fmt_char_type<_CharT> && | ||||
|     (same_as<_OutIt, _CharT*> | ||||
| #ifndef _LIBCPP_ENABLE_DEBUG_MODE | ||||
|      || same_as<_OutIt, __wrap_iter<_CharT*>> | ||||
| #endif | ||||
|     ); | ||||
| 
 | ||||
| /// Write policy for directly writing to the underlying output.
 | ||||
| template <class _OutIt, __fmt_char_type _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS __writer_direct { | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it) | ||||
|       : __out_it_(__out_it) {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) { | ||||
|     // _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator
 | ||||
|     // is adjusted.
 | ||||
|     __out_it_ += __n; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   _OutIt __out_it_; | ||||
| }; | ||||
| 
 | ||||
| /// Write policy for copying the buffer to the output.
 | ||||
| template <class _OutIt, __fmt_char_type _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS __writer_iterator { | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it) | ||||
|       : __out_it_{_VSTD::move(__out_it)} {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { | ||||
|     __out_it_ = std::ranges::copy_n(__ptr, __n, std::move(__out_it_)).out; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   _OutIt __out_it_; | ||||
| }; | ||||
| 
 | ||||
| /// Concept to see whether a \a _Container is insertable.
 | ||||
| ///
 | ||||
| /// The concept is used to validate whether multiple calls to a
 | ||||
| /// \ref back_insert_iterator can be replace by a call to \c _Container::insert.
 | ||||
| ///
 | ||||
| /// \note a \a _Container needs to opt-in to the concept by specializing
 | ||||
| /// \ref __enable_insertable.
 | ||||
| template <class _Container> | ||||
| concept __insertable = | ||||
|     __enable_insertable<_Container> && __fmt_char_type<typename _Container::value_type> && | ||||
|     requires(_Container& __t, add_pointer_t<typename _Container::value_type> __first, | ||||
|              add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); }; | ||||
| 
 | ||||
| /// Extract the container type of a \ref back_insert_iterator.
 | ||||
| template <class _It> | ||||
| struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container { | ||||
|   using type = void; | ||||
| }; | ||||
| 
 | ||||
| template <__insertable _Container> | ||||
| struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> { | ||||
|   using type = _Container; | ||||
| }; | ||||
| 
 | ||||
| /// Write policy for inserting the buffer in a container.
 | ||||
| template <class _Container> | ||||
| class _LIBCPP_TEMPLATE_VIS __writer_container { | ||||
| public: | ||||
|   using _CharT = typename _Container::value_type; | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it) | ||||
|       : __container_{__out_it.__get_container()} {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { | ||||
|     __container_->insert(__container_->end(), __ptr, __ptr + __n); | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   _Container* __container_; | ||||
| }; | ||||
| 
 | ||||
| /// Selects the type of the writer used for the output iterator.
 | ||||
| template <class _OutIt, class _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS __writer_selector { | ||||
|   using _Container = typename __back_insert_iterator_container<_OutIt>::type; | ||||
| 
 | ||||
| public: | ||||
|   using type = conditional_t<!same_as<_Container, void>, __writer_container<_Container>, | ||||
|                              conditional_t<__enable_direct_output<_OutIt, _CharT>, __writer_direct<_OutIt, _CharT>, | ||||
|                                            __writer_iterator<_OutIt, _CharT>>>; | ||||
| }; | ||||
| 
 | ||||
| /// The generic formatting buffer.
 | ||||
| template <class _OutIt, __fmt_char_type _CharT> | ||||
| requires(output_iterator<_OutIt, const _CharT&>) class _LIBCPP_TEMPLATE_VIS | ||||
|     __format_buffer { | ||||
|   using _Storage = | ||||
|       conditional_t<__enable_direct_output<_OutIt, _CharT>, | ||||
|                     __direct_storage<_CharT>, __internal_storage<_CharT>>; | ||||
| 
 | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) | ||||
|     requires(same_as<_Storage, __internal_storage<_CharT>>) | ||||
|       : __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(_VSTD::move(__out_it)) {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) requires( | ||||
|       same_as<_Storage, __direct_storage<_CharT>>) | ||||
|       : __output_(_VSTD::__unwrap_iter(__out_it), size_t(-1), this), | ||||
|         __writer_(_VSTD::move(__out_it)) {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { | ||||
|     __output_.__flush(); | ||||
|     return _VSTD::move(__writer_).__out_it(); | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_; | ||||
|   __output_buffer<_CharT> __output_; | ||||
|   typename __writer_selector<_OutIt, _CharT>::type __writer_; | ||||
| }; | ||||
| 
 | ||||
| /// A buffer that counts the number of insertions.
 | ||||
| ///
 | ||||
| /// Since \ref formatted_size only needs to know the size, the output itself is
 | ||||
| /// discarded.
 | ||||
| template <__fmt_char_type _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer { | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI size_t __result() && { | ||||
|     __output_.__flush(); | ||||
|     return __size_; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   __internal_storage<_CharT> __storage_; | ||||
|   __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this}; | ||||
|   size_t __size_{0}; | ||||
| }; | ||||
| 
 | ||||
| /// The base of a buffer that counts and limits the number of insertions.
 | ||||
| template <class _OutIt, __fmt_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 __max_size) | ||||
|       : __writer_(_VSTD::move(__out_it)), __max_size_(_VSTD::max(_Size(0), __max_size)) {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { | ||||
|     if (_Size(__size_) <= __max_size_) | ||||
|       __writer_.__flush(__ptr, _VSTD::min(_Size(__n), __max_size_ - __size_)); | ||||
|     __size_ += __n; | ||||
|   } | ||||
| 
 | ||||
| protected: | ||||
|   __internal_storage<_CharT> __storage_; | ||||
|   __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this}; | ||||
|   typename __writer_selector<_OutIt, _CharT>::type __writer_; | ||||
| 
 | ||||
|   _Size __max_size_; | ||||
|   _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 to the direct writer so it will not
 | ||||
| /// exceed the maximum number of code units.
 | ||||
| template <class _OutIt, __fmt_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 __max_size) | ||||
|       : __output_(_VSTD::__unwrap_iter(__out_it), __max_size, this), | ||||
|         __writer_(_VSTD::move(__out_it)), | ||||
|         __max_size_(__max_size) { | ||||
|     if (__max_size <= 0) [[unlikely]] | ||||
|       __output_.__reset(__storage_.__begin(), __storage_.__buffer_size); | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { | ||||
|     // A __flush to the direct writer happens in the following 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.
 | ||||
|     // - Like above, but the next "mass write" operation would overflow the
 | ||||
|     //   buffer. In that case the buffer is pre-emptively switched. The still
 | ||||
|     //   valid code units will be written separately.
 | ||||
|     // - 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 __max_size <= 0 the constructor already switched the buffers.
 | ||||
|     if (__size_ == 0 && __ptr != __storage_.__begin()) { | ||||
|       __writer_.__flush(__ptr, __n); | ||||
|       __output_.__reset(__storage_.__begin(), __storage_.__buffer_size); | ||||
|     } else if (__size_ < __max_size_) { | ||||
|       // Copies a part of the internal buffer to the output up to n characters.
 | ||||
|       // See __output_buffer<_CharT>::__flush_on_overflow for more information.
 | ||||
|       _Size __s = _VSTD::min(_Size(__n), __max_size_ - __size_); | ||||
|       std::copy_n(__ptr, __s, __writer_.__out_it()); | ||||
|       __writer_.__flush(__ptr, __s); | ||||
|     } | ||||
| 
 | ||||
|     __size_ += __n; | ||||
|   } | ||||
| 
 | ||||
| protected: | ||||
|   __internal_storage<_CharT> __storage_; | ||||
|   __output_buffer<_CharT> __output_; | ||||
|   __writer_direct<_OutIt, _CharT> __writer_; | ||||
| 
 | ||||
|   _Size __max_size_; | ||||
|   _Size __size_{0}; | ||||
| }; | ||||
| 
 | ||||
| /// The buffer that counts and limits the number of insertions.
 | ||||
| template <class _OutIt, __fmt_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 __max_size) | ||||
|       : _Base(_VSTD::move(__out_it), __max_size) {} | ||||
|   _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_it(), this->__size_}; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // A dynamically growing buffer intended to be used for retargeting a context.
 | ||||
| //
 | ||||
| // P2286 Formatting ranges adds range formatting support. It allows the user to
 | ||||
| // specify the minimum width for the entire formatted range.  The width of the
 | ||||
| // range is not known until the range is formatted. Formatting is done to an
 | ||||
| // output_iterator so there's no guarantee it would be possible to add the fill
 | ||||
| // to the front of the output. Instead the range is formatted to a temporary
 | ||||
| // buffer and that buffer is formatted as a string.
 | ||||
| //
 | ||||
| // There is an issue with that approach, the format context used in
 | ||||
| // std::formatter<T>::format contains the output iterator used as part of its
 | ||||
| // type. So using this output iterator means there needs to be a new format
 | ||||
| // context and the format arguments need to be retargeted to the new context.
 | ||||
| // This retargeting is done by a basic_format_context specialized for the
 | ||||
| // __iterator of this container.
 | ||||
| //
 | ||||
| // This class uses its own buffer management, since using vector
 | ||||
| // would lead to a circular include with formatter for vector<bool>.
 | ||||
| template <__fmt_char_type _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS __retarget_buffer { | ||||
|   using _Alloc = allocator<_CharT>; | ||||
| 
 | ||||
| public: | ||||
|   using value_type = _CharT; | ||||
| 
 | ||||
|   struct __iterator { | ||||
|     using difference_type = ptrdiff_t; | ||||
| 
 | ||||
|     _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer) | ||||
|         : __buffer_(std::addressof(__buffer)) {} | ||||
|     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) { | ||||
|       __buffer_->push_back(__c); | ||||
|       return *this; | ||||
|     } | ||||
|     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) { | ||||
|       __buffer_->push_back(__c); | ||||
|       return *this; | ||||
|     } | ||||
| 
 | ||||
|     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; } | ||||
|     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; } | ||||
|     _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; } | ||||
|     __retarget_buffer* __buffer_; | ||||
|   }; | ||||
| 
 | ||||
|   __retarget_buffer(const __retarget_buffer&)            = delete; | ||||
|   __retarget_buffer& operator=(const __retarget_buffer&) = delete; | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) { | ||||
|     auto __result = std::__allocate_at_least(__alloc_, __size_hint ? __size_hint : 256 / sizeof(_CharT)); | ||||
|     __ptr_        = __result.ptr; | ||||
|     __capacity_   = __result.count; | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() { | ||||
|     ranges::destroy_n(__ptr_, __size_); | ||||
|     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_); | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) { | ||||
|     std::construct_at(__ptr_ + __size_, __c); | ||||
|     ++__size_; | ||||
| 
 | ||||
|     if (__size_ == __capacity_) | ||||
|       __grow_buffer(); | ||||
|   } | ||||
| 
 | ||||
|   template <__fmt_char_type _InCharT> | ||||
|   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) { | ||||
|     size_t __n = __str.size(); | ||||
|     if (__size_ + __n >= __capacity_) | ||||
|       // Push_back requires the buffer to have room for at least one character.
 | ||||
|       __grow_buffer(__size_ + __n + 1); | ||||
| 
 | ||||
|     std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_); | ||||
|     __size_ += __n; | ||||
|   } | ||||
| 
 | ||||
|   template <__fmt_char_type _InCharT, class _UnaryOperation> | ||||
|   _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) { | ||||
|     _LIBCPP_ASSERT(__first <= __last, "not a valid range"); | ||||
| 
 | ||||
|     size_t __n = static_cast<size_t>(__last - __first); | ||||
|     if (__size_ + __n >= __capacity_) | ||||
|       // Push_back requires the buffer to have room for at least one character.
 | ||||
|       __grow_buffer(__size_ + __n + 1); | ||||
| 
 | ||||
|     std::uninitialized_default_construct_n(__ptr_ + __size_, __n); | ||||
|     std::transform(__first, __last, __ptr_ + __size_, std::move(__operation)); | ||||
|     __size_ += __n; | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) { | ||||
|     if (__size_ + __n >= __capacity_) | ||||
|       // Push_back requires the buffer to have room for at least one character.
 | ||||
|       __grow_buffer(__size_ + __n + 1); | ||||
| 
 | ||||
|     std::uninitialized_fill_n(__ptr_ + __size_, __n, __value); | ||||
|     __size_ += __n; | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; } | ||||
| 
 | ||||
| private: | ||||
|   _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) { | ||||
|     _LIBCPP_ASSERT(__capacity > __capacity_, "the buffer must grow"); | ||||
|     auto __result = std::__allocate_at_least(__alloc_, __capacity); | ||||
|     auto __guard  = std::__make_exception_guard([&] { | ||||
|       allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count); | ||||
|     }); | ||||
|     // This shouldn't throw, but just to be safe. Not that at -O1 this
 | ||||
|     // guard is optimized away so there is no runtime overhead.
 | ||||
|     std::uninitialized_move_n(__ptr_, __size_, __result.ptr); | ||||
|     __guard.__complete(); | ||||
|     ranges::destroy_n(__ptr_, __size_); | ||||
|     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_); | ||||
| 
 | ||||
|     __ptr_      = __result.ptr; | ||||
|     __capacity_ = __result.count; | ||||
|   } | ||||
|   _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_; | ||||
|   _CharT* __ptr_; | ||||
|   size_t __capacity_; | ||||
|   size_t __size_{0}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace __format
 | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| _LIBCPP_POP_MACROS | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_BUFFER_H
 | ||||
							
								
								
									
										76
									
								
								third_party/libcxx/__format/concepts.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								third_party/libcxx/__format/concepts.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | |||
| // -*- 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/is_specialization.h> | ||||
| #include <__utility/pair.h> | ||||
| #include <tuple> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| /// The character type specializations of \ref formatter.
 | ||||
| template <class _CharT> | ||||
| concept __fmt_char_type = | ||||
|     same_as<_CharT, char> | ||||
| #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
|     || same_as<_CharT, wchar_t> | ||||
| #  endif | ||||
|     ; | ||||
| 
 | ||||
| // 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*; | ||||
| 
 | ||||
| template <class _Tp, class _CharT> | ||||
| concept __formattable = | ||||
|     (semiregular<formatter<remove_cvref_t<_Tp>, _CharT>>) && | ||||
|     requires(formatter<remove_cvref_t<_Tp>, _CharT> __f, | ||||
|              const 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>>; | ||||
|     }; | ||||
| 
 | ||||
| #  if _LIBCPP_STD_VER >= 23 | ||||
| template <class _Tp, class _CharT> | ||||
| concept formattable = __formattable<_Tp, _CharT>; | ||||
| 
 | ||||
| // [tuple.like] defines a tuple-like exposition only concept. This concept is
 | ||||
| // not related to that. Therefore it uses a different name for the concept.
 | ||||
| //
 | ||||
| // TODO FMT Add a test to validate we fail when using that concept after P2165
 | ||||
| // has been implemented.
 | ||||
| template <class _Tp> | ||||
| concept __fmt_pair_like = | ||||
|     __is_specialization_v<_Tp, pair> || (__is_specialization_v<_Tp, tuple> && tuple_size_v<_Tp> == 2); | ||||
| 
 | ||||
| #  endif //_LIBCPP_STD_VER >= 23
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_CONCEPTS_H
 | ||||
							
								
								
									
										71
									
								
								third_party/libcxx/__format/container_adaptor.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								third_party/libcxx/__format/container_adaptor.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| // -*- 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_CONTAINER_ADAPTOR_H | ||||
| #define _LIBCPP___FORMAT_CONTAINER_ADAPTOR_H | ||||
| 
 | ||||
| #include <__availability> | ||||
| #include <__config> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/range_default_formatter.h> | ||||
| #include <__ranges/all.h> | ||||
| #include <__ranges/ref_view.h> | ||||
| #include <__type_traits/is_const.h> | ||||
| #include <__type_traits/maybe_const.h> | ||||
| #include <queue> | ||||
| #include <stack> | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 23 | ||||
| 
 | ||||
| // [container.adaptors.format] only specifies the library should provide the
 | ||||
| // formatter specializations, not which header should provide them.
 | ||||
| // Since <format> includes a lot of headers, add these headers here instead of
 | ||||
| // adding more dependencies like, locale, optinal, string, tuple, etc. to the
 | ||||
| // adaptor headers. To use the format functions users already include <format>.
 | ||||
| 
 | ||||
| template <class _Adaptor, class _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __formatter_container_adaptor { | ||||
| private: | ||||
|   using __maybe_const_container = __fmt_maybe_const<typename _Adaptor::container_type, _CharT>; | ||||
|   using __maybe_const_adaptor   = __maybe_const<is_const_v<__maybe_const_container>, _Adaptor>; | ||||
|   formatter<ranges::ref_view<__maybe_const_container>, _CharT> __underlying_; | ||||
| 
 | ||||
| public: | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     return __underlying_.parse(__ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
|   format(__maybe_const_adaptor& __adaptor, _FormatContext& __ctx) const { | ||||
|     return __underlying_.format(__adaptor.__get_container(), __ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <class _CharT, class _Tp, formattable<_CharT> _Container> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<queue<_Tp, _Container>, _CharT> | ||||
|     : public __formatter_container_adaptor<queue<_Tp, _Container>, _CharT> {}; | ||||
| 
 | ||||
| template <class _CharT, class _Tp, class _Container, class _Compare> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<priority_queue<_Tp, _Container, _Compare>, _CharT> | ||||
|     : public __formatter_container_adaptor<priority_queue<_Tp, _Container, _Compare>, _CharT> {}; | ||||
| 
 | ||||
| template <class _CharT, class _Tp, formattable<_CharT> _Container> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<stack<_Tp, _Container>, _CharT> | ||||
|     : public __formatter_container_adaptor<stack<_Tp, _Container>, _CharT> {}; | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 23
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_CONTAINER_ADAPTOR_H
 | ||||
							
								
								
									
										35
									
								
								third_party/libcxx/__format/enable_insertable.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								third_party/libcxx/__format/enable_insertable.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | |||
| // -*- 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_ENABLE_INSERTABLE_H | ||||
| #define _LIBCPP___FORMAT_ENABLE_INSERTABLE_H | ||||
| 
 | ||||
| #include <__config> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| namespace __format { | ||||
| 
 | ||||
| /// Opt-in to enable \ref __insertable for a \a _Container.
 | ||||
| template <class _Container> | ||||
| inline constexpr bool __enable_insertable = false; | ||||
| 
 | ||||
| } // namespace __format
 | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_ENABLE_INSERTABLE_H
 | ||||
							
								
								
									
										1038
									
								
								third_party/libcxx/__format/escaped_output_table.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1038
									
								
								third_party/libcxx/__format/escaped_output_table.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										1661
									
								
								third_party/libcxx/__format/extended_grapheme_cluster_table.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1661
									
								
								third_party/libcxx/__format/extended_grapheme_cluster_table.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										305
									
								
								third_party/libcxx/__format/format_arg.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								third_party/libcxx/__format/format_arg.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,305 @@ | |||
| // -*- 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_H | ||||
| #define _LIBCPP___FORMAT_FORMAT_ARG_H | ||||
| 
 | ||||
| #include <__assert> | ||||
| #include <__concepts/arithmetic.h> | ||||
| #include <__config> | ||||
| #include <__format/format_error.h> | ||||
| #include <__format/format_fwd.h> | ||||
| #include <__format/format_parse_context.h> | ||||
| #include <__functional/invoke.h> | ||||
| #include <__memory/addressof.h> | ||||
| #include <__type_traits/conditional.h> | ||||
| #include <__type_traits/is_const.h> | ||||
| #include <__utility/declval.h> | ||||
| #include <__utility/forward.h> | ||||
| #include <__utility/unreachable.h> | ||||
| #include <__variant/monostate.h> | ||||
| #include <string> | ||||
| #include <string_view> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| namespace __format { | ||||
| /// The type stored in @ref basic_format_arg.
 | ||||
| ///
 | ||||
| /// @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.
 | ||||
| ///
 | ||||
| /// @note Some members of this enum are an extension. These extensions need
 | ||||
| /// special behaviour in visit_format_arg. There they need to be wrapped in a
 | ||||
| /// handle to satisfy the user observable behaviour. The internal function
 | ||||
| /// __visit_format_arg doesn't do this wrapping. So in the format functions
 | ||||
| /// this function is used to avoid unneeded overhead.
 | ||||
| enum class _LIBCPP_ENUM_VIS __arg_t : uint8_t { | ||||
|   __none, | ||||
|   __boolean, | ||||
|   __char_type, | ||||
|   __int, | ||||
|   __long_long, | ||||
|   __i128, // extension
 | ||||
|   __unsigned, | ||||
|   __unsigned_long_long, | ||||
|   __u128, // extension
 | ||||
|   __float, | ||||
|   __double, | ||||
|   __long_double, | ||||
|   __const_char_type_ptr, | ||||
|   __string_view, | ||||
|   __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
 | ||||
| 
 | ||||
| // This function is not user obervable, so it can directly use the non-standard
 | ||||
| // types of the "variant". See __arg_t for more details.
 | ||||
| template <class _Visitor, class _Context> | ||||
| _LIBCPP_HIDE_FROM_ABI 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), __arg.__value_.__monostate_); | ||||
|   case __format::__arg_t::__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.__value_.__char_type_); | ||||
|   case __format::__arg_t::__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.__value_.__long_long_); | ||||
|   case __format::__arg_t::__i128: | ||||
| #  ifndef _LIBCPP_HAS_NO_INT128 | ||||
|     return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__i128_); | ||||
| #  else | ||||
|     __libcpp_unreachable(); | ||||
| #  endif | ||||
|   case __format::__arg_t::__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.__value_.__unsigned_long_long_); | ||||
|   case __format::__arg_t::__u128: | ||||
| #  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.__value_.__float_); | ||||
|   case __format::__arg_t::__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.__value_.__long_double_); | ||||
|   case __format::__arg_t::__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.__value_.__string_view_); | ||||
|   case __format::__arg_t::__ptr: | ||||
|     return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__ptr_); | ||||
|   case __format::__arg_t::__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(_Tp&& __v) noexcept | ||||
|         : __ptr_(_VSTD::addressof(__v)), | ||||
|           __format_([](basic_format_parse_context<_CharT>& __parse_ctx, _Context& __ctx, const void* __ptr) { | ||||
|             using _Dp = remove_cvref_t<_Tp>; | ||||
|             using _Formatter = typename _Context::template formatter_type<_Dp>; | ||||
|             constexpr bool __const_formattable = | ||||
|                 requires { _Formatter().format(std::declval<const _Dp&>(), std::declval<_Context&>()); }; | ||||
|             using _Qp = conditional_t<__const_formattable, const _Dp, _Dp>; | ||||
| 
 | ||||
|             static_assert(__const_formattable || !is_const_v<remove_reference_t<_Tp>>, "Mandated by [format.arg]/18"); | ||||
| 
 | ||||
|             _Formatter __f; | ||||
|             __parse_ctx.advance_to(__f.parse(__parse_ctx)); | ||||
|             __ctx.advance_to(__f.format(*const_cast<_Qp*>(static_cast<const _Dp*>(__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 | ||||
|       // TODO FMT Investigate why it doesn't work without the forward.
 | ||||
|       : __handle_(std::forward<__handle>(__value)) {} | ||||
| }; | ||||
| 
 | ||||
| template <class _Context> | ||||
| class _LIBCPP_TEMPLATE_VIS basic_format_arg { | ||||
| public: | ||||
|   class _LIBCPP_TEMPLATE_VIS handle; | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI basic_format_arg() noexcept | ||||
|       : __type_{__format::__arg_t::__none} {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { | ||||
|     return __type_ != __format::__arg_t::__none; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   using char_type = typename _Context::char_type; | ||||
| 
 | ||||
|   // TODO FMT Implement constrain [format.arg]/4
 | ||||
|   // Constraints: The template specialization
 | ||||
|   //   typename Context::template formatter_type<T>
 | ||||
|   // meets the Formatter requirements ([formatter.requirements]).  The extent
 | ||||
|   // to which an implementation determines that the specialization meets the
 | ||||
|   // Formatter requirements is unspecified, except that as a minimum the
 | ||||
|   // expression
 | ||||
|   //   typename Context::template formatter_type<T>()
 | ||||
|   //    .format(declval<const T&>(), declval<Context&>())
 | ||||
|   // shall be well-formed when treated as an unevaluated operand.
 | ||||
| 
 | ||||
| public: | ||||
|   __basic_format_arg_value<_Context> __value_; | ||||
|   __format::__arg_t __type_; | ||||
| 
 | ||||
|   _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 { | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI | ||||
|   void format(basic_format_parse_context<char_type>& __parse_ctx, _Context& __ctx) const { | ||||
|     __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: | ||||
|   typename __basic_format_arg_value<_Context>::__handle& __handle_; | ||||
| }; | ||||
| 
 | ||||
| // This function is user facing, so it must wrap the non-standard types of
 | ||||
| // the "variant" in a handle to stay conforming. See __arg_t for more details.
 | ||||
| template <class _Visitor, class _Context> | ||||
| _LIBCPP_HIDE_FROM_ABI decltype(auto) | ||||
| visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { | ||||
|   switch (__arg.__type_) { | ||||
| #  ifndef _LIBCPP_HAS_NO_INT128 | ||||
|   case __format::__arg_t::__i128: { | ||||
|     typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_}; | ||||
|     return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h}); | ||||
|   } | ||||
| 
 | ||||
|   case __format::__arg_t::__u128: { | ||||
|     typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_}; | ||||
|     return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h}); | ||||
|   } | ||||
| #  endif | ||||
|   default: | ||||
|     return _VSTD::__visit_format_arg(_VSTD::forward<_Visitor>(__vis), __arg); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMAT_ARG_H
 | ||||
							
								
								
									
										254
									
								
								third_party/libcxx/__format/format_arg_store.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								third_party/libcxx/__format/format_arg_store.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,254 @@ | |||
| // -*- 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 | ||||
| 
 | ||||
| #include <__concepts/arithmetic.h> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/format_arg.h> | ||||
| #include <__type_traits/conditional.h> | ||||
| #include <__type_traits/extent.h> | ||||
| #include <__type_traits/is_same.h> | ||||
| #include <__utility/forward.h> | ||||
| #include <string> | ||||
| #include <string_view> | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| 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.
 | ||||
| template <class _Context, class _Tp> | ||||
| consteval __arg_t __determine_arg_t() { | ||||
|   return __arg_t::__handle; | ||||
| } | ||||
| 
 | ||||
| // The overload for not formattable types allows triggering the static
 | ||||
| // assertion below.
 | ||||
| template <class _Context, class _Tp> | ||||
|   requires(!__formattable<_Tp, typename _Context::char_type>) | ||||
| consteval __arg_t __determine_arg_t() { | ||||
|   return __arg_t::__none; | ||||
| } | ||||
| 
 | ||||
| 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, "the supplied type is not formattable"); | ||||
| 
 | ||||
|   // 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) | ||||
|     // Using std::size on a character array will add the NUL-terminator to the size.
 | ||||
|     if constexpr (is_array_v<remove_cvref_t<_Tp>>) | ||||
|       return basic_format_arg<_Context>{ | ||||
|           __arg, basic_string_view<typename _Context::char_type>{__value, extent_v<remove_cvref_t<_Tp>> - 1}}; | ||||
|     else | ||||
|       // When the _Traits or _Allocator are different an implicit conversion will
 | ||||
|       // fail.
 | ||||
|       return basic_format_arg<_Context>{ | ||||
|           __arg, basic_string_view<typename _Context::char_type>{__value.data(), __value.size()}}; | ||||
|   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 = __format::__create_format_arg<_Context>(__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++ = __format::__create_format_arg<_Context>(__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_, __args...); | ||||
|       else | ||||
|         __format::__store_basic_format_arg<_Context>(__storage.__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 >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMAT_ARG_STORE_H
 | ||||
							
								
								
									
										82
									
								
								third_party/libcxx/__format/format_args.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								third_party/libcxx/__format/format_args.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | |||
| // -*- 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_ARGS_H | ||||
| #define _LIBCPP___FORMAT_FORMAT_ARGS_H | ||||
| 
 | ||||
| #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 | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| template <class _Context> | ||||
| class _LIBCPP_TEMPLATE_VIS basic_format_args { | ||||
| public: | ||||
|   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)) { | ||||
|     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 { | ||||
|     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}; | ||||
|   // [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_; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| template <class _Context, class... _Args> | ||||
| basic_format_args(__format_arg_store<_Context, _Args...>) -> basic_format_args<_Context>; | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMAT_ARGS_H
 | ||||
							
								
								
									
										222
									
								
								third_party/libcxx/__format/format_context.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								third_party/libcxx/__format/format_context.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,222 @@ | |||
| // -*- 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_CONTEXT_H | ||||
| #define _LIBCPP___FORMAT_FORMAT_CONTEXT_H | ||||
| 
 | ||||
| #include <__availability> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__format/buffer.h> | ||||
| #include <__format/format_arg.h> | ||||
| #include <__format/format_arg_store.h> | ||||
| #include <__format/format_args.h> | ||||
| #include <__format/format_error.h> | ||||
| #include <__format/format_fwd.h> | ||||
| #include <__iterator/back_insert_iterator.h> | ||||
| #include <__iterator/concepts.h> | ||||
| #include <__memory/addressof.h> | ||||
| #include <__utility/move.h> | ||||
| #include <__variant/monostate.h> | ||||
| #include <cstddef> | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
| #include <locale> | ||||
| #include <optional> | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| template <class _OutIt, class _CharT> | ||||
| requires output_iterator<_OutIt, const _CharT&> | ||||
| class _LIBCPP_TEMPLATE_VIS basic_format_context; | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
| /**
 | ||||
|  * Helper to create a basic_format_context. | ||||
|  * | ||||
|  * This is needed since the constructor is private. | ||||
|  */ | ||||
| template <class _OutIt, class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT> | ||||
| __format_context_create( | ||||
|     _OutIt __out_it, | ||||
|     basic_format_args<basic_format_context<_OutIt, _CharT>> __args, | ||||
|     optional<_VSTD::locale>&& __loc = nullopt) { | ||||
|   return _VSTD::basic_format_context(_VSTD::move(__out_it), __args, _VSTD::move(__loc)); | ||||
| } | ||||
| #else | ||||
| template <class _OutIt, class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT> | ||||
| __format_context_create( | ||||
|     _OutIt __out_it, | ||||
|     basic_format_args<basic_format_context<_OutIt, _CharT>> __args) { | ||||
|   return _VSTD::basic_format_context(_VSTD::move(__out_it), __args); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| using format_context = | ||||
|     basic_format_context<back_insert_iterator<__format::__output_buffer<char>>, | ||||
|                          char>; | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| using wformat_context = basic_format_context< | ||||
|     back_insert_iterator<__format::__output_buffer<wchar_t>>, wchar_t>; | ||||
| #endif | ||||
| 
 | ||||
| template <class _OutIt, class _CharT> | ||||
| requires output_iterator<_OutIt, const _CharT&> | ||||
| class | ||||
|     // clang-format off
 | ||||
|     _LIBCPP_TEMPLATE_VIS | ||||
|     _LIBCPP_PREFERRED_NAME(format_context) | ||||
|     _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wformat_context)) | ||||
|     // clang-format on
 | ||||
|     basic_format_context { | ||||
| public: | ||||
|   using iterator = _OutIt; | ||||
|   using char_type = _CharT; | ||||
|   template <class _Tp> | ||||
|   using formatter_type = formatter<_Tp, _CharT>; | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> | ||||
|   arg(size_t __id) const noexcept { | ||||
|     return __args_.get(__id); | ||||
|   } | ||||
| #ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
|   _LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() { | ||||
|     if (!__loc_) | ||||
|       __loc_ = _VSTD::locale{}; | ||||
|     return *__loc_; | ||||
|   } | ||||
| #endif | ||||
|   _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } | ||||
|   _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } | ||||
| 
 | ||||
| private: | ||||
|   iterator __out_it_; | ||||
|   basic_format_args<basic_format_context> __args_; | ||||
| #ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
| 
 | ||||
|   // The Standard doesn't specify how the locale is stored.
 | ||||
|   // [format.context]/6
 | ||||
|   // std::locale locale();
 | ||||
|   //   Returns: The locale passed to the formatting function if the latter
 | ||||
|   //   takes one, and std::locale() otherwise.
 | ||||
|   // This is done by storing the locale of the constructor in this optional. If
 | ||||
|   // locale() is called and the optional has no value the value will be created.
 | ||||
|   // This allows the implementation to lazily create the locale.
 | ||||
|   // TODO FMT Validate whether lazy creation is the best solution.
 | ||||
|   optional<_VSTD::locale> __loc_; | ||||
| 
 | ||||
|   template <class __OutIt, class __CharT> | ||||
|   friend _LIBCPP_HIDE_FROM_ABI basic_format_context<__OutIt, __CharT> | ||||
|   __format_context_create(__OutIt, basic_format_args<basic_format_context<__OutIt, __CharT>>, | ||||
|                           optional<_VSTD::locale>&&); | ||||
| 
 | ||||
|   // Note: the Standard doesn't specify the required constructors.
 | ||||
|   _LIBCPP_HIDE_FROM_ABI | ||||
|   explicit basic_format_context(_OutIt __out_it, | ||||
|                                 basic_format_args<basic_format_context> __args, | ||||
|                                 optional<_VSTD::locale>&& __loc) | ||||
|       : __out_it_(_VSTD::move(__out_it)), __args_(__args), | ||||
|         __loc_(_VSTD::move(__loc)) {} | ||||
| #else | ||||
|   template <class __OutIt, class __CharT> | ||||
|   friend _LIBCPP_HIDE_FROM_ABI basic_format_context<__OutIt, __CharT> | ||||
|       __format_context_create(__OutIt, basic_format_args<basic_format_context<__OutIt, __CharT>>); | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI | ||||
|   explicit basic_format_context(_OutIt __out_it, | ||||
|                                 basic_format_args<basic_format_context> __args) | ||||
|       : __out_it_(_VSTD::move(__out_it)), __args_(__args) {} | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| // A specialization for __retarget_buffer
 | ||||
| //
 | ||||
| // See __retarget_buffer for the motivation for this specialization.
 | ||||
| //
 | ||||
| // This context holds a reference to the instance of the basic_format_context
 | ||||
| // that is retargeted. It converts a formatting argument when it is requested
 | ||||
| // during formatting. It is expected that the usage of the arguments is rare so
 | ||||
| // the lookups are not expected to be used often. An alternative would be to
 | ||||
| // convert all elements during construction.
 | ||||
| //
 | ||||
| // The elements of the retargets context are only used when an underlying
 | ||||
| // formatter uses a locale specific formatting or an formatting argument is
 | ||||
| // part for the format spec. For example
 | ||||
| //   format("{:256:{}}", input, 8);
 | ||||
| // Here the width of an element in input is determined dynamically.
 | ||||
| // Note when the top-level element has no width the retargeting is not needed.
 | ||||
| template <class _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS | ||||
|     basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> { | ||||
| public: | ||||
|   using iterator  = typename __format::__retarget_buffer<_CharT>::__iterator; | ||||
|   using char_type = _CharT; | ||||
|   template <class _Tp> | ||||
|   using formatter_type = formatter<_Tp, _CharT>; | ||||
| 
 | ||||
|   template <class _Context> | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(iterator __out_it, _Context& __ctx) | ||||
|       : __out_it_(std::move(__out_it)), | ||||
| #  ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
|         __loc_([](void* __c) { return static_cast<_Context*>(__c)->locale(); }), | ||||
| #  endif | ||||
|         __ctx_(std::addressof(__ctx)), | ||||
|         __arg_([](void* __c, size_t __id) { | ||||
|           return std::visit_format_arg( | ||||
|               [&](auto __arg) -> basic_format_arg<basic_format_context> { | ||||
|                 if constexpr (same_as<decltype(__arg), monostate>) | ||||
|                   return {}; | ||||
|                 else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>) | ||||
|                   // At the moment it's not possible for formatting to use a re-targeted handle.
 | ||||
|                   // TODO FMT add this when support is needed.
 | ||||
|                   std::__throw_format_error("Re-targeting handle not supported"); | ||||
|                 else | ||||
|                   return basic_format_arg<basic_format_context>{ | ||||
|                       __format::__determine_arg_t<basic_format_context, decltype(__arg)>(), | ||||
|                       __basic_format_arg_value<basic_format_context>(__arg)}; | ||||
|               }, | ||||
|               static_cast<_Context*>(__c)->arg(__id)); | ||||
|         }) { | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept { | ||||
|     return __arg_(__ctx_, __id); | ||||
|   } | ||||
| #  ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
|   _LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() { return __loc_(__ctx_); } | ||||
| #  endif | ||||
|   _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } | ||||
|   _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } | ||||
| 
 | ||||
| private: | ||||
|   iterator __out_it_; | ||||
| 
 | ||||
| #  ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
|   std::locale (*__loc_)(void* __ctx); | ||||
| #  endif | ||||
| 
 | ||||
|   void* __ctx_; | ||||
|   basic_format_arg<basic_format_context> (*__arg_)(void* __ctx, size_t __id); | ||||
| }; | ||||
| 
 | ||||
| _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context); | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H
 | ||||
							
								
								
									
										52
									
								
								third_party/libcxx/__format/format_error.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								third_party/libcxx/__format/format_error.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | |||
| // -*- 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_ERROR_H | ||||
| #define _LIBCPP___FORMAT_FORMAT_ERROR_H | ||||
| 
 | ||||
| #include <__config> | ||||
| #include <cstdlib> | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| _LIBCPP_DIAGNOSTIC_PUSH | ||||
| _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wweak-vtables") | ||||
| class _LIBCPP_EXCEPTION_ABI format_error : public runtime_error { | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit format_error(const string& __s) | ||||
|       : runtime_error(__s) {} | ||||
|   _LIBCPP_HIDE_FROM_ABI explicit format_error(const char* __s) | ||||
|       : runtime_error(__s) {} | ||||
|   _LIBCPP_HIDE_FROM_ABI_VIRTUAL | ||||
|   ~format_error() noexcept override = default; | ||||
| }; | ||||
| _LIBCPP_DIAGNOSTIC_POP | ||||
| 
 | ||||
| _LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void | ||||
| __throw_format_error(const char* __s) { | ||||
| #ifndef _LIBCPP_HAS_NO_EXCEPTIONS | ||||
|   throw format_error(__s); | ||||
| #else | ||||
|   (void)__s; | ||||
|   _VSTD::abort(); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMAT_ERROR_H
 | ||||
							
								
								
									
										677
									
								
								third_party/libcxx/__format/format_functions.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										677
									
								
								third_party/libcxx/__format/format_functions.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,677 @@ | |||
| // -*- 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_FUNCTIONS | ||||
| #define _LIBCPP___FORMAT_FORMAT_FUNCTIONS | ||||
| 
 | ||||
| #include <__algorithm/clamp.h> | ||||
| #include <__availability> | ||||
| #include <__concepts/convertible_to.h> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__debug> | ||||
| #include <__format/buffer.h> | ||||
| #include <__format/format_arg.h> | ||||
| #include <__format/format_arg_store.h> | ||||
| #include <__format/format_args.h> | ||||
| #include <__format/format_context.h> | ||||
| #include <__format/format_error.h> | ||||
| #include <__format/format_parse_context.h> | ||||
| #include <__format/format_string.h> | ||||
| #include <__format/format_to_n_result.h> | ||||
| #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 <__iterator/back_insert_iterator.h> | ||||
| #include <__iterator/concepts.h> | ||||
| #include <__iterator/incrementable_traits.h> | ||||
| #include <__iterator/readable_traits.h> // iter_value_t | ||||
| #include <__variant/monostate.h> | ||||
| #include <array> | ||||
| #include <string> | ||||
| #include <string_view> | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
| #include <locale> | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| // TODO FMT Evaluate which templates should be external templates. This
 | ||||
| // improves the efficiency of the header. However since the header is still
 | ||||
| // under heavy development and not all classes are stable it makes no sense
 | ||||
| // to do this optimization now.
 | ||||
| 
 | ||||
| using format_args = basic_format_args<format_context>; | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| using wformat_args = basic_format_args<wformat_context>; | ||||
| #endif | ||||
| 
 | ||||
| template <class _Context = format_context, class... _Args> | ||||
| _LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&&... __args) { | ||||
|   return _VSTD::__format_arg_store<_Context, _Args...>(__args...); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <class... _Args> | ||||
| _LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...> make_wformat_args(_Args&&... __args) { | ||||
|   return _VSTD::__format_arg_store<wformat_context, _Args...>(__args...); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| namespace __format { | ||||
| 
 | ||||
| /// Helper class parse and handle argument.
 | ||||
| ///
 | ||||
| /// When parsing a handle which is not enabled the code is ill-formed.
 | ||||
| /// This helper uses the parser of the appropriate formatter for the stored type.
 | ||||
| template <class _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS __compile_time_handle { | ||||
| public: | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void __parse(_ParseContext& __ctx) const { | ||||
|     __parse_(__ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <class _Tp> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void __enable() { | ||||
|     __parse_ = [](basic_format_parse_context<_CharT>& __ctx) { | ||||
|       formatter<_Tp, _CharT> __f; | ||||
|       __ctx.advance_to(__f.parse(__ctx)); | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   // Before calling __parse the proper handler needs to be set with __enable.
 | ||||
|   // The default handler isn't a core constant expression.
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr __compile_time_handle() | ||||
|       : __parse_([](basic_format_parse_context<_CharT>&) { std::__throw_format_error("Not a handle"); }) {} | ||||
| 
 | ||||
| private: | ||||
|   void (*__parse_)(basic_format_parse_context<_CharT>&); | ||||
| }; | ||||
| 
 | ||||
| // Dummy format_context only providing the parts used during constant
 | ||||
| // validation of the basic_format_string.
 | ||||
| template <class _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __compile_time_basic_format_context { | ||||
| public: | ||||
|   using char_type = _CharT; | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr explicit __compile_time_basic_format_context( | ||||
|       const __arg_t* __args, const __compile_time_handle<_CharT>* __handles, size_t __size) | ||||
|       : __args_(__args), __handles_(__handles), __size_(__size) {} | ||||
| 
 | ||||
|   // During the compile-time validation nothing needs to be written.
 | ||||
|   // Therefore all operations of this iterator are a NOP.
 | ||||
|   struct iterator { | ||||
|     _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator=(_CharT) { return *this; } | ||||
|     _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator*() { return *this; } | ||||
|     _LIBCPP_HIDE_FROM_ABI constexpr iterator operator++(int) { return *this; } | ||||
|   }; | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr __arg_t arg(size_t __id) const { | ||||
|     if (__id >= __size_) | ||||
|       std::__throw_format_error("Argument index out of bounds"); | ||||
|     return __args_[__id]; | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr const __compile_time_handle<_CharT>& __handle(size_t __id) const { | ||||
|     if (__id >= __size_) | ||||
|       std::__throw_format_error("Argument index out of bounds"); | ||||
|     return __handles_[__id]; | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr iterator out() { return {}; } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void advance_to(iterator) {} | ||||
| 
 | ||||
| private: | ||||
|   const __arg_t* __args_; | ||||
|   const __compile_time_handle<_CharT>* __handles_; | ||||
|   size_t __size_; | ||||
| }; | ||||
| 
 | ||||
| // [format.string.std]/8
 | ||||
| // If { arg-idopt } is used in a width or precision, the value of the
 | ||||
| // corresponding formatting argument is used in its place. If the
 | ||||
| // corresponding formatting argument is not of standard signed or unsigned
 | ||||
| // integer type, or its value is negative for precision or non-positive for
 | ||||
| // width, an exception of type format_error is thrown.
 | ||||
| //
 | ||||
| // _HasPrecision does the formatter have a precision?
 | ||||
| template <class _CharT, class _Tp, bool _HasPrecision = false> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_validate_argument( | ||||
|     basic_format_parse_context<_CharT>& __parse_ctx, __compile_time_basic_format_context<_CharT>& __ctx) { | ||||
|   auto __validate_type = [](__arg_t __type) { | ||||
|     // LWG3720 originally allowed "signed or unsigned integer types", however
 | ||||
|     // the final version explicitly changed it to "*standard* signed or unsigned
 | ||||
|     // integer types". It's trivial to use 128-bit integrals in libc++'s
 | ||||
|     // implementation, but other implementations may not implement it.
 | ||||
|     // (Using a width or precision, that does not fit in 64-bits, sounds very
 | ||||
|     // unlikely in real world code.)
 | ||||
|     switch (__type) { | ||||
|     case __arg_t::__int: | ||||
|     case __arg_t::__long_long: | ||||
|     case __arg_t::__unsigned: | ||||
|     case __arg_t::__unsigned_long_long: | ||||
|       return; | ||||
| 
 | ||||
|     default: | ||||
|       std::__throw_format_error("Replacement argument isn't a standard signed or unsigned integer type"); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   formatter<_Tp, _CharT> __formatter; | ||||
|   __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); | ||||
|   if (__formatter.__parser_.__width_as_arg_) | ||||
|     __validate_type(__ctx.arg(__formatter.__parser_.__width_)); | ||||
| 
 | ||||
|   if constexpr (_HasPrecision) | ||||
|     if (__formatter.__parser_.__precision_as_arg_) | ||||
|       __validate_type(__ctx.arg(__formatter.__parser_.__precision_)); | ||||
| } | ||||
| 
 | ||||
| // This function is not user facing, so it can directly use the non-standard types of the "variant".
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg(basic_format_parse_context<_CharT>& __parse_ctx, | ||||
|                                                                      __compile_time_basic_format_context<_CharT>& __ctx, | ||||
|                                                                      __arg_t __type) { | ||||
|   switch (__type) { | ||||
|   case __arg_t::__none: | ||||
|     std::__throw_format_error("Invalid argument"); | ||||
|   case __arg_t::__boolean: | ||||
|     return __format::__compile_time_validate_argument<_CharT, bool>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__char_type: | ||||
|     return __format::__compile_time_validate_argument<_CharT, _CharT>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__int: | ||||
|     return __format::__compile_time_validate_argument<_CharT, int>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__long_long: | ||||
|     return __format::__compile_time_validate_argument<_CharT, long long>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__i128: | ||||
| #      ifndef _LIBCPP_HAS_NO_INT128 | ||||
|     return __format::__compile_time_validate_argument<_CharT, __int128_t>(__parse_ctx, __ctx); | ||||
| #      else | ||||
|     std::__throw_format_error("Invalid argument"); | ||||
| #      endif | ||||
|     return; | ||||
|   case __arg_t::__unsigned: | ||||
|     return __format::__compile_time_validate_argument<_CharT, unsigned>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__unsigned_long_long: | ||||
|     return __format::__compile_time_validate_argument<_CharT, unsigned long long>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__u128: | ||||
| #      ifndef _LIBCPP_HAS_NO_INT128 | ||||
|     return __format::__compile_time_validate_argument<_CharT, __uint128_t>(__parse_ctx, __ctx); | ||||
| #      else | ||||
|     std::__throw_format_error("Invalid argument"); | ||||
| #      endif | ||||
|     return; | ||||
|   case __arg_t::__float: | ||||
|     return __format::__compile_time_validate_argument<_CharT, float, true>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__double: | ||||
|     return __format::__compile_time_validate_argument<_CharT, double, true>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__long_double: | ||||
|     return __format::__compile_time_validate_argument<_CharT, long double, true>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__const_char_type_ptr: | ||||
|     return __format::__compile_time_validate_argument<_CharT, const _CharT*, true>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__string_view: | ||||
|     return __format::__compile_time_validate_argument<_CharT, basic_string_view<_CharT>, true>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__ptr: | ||||
|     return __format::__compile_time_validate_argument<_CharT, const void*>(__parse_ctx, __ctx); | ||||
|   case __arg_t::__handle: | ||||
|     std::__throw_format_error("Handle should use __compile_time_validate_handle_argument"); | ||||
|   } | ||||
|   std::__throw_format_error("Invalid argument"); | ||||
| } | ||||
| 
 | ||||
| template <contiguous_iterator _Iterator, class _ParseCtx, class _Ctx> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr _Iterator | ||||
| __handle_replacement_field(_Iterator __begin, _Iterator __end, | ||||
|                            _ParseCtx& __parse_ctx, _Ctx& __ctx) { | ||||
|   using _CharT = iter_value_t<_Iterator>; | ||||
|   __format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __parse_ctx); | ||||
| 
 | ||||
|   bool __parse = *__r.__last == _CharT(':'); | ||||
|   switch (*__r.__last) { | ||||
|   case _CharT(':'): | ||||
|     // The arg-id has a format-specifier, advance the input to the format-spec.
 | ||||
|     __parse_ctx.advance_to(__r.__last + 1); | ||||
|     break; | ||||
|   case _CharT('}'): | ||||
|     // The arg-id has no format-specifier.
 | ||||
|     __parse_ctx.advance_to(__r.__last); | ||||
|     break; | ||||
|   default: | ||||
|     std::__throw_format_error("The replacement field arg-id should terminate at a ':' or '}'"); | ||||
|   } | ||||
| 
 | ||||
|   if constexpr (same_as<_Ctx, __compile_time_basic_format_context<_CharT>>) { | ||||
|     __arg_t __type = __ctx.arg(__r.__value); | ||||
|     if (__type == __arg_t::__none) | ||||
|       std::__throw_format_error("Argument index out of bounds"); | ||||
|     else if (__type == __arg_t::__handle) | ||||
|       __ctx.__handle(__r.__value).__parse(__parse_ctx); | ||||
|     else if (__parse) | ||||
|       __format::__compile_time_visit_format_arg(__parse_ctx, __ctx, __type); | ||||
|   } else | ||||
|     _VSTD::__visit_format_arg( | ||||
|         [&](auto __arg) { | ||||
|           if constexpr (same_as<decltype(__arg), monostate>) | ||||
|             std::__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; | ||||
|             if (__parse) | ||||
|               __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); | ||||
|             __ctx.advance_to(__formatter.format(__arg, __ctx)); | ||||
|           } | ||||
|         }, | ||||
|         __ctx.arg(__r.__value)); | ||||
| 
 | ||||
|   __begin = __parse_ctx.begin(); | ||||
|   if (__begin == __end || *__begin != _CharT('}')) | ||||
|     std::__throw_format_error("The replacement field misses a terminating '}'"); | ||||
| 
 | ||||
|   return ++__begin; | ||||
| } | ||||
| 
 | ||||
| template <class _ParseCtx, class _Ctx> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr typename _Ctx::iterator | ||||
| __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) { | ||||
|   using _CharT = typename _ParseCtx::char_type; | ||||
|   static_assert(same_as<typename _Ctx::char_type, _CharT>); | ||||
| 
 | ||||
|   auto __begin = __parse_ctx.begin(); | ||||
|   auto __end = __parse_ctx.end(); | ||||
|   typename _Ctx::iterator __out_it = __ctx.out(); | ||||
|   while (__begin != __end) { | ||||
|     switch (*__begin) { | ||||
|     case _CharT('{'): | ||||
|       ++__begin; | ||||
|       if (__begin == __end) | ||||
|         std::__throw_format_error("The format string terminates at a '{'"); | ||||
| 
 | ||||
|       if (*__begin != _CharT('{')) [[likely]] { | ||||
|         __ctx.advance_to(_VSTD::move(__out_it)); | ||||
|         __begin = | ||||
|             __format::__handle_replacement_field(__begin, __end, __parse_ctx, __ctx); | ||||
|         __out_it = __ctx.out(); | ||||
| 
 | ||||
|         // The output is written and __begin points to the next character. So
 | ||||
|         // start the next iteration.
 | ||||
|         continue; | ||||
|       } | ||||
|       // The string is an escape character.
 | ||||
|       break; | ||||
| 
 | ||||
|     case _CharT('}'): | ||||
|       ++__begin; | ||||
|       if (__begin == __end || *__begin != _CharT('}')) | ||||
|         std::__throw_format_error("The format string contains an invalid escape sequence"); | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|     // Copy the character to the output verbatim.
 | ||||
|     *__out_it++ = *__begin++; | ||||
|   } | ||||
|   return __out_it; | ||||
| } | ||||
| 
 | ||||
| } // namespace __format
 | ||||
| 
 | ||||
| template <class _CharT, class... _Args> | ||||
| struct _LIBCPP_TEMPLATE_VIS basic_format_string { | ||||
|   template <class _Tp> | ||||
|     requires convertible_to<const _Tp&, basic_string_view<_CharT>> | ||||
|   consteval basic_format_string(const _Tp& __str) : __str_{__str} { | ||||
|     __format::__vformat_to(basic_format_parse_context<_CharT>{__str_, sizeof...(_Args)}, | ||||
|                            _Context{__types_.data(), __handles_.data(), sizeof...(_Args)}); | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<_CharT> get() const noexcept { | ||||
|     return __str_; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   basic_string_view<_CharT> __str_; | ||||
| 
 | ||||
|   using _Context = __format::__compile_time_basic_format_context<_CharT>; | ||||
| 
 | ||||
|   static constexpr array<__format::__arg_t, sizeof...(_Args)> __types_{ | ||||
|       __format::__determine_arg_t<_Context, remove_cvref_t<_Args>>()...}; | ||||
| 
 | ||||
|   // TODO FMT remove this work-around when the AIX ICE has been resolved.
 | ||||
| #    if defined(_AIX) && defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER < 1400 | ||||
|   template <class _Tp> | ||||
|   static constexpr __format::__compile_time_handle<_CharT> __get_handle() { | ||||
|     __format::__compile_time_handle<_CharT> __handle; | ||||
|     if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle) | ||||
|       __handle.template __enable<_Tp>(); | ||||
| 
 | ||||
|     return __handle; | ||||
|   } | ||||
| 
 | ||||
|   static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{ | ||||
|       __get_handle<_Args>()...}; | ||||
| #    else | ||||
|   static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{[] { | ||||
|     using _Tp = remove_cvref_t<_Args>; | ||||
|     __format::__compile_time_handle<_CharT> __handle; | ||||
|     if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle) | ||||
|       __handle.template __enable<_Tp>(); | ||||
| 
 | ||||
|     return __handle; | ||||
|   }()...}; | ||||
| #    endif | ||||
| }; | ||||
| 
 | ||||
| template <class... _Args> | ||||
| using format_string = basic_format_string<char, type_identity_t<_Args>...>; | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <class... _Args> | ||||
| using wformat_string = basic_format_string<wchar_t, type_identity_t<_Args>...>; | ||||
| #endif | ||||
| 
 | ||||
| template <class _OutIt, class _CharT, class _FormatOutIt> | ||||
| requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt | ||||
|     __vformat_to( | ||||
|         _OutIt __out_it, basic_string_view<_CharT> __fmt, | ||||
|         basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) { | ||||
|   if constexpr (same_as<_OutIt, _FormatOutIt>) | ||||
|     return _VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, | ||||
|                                          _VSTD::__format_context_create(_VSTD::move(__out_it), __args)); | ||||
|   else { | ||||
|     __format::__format_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it)}; | ||||
|     _VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, | ||||
|                                   _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args)); | ||||
|     return _VSTD::move(__buffer).__out_it(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // The function is _LIBCPP_ALWAYS_INLINE since the compiler is bad at inlining
 | ||||
| // https://reviews.llvm.org/D110499#inline-1180704
 | ||||
| // TODO FMT Evaluate whether we want to file a Clang bug report regarding this.
 | ||||
| template <output_iterator<const char&> _OutIt> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt | ||||
| vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) { | ||||
|   return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <output_iterator<const wchar_t&> _OutIt> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt | ||||
| vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) { | ||||
|   return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <output_iterator<const char&> _OutIt, class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt | ||||
| format_to(_OutIt __out_it, format_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.get(), | ||||
|                            _VSTD::make_format_args(__args...)); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <output_iterator<const wchar_t&> _OutIt, class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt | ||||
| format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.get(), | ||||
|                            _VSTD::make_wformat_args(__args...)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| // TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
 | ||||
| // fires too eagerly, see http://llvm.org/PR61563.
 | ||||
| template <class = void> | ||||
| _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string | ||||
| vformat(string_view __fmt, format_args __args) { | ||||
|   string __res; | ||||
|   _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args); | ||||
|   return __res; | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| // TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
 | ||||
| // fires too eagerly, see http://llvm.org/PR61563.
 | ||||
| template <class = void> | ||||
| _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring | ||||
| vformat(wstring_view __fmt, wformat_args __args) { | ||||
|   wstring __res; | ||||
|   _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args); | ||||
|   return __res; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string format(format_string<_Args...> __fmt, | ||||
|                                                                                       _Args&&... __args) { | ||||
|   return _VSTD::vformat(__fmt.get(), _VSTD::make_format_args(__args...)); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring | ||||
| format(wformat_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::vformat(__fmt.get(), _VSTD::make_wformat_args(__args...)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <class _Context, class _OutIt, class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, | ||||
|                                                                 basic_string_view<_CharT> __fmt, | ||||
|                                                                 basic_format_args<_Context> __args) { | ||||
|   __format::__format_to_n_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it), __n}; | ||||
|   _VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, | ||||
|                                 _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args)); | ||||
|   return _VSTD::move(__buffer).__result(); | ||||
| } | ||||
| 
 | ||||
| template <output_iterator<const char&> _OutIt, class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> | ||||
| format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, format_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, __fmt.get(), _VSTD::make_format_args(__args...)); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <output_iterator<const wchar_t&> _OutIt, class... _Args> | ||||
| _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> | ||||
| format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wformat_string<_Args...> __fmt, | ||||
|             _Args&&... __args) { | ||||
|   return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, __fmt.get(), _VSTD::make_wformat_args(__args...)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt, auto __args) { | ||||
|   __format::__formatted_size_buffer<_CharT> __buffer; | ||||
|   _VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, | ||||
|                                 _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args)); | ||||
|   return _VSTD::move(__buffer).__result(); | ||||
| } | ||||
| 
 | ||||
| template <class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t | ||||
| formatted_size(format_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_format_args(__args...)}); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t | ||||
| formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)}); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
| 
 | ||||
| template <class _OutIt, class _CharT, class _FormatOutIt> | ||||
| requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt | ||||
|     __vformat_to( | ||||
|         _OutIt __out_it, locale __loc, basic_string_view<_CharT> __fmt, | ||||
|         basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) { | ||||
|   if constexpr (same_as<_OutIt, _FormatOutIt>) | ||||
|     return _VSTD::__format::__vformat_to( | ||||
|         basic_format_parse_context{__fmt, __args.__size()}, | ||||
|         _VSTD::__format_context_create(_VSTD::move(__out_it), __args, _VSTD::move(__loc))); | ||||
|   else { | ||||
|     __format::__format_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it)}; | ||||
|     _VSTD::__format::__vformat_to( | ||||
|         basic_format_parse_context{__fmt, __args.__size()}, | ||||
|         _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc))); | ||||
|     return _VSTD::move(__buffer).__out_it(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <output_iterator<const char&> _OutIt> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt vformat_to( | ||||
|     _OutIt __out_it, locale __loc, string_view __fmt, format_args __args) { | ||||
|   return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt, | ||||
|                              __args); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <output_iterator<const wchar_t&> _OutIt> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt vformat_to( | ||||
|     _OutIt __out_it, locale __loc, wstring_view __fmt, wformat_args __args) { | ||||
|   return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt, | ||||
|                              __args); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <output_iterator<const char&> _OutIt, class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt | ||||
| format_to(_OutIt __out_it, locale __loc, format_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.get(), | ||||
|                            _VSTD::make_format_args(__args...)); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <output_iterator<const wchar_t&> _OutIt, class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt | ||||
| format_to(_OutIt __out_it, locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.get(), | ||||
|                            _VSTD::make_wformat_args(__args...)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| // TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
 | ||||
| // fires too eagerly, see http://llvm.org/PR61563.
 | ||||
| template <class = void> | ||||
| _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string | ||||
| vformat(locale __loc, string_view __fmt, format_args __args) { | ||||
|   string __res; | ||||
|   _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt, | ||||
|                     __args); | ||||
|   return __res; | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| // TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
 | ||||
| // fires too eagerly, see http://llvm.org/PR61563.
 | ||||
| template <class = void> | ||||
| _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring | ||||
| vformat(locale __loc, wstring_view __fmt, wformat_args __args) { | ||||
|   wstring __res; | ||||
|   _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt, | ||||
|                     __args); | ||||
|   return __res; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string format(locale __loc, | ||||
|                                                                                       format_string<_Args...> __fmt, | ||||
|                                                                                       _Args&&... __args) { | ||||
|   return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(), | ||||
|                         _VSTD::make_format_args(__args...)); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring | ||||
| format(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(), | ||||
|                         _VSTD::make_wformat_args(__args...)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <class _Context, class _OutIt, class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, | ||||
|                                                                 locale __loc, basic_string_view<_CharT> __fmt, | ||||
|                                                                 basic_format_args<_Context> __args) { | ||||
|   __format::__format_to_n_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it), __n}; | ||||
|   _VSTD::__format::__vformat_to( | ||||
|       basic_format_parse_context{__fmt, __args.__size()}, | ||||
|       _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc))); | ||||
|   return _VSTD::move(__buffer).__result(); | ||||
| } | ||||
| 
 | ||||
| template <output_iterator<const char&> _OutIt, class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> | ||||
| format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, format_string<_Args...> __fmt, | ||||
|             _Args&&... __args) { | ||||
|   return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.get(), | ||||
|                                                _VSTD::make_format_args(__args...)); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <output_iterator<const wchar_t&> _OutIt, class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> | ||||
| format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, wformat_string<_Args...> __fmt, | ||||
|             _Args&&... __args) { | ||||
|   return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.get(), | ||||
|                                                 _VSTD::make_wformat_args(__args...)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(locale __loc, basic_string_view<_CharT> __fmt, auto __args) { | ||||
|   __format::__formatted_size_buffer<_CharT> __buffer; | ||||
|   _VSTD::__format::__vformat_to( | ||||
|       basic_format_parse_context{__fmt, __args.__size()}, | ||||
|       _VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc))); | ||||
|   return _VSTD::move(__buffer).__result(); | ||||
| } | ||||
| 
 | ||||
| template <class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t | ||||
| formatted_size(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_format_args(__args...)}); | ||||
| } | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <class... _Args> | ||||
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t | ||||
| formatted_size(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { | ||||
|   return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)}); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif // _LIBCPP_HAS_NO_LOCALIZATION
 | ||||
| 
 | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMAT_FUNCTIONS
 | ||||
							
								
								
									
										39
									
								
								third_party/libcxx/__format/format_fwd.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								third_party/libcxx/__format/format_fwd.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| // -*- 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_FWD_H | ||||
| #define _LIBCPP___FORMAT_FORMAT_FWD_H | ||||
| 
 | ||||
| #include <__availability> | ||||
| #include <__config> | ||||
| #include <__iterator/concepts.h> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| template <class _Context> | ||||
| class _LIBCPP_TEMPLATE_VIS basic_format_arg; | ||||
| 
 | ||||
| template <class _OutIt, class _CharT> | ||||
|   requires output_iterator<_OutIt, const _CharT&> | ||||
| class _LIBCPP_TEMPLATE_VIS basic_format_context; | ||||
| 
 | ||||
| template <class _Tp, class _CharT = char> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter; | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMAT_FWD_H
 | ||||
							
								
								
									
										113
									
								
								third_party/libcxx/__format/format_parse_context.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								third_party/libcxx/__format/format_parse_context.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,113 @@ | |||
| // -*- 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_PARSE_CONTEXT_H | ||||
| #define _LIBCPP___FORMAT_FORMAT_PARSE_CONTEXT_H | ||||
| 
 | ||||
| #include <__config> | ||||
| #include <__format/format_error.h> | ||||
| #include <__type_traits/is_constant_evaluated.h> | ||||
| #include <string_view> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| template <class _CharT> | ||||
| class _LIBCPP_TEMPLATE_VIS basic_format_parse_context { | ||||
| public: | ||||
|   using char_type = _CharT; | ||||
|   using const_iterator = typename basic_string_view<_CharT>::const_iterator; | ||||
|   using iterator = const_iterator; | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI | ||||
|   constexpr explicit basic_format_parse_context(basic_string_view<_CharT> __fmt, | ||||
|                                                 size_t __num_args = 0) noexcept | ||||
|       : __begin_(__fmt.begin()), | ||||
|         __end_(__fmt.end()), | ||||
|         __indexing_(__unknown), | ||||
|         __next_arg_id_(0), | ||||
|         __num_args_(__num_args) {} | ||||
| 
 | ||||
|   basic_format_parse_context(const basic_format_parse_context&) = delete; | ||||
|   basic_format_parse_context& | ||||
|   operator=(const basic_format_parse_context&) = delete; | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept { | ||||
|     return __begin_; | ||||
|   } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept { | ||||
|     return __end_; | ||||
|   } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void advance_to(const_iterator __it) { | ||||
|     __begin_ = __it; | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr size_t next_arg_id() { | ||||
|     if (__indexing_ == __manual) | ||||
|       std::__throw_format_error("Using automatic argument numbering in manual argument numbering mode"); | ||||
| 
 | ||||
|     if (__indexing_ == __unknown) | ||||
|       __indexing_ = __automatic; | ||||
| 
 | ||||
|     // Throws an exception to make the expression a non core constant
 | ||||
|     // expression as required by:
 | ||||
|     // [format.parse.ctx]/8
 | ||||
|     //   Remarks: Let cur-arg-id be the value of next_arg_id_ prior to this
 | ||||
|     //   call. Call expressions where cur-arg-id >= num_args_ is true are not
 | ||||
|     //   core constant expressions (7.7 [expr.const]).
 | ||||
|     // Note: the Throws clause [format.parse.ctx]/9 doesn't specify the
 | ||||
|     // behavior when id >= num_args_.
 | ||||
|     if (is_constant_evaluated() && __next_arg_id_ >= __num_args_) | ||||
|       std::__throw_format_error("Argument index outside the valid range"); | ||||
| 
 | ||||
|     return __next_arg_id_++; | ||||
|   } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void check_arg_id(size_t __id) { | ||||
|     if (__indexing_ == __automatic) | ||||
|       std::__throw_format_error("Using manual argument numbering in automatic argument numbering mode"); | ||||
| 
 | ||||
|     if (__indexing_ == __unknown) | ||||
|       __indexing_ = __manual; | ||||
| 
 | ||||
|     // Throws an exception to make the expression a non core constant
 | ||||
|     // expression as required by:
 | ||||
|     // [format.parse.ctx]/11
 | ||||
|     //   Remarks: Call expressions where id >= num_args_ are not core constant
 | ||||
|     //   expressions ([expr.const]).
 | ||||
|     // Note: the Throws clause [format.parse.ctx]/10 doesn't specify the
 | ||||
|     // behavior when id >= num_args_.
 | ||||
|     if (is_constant_evaluated() && __id >= __num_args_) | ||||
|       std::__throw_format_error("Argument index outside the valid range"); | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   iterator __begin_; | ||||
|   iterator __end_; | ||||
|   enum _Indexing { __unknown, __manual, __automatic }; | ||||
|   _Indexing __indexing_; | ||||
|   size_t __next_arg_id_; | ||||
|   size_t __num_args_; | ||||
| }; | ||||
| _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_parse_context); | ||||
| 
 | ||||
| using format_parse_context = basic_format_parse_context<char>; | ||||
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| using wformat_parse_context = basic_format_parse_context<wchar_t>; | ||||
| #endif | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMAT_PARSE_CONTEXT_H
 | ||||
							
								
								
									
										167
									
								
								third_party/libcxx/__format/format_string.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								third_party/libcxx/__format/format_string.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,167 @@ | |||
| // -*- 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_STRING_H | ||||
| #define _LIBCPP___FORMAT_FORMAT_STRING_H | ||||
| 
 | ||||
| #include <__assert> | ||||
| #include <__config> | ||||
| #include <__format/format_error.h> | ||||
| #include <__iterator/concepts.h> | ||||
| #include <__iterator/readable_traits.h> // iter_value_t | ||||
| #include <cstddef> | ||||
| #include <cstdint> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| namespace __format { | ||||
| 
 | ||||
| template <contiguous_iterator _Iterator> | ||||
| struct _LIBCPP_TEMPLATE_VIS __parse_number_result { | ||||
|   _Iterator __last; | ||||
|   uint32_t __value; | ||||
| }; | ||||
| 
 | ||||
| template <contiguous_iterator _Iterator> | ||||
| __parse_number_result(_Iterator, uint32_t) -> __parse_number_result<_Iterator>; | ||||
| 
 | ||||
| template <contiguous_iterator _Iterator> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> | ||||
| __parse_number(_Iterator __begin, _Iterator __end); | ||||
| 
 | ||||
| /**
 | ||||
|  * The maximum value of a numeric argument. | ||||
|  * | ||||
|  * This is used for: | ||||
|  * * arg-id | ||||
|  * * width as value or arg-id. | ||||
|  * * precision as value or arg-id. | ||||
|  * | ||||
|  * The value is compatible with the maximum formatting width and precision | ||||
|  * using the `%*` syntax on a 32-bit system. | ||||
|  */ | ||||
| inline constexpr uint32_t __number_max = INT32_MAX; | ||||
| 
 | ||||
| namespace __detail { | ||||
| template <contiguous_iterator _Iterator> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> | ||||
| __parse_zero(_Iterator __begin, _Iterator, auto& __parse_ctx) { | ||||
|   __parse_ctx.check_arg_id(0); | ||||
|   return {++__begin, 0}; // can never be larger than the maximum.
 | ||||
| } | ||||
| 
 | ||||
| template <contiguous_iterator _Iterator> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> | ||||
| __parse_automatic(_Iterator __begin, _Iterator, auto& __parse_ctx) { | ||||
|   size_t __value = __parse_ctx.next_arg_id(); | ||||
|   _LIBCPP_ASSERT(__value <= __number_max, | ||||
|                  "Compilers don't support this number of arguments"); | ||||
| 
 | ||||
|   return {__begin, uint32_t(__value)}; | ||||
| } | ||||
| 
 | ||||
| template <contiguous_iterator _Iterator> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> | ||||
| __parse_manual(_Iterator __begin, _Iterator __end, auto& __parse_ctx) { | ||||
|   __parse_number_result<_Iterator> __r = __format::__parse_number(__begin, __end); | ||||
|   __parse_ctx.check_arg_id(__r.__value); | ||||
|   return __r; | ||||
| } | ||||
| 
 | ||||
| } // namespace __detail
 | ||||
| 
 | ||||
| /**
 | ||||
|  * Parses a number. | ||||
|  * | ||||
|  * The number is used for the 31-bit values @em width and @em precision. This | ||||
|  * allows a maximum value of 2147483647. | ||||
|  */ | ||||
| template <contiguous_iterator _Iterator> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> | ||||
| __parse_number(_Iterator __begin, _Iterator __end_input) { | ||||
|   using _CharT = iter_value_t<_Iterator>; | ||||
|   static_assert(__format::__number_max == INT32_MAX, | ||||
|                 "The algorithm is implemented based on this value."); | ||||
|   /*
 | ||||
|    * Limit the input to 9 digits, otherwise we need two checks during every | ||||
|    * iteration: | ||||
|    * - Are we at the end of the input? | ||||
|    * - Does the value exceed width of an uint32_t? (Switching to uint64_t would | ||||
|    *   have the same issue, but with a higher maximum.) | ||||
|    */ | ||||
|   _Iterator __end = __end_input - __begin > 9 ? __begin + 9 : __end_input; | ||||
|   uint32_t __value = *__begin - _CharT('0'); | ||||
|   while (++__begin != __end) { | ||||
|     if (*__begin < _CharT('0') || *__begin > _CharT('9')) | ||||
|       return {__begin, __value}; | ||||
| 
 | ||||
|     __value = __value * 10 + *__begin - _CharT('0'); | ||||
|   } | ||||
| 
 | ||||
|   if (__begin != __end_input && *__begin >= _CharT('0') && | ||||
|       *__begin <= _CharT('9')) { | ||||
| 
 | ||||
|     /*
 | ||||
|      * There are more than 9 digits, do additional validations: | ||||
|      * - Does the 10th digit exceed the maximum allowed value? | ||||
|      * - Are there more than 10 digits? | ||||
|      * (More than 10 digits always overflows the maximum.) | ||||
|      */ | ||||
|     uint64_t __v = uint64_t(__value) * 10 + *__begin++ - _CharT('0'); | ||||
|     if (__v > __number_max || | ||||
|         (__begin != __end_input && *__begin >= _CharT('0') && | ||||
|          *__begin <= _CharT('9'))) | ||||
|       std::__throw_format_error("The numeric value of the format-spec is too large"); | ||||
| 
 | ||||
|     __value = __v; | ||||
|   } | ||||
| 
 | ||||
|   return {__begin, __value}; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Multiplexer for all parse functions. | ||||
|  * | ||||
|  * The parser will return a pointer beyond the last consumed character. This | ||||
|  * should be the closing '}' of the arg-id. | ||||
|  */ | ||||
| template <contiguous_iterator _Iterator> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> | ||||
| __parse_arg_id(_Iterator __begin, _Iterator __end, auto& __parse_ctx) { | ||||
|   using _CharT = iter_value_t<_Iterator>; | ||||
|   switch (*__begin) { | ||||
|   case _CharT('0'): | ||||
|     return __detail::__parse_zero(__begin, __end, __parse_ctx); | ||||
| 
 | ||||
|   case _CharT(':'): | ||||
|     // This case is conditionally valid. It's allowed in an arg-id in the
 | ||||
|     // replacement-field, but not in the std-format-spec. The caller can
 | ||||
|     // provide a better diagnostic, so accept it here unconditionally.
 | ||||
|   case _CharT('}'): | ||||
|     return __detail::__parse_automatic(__begin, __end, __parse_ctx); | ||||
|   } | ||||
|   if (*__begin < _CharT('0') || *__begin > _CharT('9')) | ||||
|     std::__throw_format_error("The arg-id of the format-spec starts with an invalid character"); | ||||
| 
 | ||||
|   return __detail::__parse_manual(__begin, __end, __parse_ctx); | ||||
| } | ||||
| 
 | ||||
| } // namespace __format
 | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMAT_STRING_H
 | ||||
							
								
								
									
										35
									
								
								third_party/libcxx/__format/format_to_n_result.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								third_party/libcxx/__format/format_to_n_result.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | |||
| // -*- 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_TO_N_RESULT_H | ||||
| #define _LIBCPP___FORMAT_FORMAT_TO_N_RESULT_H | ||||
| 
 | ||||
| #include <__config> | ||||
| #include <__iterator/incrementable_traits.h> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| template <class _OutIt> | ||||
| struct _LIBCPP_TEMPLATE_VIS format_to_n_result { | ||||
|   _OutIt out; | ||||
|   iter_difference_t<_OutIt> size; | ||||
| }; | ||||
| _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(format_to_n_result); | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMAT_TO_N_RESULT_H
 | ||||
							
								
								
									
										54
									
								
								third_party/libcxx/__format/formatter.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								third_party/libcxx/__format/formatter.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| // -*- 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_H | ||||
| #define _LIBCPP___FORMAT_FORMATTER_H | ||||
| 
 | ||||
| #include <__availability> | ||||
| #include <__config> | ||||
| #include <__format/format_fwd.h> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| /// 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 formatter { | ||||
|   formatter() = delete; | ||||
|   formatter(const formatter&) = delete; | ||||
|   formatter& operator=(const formatter&) = delete; | ||||
| }; | ||||
| 
 | ||||
| #  if _LIBCPP_STD_VER >= 23 | ||||
| 
 | ||||
| template <class _Tp> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr void __set_debug_format(_Tp& __formatter) { | ||||
|   if constexpr (requires { __formatter.set_debug_format(); }) | ||||
|     __formatter.set_debug_format(); | ||||
| } | ||||
| 
 | ||||
| #  endif // _LIBCPP_STD_VER >= 23
 | ||||
| #endif   // _LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMATTER_H
 | ||||
							
								
								
									
										79
									
								
								third_party/libcxx/__format/formatter_bool.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								third_party/libcxx/__format/formatter_bool.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,79 @@ | |||
| // -*- 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_BOOL_H | ||||
| #define _LIBCPP___FORMAT_FORMATTER_BOOL_H | ||||
| 
 | ||||
| #include <__algorithm/copy.h> | ||||
| #include <__availability> | ||||
| #include <__config> | ||||
| #include <__debug> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/format_error.h> | ||||
| #include <__format/format_parse_context.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/formatter_integral.h> | ||||
| #include <__format/parser_std_format_spec.h> | ||||
| #include <__utility/unreachable.h> | ||||
| #include <string_view> | ||||
| 
 | ||||
| #ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
| #  include <locale> | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<bool, _CharT> { | ||||
| public: | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral); | ||||
|     __format_spec::__process_parsed_bool(__parser_); | ||||
|     return __result; | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(bool __value, _FormatContext& __ctx) const { | ||||
|     switch (__parser_.__type_) { | ||||
|     case __format_spec::__type::__default: | ||||
|     case __format_spec::__type::__string: | ||||
|       return __formatter::__format_bool(__value, __ctx, __parser_.__get_parsed_std_specifications(__ctx)); | ||||
| 
 | ||||
|     case __format_spec::__type::__binary_lower_case: | ||||
|     case __format_spec::__type::__binary_upper_case: | ||||
|     case __format_spec::__type::__octal: | ||||
|     case __format_spec::__type::__decimal: | ||||
|     case __format_spec::__type::__hexadecimal_lower_case: | ||||
|     case __format_spec::__type::__hexadecimal_upper_case: | ||||
|       // Promotes bool to an integral type. This reduces the number of
 | ||||
|       // instantiations of __format_integer reducing code size.
 | ||||
|       return __formatter::__format_integer( | ||||
|           static_cast<unsigned>(__value), __ctx, __parser_.__get_parsed_std_specifications(__ctx)); | ||||
| 
 | ||||
|     default: | ||||
|       _LIBCPP_ASSERT(false, "The parse function should have validated the type"); | ||||
|       __libcpp_unreachable(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   __format_spec::__parser<_CharT> __parser_; | ||||
| }; | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMATTER_BOOL_H
 | ||||
							
								
								
									
										95
									
								
								third_party/libcxx/__format/formatter_char.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								third_party/libcxx/__format/formatter_char.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | |||
| // -*- 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_CHAR_H | ||||
| #define _LIBCPP___FORMAT_FORMATTER_CHAR_H | ||||
| 
 | ||||
| #include <__availability> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/format_parse_context.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/formatter_integral.h> | ||||
| #include <__format/formatter_output.h> | ||||
| #include <__format/parser_std_format_spec.h> | ||||
| #include <__type_traits/conditional.h> | ||||
| #include <__type_traits/is_signed.h> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __formatter_char { | ||||
| public: | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral); | ||||
|     __format_spec::__process_parsed_char(__parser_); | ||||
|     return __result; | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT __value, _FormatContext& __ctx) const { | ||||
|     if (__parser_.__type_ == __format_spec::__type::__default || __parser_.__type_ == __format_spec::__type::__char) | ||||
|       return __formatter::__format_char(__value, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx)); | ||||
| 
 | ||||
| #  if _LIBCPP_STD_VER >= 23 | ||||
|     if (__parser_.__type_ == __format_spec::__type::__debug) | ||||
|       return __formatter::__format_escaped_char(__value, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx)); | ||||
| #  endif | ||||
| 
 | ||||
|     if constexpr (sizeof(_CharT) <= sizeof(int)) | ||||
|       // Promotes _CharT to an integral type. This reduces the number of
 | ||||
|       // instantiations of __format_integer reducing code size.
 | ||||
|       return __formatter::__format_integer( | ||||
|           static_cast<conditional_t<is_signed_v<_CharT>, int, unsigned>>(__value), | ||||
|           __ctx, | ||||
|           __parser_.__get_parsed_std_specifications(__ctx)); | ||||
|     else | ||||
|       return __formatter::__format_integer(__value, __ctx, __parser_.__get_parsed_std_specifications(__ctx)); | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(char __value, _FormatContext& __ctx) const | ||||
|     requires(same_as<_CharT, wchar_t>) | ||||
|   { | ||||
|     return format(static_cast<wchar_t>(__value), __ctx); | ||||
|   } | ||||
| 
 | ||||
| #  if _LIBCPP_STD_VER >= 23 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void set_debug_format() { __parser_.__type_ = __format_spec::__type::__debug; } | ||||
| #  endif | ||||
| 
 | ||||
|   __format_spec::__parser<_CharT> __parser_; | ||||
| }; | ||||
| 
 | ||||
| template <> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<char, char> : public __formatter_char<char> {}; | ||||
| 
 | ||||
| #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<char, wchar_t> : public __formatter_char<wchar_t> {}; | ||||
| 
 | ||||
| template <> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<wchar_t, wchar_t> : public __formatter_char<wchar_t> { | ||||
| }; | ||||
| 
 | ||||
| #  endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
 | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMATTER_CHAR_H
 | ||||
							
								
								
									
										761
									
								
								third_party/libcxx/__format/formatter_floating_point.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										761
									
								
								third_party/libcxx/__format/formatter_floating_point.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,761 @@ | |||
| // -*- 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_n.h> | ||||
| #include <__algorithm/find.h> | ||||
| #include <__algorithm/max.h> | ||||
| #include <__algorithm/min.h> | ||||
| #include <__algorithm/rotate.h> | ||||
| #include <__algorithm/transform.h> | ||||
| #include <__charconv/chars_format.h> | ||||
| #include <__charconv/to_chars_floating_point.h> | ||||
| #include <__charconv/to_chars_result.h> | ||||
| #include <__concepts/arithmetic.h> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/format_parse_context.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/formatter_integral.h> | ||||
| #include <__format/formatter_output.h> | ||||
| #include <__format/parser_std_format_spec.h> | ||||
| #include <__memory/allocator.h> | ||||
| #include <__system_error/errc.h> | ||||
| #include <__type_traits/conditional.h> | ||||
| #include <__utility/move.h> | ||||
| #include <__utility/unreachable.h> | ||||
| #include <cmath> | ||||
| #include <cstddef> | ||||
| 
 | ||||
| #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 >= 20 | ||||
| 
 | ||||
| namespace __formatter { | ||||
| 
 | ||||
| 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> | ||||
| _LIBCPP_HIDE_FROM_ABI 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_ = __formatter::__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; } | ||||
|   _LIBCPP_HIDE_FROM_ABI void __add_trailing_zeros(int __zeros) { __num_trailing_zeros_ += __zeros; } | ||||
| 
 | ||||
| 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     = __formatter::__to_buffer(__integral, __buffer.end(), __value); | ||||
| 
 | ||||
|   __result.__exponent = __formatter::__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 = __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex); | ||||
|   else | ||||
|     __result.__last = __formatter::__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 = | ||||
|       __formatter::__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 = | ||||
|       __formatter::__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    = __formatter::__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 = | ||||
|       __formatter::__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     = __formatter::__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 = __formatter::__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 = __formatter::__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 = __formatter::__format_buffer_general_lower_case(__buffer, __value, __precision, __integral); | ||||
|   if (__result.__exponent != __result.__last) | ||||
|     *__result.__exponent = 'E'; | ||||
|   return __result; | ||||
| } | ||||
| 
 | ||||
| /// 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, | ||||
|     __format_spec::__sign __sign, | ||||
|     __format_spec::__type __type) { | ||||
|   char* __first = __formatter::__insert_sign(__buffer.begin(), __negative, __sign); | ||||
|   switch (__type) { | ||||
|   case __format_spec::__type::__default: | ||||
|     if (__has_precision) | ||||
|       return __formatter::__format_buffer_general_lower_case(__buffer, __value, __buffer.__precision(), __first); | ||||
|     else | ||||
|       return __formatter::__format_buffer_default(__buffer, __value, __first); | ||||
| 
 | ||||
|   case __format_spec::__type::__hexfloat_lower_case: | ||||
|     return __formatter::__format_buffer_hexadecimal_lower_case( | ||||
|         __buffer, __value, __has_precision ? __buffer.__precision() : -1, __first); | ||||
| 
 | ||||
|   case __format_spec::__type::__hexfloat_upper_case: | ||||
|     return __formatter::__format_buffer_hexadecimal_upper_case( | ||||
|         __buffer, __value, __has_precision ? __buffer.__precision() : -1, __first); | ||||
| 
 | ||||
|   case __format_spec::__type::__scientific_lower_case: | ||||
|     return __formatter::__format_buffer_scientific_lower_case(__buffer, __value, __buffer.__precision(), __first); | ||||
| 
 | ||||
|   case __format_spec::__type::__scientific_upper_case: | ||||
|     return __formatter::__format_buffer_scientific_upper_case(__buffer, __value, __buffer.__precision(), __first); | ||||
| 
 | ||||
|   case __format_spec::__type::__fixed_lower_case: | ||||
|   case __format_spec::__type::__fixed_upper_case: | ||||
|     return __formatter::__format_buffer_fixed(__buffer, __value, __buffer.__precision(), __first); | ||||
| 
 | ||||
|   case __format_spec::__type::__general_lower_case: | ||||
|     return __formatter::__format_buffer_general_lower_case(__buffer, __value, __buffer.__precision(), __first); | ||||
| 
 | ||||
|   case __format_spec::__type::__general_upper_case: | ||||
|     return __formatter::__format_buffer_general_upper_case(__buffer, __value, __buffer.__precision(), __first); | ||||
| 
 | ||||
|   default: | ||||
|     _LIBCPP_ASSERT(false, "The parser should have validated the type"); | ||||
|     __libcpp_unreachable(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| #  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, | ||||
|     __format_spec::__parsed_specifications<_CharT> __specs) { | ||||
|   const auto& __np = std::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 = __formatter::__determine_grouping(__digits, __grouping); | ||||
|   } | ||||
| 
 | ||||
|   ptrdiff_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                             = __specs.__alignment_ == __format_spec::__alignment::__zero_padding; | ||||
|   if (__size < __specs.__width_) { | ||||
|     if (__zero_padding) { | ||||
|       __specs.__alignment_ = __format_spec::__alignment::__right; | ||||
|       __specs.__fill_.__data[0] = _CharT('0'); | ||||
|     } | ||||
| 
 | ||||
|     __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_); | ||||
|   } | ||||
| 
 | ||||
|   // sign and (zero padding or alignment)
 | ||||
|   if (__zero_padding && __first != __buffer.begin()) | ||||
|     *__out_it++ = *__buffer.begin(); | ||||
|   __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); | ||||
|   if (!__zero_padding && __first != __buffer.begin()) | ||||
|     *__out_it++ = *__buffer.begin(); | ||||
| 
 | ||||
|   // integral part
 | ||||
|   if (__grouping.empty()) { | ||||
|     __out_it = __formatter::__copy(__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 = __formatter::__copy(__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    = __formatter::__copy(__result.__radix_point + 1, __result.__exponent, _VSTD::move(__out_it)); | ||||
|     __out_it    = __formatter::__fill(_VSTD::move(__out_it), __buffer.__num_trailing_zeros(), _CharT('0')); | ||||
|   } | ||||
| 
 | ||||
|   // exponent
 | ||||
|   if (__result.__exponent != __result.__last) | ||||
|     __out_it = __formatter::__copy(__result.__exponent, __result.__last, _VSTD::move(__out_it)); | ||||
| 
 | ||||
|   // alignment
 | ||||
|   return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); | ||||
| } | ||||
| #  endif // _LIBCPP_HAS_NO_LOCALIZATION
 | ||||
| 
 | ||||
| template <class _OutIt, class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI _OutIt __format_floating_point_non_finite( | ||||
|     _OutIt __out_it, __format_spec::__parsed_specifications<_CharT> __specs, bool __negative, bool __isnan) { | ||||
|   char __buffer[4]; | ||||
|   char* __last = __formatter::__insert_sign(__buffer, __negative, __specs.__std_.__sign_); | ||||
| 
 | ||||
|   // to_chars 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.
 | ||||
|   bool __upper_case = | ||||
|       __specs.__std_.__type_ == __format_spec::__type::__hexfloat_upper_case || | ||||
|       __specs.__std_.__type_ == __format_spec::__type::__scientific_upper_case || | ||||
|       __specs.__std_.__type_ == __format_spec::__type::__fixed_upper_case || | ||||
|       __specs.__std_.__type_ == __format_spec::__type::__general_upper_case; | ||||
|   __last = _VSTD::copy_n(&("infnanINFNAN"[6 * __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 (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) | ||||
|     __specs.__alignment_ = __format_spec::__alignment::__right; | ||||
| 
 | ||||
|   return __formatter::__write(__buffer, __last, _VSTD::move(__out_it), __specs); | ||||
| } | ||||
| 
 | ||||
| template <floating_point _Tp, class _CharT, class _FormatContext> | ||||
| _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
| __format_floating_point(_Tp __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { | ||||
|   bool __negative = _VSTD::signbit(__value); | ||||
| 
 | ||||
|   if (!_VSTD::isfinite(__value)) [[unlikely]] | ||||
|     return __formatter::__format_floating_point_non_finite(__ctx.out(), __specs, __negative, _VSTD::isnan(__value)); | ||||
| 
 | ||||
|   // 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 = -__value; | ||||
| 
 | ||||
|   // 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(__specs.__precision_); | ||||
|   __float_result __result = __formatter::__format_buffer( | ||||
|       __buffer, __value, __negative, (__specs.__has_precision()), __specs.__std_.__sign_, __specs.__std_.__type_); | ||||
| 
 | ||||
|   if (__specs.__std_.__alternate_form_) { | ||||
|     if (__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; | ||||
|     } | ||||
| 
 | ||||
|     // [format.string.std]/6
 | ||||
|     //   In addition, for g and G conversions, trailing zeros are not removed
 | ||||
|     //   from the result.
 | ||||
|     //
 | ||||
|     // If the type option for a floating-point type is none it may use the
 | ||||
|     // general formatting, but it's not a g or G conversion. So in that case
 | ||||
|     // the formatting should not append trailing zeros.
 | ||||
|     bool __is_general = __specs.__std_.__type_ == __format_spec::__type::__general_lower_case || | ||||
|                         __specs.__std_.__type_ == __format_spec::__type::__general_upper_case; | ||||
| 
 | ||||
|     if (__is_general) { | ||||
|       // https://en.cppreference.com/w/c/io/fprintf
 | ||||
|       // Let P equal the precision if nonzero, 6 if the precision is not
 | ||||
|       // specified, or 1 if the precision is 0. Then, if a conversion with
 | ||||
|       // style E would have an exponent of X:
 | ||||
|       int __p = _VSTD::max(1, (__specs.__has_precision() ? __specs.__precision_ : 6)); | ||||
|       if (__result.__exponent == __result.__last) | ||||
|         // if P > X >= -4, the conversion is with style f or F and precision P - 1 - X.
 | ||||
|         // By including the radix point it calculates P - (1 + X)
 | ||||
|         __p -= __result.__radix_point - __result.__integral; | ||||
|       else | ||||
|         // otherwise, the conversion is with style e or E and precision P - 1.
 | ||||
|         --__p; | ||||
| 
 | ||||
|       ptrdiff_t __precision = (__result.__exponent - __result.__radix_point) - 1; | ||||
|       if (__precision < __p) | ||||
|         __buffer.__add_trailing_zeros(__p - __precision); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| #  ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
|   if (__specs.__std_.__locale_specific_form_) | ||||
|     return __formatter::__format_locale_specific_form(__ctx.out(), __buffer, __result, __ctx.locale(), __specs); | ||||
| #  endif | ||||
| 
 | ||||
|   ptrdiff_t __size         = __result.__last - __buffer.begin(); | ||||
|   int __num_trailing_zeros = __buffer.__num_trailing_zeros(); | ||||
|   if (__size + __num_trailing_zeros >= __specs.__width_) { | ||||
|     if (__num_trailing_zeros && __result.__exponent != __result.__last) | ||||
|       // Insert trailing zeros before exponent character.
 | ||||
|       return __formatter::__copy( | ||||
|           __result.__exponent, | ||||
|           __result.__last, | ||||
|           __formatter::__fill(__formatter::__copy(__buffer.begin(), __result.__exponent, __ctx.out()), | ||||
|                               __num_trailing_zeros, | ||||
|                               _CharT('0'))); | ||||
| 
 | ||||
|     return __formatter::__fill( | ||||
|         __formatter::__copy(__buffer.begin(), __result.__last, __ctx.out()), __num_trailing_zeros, _CharT('0')); | ||||
|   } | ||||
| 
 | ||||
|   auto __out_it = __ctx.out(); | ||||
|   char* __first = __buffer.begin(); | ||||
|   if (__specs.__alignment_ == __format_spec::__alignment ::__zero_padding) { | ||||
|     // 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'.
 | ||||
|     __specs.__alignment_ = __format_spec::__alignment::__right; | ||||
|     __specs.__fill_.__data[0] = _CharT('0'); | ||||
|   } | ||||
| 
 | ||||
|   if (__num_trailing_zeros) | ||||
|     return __formatter::__write_using_trailing_zeros( | ||||
|         __first, __result.__last, _VSTD::move(__out_it), __specs, __size, __result.__exponent, __num_trailing_zeros); | ||||
| 
 | ||||
|   return __formatter::__write(__first, __result.__last, _VSTD::move(__out_it), __specs, __size); | ||||
| } | ||||
| 
 | ||||
| } // namespace __formatter
 | ||||
| 
 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __formatter_floating_point { | ||||
| public: | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_floating_point); | ||||
|     __format_spec::__process_parsed_floating_point(__parser_); | ||||
|     return __result; | ||||
|   } | ||||
| 
 | ||||
|   template <floating_point _Tp, class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Tp __value, _FormatContext& __ctx) const { | ||||
|     return __formatter::__format_floating_point(__value, __ctx, __parser_.__get_parsed_std_specifications(__ctx)); | ||||
|   } | ||||
| 
 | ||||
|   __format_spec::__parser<_CharT> __parser_; | ||||
| }; | ||||
| 
 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<float, _CharT> | ||||
|     : public __formatter_floating_point<_CharT> {}; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<double, _CharT> | ||||
|     : public __formatter_floating_point<_CharT> {}; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<long double, _CharT> | ||||
|     : public __formatter_floating_point<_CharT> {}; | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| _LIBCPP_POP_MACROS | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H
 | ||||
							
								
								
									
										107
									
								
								third_party/libcxx/__format/formatter_integer.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								third_party/libcxx/__format/formatter_integer.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | |||
| // -*- 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_INTEGER_H | ||||
| #define _LIBCPP___FORMAT_FORMATTER_INTEGER_H | ||||
| 
 | ||||
| #include <__availability> | ||||
| #include <__concepts/arithmetic.h> | ||||
| #include <__config> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/format_parse_context.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/formatter_integral.h> | ||||
| #include <__format/formatter_output.h> | ||||
| #include <__format/parser_std_format_spec.h> | ||||
| #include <__type_traits/is_same.h> | ||||
| #include <__type_traits/make_32_64_or_128_bit.h> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
|     _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
|     template <__fmt_char_type _CharT> | ||||
|     struct _LIBCPP_TEMPLATE_VIS __formatter_integer { | ||||
| 
 | ||||
| public: | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral); | ||||
|     __format_spec::__process_parsed_integer(__parser_); | ||||
|     return __result; | ||||
|   } | ||||
| 
 | ||||
|   template <integral _Tp, class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Tp __value, _FormatContext& __ctx) const { | ||||
|     __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); | ||||
| 
 | ||||
|     if (__specs.__std_.__type_ == __format_spec::__type::__char) | ||||
|       return __formatter::__format_char(__value, __ctx.out(), __specs); | ||||
| 
 | ||||
|     using _Type = __make_32_64_or_128_bit_t<_Tp>; | ||||
|     static_assert(!is_same<_Type, void>::value, "unsupported integral type used in __formatter_integer::__format"); | ||||
| 
 | ||||
|     // Reduce the number of instantiation of the integer formatter
 | ||||
|     return __formatter::__format_integer(static_cast<_Type>(__value), __ctx, __specs); | ||||
|   } | ||||
| 
 | ||||
|   __format_spec::__parser<_CharT> __parser_; | ||||
| }; | ||||
| 
 | ||||
| // Signed integral types.
 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<signed char, _CharT> | ||||
|     : public __formatter_integer<_CharT> {}; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<short, _CharT> : public __formatter_integer<_CharT> { | ||||
| }; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<int, _CharT> : public __formatter_integer<_CharT> {}; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<long, _CharT> : public __formatter_integer<_CharT> {}; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<long long, _CharT> | ||||
|     : public __formatter_integer<_CharT> {}; | ||||
| #  ifndef _LIBCPP_HAS_NO_INT128 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<__int128_t, _CharT> | ||||
|     : public __formatter_integer<_CharT> {}; | ||||
| #  endif | ||||
| 
 | ||||
| // Unsigned integral types.
 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<unsigned char, _CharT> | ||||
|     : public __formatter_integer<_CharT> {}; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<unsigned short, _CharT> | ||||
|     : public __formatter_integer<_CharT> {}; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<unsigned, _CharT> | ||||
|     : public __formatter_integer<_CharT> {}; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long, _CharT> | ||||
|     : public __formatter_integer<_CharT> {}; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long long, _CharT> | ||||
|     : public __formatter_integer<_CharT> {}; | ||||
| #  ifndef _LIBCPP_HAS_NO_INT128 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<__uint128_t, _CharT> | ||||
|     : public __formatter_integer<_CharT> {}; | ||||
| #  endif | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMATTER_INTEGER_H
 | ||||
							
								
								
									
										368
									
								
								third_party/libcxx/__format/formatter_integral.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										368
									
								
								third_party/libcxx/__format/formatter_integral.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,368 @@ | |||
| // -*- C++ -*-
 | ||||
| //===----------------------------------------------------------------------===//
 | ||||
| //
 | ||||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | ||||
| // See https://llvm.org/LICENSE.txt for license information.
 | ||||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | ||||
| //
 | ||||
| //===----------------------------------------------------------------------===//
 | ||||
| 
 | ||||
| #ifndef _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H | ||||
| #define _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H | ||||
| 
 | ||||
| #include <__charconv/to_chars_integral.h> | ||||
| #include <__charconv/to_chars_result.h> | ||||
| #include <__charconv/traits.h> | ||||
| #include <__concepts/arithmetic.h> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/format_error.h> | ||||
| #include <__format/formatter_output.h> | ||||
| #include <__format/parser_std_format_spec.h> | ||||
| #include <__system_error/errc.h> | ||||
| #include <__type_traits/make_unsigned.h> | ||||
| #include <__utility/unreachable.h> | ||||
| #include <array> | ||||
| #include <limits> | ||||
| #include <string> | ||||
| #include <string_view> | ||||
| 
 | ||||
| #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 >= 20 | ||||
| 
 | ||||
| namespace __formatter { | ||||
| 
 | ||||
| //
 | ||||
| // Generic
 | ||||
| //
 | ||||
| 
 | ||||
| _LIBCPP_HIDE_FROM_ABI inline char* __insert_sign(char* __buf, bool __negative, __format_spec::__sign __sign) { | ||||
|   if (__negative) | ||||
|     *__buf++ = '-'; | ||||
|   else | ||||
|     switch (__sign) { | ||||
|     case __format_spec::__sign::__default: | ||||
|     case __format_spec::__sign::__minus: | ||||
|       // No sign added.
 | ||||
|       break; | ||||
|     case __format_spec::__sign::__plus: | ||||
|       *__buf++ = '+'; | ||||
|       break; | ||||
|     case __format_spec::__sign::__space: | ||||
|       *__buf++ = ' '; | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   return __buf; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Determines the required grouping based on the size of the input. | ||||
|  * | ||||
|  * The grouping's last element will be repeated. For simplicity this repeating | ||||
|  * is unwrapped based on the length of the input. (When the input is short some | ||||
|  * groups are not processed.) | ||||
|  * | ||||
|  * @returns The size of the groups to write. This means the number of | ||||
|  * separator characters written is size() - 1. | ||||
|  * | ||||
|  * @note Since zero-sized groups cause issues they are silently ignored. | ||||
|  * | ||||
|  * @note The grouping field of the locale is always a @c std::string, | ||||
|  * regardless whether the @c std::numpunct's type is @c char or @c wchar_t. | ||||
|  */ | ||||
| _LIBCPP_HIDE_FROM_ABI inline string __determine_grouping(ptrdiff_t __size, const string& __grouping) { | ||||
|   _LIBCPP_ASSERT(!__grouping.empty() && __size > __grouping[0], | ||||
|                  "The slow grouping formatting is used while there will be no " | ||||
|                  "separators written"); | ||||
|   string __r; | ||||
|   auto __end = __grouping.end() - 1; | ||||
|   auto __ptr = __grouping.begin(); | ||||
| 
 | ||||
|   while (true) { | ||||
|     __size -= *__ptr; | ||||
|     if (__size > 0) | ||||
|       __r.push_back(*__ptr); | ||||
|     else { | ||||
|       // __size <= 0 so the value pushed will be <= *__ptr.
 | ||||
|       __r.push_back(*__ptr + __size); | ||||
|       return __r; | ||||
|     } | ||||
| 
 | ||||
|     // Proceed to the next group.
 | ||||
|     if (__ptr != __end) { | ||||
|       do { | ||||
|         ++__ptr; | ||||
|         // Skip grouping with a width of 0.
 | ||||
|       } while (*__ptr == 0 && __ptr != __end); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   __libcpp_unreachable(); | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| // Char
 | ||||
| //
 | ||||
| 
 | ||||
| template <__fmt_char_type _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto __format_char( | ||||
|     integral auto __value, | ||||
|     output_iterator<const _CharT&> auto __out_it, | ||||
|     __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { | ||||
|   using _Tp = decltype(__value); | ||||
|   if constexpr (!same_as<_CharT, _Tp>) { | ||||
|     // cmp_less and cmp_greater can't be used for character types.
 | ||||
|     if constexpr (signed_integral<_CharT> == signed_integral<_Tp>) { | ||||
|       if (__value < numeric_limits<_CharT>::min() || __value > numeric_limits<_CharT>::max()) | ||||
|         std::__throw_format_error("Integral value outside the range of the char type"); | ||||
|     } else if constexpr (signed_integral<_CharT>) { | ||||
|       // _CharT is signed _Tp is unsigned
 | ||||
|       if (__value > static_cast<make_unsigned_t<_CharT>>(numeric_limits<_CharT>::max())) | ||||
|         std::__throw_format_error("Integral value outside the range of the char type"); | ||||
|     } else { | ||||
|       // _CharT is unsigned _Tp is signed
 | ||||
|       if (__value < 0 || static_cast<make_unsigned_t<_Tp>>(__value) > numeric_limits<_CharT>::max()) | ||||
|         std::__throw_format_error("Integral value outside the range of the char type"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const auto __c = static_cast<_CharT>(__value); | ||||
|   return __formatter::__write(_VSTD::addressof(__c), _VSTD::addressof(__c) + 1, _VSTD::move(__out_it), __specs); | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| // Integer
 | ||||
| //
 | ||||
| 
 | ||||
| /** Wrapper around @ref to_chars, returning the output pointer. */ | ||||
| template <integral _Tp> | ||||
| _LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, int __base) { | ||||
|   // TODO FMT Evaluate code overhead due to not calling the internal function
 | ||||
|   // directly. (Should be zero overhead.)
 | ||||
|   to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __base); | ||||
|   _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small"); | ||||
|   return __r.ptr; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Helper to determine the buffer size to output a integer in Base @em x. | ||||
|  * | ||||
|  * There are several overloads for the supported bases. The function uses the | ||||
|  * base as template argument so it can be used in a constant expression. | ||||
|  */ | ||||
| template <unsigned_integral _Tp, size_t _Base> | ||||
| consteval size_t __buffer_size() noexcept | ||||
|   requires(_Base == 2) | ||||
| { | ||||
|   return numeric_limits<_Tp>::digits // The number of binary digits.
 | ||||
|        + 2                           // Reserve space for the '0[Bb]' prefix.
 | ||||
|        + 1;                          // Reserve space for the sign.
 | ||||
| } | ||||
| 
 | ||||
| template <unsigned_integral _Tp, size_t _Base> | ||||
| consteval size_t __buffer_size() noexcept | ||||
|   requires(_Base == 8) | ||||
| { | ||||
|   return numeric_limits<_Tp>::digits // The number of binary digits.
 | ||||
|            / 3                       // Adjust to octal.
 | ||||
|        + 1                           // Turn floor to ceil.
 | ||||
|        + 1                           // Reserve space for the '0' prefix.
 | ||||
|        + 1;                          // Reserve space for the sign.
 | ||||
| } | ||||
| 
 | ||||
| template <unsigned_integral _Tp, size_t _Base> | ||||
| consteval size_t __buffer_size() noexcept | ||||
|   requires(_Base == 10) | ||||
| { | ||||
|   return numeric_limits<_Tp>::digits10 // The floored value.
 | ||||
|        + 1                             // Turn floor to ceil.
 | ||||
|        + 1;                            // Reserve space for the sign.
 | ||||
| } | ||||
| 
 | ||||
| template <unsigned_integral _Tp, size_t _Base> | ||||
| consteval size_t __buffer_size() noexcept | ||||
|   requires(_Base == 16) | ||||
| { | ||||
|   return numeric_limits<_Tp>::digits // The number of binary digits.
 | ||||
|            / 4                       // Adjust to hexadecimal.
 | ||||
|        + 2                           // Reserve space for the '0[Xx]' prefix.
 | ||||
|        + 1;                          // Reserve space for the sign.
 | ||||
| } | ||||
| 
 | ||||
| template <unsigned_integral _Tp, class _CharT, class _FormatContext> | ||||
| _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_integer( | ||||
|     _Tp __value, | ||||
|     _FormatContext& __ctx, | ||||
|     __format_spec::__parsed_specifications<_CharT> __specs, | ||||
|     bool __negative, | ||||
|     char* __begin, | ||||
|     char* __end, | ||||
|     const char* __prefix, | ||||
|     int __base) { | ||||
|   char* __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_); | ||||
|   if (__specs.__std_.__alternate_form_ && __prefix) | ||||
|     while (*__prefix) | ||||
|       *__first++ = *__prefix++; | ||||
| 
 | ||||
|   char* __last = __formatter::__to_buffer(__first, __end, __value, __base); | ||||
| 
 | ||||
| #  ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
|   if (__specs.__std_.__locale_specific_form_) { | ||||
|     const auto& __np  = std::use_facet<numpunct<_CharT>>(__ctx.locale()); | ||||
|     string __grouping = __np.grouping(); | ||||
|     ptrdiff_t __size  = __last - __first; | ||||
|     // Writing the grouped form has more overhead than the normal output
 | ||||
|     // routines. If there will be no separators written the locale-specific
 | ||||
|     // form is identical to the normal routine. Test whether to grouped form
 | ||||
|     // is required.
 | ||||
|     if (!__grouping.empty() && __size > __grouping[0]) | ||||
|       return __formatter::__write_using_decimal_separators( | ||||
|           __ctx.out(), | ||||
|           __begin, | ||||
|           __first, | ||||
|           __last, | ||||
|           __formatter::__determine_grouping(__size, __grouping), | ||||
|           __np.thousands_sep(), | ||||
|           __specs); | ||||
|   } | ||||
| #  endif | ||||
|   auto __out_it = __ctx.out(); | ||||
|   if (__specs.__alignment_ != __format_spec::__alignment::__zero_padding) | ||||
|     __first = __begin; | ||||
|   else { | ||||
|     // __buf contains [sign][prefix]data
 | ||||
|     //                              ^ location of __first
 | ||||
|     // The zero padding is done like:
 | ||||
|     // - Write [sign][prefix]
 | ||||
|     // - Write data right aligned with '0' as fill character.
 | ||||
|     __out_it             = __formatter::__copy(__begin, __first, _VSTD::move(__out_it)); | ||||
|     __specs.__alignment_ = __format_spec::__alignment::__right; | ||||
|     __specs.__fill_.__data[0] = _CharT('0'); | ||||
|     int32_t __size       = __first - __begin; | ||||
| 
 | ||||
|     __specs.__width_ -= _VSTD::min(__size, __specs.__width_); | ||||
|   } | ||||
| 
 | ||||
|   if (__specs.__std_.__type_ != __format_spec::__type::__hexadecimal_upper_case) [[likely]] | ||||
|     return __formatter::__write(__first, __last, __ctx.out(), __specs); | ||||
| 
 | ||||
|   return __formatter::__write_transformed(__first, __last, __ctx.out(), __specs, __formatter::__hex_to_upper); | ||||
| } | ||||
| 
 | ||||
| template <unsigned_integral _Tp, class _CharT, class _FormatContext> | ||||
| _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
| __format_integer(_Tp __value, | ||||
|                  _FormatContext& __ctx, | ||||
|                  __format_spec::__parsed_specifications<_CharT> __specs, | ||||
|                  bool __negative = false) { | ||||
|   switch (__specs.__std_.__type_) { | ||||
|   case __format_spec::__type::__binary_lower_case: { | ||||
|     array<char, __formatter::__buffer_size<decltype(__value), 2>()> __array; | ||||
|     return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0b", 2); | ||||
|   } | ||||
|   case __format_spec::__type::__binary_upper_case: { | ||||
|     array<char, __formatter::__buffer_size<decltype(__value), 2>()> __array; | ||||
|     return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0B", 2); | ||||
|   } | ||||
|   case __format_spec::__type::__octal: { | ||||
|     // Octal is special; if __value == 0 there's no prefix.
 | ||||
|     array<char, __formatter::__buffer_size<decltype(__value), 8>()> __array; | ||||
|     return __formatter::__format_integer( | ||||
|         __value, __ctx, __specs, __negative, __array.begin(), __array.end(), __value != 0 ? "0" : nullptr, 8); | ||||
|   } | ||||
|   case __format_spec::__type::__default: | ||||
|   case __format_spec::__type::__decimal: { | ||||
|     array<char, __formatter::__buffer_size<decltype(__value), 10>()> __array; | ||||
|     return __formatter::__format_integer( | ||||
|         __value, __ctx, __specs, __negative, __array.begin(), __array.end(), nullptr, 10); | ||||
|   } | ||||
|   case __format_spec::__type::__hexadecimal_lower_case: { | ||||
|     array<char, __formatter::__buffer_size<decltype(__value), 16>()> __array; | ||||
|     return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0x", 16); | ||||
|   } | ||||
|   case __format_spec::__type::__hexadecimal_upper_case: { | ||||
|     array<char, __formatter::__buffer_size<decltype(__value), 16>()> __array; | ||||
|     return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0X", 16); | ||||
|   } | ||||
|   default: | ||||
|     _LIBCPP_ASSERT(false, "The parse function should have validated the type"); | ||||
|     __libcpp_unreachable(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <signed_integral _Tp, class _CharT, class _FormatContext> | ||||
| _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
| __format_integer(_Tp __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { | ||||
|   // Depending on the std-format-spec string the sign and the value
 | ||||
|   // might not be outputted together:
 | ||||
|   // - alternate form may insert a prefix string.
 | ||||
|   // - zero-padding may insert additional '0' characters.
 | ||||
|   // Therefore the value is processed as a positive unsigned value.
 | ||||
|   // The function @ref __insert_sign will a '-' when the value was negative.
 | ||||
|   auto __r        = std::__to_unsigned_like(__value); | ||||
|   bool __negative = __value < 0; | ||||
|   if (__negative) | ||||
|     __r = std::__complement(__r); | ||||
| 
 | ||||
|   return __formatter::__format_integer(__r, __ctx, __specs, __negative); | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| // Formatter arithmetic (bool)
 | ||||
| //
 | ||||
| 
 | ||||
| template <class _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __bool_strings; | ||||
| 
 | ||||
| template <> | ||||
| struct _LIBCPP_TEMPLATE_VIS __bool_strings<char> { | ||||
|   static constexpr string_view __true{"true"}; | ||||
|   static constexpr string_view __false{"false"}; | ||||
| }; | ||||
| 
 | ||||
| #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <> | ||||
| struct _LIBCPP_TEMPLATE_VIS __bool_strings<wchar_t> { | ||||
|   static constexpr wstring_view __true{L"true"}; | ||||
|   static constexpr wstring_view __false{L"false"}; | ||||
| }; | ||||
| #  endif | ||||
| 
 | ||||
| template <class _CharT, class _FormatContext> | ||||
| _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
| __format_bool(bool __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { | ||||
| #  ifndef _LIBCPP_HAS_NO_LOCALIZATION | ||||
|   if (__specs.__std_.__locale_specific_form_) { | ||||
|     const auto& __np           = std::use_facet<numpunct<_CharT>>(__ctx.locale()); | ||||
|     basic_string<_CharT> __str = __value ? __np.truename() : __np.falsename(); | ||||
|     return __formatter::__write_string_no_precision(basic_string_view<_CharT>{__str}, __ctx.out(), __specs); | ||||
|   } | ||||
| #  endif | ||||
|   basic_string_view<_CharT> __str = | ||||
|       __value ? __formatter::__bool_strings<_CharT>::__true : __formatter::__bool_strings<_CharT>::__false; | ||||
|   return __formatter::__write(__str.begin(), __str.end(), __ctx.out(), __specs); | ||||
| } | ||||
| 
 | ||||
| } // namespace __formatter
 | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| _LIBCPP_POP_MACROS | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H
 | ||||
							
								
								
									
										597
									
								
								third_party/libcxx/__format/formatter_output.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										597
									
								
								third_party/libcxx/__format/formatter_output.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,597 @@ | |||
| // -*- 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_OUTPUT_H | ||||
| #define _LIBCPP___FORMAT_FORMATTER_OUTPUT_H | ||||
| 
 | ||||
| #include <__algorithm/ranges_copy.h> | ||||
| #include <__algorithm/ranges_fill_n.h> | ||||
| #include <__algorithm/ranges_for_each.h> | ||||
| #include <__algorithm/ranges_transform.h> | ||||
| #include <__bit/countl.h> | ||||
| #include <__charconv/to_chars_integral.h> | ||||
| #include <__charconv/to_chars_result.h> | ||||
| #include <__chrono/statically_widen.h> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__format/buffer.h> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/escaped_output_table.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/parser_std_format_spec.h> | ||||
| #include <__format/unicode.h> | ||||
| #include <__iterator/back_insert_iterator.h> | ||||
| #include <__iterator/concepts.h> | ||||
| #include <__iterator/readable_traits.h> // iter_value_t | ||||
| #include <__system_error/errc.h> | ||||
| #include <__type_traits/make_unsigned.h> | ||||
| #include <__utility/move.h> | ||||
| #include <__utility/unreachable.h> | ||||
| #include <cstddef> | ||||
| #include <string> | ||||
| #include <string_view> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| namespace __formatter { | ||||
| 
 | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char __c) { | ||||
|   switch (__c) { | ||||
|   case 'a': | ||||
|     return 'A'; | ||||
|   case 'b': | ||||
|     return 'B'; | ||||
|   case 'c': | ||||
|     return 'C'; | ||||
|   case 'd': | ||||
|     return 'D'; | ||||
|   case 'e': | ||||
|     return 'E'; | ||||
|   case 'f': | ||||
|     return 'F'; | ||||
|   } | ||||
|   return __c; | ||||
| } | ||||
| 
 | ||||
| struct _LIBCPP_TYPE_VIS __padding_size_result { | ||||
|   size_t __before_; | ||||
|   size_t __after_; | ||||
| }; | ||||
| 
 | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result | ||||
| __padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) { | ||||
|   _LIBCPP_ASSERT(__width > __size, "don't call this function when no padding is required"); | ||||
|   _LIBCPP_ASSERT( | ||||
|       __align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding"); | ||||
| 
 | ||||
|   size_t __fill = __width - __size; | ||||
|   switch (__align) { | ||||
|   case __format_spec::__alignment::__zero_padding: | ||||
|     __libcpp_unreachable(); | ||||
| 
 | ||||
|   case __format_spec::__alignment::__left: | ||||
|     return {0, __fill}; | ||||
| 
 | ||||
|   case __format_spec::__alignment::__center: { | ||||
|     // The extra padding is divided per [format.string.std]/3
 | ||||
|     // __before = floor(__fill, 2);
 | ||||
|     // __after = ceil(__fill, 2);
 | ||||
|     size_t __before = __fill / 2; | ||||
|     size_t __after  = __fill - __before; | ||||
|     return {__before, __after}; | ||||
|   } | ||||
|   case __format_spec::__alignment::__default: | ||||
|   case __format_spec::__alignment::__right: | ||||
|     return {__fill, 0}; | ||||
|   } | ||||
|   __libcpp_unreachable(); | ||||
| } | ||||
| 
 | ||||
| /// Copy wrapper.
 | ||||
| ///
 | ||||
| /// This uses a "mass output function" of __format::__output_buffer when possible.
 | ||||
| template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto __copy(basic_string_view<_CharT> __str, output_iterator<const _OutCharT&> auto __out_it) | ||||
|     -> decltype(__out_it) { | ||||
|   if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) { | ||||
|     __out_it.__get_container()->__copy(__str); | ||||
|     return __out_it; | ||||
|   } else if constexpr (_VSTD::same_as<decltype(__out_it), | ||||
|                                       typename __format::__retarget_buffer<_OutCharT>::__iterator>) { | ||||
|     __out_it.__buffer_->__copy(__str); | ||||
|     return __out_it; | ||||
|   } else { | ||||
|     return std::ranges::copy(__str, _VSTD::move(__out_it)).out; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto | ||||
| __copy(const _CharT* __first, const _CharT* __last, output_iterator<const _OutCharT&> auto __out_it) | ||||
|     -> decltype(__out_it) { | ||||
|   return __formatter::__copy(basic_string_view{__first, __last}, _VSTD::move(__out_it)); | ||||
| } | ||||
| 
 | ||||
| template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto __copy(const _CharT* __first, size_t __n, output_iterator<const _OutCharT&> auto __out_it) | ||||
|     -> decltype(__out_it) { | ||||
|   return __formatter::__copy(basic_string_view{__first, __n}, _VSTD::move(__out_it)); | ||||
| } | ||||
| 
 | ||||
| /// Transform wrapper.
 | ||||
| ///
 | ||||
| /// This uses a "mass output function" of __format::__output_buffer when possible.
 | ||||
| template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT, class _UnaryOperation> | ||||
| _LIBCPP_HIDE_FROM_ABI auto | ||||
| __transform(const _CharT* __first, | ||||
|             const _CharT* __last, | ||||
|             output_iterator<const _OutCharT&> auto __out_it, | ||||
|             _UnaryOperation __operation) -> decltype(__out_it) { | ||||
|   if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) { | ||||
|     __out_it.__get_container()->__transform(__first, __last, _VSTD::move(__operation)); | ||||
|     return __out_it; | ||||
|   } else if constexpr (_VSTD::same_as<decltype(__out_it), | ||||
|                                       typename __format::__retarget_buffer<_OutCharT>::__iterator>) { | ||||
|     __out_it.__buffer_->__transform(__first, __last, _VSTD::move(__operation)); | ||||
|     return __out_it; | ||||
|   } else { | ||||
|     return std::ranges::transform(__first, __last, _VSTD::move(__out_it), __operation).out; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /// Fill wrapper.
 | ||||
| ///
 | ||||
| /// This uses a "mass output function" of __format::__output_buffer when possible.
 | ||||
| template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> | ||||
| _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, _CharT __value) { | ||||
|   if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_CharT>>>) { | ||||
|     __out_it.__get_container()->__fill(__n, __value); | ||||
|     return __out_it; | ||||
|   } else if constexpr (_VSTD::same_as<decltype(__out_it), typename __format::__retarget_buffer<_CharT>::__iterator>) { | ||||
|     __out_it.__buffer_->__fill(__n, __value); | ||||
|     return __out_it; | ||||
|   } else { | ||||
|     return std::ranges::fill_n(_VSTD::move(__out_it), __n, __value); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| #  ifndef _LIBCPP_HAS_NO_UNICODE | ||||
| template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> | ||||
|   requires(same_as<_CharT, char>) | ||||
| _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { | ||||
|   std::size_t __bytes = std::countl_one(static_cast<unsigned char>(__value.__data[0])); | ||||
|   if (__bytes == 0) | ||||
|     return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); | ||||
| 
 | ||||
|   for (size_t __i = 0; __i < __n; ++__i) | ||||
|     __out_it = __formatter::__copy( | ||||
|         std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + __bytes, std::move(__out_it)); | ||||
|   return __out_it; | ||||
| } | ||||
| 
 | ||||
| #    ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> | ||||
|   requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2) | ||||
| _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { | ||||
|   if (!__unicode::__is_high_surrogate(__value.__data[0])) | ||||
|     return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); | ||||
| 
 | ||||
|   for (size_t __i = 0; __i < __n; ++__i) | ||||
|     __out_it = __formatter::__copy( | ||||
|         std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + 2, std::move(__out_it)); | ||||
|   return __out_it; | ||||
| } | ||||
| 
 | ||||
| template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> | ||||
|   requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4) | ||||
| _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { | ||||
|   return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); | ||||
| } | ||||
| #    endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
 | ||||
| #  else    // _LIBCPP_HAS_NO_UNICODE
 | ||||
| template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> | ||||
| _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { | ||||
|   return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); | ||||
| } | ||||
| #  endif   // _LIBCPP_HAS_NO_UNICODE
 | ||||
| 
 | ||||
| template <class _OutIt, class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, const char* __begin, const char* __first, | ||||
|                                                               const char* __last, string&& __grouping, _CharT __sep, | ||||
|                                                               __format_spec::__parsed_specifications<_CharT> __specs) { | ||||
|   int __size = (__first - __begin) +    // [sign][prefix]
 | ||||
|                (__last - __first) +     // data
 | ||||
|                (__grouping.size() - 1); // number of separator characters
 | ||||
| 
 | ||||
|   __padding_size_result __padding = {0, 0}; | ||||
|   if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) { | ||||
|     // Write [sign][prefix].
 | ||||
|     __out_it = __formatter::__copy(__begin, __first, _VSTD::move(__out_it)); | ||||
| 
 | ||||
|     if (__specs.__width_ > __size) { | ||||
|       // Write zero padding.
 | ||||
|       __padding.__before_ = __specs.__width_ - __size; | ||||
|       __out_it            = __formatter::__fill(_VSTD::move(__out_it), __specs.__width_ - __size, _CharT('0')); | ||||
|     } | ||||
|   } else { | ||||
|     if (__specs.__width_ > __size) { | ||||
|       // Determine padding and write padding.
 | ||||
|       __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_); | ||||
| 
 | ||||
|       __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); | ||||
|     } | ||||
|     // Write [sign][prefix].
 | ||||
|     __out_it = __formatter::__copy(__begin, __first, _VSTD::move(__out_it)); | ||||
|   } | ||||
| 
 | ||||
|   auto __r = __grouping.rbegin(); | ||||
|   auto __e = __grouping.rend() - 1; | ||||
|   _LIBCPP_ASSERT(__r != __e, "The slow grouping formatting is used while " | ||||
|                              "there will be no separators written."); | ||||
|   // The output is divided in small groups of numbers to write:
 | ||||
|   // - A group before the first separator.
 | ||||
|   // - A separator and a group, repeated for the number of separators.
 | ||||
|   // - A group after the last separator.
 | ||||
|   // This loop achieves that process by testing the termination condition
 | ||||
|   // midway in the loop.
 | ||||
|   //
 | ||||
|   // TODO FMT This loop evaluates the loop invariant `__parser.__type !=
 | ||||
|   // _Flags::_Type::__hexadecimal_upper_case` for every iteration. (This test
 | ||||
|   // happens in the __write call.) Benchmark whether making two loops and
 | ||||
|   // hoisting the invariant is worth the effort.
 | ||||
|   while (true) { | ||||
|     if (__specs.__std_.__type_ == __format_spec::__type::__hexadecimal_upper_case) { | ||||
|       __last = __first + *__r; | ||||
|       __out_it = __formatter::__transform(__first, __last, _VSTD::move(__out_it), __hex_to_upper); | ||||
|       __first = __last; | ||||
|     } else { | ||||
|       __out_it = __formatter::__copy(__first, *__r, _VSTD::move(__out_it)); | ||||
|       __first += *__r; | ||||
|     } | ||||
| 
 | ||||
|     if (__r == __e) | ||||
|       break; | ||||
| 
 | ||||
|     ++__r; | ||||
|     *__out_it++ = __sep; | ||||
|   } | ||||
| 
 | ||||
|   return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); | ||||
| } | ||||
| 
 | ||||
| /// Writes the input to the output with the required padding.
 | ||||
| ///
 | ||||
| /// Since the output column width is specified the function can be used for
 | ||||
| /// ASCII and Unicode output.
 | ||||
| ///
 | ||||
| /// \pre \a __size <= \a __width. Using this function when this pre-condition
 | ||||
| ///      doesn't hold incurs an unwanted overhead.
 | ||||
| ///
 | ||||
| /// \param __str       The string to write.
 | ||||
| /// \param __out_it    The output iterator to write to.
 | ||||
| /// \param __specs     The parsed formatting specifications.
 | ||||
| /// \param __size      The (estimated) output column width. When the elements
 | ||||
| ///                    to be written are ASCII the following condition holds
 | ||||
| ///                    \a __size == \a __last - \a __first.
 | ||||
| ///
 | ||||
| /// \returns           An iterator pointing beyond the last element written.
 | ||||
| ///
 | ||||
| /// \note The type of the elements in range [\a __first, \a __last) can differ
 | ||||
| /// from the type of \a __specs. Integer output uses \c std::to_chars for its
 | ||||
| /// conversion, which means the [\a __first, \a __last) always contains elements
 | ||||
| /// of the type \c char.
 | ||||
| template <class _CharT, class _ParserCharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto | ||||
| __write(basic_string_view<_CharT> __str, | ||||
|         output_iterator<const _CharT&> auto __out_it, | ||||
|         __format_spec::__parsed_specifications<_ParserCharT> __specs, | ||||
|         ptrdiff_t __size) -> decltype(__out_it) { | ||||
|   if (__size >= __specs.__width_) | ||||
|     return __formatter::__copy(__str, _VSTD::move(__out_it)); | ||||
| 
 | ||||
|   __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__std_.__alignment_); | ||||
|   __out_it                        = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); | ||||
|   __out_it                        = __formatter::__copy(__str, _VSTD::move(__out_it)); | ||||
|   return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); | ||||
| } | ||||
| 
 | ||||
| template <contiguous_iterator _Iterator, class _ParserCharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto | ||||
| __write(_Iterator __first, | ||||
|         _Iterator __last, | ||||
|         output_iterator<const iter_value_t<_Iterator>&> auto __out_it, | ||||
|         __format_spec::__parsed_specifications<_ParserCharT> __specs, | ||||
|         ptrdiff_t __size) -> decltype(__out_it) { | ||||
|   _LIBCPP_ASSERT(__first <= __last, "Not a valid range"); | ||||
|   return __formatter::__write(basic_string_view{__first, __last}, _VSTD::move(__out_it), __specs, __size); | ||||
| } | ||||
| 
 | ||||
| /// \overload
 | ||||
| ///
 | ||||
| /// Calls the function above where \a __size = \a __last - \a __first.
 | ||||
| template <contiguous_iterator _Iterator, class _ParserCharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto | ||||
| __write(_Iterator __first, | ||||
|         _Iterator __last, | ||||
|         output_iterator<const iter_value_t<_Iterator>&> auto __out_it, | ||||
|         __format_spec::__parsed_specifications<_ParserCharT> __specs) -> decltype(__out_it) { | ||||
|   _LIBCPP_ASSERT(__first <= __last, "Not a valid range"); | ||||
|   return __formatter::__write(__first, __last, _VSTD::move(__out_it), __specs, __last - __first); | ||||
| } | ||||
| 
 | ||||
| template <class _CharT, class _ParserCharT, class _UnaryOperation> | ||||
| _LIBCPP_HIDE_FROM_ABI auto __write_transformed(const _CharT* __first, const _CharT* __last, | ||||
|                                                output_iterator<const _CharT&> auto __out_it, | ||||
|                                                __format_spec::__parsed_specifications<_ParserCharT> __specs, | ||||
|                                                _UnaryOperation __op) -> decltype(__out_it) { | ||||
|   _LIBCPP_ASSERT(__first <= __last, "Not a valid range"); | ||||
| 
 | ||||
|   ptrdiff_t __size = __last - __first; | ||||
|   if (__size >= __specs.__width_) | ||||
|     return __formatter::__transform(__first, __last, _VSTD::move(__out_it), __op); | ||||
| 
 | ||||
|   __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_); | ||||
|   __out_it                        = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); | ||||
|   __out_it                        = __formatter::__transform(__first, __last, _VSTD::move(__out_it), __op); | ||||
|   return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); | ||||
| } | ||||
| 
 | ||||
| /// 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 _ParserCharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto __write_using_trailing_zeros( | ||||
|     const _CharT* __first, | ||||
|     const _CharT* __last, | ||||
|     output_iterator<const _CharT&> auto __out_it, | ||||
|     __format_spec::__parsed_specifications<_ParserCharT> __specs, | ||||
|     size_t __size, | ||||
|     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 = | ||||
|       __formatter::__padding_size(__size + __num_trailing_zeros, __specs.__width_, __specs.__alignment_); | ||||
|   __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); | ||||
|   __out_it = __formatter::__copy(__first, __exponent, _VSTD::move(__out_it)); | ||||
|   __out_it = __formatter::__fill(_VSTD::move(__out_it), __num_trailing_zeros, _CharT('0')); | ||||
|   __out_it = __formatter::__copy(__exponent, __last, _VSTD::move(__out_it)); | ||||
|   return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); | ||||
| } | ||||
| 
 | ||||
| /// Writes a string using format's width estimation algorithm.
 | ||||
| ///
 | ||||
| /// \pre !__specs.__has_precision()
 | ||||
| ///
 | ||||
| /// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the
 | ||||
| /// input is ASCII.
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision( | ||||
|     basic_string_view<_CharT> __str, | ||||
|     output_iterator<const _CharT&> auto __out_it, | ||||
|     __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { | ||||
|   _LIBCPP_ASSERT(!__specs.__has_precision(), "use __write_string"); | ||||
| 
 | ||||
|   // No padding -> copy the string
 | ||||
|   if (!__specs.__has_width()) | ||||
|     return __formatter::__copy(__str, _VSTD::move(__out_it)); | ||||
| 
 | ||||
|   // Note when the estimated width is larger than size there's no padding. So
 | ||||
|   // there's no reason to get the real size when the estimate is larger than or
 | ||||
|   // equal to the minimum field width.
 | ||||
|   size_t __size = | ||||
|       __format_spec::__estimate_column_width(__str, __specs.__width_, __format_spec::__column_width_rounding::__up) | ||||
|           .__width_; | ||||
|   return __formatter::__write(__str, _VSTD::move(__out_it), __specs, __size); | ||||
| } | ||||
| 
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __precision) { | ||||
|   __format_spec::__column_width_result __result = | ||||
|       __format_spec::__estimate_column_width(__str, __precision, __format_spec::__column_width_rounding::__down); | ||||
|   __str = basic_string_view<_CharT>{__str.begin(), __result.__last_}; | ||||
|   return __result.__width_; | ||||
| } | ||||
| 
 | ||||
| /// Writes a string using format's width estimation algorithm.
 | ||||
| ///
 | ||||
| /// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the
 | ||||
| /// input is ASCII.
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto __write_string( | ||||
|     basic_string_view<_CharT> __str, | ||||
|     output_iterator<const _CharT&> auto __out_it, | ||||
|     __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { | ||||
|   if (!__specs.__has_precision()) | ||||
|     return __formatter::__write_string_no_precision(__str, _VSTD::move(__out_it), __specs); | ||||
| 
 | ||||
|   int __size = __formatter::__truncate(__str, __specs.__precision_); | ||||
| 
 | ||||
|   return __formatter::__write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __size); | ||||
| } | ||||
| 
 | ||||
| #  if _LIBCPP_STD_VER >= 23 | ||||
| 
 | ||||
| struct __nul_terminator {}; | ||||
| 
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI bool operator==(const _CharT* __cstr, __nul_terminator) { | ||||
|   return *__cstr == _CharT('\0'); | ||||
| } | ||||
| 
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI void | ||||
| __write_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value, const _CharT* __prefix) { | ||||
|   back_insert_iterator __out_it{__str}; | ||||
|   std::ranges::copy(__prefix, __nul_terminator{}, __out_it); | ||||
| 
 | ||||
|   char __buffer[8]; | ||||
|   to_chars_result __r = std::to_chars(std::begin(__buffer), std::end(__buffer), __value, 16); | ||||
|   _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small"); | ||||
|   std::ranges::copy(std::begin(__buffer), __r.ptr, __out_it); | ||||
| 
 | ||||
|   __str += _CharT('}'); | ||||
| } | ||||
| 
 | ||||
| // [format.string.escaped]/2.2.1.2
 | ||||
| // ...
 | ||||
| // then the sequence \u{hex-digit-sequence} is appended to E, where
 | ||||
| // hex-digit-sequence is the shortest hexadecimal representation of C using
 | ||||
| // lower-case hexadecimal digits.
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI void __write_well_formed_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value) { | ||||
|   __formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\u{")); | ||||
| } | ||||
| 
 | ||||
| // [format.string.escaped]/2.2.3
 | ||||
| // Otherwise (X is a sequence of ill-formed code units), each code unit U is
 | ||||
| // appended to E in order as the sequence \x{hex-digit-sequence}, where
 | ||||
| // hex-digit-sequence is the shortest hexadecimal representation of U using
 | ||||
| // lower-case hexadecimal digits.
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI void __write_escape_ill_formed_code_unit(basic_string<_CharT>& __str, char32_t __value) { | ||||
|   __formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\x{")); | ||||
| } | ||||
| 
 | ||||
| template <class _CharT> | ||||
| [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_escaped_sequence_written(basic_string<_CharT>& __str, char32_t __value) { | ||||
| #    ifdef _LIBCPP_HAS_NO_UNICODE | ||||
|   // For ASCII assume everything above 127 is printable.
 | ||||
|   if (__value > 127) | ||||
|     return false; | ||||
| #    endif | ||||
| 
 | ||||
|   if (!__escaped_output_table::__needs_escape(__value)) | ||||
|     return false; | ||||
| 
 | ||||
|   __formatter::__write_well_formed_escaped_code_unit(__str, __value); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| template <class _CharT> | ||||
| [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr char32_t __to_char32(_CharT __value) { | ||||
|   return static_cast<make_unsigned_t<_CharT>>(__value); | ||||
| } | ||||
| 
 | ||||
| enum class _LIBCPP_ENUM_VIS __escape_quotation_mark { __apostrophe, __double_quote }; | ||||
| 
 | ||||
| // [format.string.escaped]/2
 | ||||
| template <class _CharT> | ||||
| [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool | ||||
| __is_escaped_sequence_written(basic_string<_CharT>& __str, char32_t __value, __escape_quotation_mark __mark) { | ||||
|   // 2.2.1.1 - Mapped character in [tab:format.escape.sequences]
 | ||||
|   switch (__value) { | ||||
|   case _CharT('\t'): | ||||
|     __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\t"); | ||||
|     return true; | ||||
|   case _CharT('\n'): | ||||
|     __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\n"); | ||||
|     return true; | ||||
|   case _CharT('\r'): | ||||
|     __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\r"); | ||||
|     return true; | ||||
|   case _CharT('\''): | ||||
|     if (__mark == __escape_quotation_mark::__apostrophe) | ||||
|       __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\')"); | ||||
|     else | ||||
|       __str += __value; | ||||
|     return true; | ||||
|   case _CharT('"'): | ||||
|     if (__mark == __escape_quotation_mark::__double_quote) | ||||
|       __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\")"); | ||||
|     else | ||||
|       __str += __value; | ||||
|     return true; | ||||
|   case _CharT('\\'): | ||||
|     __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\\)"); | ||||
|     return true; | ||||
| 
 | ||||
|   // 2.2.1.2 - Space
 | ||||
|   case _CharT(' '): | ||||
|     __str += __value; | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   // 2.2.2
 | ||||
|   //   Otherwise, if X is a shift sequence, the effect on E and further
 | ||||
|   //   decoding of S is unspecified.
 | ||||
|   // For now shift sequences are ignored and treated as Unicode. Other parts
 | ||||
|   // of the format library do the same. It's unknown how ostream treats them.
 | ||||
|   // TODO FMT determine what to do with shift sequences.
 | ||||
| 
 | ||||
|   // 2.2.1.2.1 and 2.2.1.2.2 - Escape
 | ||||
|   return __formatter::__is_escaped_sequence_written(__str, __formatter::__to_char32(__value)); | ||||
| } | ||||
| 
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI void | ||||
| __escape(basic_string<_CharT>& __str, basic_string_view<_CharT> __values, __escape_quotation_mark __mark) { | ||||
|   __unicode::__code_point_view<_CharT> __view{__values.begin(), __values.end()}; | ||||
| 
 | ||||
|   while (!__view.__at_end()) { | ||||
|     auto __first                                  = __view.__position(); | ||||
|     typename __unicode::__consume_result __result = __view.__consume(); | ||||
|     if (__result.__status == __unicode::__consume_result::__ok) { | ||||
|       if (!__formatter::__is_escaped_sequence_written(__str, __result.__code_point, __mark)) | ||||
|         // 2.2.1.3 - Add the character
 | ||||
|         ranges::copy(__first, __view.__position(), std::back_insert_iterator(__str)); | ||||
|     } else { | ||||
|       // 2.2.3 sequence of ill-formed code units
 | ||||
|       ranges::for_each(__first, __view.__position(), [&](_CharT __value) { | ||||
|         __formatter::__write_escape_ill_formed_code_unit(__str, __formatter::__to_char32(__value)); | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto | ||||
| __format_escaped_char(_CharT __value, | ||||
|                       output_iterator<const _CharT&> auto __out_it, | ||||
|                       __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { | ||||
|   basic_string<_CharT> __str; | ||||
|   __str += _CharT('\''); | ||||
|   __formatter::__escape(__str, basic_string_view{std::addressof(__value), 1}, __escape_quotation_mark::__apostrophe); | ||||
|   __str += _CharT('\''); | ||||
|   return __formatter::__write(__str.data(), __str.data() + __str.size(), _VSTD::move(__out_it), __specs, __str.size()); | ||||
| } | ||||
| 
 | ||||
| template <class _CharT> | ||||
| _LIBCPP_HIDE_FROM_ABI auto | ||||
| __format_escaped_string(basic_string_view<_CharT> __values, | ||||
|                         output_iterator<const _CharT&> auto __out_it, | ||||
|                         __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { | ||||
|   basic_string<_CharT> __str; | ||||
|   __str += _CharT('"'); | ||||
|   __formatter::__escape(__str, __values, __escape_quotation_mark::__double_quote); | ||||
|   __str += _CharT('"'); | ||||
|   return __formatter::__write_string(basic_string_view{__str}, _VSTD::move(__out_it), __specs); | ||||
| } | ||||
| 
 | ||||
| #  endif // _LIBCPP_STD_VER >= 23
 | ||||
| 
 | ||||
| } // namespace __formatter
 | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMATTER_OUTPUT_H
 | ||||
							
								
								
									
										72
									
								
								third_party/libcxx/__format/formatter_pointer.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								third_party/libcxx/__format/formatter_pointer.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | |||
| // -*- 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 <__availability> | ||||
| #include <__config> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/format_parse_context.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/formatter_integral.h> | ||||
| #include <__format/formatter_output.h> | ||||
| #include <__format/parser_std_format_spec.h> | ||||
| #include <cstddef> | ||||
| #include <cstdint> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __formatter_pointer { | ||||
| public: | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_pointer); | ||||
|     __format_spec::__process_display_type_pointer(__parser_.__type_); | ||||
|     return __result; | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const void* __ptr, _FormatContext& __ctx) const { | ||||
|     __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); | ||||
|     __specs.__std_.__alternate_form_                       = true; | ||||
|     __specs.__std_.__type_                                 = __format_spec::__type::__hexadecimal_lower_case; | ||||
|     return __formatter::__format_integer(reinterpret_cast<uintptr_t>(__ptr), __ctx, __specs); | ||||
|   } | ||||
| 
 | ||||
|   __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right}; | ||||
| }; | ||||
| 
 | ||||
| // [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 <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<nullptr_t, _CharT> | ||||
|     : public __formatter_pointer<_CharT> {}; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<void*, _CharT> : public __formatter_pointer<_CharT> { | ||||
| }; | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<const void*, _CharT> | ||||
|     : public __formatter_pointer<_CharT> {}; | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMATTER_POINTER_H
 | ||||
							
								
								
									
										155
									
								
								third_party/libcxx/__format/formatter_string.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								third_party/libcxx/__format/formatter_string.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,155 @@ | |||
| // -*- 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_STRING_H | ||||
| #define _LIBCPP___FORMAT_FORMATTER_STRING_H | ||||
| 
 | ||||
| #include <__availability> | ||||
| #include <__config> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/format_parse_context.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/formatter_output.h> | ||||
| #include <__format/parser_std_format_spec.h> | ||||
| #include <__utility/move.h> | ||||
| #include <string> | ||||
| #include <string_view> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __formatter_string { | ||||
| public: | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_string); | ||||
|     __format_spec::__process_display_type_string(__parser_.__type_); | ||||
|     return __result; | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
|   format(basic_string_view<_CharT> __str, _FormatContext& __ctx) const { | ||||
| #  if _LIBCPP_STD_VER >= 23 | ||||
|     if (__parser_.__type_ == __format_spec::__type::__debug) | ||||
|       return __formatter::__format_escaped_string(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx)); | ||||
| #  endif | ||||
| 
 | ||||
|     return __formatter::__write_string(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx)); | ||||
|   } | ||||
| 
 | ||||
| #  if _LIBCPP_STD_VER >= 23 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void set_debug_format() { __parser_.__type_ = __format_spec::__type::__debug; } | ||||
| #  endif | ||||
| 
 | ||||
|   __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left}; | ||||
| }; | ||||
| 
 | ||||
| // Formatter const char*.
 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT*, _CharT> | ||||
|     : public __formatter_string<_CharT> { | ||||
|   using _Base = __formatter_string<_CharT>; | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _CharT* __str, _FormatContext& __ctx) const { | ||||
|     _LIBCPP_ASSERT(__str, "The basic_format_arg constructor should have " | ||||
|                           "prevented an invalid pointer."); | ||||
| 
 | ||||
|     __format_spec::__parsed_specifications<_CharT> __specs = _Base::__parser_.__get_parsed_std_specifications(__ctx); | ||||
| #  if _LIBCPP_STD_VER >= 23 | ||||
|     if (_Base::__parser_.__type_ == __format_spec::__type::__debug) | ||||
|       return __formatter::__format_escaped_string(basic_string_view<_CharT>{__str}, __ctx.out(), __specs); | ||||
| #  endif | ||||
| 
 | ||||
|     // When using a center or right alignment and the width option the length
 | ||||
|     // of __str must be known to add the padding upfront. This case is handled
 | ||||
|     // by the base class by converting the argument to a basic_string_view.
 | ||||
|     //
 | ||||
|     // When using left alignment and the width option the padding is added
 | ||||
|     // after outputting __str so the length can be determined while outputting
 | ||||
|     // __str. The same holds true for the precision, during outputting __str it
 | ||||
|     // can be validated whether the precision threshold has been reached. For
 | ||||
|     // now these optimizations aren't implemented. Instead the base class
 | ||||
|     // handles these options.
 | ||||
|     // TODO FMT Implement these improvements.
 | ||||
|     if (__specs.__has_width() || __specs.__has_precision()) | ||||
|       return __formatter::__write_string(basic_string_view<_CharT>{__str}, __ctx.out(), __specs); | ||||
| 
 | ||||
|     // No formatting required, copy the string to the output.
 | ||||
|     auto __out_it = __ctx.out(); | ||||
|     while (*__str) | ||||
|       *__out_it++ = *__str++; | ||||
|     return __out_it; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // Formatter char*.
 | ||||
| template <__fmt_char_type _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<_CharT*, _CharT> | ||||
|     : public formatter<const _CharT*, _CharT> { | ||||
|   using _Base = formatter<const _CharT*, _CharT>; | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT* __str, _FormatContext& __ctx) const { | ||||
|     return _Base::format(__str, __ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // Formatter char[].
 | ||||
| template <__fmt_char_type _CharT, size_t _Size> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<_CharT[_Size], _CharT> | ||||
|     : public __formatter_string<_CharT> { | ||||
|   using _Base = __formatter_string<_CharT>; | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT __str[_Size], _FormatContext& __ctx) const { | ||||
|     return _Base::format(basic_string_view<_CharT>(__str, _Size), __ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // Formatter std::string.
 | ||||
| template <__fmt_char_type _CharT, class _Traits, class _Allocator> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<basic_string<_CharT, _Traits, _Allocator>, _CharT> | ||||
|     : public __formatter_string<_CharT> { | ||||
|   using _Base = __formatter_string<_CharT>; | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
|   format(const basic_string<_CharT, _Traits, _Allocator>& __str, _FormatContext& __ctx) const { | ||||
|     // Drop _Traits and _Allocator to have one std::basic_string formatter.
 | ||||
|     return _Base::format(basic_string_view<_CharT>(__str.data(), __str.size()), __ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // Formatter std::string_view.
 | ||||
| template <__fmt_char_type _CharT, class _Traits> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<basic_string_view<_CharT, _Traits>, _CharT> | ||||
|     : public __formatter_string<_CharT> { | ||||
|   using _Base = __formatter_string<_CharT>; | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
|   format(basic_string_view<_CharT, _Traits> __str, _FormatContext& __ctx) const { | ||||
|     // Drop _Traits to have one std::basic_string_view formatter.
 | ||||
|     return _Base::format(basic_string_view<_CharT>(__str.data(), __str.size()), __ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMATTER_STRING_H
 | ||||
							
								
								
									
										155
									
								
								third_party/libcxx/__format/formatter_tuple.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								third_party/libcxx/__format/formatter_tuple.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,155 @@ | |||
| // -*- 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_TUPLE_H | ||||
| #define _LIBCPP___FORMAT_FORMATTER_TUPLE_H | ||||
| 
 | ||||
| #include <__algorithm/ranges_copy.h> | ||||
| #include <__availability> | ||||
| #include <__chrono/statically_widen.h> | ||||
| #include <__config> | ||||
| #include <__format/buffer.h> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/format_args.h> | ||||
| #include <__format/format_context.h> | ||||
| #include <__format/format_error.h> | ||||
| #include <__format/format_parse_context.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/formatter_output.h> | ||||
| #include <__format/parser_std_format_spec.h> | ||||
| #include <__iterator/back_insert_iterator.h> | ||||
| #include <__type_traits/remove_cvref.h> | ||||
| #include <__utility/integer_sequence.h> | ||||
| #include <__utility/pair.h> | ||||
| #include <string_view> | ||||
| #include <tuple> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 23 | ||||
| 
 | ||||
| template <__fmt_char_type _CharT, class _Tuple, formattable<_CharT>... _Args> | ||||
| struct _LIBCPP_TEMPLATE_VIS __formatter_tuple { | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { | ||||
|     __separator_ = __separator; | ||||
|   } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void | ||||
|   set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { | ||||
|     __opening_bracket_ = __opening_bracket; | ||||
|     __closing_bracket_ = __closing_bracket; | ||||
|   } | ||||
| 
 | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_tuple); | ||||
| 
 | ||||
|     auto __end = __ctx.end(); | ||||
|     if (__begin != __end) { | ||||
|       if (*__begin == _CharT('m')) { | ||||
|         if constexpr (sizeof...(_Args) == 2) { | ||||
|           set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": ")); | ||||
|           set_brackets({}, {}); | ||||
|           ++__begin; | ||||
|         } else | ||||
|           std::__throw_format_error("The format specifier m requires a pair or a two-element tuple"); | ||||
|       } else if (*__begin == _CharT('n')) { | ||||
|         set_brackets({}, {}); | ||||
|         ++__begin; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (__begin != __end && *__begin != _CharT('}')) | ||||
|       std::__throw_format_error("The format-spec should consume the input or end with a '}'"); | ||||
| 
 | ||||
|     __ctx.advance_to(__begin); | ||||
| 
 | ||||
|     // [format.tuple]/7
 | ||||
|     //   ... For each element e in underlying_, if e.set_debug_format()
 | ||||
|     //   is a valid expression, calls e.set_debug_format().
 | ||||
|     std::__for_each_index_sequence(make_index_sequence<sizeof...(_Args)>(), [&]<size_t _Index> { | ||||
|       auto& __formatter = std::get<_Index>(__underlying_); | ||||
|       __formatter.parse(__ctx); | ||||
|       // Unlike the range_formatter we don't guard against evil parsers. Since
 | ||||
|       // this format-spec never has a format-spec for the underlying type
 | ||||
|       // adding the test would give additional overhead.
 | ||||
|       std::__set_debug_format(__formatter); | ||||
|     }); | ||||
| 
 | ||||
|     return __begin; | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   typename _FormatContext::iterator _LIBCPP_HIDE_FROM_ABI | ||||
|   format(conditional_t<(formattable<const _Args, _CharT> && ...), const _Tuple&, _Tuple&> __tuple, | ||||
|          _FormatContext& __ctx) const { | ||||
|     __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); | ||||
| 
 | ||||
|     if (!__specs.__has_width()) | ||||
|       return __format_tuple(__tuple, __ctx); | ||||
| 
 | ||||
|     // The size of the buffer needed is:
 | ||||
|     // - open bracket characters
 | ||||
|     // - close bracket character
 | ||||
|     // - n elements where every element may have a different size
 | ||||
|     // - (n -1) separators
 | ||||
|     // The size of the element is hard to predict, knowing the type helps but
 | ||||
|     // it depends on the format-spec. As an initial estimate we guess 6
 | ||||
|     // characters.
 | ||||
|     // Typically both brackets are 1 character and the separator is 2
 | ||||
|     // characters. Which means there will be
 | ||||
|     //   (n - 1) * 2 + 1 + 1 = n * 2 character
 | ||||
|     // So estimate 8 times the range size as buffer.
 | ||||
|     __format::__retarget_buffer<_CharT> __buffer{8 * tuple_size_v<_Tuple>}; | ||||
|     basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> __c{ | ||||
|         __buffer.__make_output_iterator(), __ctx}; | ||||
| 
 | ||||
|     __format_tuple(__tuple, __c); | ||||
| 
 | ||||
|     return __formatter::__write_string_no_precision(basic_string_view{__buffer.__view()}, __ctx.out(), __specs); | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_tuple(auto&& __tuple, _FormatContext& __ctx) const { | ||||
|     __ctx.advance_to(std::ranges::copy(__opening_bracket_, __ctx.out()).out); | ||||
| 
 | ||||
|     std::__for_each_index_sequence(make_index_sequence<sizeof...(_Args)>(), [&]<size_t _Index> { | ||||
|       if constexpr (_Index) | ||||
|         __ctx.advance_to(std::ranges::copy(__separator_, __ctx.out()).out); | ||||
|       __ctx.advance_to(std::get<_Index>(__underlying_).format(std::get<_Index>(__tuple), __ctx)); | ||||
|     }); | ||||
| 
 | ||||
|     return std::ranges::copy(__closing_bracket_, __ctx.out()).out; | ||||
|   } | ||||
| 
 | ||||
|   __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left}; | ||||
| 
 | ||||
| private: | ||||
|   tuple<formatter<remove_cvref_t<_Args>, _CharT>...> __underlying_; | ||||
|   basic_string_view<_CharT> __separator_       = _LIBCPP_STATICALLY_WIDEN(_CharT, ", "); | ||||
|   basic_string_view<_CharT> __opening_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "("); | ||||
|   basic_string_view<_CharT> __closing_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, ")"); | ||||
| }; | ||||
| 
 | ||||
| template <__fmt_char_type _CharT, formattable<_CharT>... _Args> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<pair<_Args...>, _CharT> | ||||
|     : public __formatter_tuple<_CharT, pair<_Args...>, _Args...> {}; | ||||
| 
 | ||||
| template <__fmt_char_type _CharT, formattable<_CharT>... _Args> | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<tuple<_Args...>, _CharT> | ||||
|     : public __formatter_tuple<_CharT, tuple<_Args...>, _Args...> {}; | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 23
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_FORMATTER_TUPLE_H
 | ||||
							
								
								
									
										1019
									
								
								third_party/libcxx/__format/parser_std_format_spec.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1019
									
								
								third_party/libcxx/__format/parser_std_format_spec.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										216
									
								
								third_party/libcxx/__format/range_default_formatter.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								third_party/libcxx/__format/range_default_formatter.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,216 @@ | |||
| // -*- 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_RANGE_DEFAULT_FORMATTER_H | ||||
| #define _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H | ||||
| 
 | ||||
| #include <__algorithm/ranges_copy.h> | ||||
| #include <__availability> | ||||
| #include <__chrono/statically_widen.h> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/range_formatter.h> | ||||
| #include <__iterator/back_insert_iterator.h> | ||||
| #include <__ranges/concepts.h> | ||||
| #include <__ranges/data.h> | ||||
| #include <__ranges/size.h> | ||||
| #include <__type_traits/remove_cvref.h> | ||||
| #include <__utility/pair.h> | ||||
| #include <string_view> | ||||
| #include <tuple> | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 23 | ||||
| 
 | ||||
| template <class _Rp, class _CharT> | ||||
| concept __const_formattable_range = | ||||
|     ranges::input_range<const _Rp> && formattable<ranges::range_reference_t<const _Rp>, _CharT>; | ||||
| 
 | ||||
| template <class _Rp, class _CharT> | ||||
| using __fmt_maybe_const = conditional_t<__const_formattable_range<_Rp, _CharT>, const _Rp, _Rp>; | ||||
| 
 | ||||
| _LIBCPP_DIAGNOSTIC_PUSH | ||||
| _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wshadow") | ||||
| _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshadow") | ||||
| // This shadows map, set, and string.
 | ||||
| enum class range_format { disabled, map, set, sequence, string, debug_string }; | ||||
| _LIBCPP_DIAGNOSTIC_POP | ||||
| 
 | ||||
| // There is no definition of this struct, it's purely intended to be used to
 | ||||
| // generate diagnostics.
 | ||||
| template <class _Rp> | ||||
| struct _LIBCPP_TEMPLATE_VIS __instantiated_the_primary_template_of_format_kind; | ||||
| 
 | ||||
| template <class _Rp> | ||||
| constexpr range_format format_kind = [] { | ||||
|   // [format.range.fmtkind]/1
 | ||||
|   // A program that instantiates the primary template of format_kind is ill-formed.
 | ||||
|   static_assert(sizeof(_Rp) != sizeof(_Rp), "create a template specialization of format_kind for your type"); | ||||
|   return range_format::disabled; | ||||
| }(); | ||||
| 
 | ||||
| template <ranges::input_range _Rp> | ||||
|   requires same_as<_Rp, remove_cvref_t<_Rp>> | ||||
| inline constexpr range_format format_kind<_Rp> = [] { | ||||
|   // [format.range.fmtkind]/2
 | ||||
| 
 | ||||
|   // 2.1 If same_as<remove_cvref_t<ranges::range_reference_t<R>>, R> is true,
 | ||||
|   // Otherwise format_kind<R> is range_format::disabled.
 | ||||
|   if constexpr (same_as<remove_cvref_t<ranges::range_reference_t<_Rp>>, _Rp>) | ||||
|     return range_format::disabled; | ||||
|   // 2.2 Otherwise, if the qualified-id R::key_type is valid and denotes a type:
 | ||||
|   else if constexpr (requires { typename _Rp::key_type; }) { | ||||
|     // 2.2.1 If the qualified-id R::mapped_type is valid and denotes a type ...
 | ||||
|     if constexpr (requires { typename _Rp::mapped_type; } && | ||||
|                   // 2.2.1 ... If either U is a specialization of pair or U is a specialization
 | ||||
|                   // of tuple and tuple_size_v<U> == 2
 | ||||
|                   __fmt_pair_like<remove_cvref_t<ranges::range_reference_t<_Rp>>>) | ||||
|       return range_format::map; | ||||
|     else | ||||
|       // 2.2.2 Otherwise format_kind<R> is range_format::set.
 | ||||
|       return range_format::set; | ||||
|   } else | ||||
|     // 2.3 Otherwise, format_kind<R> is range_format::sequence.
 | ||||
|     return range_format::sequence; | ||||
| }(); | ||||
| 
 | ||||
| template <range_format _Kp, ranges::input_range _Rp, class _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __range_default_formatter; | ||||
| 
 | ||||
| // Required specializations
 | ||||
| 
 | ||||
| template <ranges::input_range _Rp, class _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<range_format::sequence, _Rp, _CharT> { | ||||
| private: | ||||
|   using __maybe_const_r = __fmt_maybe_const<_Rp, _CharT>; | ||||
|   range_formatter<remove_cvref_t<ranges::range_reference_t<__maybe_const_r>>, _CharT> __underlying_; | ||||
| 
 | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { | ||||
|     __underlying_.set_separator(__separator); | ||||
|   } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void | ||||
|   set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { | ||||
|     __underlying_.set_brackets(__opening_bracket, __closing_bracket); | ||||
|   } | ||||
| 
 | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     return __underlying_.parse(__ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <class FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename FormatContext::iterator format(__maybe_const_r& __range, FormatContext& __ctx) const { | ||||
|     return __underlying_.format(__range, __ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <ranges::input_range _Rp, class _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<range_format::map, _Rp, _CharT> { | ||||
| private: | ||||
|   using __maybe_const_map = __fmt_maybe_const<_Rp, _CharT>; | ||||
|   using __element_type    = remove_cvref_t<ranges::range_reference_t<__maybe_const_map>>; | ||||
|   range_formatter<__element_type, _CharT> __underlying_; | ||||
| 
 | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter() | ||||
|     requires(__fmt_pair_like<__element_type>) | ||||
|   { | ||||
|     __underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}")); | ||||
|     __underlying_.underlying().set_brackets({}, {}); | ||||
|     __underlying_.underlying().set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": ")); | ||||
|   } | ||||
| 
 | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     return __underlying_.parse(__ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
|   format(__maybe_const_map& __range, _FormatContext& __ctx) const { | ||||
|     return __underlying_.format(__range, __ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <ranges::input_range _Rp, class _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<range_format::set, _Rp, _CharT> { | ||||
| private: | ||||
|   using __maybe_const_set = __fmt_maybe_const<_Rp, _CharT>; | ||||
|   using __element_type    = remove_cvref_t<ranges::range_reference_t<__maybe_const_set>>; | ||||
|   range_formatter<__element_type, _CharT> __underlying_; | ||||
| 
 | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter() { | ||||
|     __underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}")); | ||||
|   } | ||||
| 
 | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     return __underlying_.parse(__ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
|   format(__maybe_const_set& __range, _FormatContext& __ctx) const { | ||||
|     return __underlying_.format(__range, __ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <range_format _Kp, ranges::input_range _Rp, class _CharT> | ||||
|   requires(_Kp == range_format::string || _Kp == range_format::debug_string) | ||||
| struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<_Kp, _Rp, _CharT> { | ||||
| private: | ||||
|   // This deviates from the Standard, there the exposition only type is
 | ||||
|   //   formatter<basic_string<charT>, charT> underlying_;
 | ||||
|   // Using a string_view allows the format function to avoid a copy of the
 | ||||
|   // input range when it is a contigious range.
 | ||||
|   formatter<basic_string_view<_CharT>, _CharT> __underlying_; | ||||
| 
 | ||||
| public: | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     typename _ParseContext::iterator __i = __underlying_.parse(__ctx); | ||||
|     if constexpr (_Kp == range_format::debug_string) | ||||
|       __underlying_.set_debug_format(); | ||||
|     return __i; | ||||
|   } | ||||
| 
 | ||||
|   template <class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
|   format(conditional_t<ranges::input_range<const _Rp>, const _Rp&, _Rp&> __range, _FormatContext& __ctx) const { | ||||
|     // When the range is contiguous use a basic_string_view instead to avoid a
 | ||||
|     // copy of the underlying data. The basic_string_view formatter
 | ||||
|     // specialization is the "basic" string formatter in libc++.
 | ||||
|     if constexpr (ranges::contiguous_range<_Rp> && std::ranges::sized_range<_Rp>) | ||||
|       return __underlying_.format(basic_string_view<_CharT>{ranges::data(__range), ranges::size(__range)}, __ctx); | ||||
|     else { | ||||
|       // P2106's from_range has not been implemented yet. Instead use a simple
 | ||||
|       // copy operation.
 | ||||
|       // TODO FMT use basic_string's "from_range" constructor.
 | ||||
|       // return __underlying_.format(basic_string<_CharT>{from_range, __range}, __ctx);
 | ||||
|       basic_string<_CharT> __str; | ||||
|       std::ranges::copy(__range, back_insert_iterator{__str}); | ||||
|       return __underlying_.format(static_cast<basic_string_view<_CharT>>(__str), __ctx); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <ranges::input_range _Rp, class _CharT> | ||||
|   requires(format_kind<_Rp> != range_format::disabled && formattable<ranges::range_reference_t<_Rp>, _CharT>) | ||||
| struct _LIBCPP_TEMPLATE_VIS formatter<_Rp, _CharT> : __range_default_formatter<format_kind<_Rp>, _Rp, _CharT> {}; | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 23
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H
 | ||||
							
								
								
									
										277
									
								
								third_party/libcxx/__format/range_formatter.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								third_party/libcxx/__format/range_formatter.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,277 @@ | |||
| // -*- 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_RANGE_FORMATTER_H | ||||
| #define _LIBCPP___FORMAT_RANGE_FORMATTER_H | ||||
| 
 | ||||
| #include <__algorithm/ranges_copy.h> | ||||
| #include <__availability> | ||||
| #include <__chrono/statically_widen.h> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__format/buffer.h> | ||||
| #include <__format/concepts.h> | ||||
| #include <__format/format_args.h> | ||||
| #include <__format/format_context.h> | ||||
| #include <__format/format_error.h> | ||||
| #include <__format/formatter.h> | ||||
| #include <__format/formatter_output.h> | ||||
| #include <__format/parser_std_format_spec.h> | ||||
| #include <__iterator/back_insert_iterator.h> | ||||
| #include <__ranges/concepts.h> | ||||
| #include <__ranges/data.h> | ||||
| #include <__ranges/size.h> | ||||
| #include <__type_traits/remove_cvref.h> | ||||
| #include <string_view> | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 23 | ||||
| 
 | ||||
| template <class _Tp, class _CharT = char> | ||||
|   requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT> | ||||
| struct _LIBCPP_TEMPLATE_VIS range_formatter { | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { | ||||
|     __separator_ = __separator; | ||||
|   } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void | ||||
|   set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { | ||||
|     __opening_bracket_ = __opening_bracket; | ||||
|     __closing_bracket_ = __closing_bracket; | ||||
|   } | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr formatter<_Tp, _CharT>& underlying() noexcept { return __underlying_; } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr const formatter<_Tp, _CharT>& underlying() const noexcept { return __underlying_; } | ||||
| 
 | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { | ||||
|     auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_range); | ||||
|     auto __end   = __ctx.end(); | ||||
|     // Note the cases where __begin == __end in this code only happens when the
 | ||||
|     // replacement-field has no terminating }, or when the parse is manually
 | ||||
|     // called with a format-spec. The former is an error and the latter means
 | ||||
|     // using a formatter without the format functions or print.
 | ||||
|     if (__begin == __end) [[unlikely]] | ||||
|       return __parse_empty_range_underlying_spec(__ctx, __begin); | ||||
| 
 | ||||
|     // The n field overrides a possible m type, therefore delay applying the
 | ||||
|     // effect of n until the type has been procesed.
 | ||||
|     bool __clear_brackets = (*__begin == _CharT('n')); | ||||
|     if (__clear_brackets) { | ||||
|       ++__begin; | ||||
|       if (__begin == __end) [[unlikely]] { | ||||
|         // Since there is no more data, clear the brackets before returning.
 | ||||
|         set_brackets({}, {}); | ||||
|         return __parse_empty_range_underlying_spec(__ctx, __begin); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     __parse_type(__begin, __end); | ||||
|     if (__clear_brackets) | ||||
|       set_brackets({}, {}); | ||||
|     if (__begin == __end) [[unlikely]] | ||||
|       return __parse_empty_range_underlying_spec(__ctx, __begin); | ||||
| 
 | ||||
|     bool __has_range_underlying_spec = *__begin == _CharT(':'); | ||||
|     if (__has_range_underlying_spec) { | ||||
|       // range-underlying-spec:
 | ||||
|       //   :  format-spec
 | ||||
|       ++__begin; | ||||
|     } else if (__begin != __end && *__begin != _CharT('}')) | ||||
|       // When there is no underlaying range the current parse should have
 | ||||
|       // consumed the format-spec. If not, the not consumed input will be
 | ||||
|       // processed by the underlying. For example {:-} for a range in invalid,
 | ||||
|       // the sign field is not present. Without this check the underlying_ will
 | ||||
|       // get -} as input which my be valid.
 | ||||
|       std::__throw_format_error("The format-spec should consume the input or end with a '}'"); | ||||
| 
 | ||||
|     __ctx.advance_to(__begin); | ||||
|     __begin = __underlying_.parse(__ctx); | ||||
| 
 | ||||
|     // This test should not be required if __has_range_underlying_spec is false.
 | ||||
|     // However this test makes sure the underlying formatter left the parser in
 | ||||
|     // a valid state. (Note this is not a full protection against evil parsers.
 | ||||
|     // For example
 | ||||
|     //   } this is test for the next argument {}
 | ||||
|     //   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
 | ||||
|     // could consume more than it should.
 | ||||
|     if (__begin != __end && *__begin != _CharT('}')) | ||||
|       std::__throw_format_error("The format-spec should consume the input or end with a '}'"); | ||||
| 
 | ||||
|     if (__parser_.__type_ != __format_spec::__type::__default) { | ||||
|       // [format.range.formatter]/6
 | ||||
|       //   If the range-type is s or ?s, then there shall be no n option and no
 | ||||
|       //   range-underlying-spec.
 | ||||
|       if (__clear_brackets) { | ||||
|         if (__parser_.__type_ == __format_spec::__type::__string) | ||||
|           std::__throw_format_error("The n option and type s can't be used together"); | ||||
|         std::__throw_format_error("The n option and type ?s can't be used together"); | ||||
|       } | ||||
|       if (__has_range_underlying_spec) { | ||||
|         if (__parser_.__type_ == __format_spec::__type::__string) | ||||
|           std::__throw_format_error("Type s and an underlying format specification can't be used together"); | ||||
|         std::__throw_format_error("Type ?s and an underlying format specification can't be used together"); | ||||
|       } | ||||
|     } else if (!__has_range_underlying_spec) | ||||
|       std::__set_debug_format(__underlying_); | ||||
| 
 | ||||
|     return __begin; | ||||
|   } | ||||
| 
 | ||||
|   template <ranges::input_range _Rp, class _FormatContext> | ||||
|     requires formattable<ranges::range_reference_t<_Rp>, _CharT> && | ||||
|              same_as<remove_cvref_t<ranges::range_reference_t<_Rp>>, _Tp> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Rp&& __range, _FormatContext& __ctx) const { | ||||
|     __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); | ||||
| 
 | ||||
|     if (!__specs.__has_width()) | ||||
|       return __format_range(__range, __ctx, __specs); | ||||
| 
 | ||||
|     // The size of the buffer needed is:
 | ||||
|     // - open bracket characters
 | ||||
|     // - close bracket character
 | ||||
|     // - n elements where every element may have a different size
 | ||||
|     // - (n -1) separators
 | ||||
|     // The size of the element is hard to predict, knowing the type helps but
 | ||||
|     // it depends on the format-spec. As an initial estimate we guess 6
 | ||||
|     // characters.
 | ||||
|     // Typically both brackets are 1 character and the separator is 2
 | ||||
|     // characters. Which means there will be
 | ||||
|     //   (n - 1) * 2 + 1 + 1 = n * 2 character
 | ||||
|     // So estimate 8 times the range size as buffer.
 | ||||
|     std::size_t __capacity_hint = 0; | ||||
|     if constexpr (std::ranges::sized_range<_Rp>) | ||||
|       __capacity_hint = 8 * ranges::size(__range); | ||||
|     __format::__retarget_buffer<_CharT> __buffer{__capacity_hint}; | ||||
|     basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> __c{ | ||||
|         __buffer.__make_output_iterator(), __ctx}; | ||||
| 
 | ||||
|     __format_range(__range, __c, __specs); | ||||
| 
 | ||||
|     return __formatter::__write_string_no_precision(__buffer.__view(), __ctx.out(), __specs); | ||||
|   } | ||||
| 
 | ||||
|   template <ranges::input_range _Rp, class _FormatContext> | ||||
|   typename _FormatContext::iterator _LIBCPP_HIDE_FROM_ABI | ||||
|   __format_range(_Rp&& __range, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) const { | ||||
|     if constexpr (same_as<_Tp, _CharT>) { | ||||
|       switch (__specs.__std_.__type_) { | ||||
|       case __format_spec::__type::__string: | ||||
|       case __format_spec::__type::__debug: | ||||
|         return __format_as_string(__range, __ctx, __specs.__std_.__type_ == __format_spec::__type::__debug); | ||||
|       default: | ||||
|         return __format_as_sequence(__range, __ctx); | ||||
|       } | ||||
|     } else | ||||
|       return __format_as_sequence(__range, __ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <ranges::input_range _Rp, class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
|   __format_as_string(_Rp&& __range, _FormatContext& __ctx, bool __debug_format) const { | ||||
|     // When the range is contiguous use a basic_string_view instead to avoid a
 | ||||
|     // copy of the underlying data. The basic_string_view formatter
 | ||||
|     // specialization is the "basic" string formatter in libc++.
 | ||||
|     if constexpr (ranges::contiguous_range<_Rp> && std::ranges::sized_range<_Rp>) { | ||||
|       std::formatter<basic_string_view<_CharT>, _CharT> __formatter; | ||||
|       if (__debug_format) | ||||
|         __formatter.set_debug_format(); | ||||
|       return __formatter.format( | ||||
|           basic_string_view<_CharT>{ | ||||
|               ranges::data(__range), | ||||
|               ranges::size(__range), | ||||
|           }, | ||||
|           __ctx); | ||||
|     } else { | ||||
|       std::formatter<basic_string<_CharT>, _CharT> __formatter; | ||||
|       if (__debug_format) | ||||
|         __formatter.set_debug_format(); | ||||
|       // P2106's from_range has not been implemented yet. Instead use a simple
 | ||||
|       // copy operation.
 | ||||
|       // TODO FMT use basic_string's "from_range" constructor.
 | ||||
|       // return std::formatter<basic_string<_CharT>, _CharT>{}.format(basic_string<_CharT>{from_range, __range}, __ctx);
 | ||||
|       basic_string<_CharT> __str; | ||||
|       ranges::copy(__range, back_insert_iterator{__str}); | ||||
|       return __formatter.format(__str, __ctx); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   template <ranges::input_range _Rp, class _FormatContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator | ||||
|   __format_as_sequence(_Rp&& __range, _FormatContext& __ctx) const { | ||||
|     __ctx.advance_to(ranges::copy(__opening_bracket_, __ctx.out()).out); | ||||
|     bool __use_separator = false; | ||||
|     for (auto&& __e : __range) { | ||||
|       if (__use_separator) | ||||
|         __ctx.advance_to(ranges::copy(__separator_, __ctx.out()).out); | ||||
|       else | ||||
|         __use_separator = true; | ||||
| 
 | ||||
|       __ctx.advance_to(__underlying_.format(__e, __ctx)); | ||||
|     } | ||||
| 
 | ||||
|     return ranges::copy(__closing_bracket_, __ctx.out()).out; | ||||
|   } | ||||
| 
 | ||||
|   __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left}; | ||||
| 
 | ||||
| private: | ||||
|   template <contiguous_iterator _Iterator> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(_Iterator& __begin, _Iterator __end) { | ||||
|     switch (*__begin) { | ||||
|     case _CharT('m'): | ||||
|       if constexpr (__fmt_pair_like<_Tp>) { | ||||
|         set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}")); | ||||
|         set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ", ")); | ||||
|         ++__begin; | ||||
|       } else | ||||
|         std::__throw_format_error("The range-format-spec type m requires two elements for a pair or tuple"); | ||||
|       break; | ||||
| 
 | ||||
|     case _CharT('s'): | ||||
|       if constexpr (same_as<_Tp, _CharT>) { | ||||
|         __parser_.__type_ = __format_spec::__type::__string; | ||||
|         ++__begin; | ||||
|       } else | ||||
|         std::__throw_format_error("The range-format-spec type s requires formatting a character type"); | ||||
|       break; | ||||
| 
 | ||||
|     case _CharT('?'): | ||||
|       ++__begin; | ||||
|       if (__begin == __end || *__begin != _CharT('s')) | ||||
|         std::__throw_format_error("The format-spec should consume the input or end with a '}'"); | ||||
|       if constexpr (same_as<_Tp, _CharT>) { | ||||
|         __parser_.__type_ = __format_spec::__type::__debug; | ||||
|         ++__begin; | ||||
|       } else | ||||
|         std::__throw_format_error("The range-format-spec type ?s requires formatting a character type"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   template <class _ParseContext> | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator | ||||
|   __parse_empty_range_underlying_spec(_ParseContext& __ctx, typename _ParseContext::iterator __begin) { | ||||
|     __ctx.advance_to(__begin); | ||||
|     [[maybe_unused]] typename _ParseContext::iterator __result = __underlying_.parse(__ctx); | ||||
|     _LIBCPP_ASSERT(__result == __begin, | ||||
|                    "the underlying's parse function should not advance the input beyond the end of the input"); | ||||
|     return __begin; | ||||
|   } | ||||
| 
 | ||||
|   formatter<_Tp, _CharT> __underlying_; | ||||
|   basic_string_view<_CharT> __separator_       = _LIBCPP_STATICALLY_WIDEN(_CharT, ", "); | ||||
|   basic_string_view<_CharT> __opening_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "["); | ||||
|   basic_string_view<_CharT> __closing_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "]"); | ||||
| }; | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 23
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_RANGE_FORMATTER_H
 | ||||
							
								
								
									
										483
									
								
								third_party/libcxx/__format/unicode.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										483
									
								
								third_party/libcxx/__format/unicode.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,483 @@ | |||
| // -*- 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_UNICODE_H | ||||
| #define _LIBCPP___FORMAT_UNICODE_H | ||||
| 
 | ||||
| #include <__assert> | ||||
| #include <__bit/countl.h> | ||||
| #include <__concepts/same_as.h> | ||||
| #include <__config> | ||||
| #include <__format/extended_grapheme_cluster_table.h> | ||||
| #include <__iterator/concepts.h> | ||||
| #include <__iterator/readable_traits.h> // iter_value_t | ||||
| #include <__type_traits/make_unsigned.h> | ||||
| #include <__utility/unreachable.h> | ||||
| #include <string_view> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| namespace __unicode { | ||||
| 
 | ||||
| // Helper struct for the result of a consume operation.
 | ||||
| //
 | ||||
| // The status value for a correct code point is 0. This allows a valid value to
 | ||||
| // be used without masking.
 | ||||
| // When the decoding fails it know the number of code units affected. For the
 | ||||
| // current use-cases that value is not needed, therefore it is not stored.
 | ||||
| // The escape routine needs the number of code units for both a valid and
 | ||||
| // invalid character and keeps track of it itself. Doing it in this result
 | ||||
| // unconditionally would give some overhead when the value is unneeded.
 | ||||
| struct __consume_result { | ||||
|   // When __status == __ok it contains the decoded code point.
 | ||||
|   // Else it contains the replacement character U+FFFD
 | ||||
|   char32_t __code_point : 31; | ||||
| 
 | ||||
|   enum : char32_t { | ||||
|     // Consumed a well-formed code point.
 | ||||
|     __ok = 0, | ||||
|     // Encountered invalid UTF-8
 | ||||
|     __error = 1 | ||||
|   } __status : 1 {__ok}; | ||||
| }; | ||||
| static_assert(sizeof(__consume_result) == sizeof(char32_t)); | ||||
| 
 | ||||
| #  ifndef _LIBCPP_HAS_NO_UNICODE | ||||
| 
 | ||||
| /// Implements the grapheme cluster boundary rules
 | ||||
| ///
 | ||||
| /// These rules are used to implement format's width estimation as stated in
 | ||||
| /// [format.string.std]/11
 | ||||
| ///
 | ||||
| /// The Standard refers to UAX \#29 for Unicode 12.0.0
 | ||||
| /// https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules
 | ||||
| ///
 | ||||
| /// The data tables used are
 | ||||
| /// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt
 | ||||
| /// https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
 | ||||
| /// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt (for testing only)
 | ||||
| 
 | ||||
| inline constexpr char32_t __replacement_character = U'\ufffd'; | ||||
| 
 | ||||
| // The error of a consume operation.
 | ||||
| //
 | ||||
| // This sets the code point to the replacement character. This code point does
 | ||||
| // not participate in the grapheme clustering, so grapheme clustering code can
 | ||||
| // ignore the error status and always use the code point.
 | ||||
| inline constexpr __consume_result __consume_result_error{__replacement_character, __consume_result::__error}; | ||||
| 
 | ||||
| [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool __is_high_surrogate(char32_t __value) { | ||||
|   return __value >= 0xd800 && __value <= 0xdbff; | ||||
| } | ||||
| 
 | ||||
| [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool __is_low_surrogate(char32_t __value) { | ||||
|   return __value >= 0xdc00 && __value <= 0xdfff; | ||||
| } | ||||
| 
 | ||||
| // https://www.unicode.org/glossary/#surrogate_code_point
 | ||||
| [[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool __is_surrogate(char32_t __value) { | ||||
|   return __value >= 0xd800 && __value <= 0xdfff; | ||||
| } | ||||
| 
 | ||||
| // https://www.unicode.org/glossary/#code_point
 | ||||
| [[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool __is_code_point(char32_t __value) { | ||||
|   return __value <= 0x10ffff; | ||||
| } | ||||
| 
 | ||||
| // https://www.unicode.org/glossary/#unicode_scalar_value
 | ||||
| [[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool __is_scalar_value(char32_t __value) { | ||||
|   return __unicode::__is_code_point(__value) && !__unicode::__is_surrogate(__value); | ||||
| } | ||||
| 
 | ||||
| template <contiguous_iterator _Iterator> | ||||
|   requires same_as<iter_value_t<_Iterator>, char> | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr bool __is_continuation(_Iterator __char, int __count) { | ||||
|   do { | ||||
|     if ((*__char & 0b1000'0000) != 0b1000'0000) | ||||
|       return false; | ||||
|     --__count; | ||||
|     ++__char; | ||||
|   } while (__count); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| /// Helper class to extract a code unit from a Unicode character range.
 | ||||
| ///
 | ||||
| /// The stored range is a view. There are multiple specialization for different
 | ||||
| /// character types.
 | ||||
| template <class _CharT> | ||||
| class __code_point_view; | ||||
| 
 | ||||
| /// UTF-8 specialization.
 | ||||
| template <> | ||||
| class __code_point_view<char> { | ||||
|   using _Iterator = basic_string_view<char>::const_iterator; | ||||
| 
 | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last) | ||||
|       : __first_(__first), __last_(__last) {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; } | ||||
| 
 | ||||
|   // https://www.unicode.org/versions/latest/ch03.pdf#G7404
 | ||||
|   // Based on Table 3-7, Well-Formed UTF-8 Byte Sequences
 | ||||
|   //
 | ||||
|   // Code Points        First Byte Second Byte Third Byte Fourth Byte  Remarks
 | ||||
|   // U+0000..U+007F     00..7F                                         U+0000..U+007F 1 code unit range
 | ||||
|   //                    C0..C1     80..BF                              invalid overlong encoding
 | ||||
|   // U+0080..U+07FF     C2..DF     80..BF                              U+0080..U+07FF 2 code unit range
 | ||||
|   //                    E0         80..9F      80..BF                  invalid overlong encoding
 | ||||
|   // U+0800..U+0FFF     E0         A0..BF      80..BF                  U+0800..U+FFFF 3 code unit range
 | ||||
|   // U+1000..U+CFFF     E1..EC     80..BF      80..BF
 | ||||
|   // U+D000..U+D7FF     ED         80..9F      80..BF
 | ||||
|   // U+D800..U+DFFF     ED         A0..BF      80..BF                  invalid encoding of surrogate code point
 | ||||
|   // U+E000..U+FFFF     EE..EF     80..BF      80..BF
 | ||||
|   //                    F0         80..8F      80..BF     80..BF       invalid overlong encoding
 | ||||
|   // U+10000..U+3FFFF   F0         90..BF      80..BF     80..BF       U+10000..U+10FFFF 4 code unit range
 | ||||
|   // U+40000..U+FFFFF   F1..F3     80..BF      80..BF     80..BF
 | ||||
|   // U+100000..U+10FFFF F4         80..8F      80..BF     80..BF
 | ||||
|   //                    F4         90..BF      80..BF     80..BF       U+110000.. invalid code point range
 | ||||
|   //
 | ||||
|   // Unlike other parsers, these invalid entries are tested after decoding.
 | ||||
|   // - The parser always needs to consume these code units
 | ||||
|   // - The code is optimized for well-formed UTF-8
 | ||||
|   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept { | ||||
|     _LIBCPP_ASSERT(__first_ != __last_, "can't move beyond the end of input"); | ||||
| 
 | ||||
|     // Based on the number of leading 1 bits the number of code units in the
 | ||||
|     // code point can be determined. See
 | ||||
|     // https://en.wikipedia.org/wiki/UTF-8#Encoding
 | ||||
|     switch (std::countl_one(static_cast<unsigned char>(*__first_))) { | ||||
|     case 0: | ||||
|       return {static_cast<unsigned char>(*__first_++)}; | ||||
| 
 | ||||
|     case 2: { | ||||
|       if (__last_ - __first_ < 2 || !__unicode::__is_continuation(__first_ + 1, 1)) [[unlikely]] | ||||
|         break; | ||||
| 
 | ||||
|       char32_t __value = static_cast<unsigned char>(*__first_++) & 0x1f; | ||||
|       __value <<= 6; | ||||
|       __value |= static_cast<unsigned char>(*__first_++) & 0x3f; | ||||
| 
 | ||||
|       // These values should be encoded in 1 UTF-8 code unit.
 | ||||
|       if (__value < 0x0080) [[unlikely]] | ||||
|         return __consume_result_error; | ||||
| 
 | ||||
|       return {__value}; | ||||
|     } | ||||
| 
 | ||||
|     case 3: { | ||||
|       if (__last_ - __first_ < 3 || !__unicode::__is_continuation(__first_ + 1, 2)) [[unlikely]] | ||||
|         break; | ||||
| 
 | ||||
|       char32_t __value = static_cast<unsigned char>(*__first_++) & 0x0f; | ||||
|       __value <<= 6; | ||||
|       __value |= static_cast<unsigned char>(*__first_++) & 0x3f; | ||||
|       __value <<= 6; | ||||
|       __value |= static_cast<unsigned char>(*__first_++) & 0x3f; | ||||
| 
 | ||||
|       // These values should be encoded in 1 or 2 UTF-8 code units.
 | ||||
|       if (__value < 0x0800) [[unlikely]] | ||||
|         return __consume_result_error; | ||||
| 
 | ||||
|       // A surrogate value is always encoded in 3 UTF-8 code units.
 | ||||
|       if (__unicode::__is_surrogate(__value)) [[unlikely]] | ||||
|         return __consume_result_error; | ||||
| 
 | ||||
|       return {__value}; | ||||
|     } | ||||
| 
 | ||||
|     case 4: { | ||||
|       if (__last_ - __first_ < 4 || !__unicode::__is_continuation(__first_ + 1, 3)) [[unlikely]] | ||||
|         break; | ||||
| 
 | ||||
|       char32_t __value = static_cast<unsigned char>(*__first_++) & 0x07; | ||||
|       __value <<= 6; | ||||
|       __value |= static_cast<unsigned char>(*__first_++) & 0x3f; | ||||
|       __value <<= 6; | ||||
|       __value |= static_cast<unsigned char>(*__first_++) & 0x3f; | ||||
|       __value <<= 6; | ||||
|       __value |= static_cast<unsigned char>(*__first_++) & 0x3f; | ||||
| 
 | ||||
|       // These values should be encoded in 1, 2, or 3 UTF-8 code units.
 | ||||
|       if (__value < 0x10000) [[unlikely]] | ||||
|         return __consume_result_error; | ||||
| 
 | ||||
|       // A value too large is always encoded in 4 UTF-8 code units.
 | ||||
|       if (!__unicode::__is_code_point(__value)) [[unlikely]] | ||||
|         return __consume_result_error; | ||||
| 
 | ||||
|       return {__value}; | ||||
|     } | ||||
|     } | ||||
|     // An invalid number of leading ones can be garbage or a code unit in the
 | ||||
|     // middle of a code point. By consuming one code unit the parser may get
 | ||||
|     // "in sync" after a few code units.
 | ||||
|     ++__first_; | ||||
|     return __consume_result_error; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   _Iterator __first_; | ||||
|   _Iterator __last_; | ||||
| }; | ||||
| 
 | ||||
| #    ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr bool __is_surrogate_pair_high(wchar_t __value) { | ||||
|   return __value >= 0xd800 && __value <= 0xdbff; | ||||
| } | ||||
| 
 | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr bool __is_surrogate_pair_low(wchar_t __value) { | ||||
|   return __value >= 0xdc00 && __value <= 0xdfff; | ||||
| } | ||||
| 
 | ||||
| /// This specialization depends on the size of wchar_t
 | ||||
| /// - 2 UTF-16 (for example Windows and AIX)
 | ||||
| /// - 4 UTF-32 (for example Linux)
 | ||||
| template <> | ||||
| class __code_point_view<wchar_t> { | ||||
|   using _Iterator = typename basic_string_view<wchar_t>::const_iterator; | ||||
| 
 | ||||
| public: | ||||
|   static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "sizeof(wchar_t) has a not implemented value"); | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last) | ||||
|       : __first_(__first), __last_(__last) {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; } | ||||
| 
 | ||||
|   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept { | ||||
|     _LIBCPP_ASSERT(__first_ != __last_, "can't move beyond the end of input"); | ||||
| 
 | ||||
|     char32_t __value = static_cast<char32_t>(*__first_++); | ||||
|     if constexpr (sizeof(wchar_t) == 2) { | ||||
|       if (__unicode::__is_low_surrogate(__value)) [[unlikely]] | ||||
|         return __consume_result_error; | ||||
| 
 | ||||
|       if (__unicode::__is_high_surrogate(__value)) { | ||||
|         if (__first_ == __last_ || !__unicode::__is_low_surrogate(static_cast<char32_t>(*__first_))) [[unlikely]] | ||||
|           return __consume_result_error; | ||||
| 
 | ||||
|         __value -= 0xd800; | ||||
|         __value <<= 10; | ||||
|         __value += static_cast<char32_t>(*__first_++) - 0xdc00; | ||||
|         __value += 0x10000; | ||||
| 
 | ||||
|         if (!__unicode::__is_code_point(__value)) [[unlikely]] | ||||
|           return __consume_result_error; | ||||
|       } | ||||
|     } else { | ||||
|       if (!__unicode::__is_scalar_value(__value)) [[unlikely]] | ||||
|         return __consume_result_error; | ||||
|     } | ||||
| 
 | ||||
|     return {__value}; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   _Iterator __first_; | ||||
|   _Iterator __last_; | ||||
| }; | ||||
| #    endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
 | ||||
| 
 | ||||
| _LIBCPP_HIDE_FROM_ABI constexpr bool __at_extended_grapheme_cluster_break( | ||||
|     bool& __ri_break_allowed, | ||||
|     bool __has_extened_pictographic, | ||||
|     __extended_grapheme_custer_property_boundary::__property __prev, | ||||
|     __extended_grapheme_custer_property_boundary::__property __next) { | ||||
|   using __extended_grapheme_custer_property_boundary::__property; | ||||
| 
 | ||||
|   __has_extened_pictographic |= __prev == __property::__Extended_Pictographic; | ||||
| 
 | ||||
|   // https://www.unicode.org/reports/tr29/tr29-39.html#Grapheme_Cluster_Boundary_Rules
 | ||||
| 
 | ||||
|   // *** Break at the start and end of text, unless the text is empty. ***
 | ||||
| 
 | ||||
|   _LIBCPP_ASSERT(__prev != __property::__sot, "should be handled in the constructor"); // GB1
 | ||||
|   _LIBCPP_ASSERT(__prev != __property::__eot, "should be handled by our caller");      // GB2
 | ||||
| 
 | ||||
|   // *** Do not break between a CR and LF. Otherwise, break before and after controls. ***
 | ||||
|   if (__prev == __property::__CR && __next == __property::__LF) // GB3
 | ||||
|     return false; | ||||
| 
 | ||||
|   if (__prev == __property::__Control || __prev == __property::__CR || __prev == __property::__LF) // GB4
 | ||||
|     return true; | ||||
| 
 | ||||
|   if (__next == __property::__Control || __next == __property::__CR || __next == __property::__LF) // GB5
 | ||||
|     return true; | ||||
| 
 | ||||
|   // *** Do not break Hangul syllable sequences. ***
 | ||||
|   if (__prev == __property::__L && | ||||
|       (__next == __property::__L || __next == __property::__V || __next == __property::__LV || | ||||
|        __next == __property::__LVT)) // GB6
 | ||||
|     return false; | ||||
| 
 | ||||
|   if ((__prev == __property::__LV || __prev == __property::__V) && | ||||
|       (__next == __property::__V || __next == __property::__T)) // GB7
 | ||||
|     return false; | ||||
| 
 | ||||
|   if ((__prev == __property::__LVT || __prev == __property::__T) && __next == __property::__T) // GB8
 | ||||
|     return false; | ||||
| 
 | ||||
|   // *** Do not break before extending characters or ZWJ. ***
 | ||||
|   if (__next == __property::__Extend || __next == __property::__ZWJ) | ||||
|     return false; // GB9
 | ||||
| 
 | ||||
|   // *** Do not break before SpacingMarks, or after Prepend characters. ***
 | ||||
|   if (__next == __property::__SpacingMark) // GB9a
 | ||||
|     return false; | ||||
| 
 | ||||
|   if (__prev == __property::__Prepend) // GB9b
 | ||||
|     return false; | ||||
| 
 | ||||
|   // *** Do not break within emoji modifier sequences or emoji zwj sequences. ***
 | ||||
| 
 | ||||
|   // GB11 \p{Extended_Pictographic} Extend* ZWJ x \p{Extended_Pictographic}
 | ||||
|   //
 | ||||
|   // Note that several parts of this rule are matched by GB9: Any x (Extend | ZWJ)
 | ||||
|   // - \p{Extended_Pictographic} x Extend
 | ||||
|   // - Extend x Extend
 | ||||
|   // - \p{Extended_Pictographic} x ZWJ
 | ||||
|   // - Extend x ZWJ
 | ||||
|   //
 | ||||
|   // So the only case left to test is
 | ||||
|   // - \p{Extended_Pictographic}' x ZWJ x \p{Extended_Pictographic}
 | ||||
|   //   where  \p{Extended_Pictographic}' is stored in __has_extened_pictographic
 | ||||
|   if (__has_extened_pictographic && __prev == __property::__ZWJ && __next == __property::__Extended_Pictographic) | ||||
|     return false; | ||||
| 
 | ||||
|   // *** Do not break within emoji flag sequences ***
 | ||||
| 
 | ||||
|   // That is, do not break between regional indicator (RI) symbols if there
 | ||||
|   // is an odd number of RI characters before the break point.
 | ||||
| 
 | ||||
|   if (__prev == __property::__Regional_Indicator && __next == __property::__Regional_Indicator) { // GB12 + GB13
 | ||||
|     __ri_break_allowed = !__ri_break_allowed; | ||||
|     return __ri_break_allowed; | ||||
|   } | ||||
| 
 | ||||
|   // *** Otherwise, break everywhere. ***
 | ||||
|   return true; // GB999
 | ||||
| } | ||||
| 
 | ||||
| /// Helper class to extract an extended grapheme cluster from a Unicode character range.
 | ||||
| ///
 | ||||
| /// This function is used to determine the column width of an extended grapheme
 | ||||
| /// cluster. In order to do that only the first code point is evaluated.
 | ||||
| /// Therefore only this code point is extracted.
 | ||||
| template <class _CharT> | ||||
| class __extended_grapheme_cluster_view { | ||||
|   using _Iterator = typename basic_string_view<_CharT>::const_iterator; | ||||
| 
 | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr explicit __extended_grapheme_cluster_view(_Iterator __first, _Iterator __last) | ||||
|       : __code_point_view_(__first, __last), | ||||
|         __next_code_point_(__code_point_view_.__consume().__code_point), | ||||
|         __next_prop_(__extended_grapheme_custer_property_boundary::__get_property(__next_code_point_)) {} | ||||
| 
 | ||||
|   struct __cluster { | ||||
|     /// The first code point of the extended grapheme cluster.
 | ||||
|     ///
 | ||||
|     /// The first code point is used to estimate the width of the extended
 | ||||
|     /// grapheme cluster.
 | ||||
|     char32_t __code_point_; | ||||
| 
 | ||||
|     /// Points one beyond the last code unit in the extended grapheme cluster.
 | ||||
|     ///
 | ||||
|     /// It's expected the caller has the start position and thus can determine
 | ||||
|     /// the code unit range of the extended grapheme cluster.
 | ||||
|     _Iterator __last_; | ||||
|   }; | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr __cluster __consume() { | ||||
|     _LIBCPP_ASSERT( | ||||
|         __next_prop_ != __extended_grapheme_custer_property_boundary::__property::__eot, | ||||
|         "can't move beyond the end of input"); | ||||
| 
 | ||||
|     char32_t __code_point = __next_code_point_; | ||||
|     if (!__code_point_view_.__at_end()) | ||||
|       return {__code_point, __get_break()}; | ||||
| 
 | ||||
|     __next_prop_ = __extended_grapheme_custer_property_boundary::__property::__eot; | ||||
|     return {__code_point, __code_point_view_.__position()}; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   __code_point_view<_CharT> __code_point_view_; | ||||
| 
 | ||||
|   char32_t __next_code_point_; | ||||
|   __extended_grapheme_custer_property_boundary::__property __next_prop_; | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __get_break() { | ||||
|     bool __ri_break_allowed         = true; | ||||
|     bool __has_extened_pictographic = false; | ||||
|     while (true) { | ||||
|       _Iterator __result                                              = __code_point_view_.__position(); | ||||
|       __extended_grapheme_custer_property_boundary::__property __prev = __next_prop_; | ||||
|       if (__code_point_view_.__at_end()) { | ||||
|         __next_prop_ = __extended_grapheme_custer_property_boundary::__property::__eot; | ||||
|         return __result; | ||||
|       } | ||||
|       __next_code_point_ = __code_point_view_.__consume().__code_point; | ||||
|       __next_prop_       = __extended_grapheme_custer_property_boundary::__get_property(__next_code_point_); | ||||
| 
 | ||||
|       __has_extened_pictographic |= | ||||
|           __prev == __extended_grapheme_custer_property_boundary::__property::__Extended_Pictographic; | ||||
| 
 | ||||
|       if (__at_extended_grapheme_cluster_break(__ri_break_allowed, __has_extened_pictographic, __prev, __next_prop_)) | ||||
|         return __result; | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <contiguous_iterator _Iterator> | ||||
| __extended_grapheme_cluster_view(_Iterator, _Iterator) -> __extended_grapheme_cluster_view<iter_value_t<_Iterator>>; | ||||
| 
 | ||||
| #  else //  _LIBCPP_HAS_NO_UNICODE
 | ||||
| 
 | ||||
| // For ASCII every character is a "code point".
 | ||||
| // This makes it easier to write code agnostic of the _LIBCPP_HAS_NO_UNICODE define.
 | ||||
| template <class _CharT> | ||||
| class __code_point_view { | ||||
|   using _Iterator = typename basic_string_view<_CharT>::const_iterator; | ||||
| 
 | ||||
| public: | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last) | ||||
|       : __first_(__first), __last_(__last) {} | ||||
| 
 | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; } | ||||
|   _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; } | ||||
| 
 | ||||
|   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept { | ||||
|     _LIBCPP_ASSERT(__first_ != __last_, "can't move beyond the end of input"); | ||||
|     return {static_cast<char32_t>(*__first_++)}; | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   _Iterator __first_; | ||||
|   _Iterator __last_; | ||||
| }; | ||||
| 
 | ||||
| #  endif //  _LIBCPP_HAS_NO_UNICODE
 | ||||
| 
 | ||||
| } // namespace __unicode
 | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_UNICODE_H
 | ||||
							
								
								
									
										271
									
								
								third_party/libcxx/__format/width_estimation_table.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								third_party/libcxx/__format/width_estimation_table.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,271 @@ | |||
| // -*- 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
 | ||||
| //
 | ||||
| //===----------------------------------------------------------------------===//
 | ||||
| 
 | ||||
| // WARNING, this entire header is generated by
 | ||||
| // utils/generate_width_estimation_table.py
 | ||||
| // DO NOT MODIFY!
 | ||||
| 
 | ||||
| // UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
 | ||||
| //
 | ||||
| // See Terms of Use <https://www.unicode.org/copyright.html>
 | ||||
| // for definitions of Unicode Inc.'s Data Files and Software.
 | ||||
| //
 | ||||
| // NOTICE TO USER: Carefully read the following legal agreement.
 | ||||
| // BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
 | ||||
| // DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
 | ||||
| // YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
 | ||||
| // TERMS AND CONDITIONS OF THIS AGREEMENT.
 | ||||
| // IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
 | ||||
| // THE DATA FILES OR SOFTWARE.
 | ||||
| //
 | ||||
| // COPYRIGHT AND PERMISSION NOTICE
 | ||||
| //
 | ||||
| // Copyright (c) 1991-2022 Unicode, Inc. All rights reserved.
 | ||||
| // Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
 | ||||
| //
 | ||||
| // Permission is hereby granted, free of charge, to any person obtaining
 | ||||
| // a copy of the Unicode data files and any associated documentation
 | ||||
| // (the "Data Files") or Unicode software and any associated documentation
 | ||||
| // (the "Software") to deal in the Data Files or Software
 | ||||
| // without restriction, including without limitation the rights to use,
 | ||||
| // copy, modify, merge, publish, distribute, and/or sell copies of
 | ||||
| // the Data Files or Software, and to permit persons to whom the Data Files
 | ||||
| // or Software are furnished to do so, provided that either
 | ||||
| // (a) this copyright and permission notice appear with all copies
 | ||||
| // of the Data Files or Software, or
 | ||||
| // (b) this copyright and permission notice appear in associated
 | ||||
| // Documentation.
 | ||||
| //
 | ||||
| // THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
 | ||||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 | ||||
| // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | ||||
| // NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 | ||||
| // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
 | ||||
| // NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
 | ||||
| // DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | ||||
| // DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | ||||
| // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 | ||||
| // PERFORMANCE OF THE DATA FILES OR SOFTWARE.
 | ||||
| //
 | ||||
| // Except as contained in this notice, the name of a copyright holder
 | ||||
| // shall not be used in advertising or otherwise to promote the sale,
 | ||||
| // use or other dealings in these Data Files or Software without prior
 | ||||
| // written authorization of the copyright holder.
 | ||||
| 
 | ||||
| #ifndef _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H | ||||
| #define _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H | ||||
| 
 | ||||
| #include <__algorithm/ranges_upper_bound.h> | ||||
| #include <__config> | ||||
| #include <cstddef> | ||||
| #include <cstdint> | ||||
| 
 | ||||
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||||
| #  pragma GCC system_header | ||||
| #endif | ||||
| 
 | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| 
 | ||||
| #if _LIBCPP_STD_VER >= 20 | ||||
| 
 | ||||
| namespace __width_estimation_table { | ||||
| 
 | ||||
| /// The entries of the characters with an estimated width of 2.
 | ||||
| ///
 | ||||
| /// Contains the entries for [format.string.std]/12
 | ||||
| ///  -  Any code point with the East_Asian_Width="W" or East_Asian_Width="F"
 | ||||
| ///     Derived Extracted Property as described by UAX #44
 | ||||
| /// - U+4DC0 - U+4DFF (Yijing Hexagram Symbols)
 | ||||
| /// - U+1F300 - U+1F5FF (Miscellaneous Symbols and Pictographs)
 | ||||
| /// - U+1F900 - U+1F9FF (Supplemental Symbols and Pictographs)
 | ||||
| ///
 | ||||
| /// The data is generated from
 | ||||
| /// - https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
 | ||||
| /// - The "overrides" in [format.string.std]/12
 | ||||
| ///
 | ||||
| /// The format of EastAsianWidth.txt is two fields separated by a semicolon.
 | ||||
| /// Field 0: Unicode code point value or range of code point values
 | ||||
| /// Field 1: East_Asian_Width property, consisting of one of the following values:
 | ||||
| ///         "A", "F", "H", "N", "Na", "W"
 | ||||
| ///  - All code points, assigned or unassigned, that are not listed
 | ||||
| ///      explicitly are given the value "N".
 | ||||
| ///  - The unassigned code points in the following blocks default to "W":
 | ||||
| ///         CJK Unified Ideographs Extension A: U+3400..U+4DBF
 | ||||
| ///         CJK Unified Ideographs:             U+4E00..U+9FFF
 | ||||
| ///         CJK Compatibility Ideographs:       U+F900..U+FAFF
 | ||||
| ///  - All undesignated code points in Planes 2 and 3, whether inside or
 | ||||
| ///      outside of allocated blocks, default to "W":
 | ||||
| ///         Plane 2:                            U+20000..U+2FFFD
 | ||||
| ///         Plane 3:                            U+30000..U+3FFFD
 | ||||
| ///
 | ||||
| /// The table is similar to the table
 | ||||
| ///  __extended_grapheme_custer_property_boundary::__entries
 | ||||
| /// which explains the details of these classes. The only difference is this
 | ||||
| /// table lacks a property, thus having more bits available for the size.
 | ||||
| ///
 | ||||
| /// The maximum code point that has an estimated width of 2 is U+3FFFD. This
 | ||||
| /// value can be encoded in 18 bits. Thus the upper 3 bits of the code point
 | ||||
| /// are always 0. These 3 bits are used to enlarge the offset range. This
 | ||||
| /// optimization reduces the table in Unicode 15 from 184 to 104 entries,
 | ||||
| /// saving 320 bytes.
 | ||||
| ///
 | ||||
| /// The data has 2 values:
 | ||||
| /// - bits [0, 13] The size of the range, allowing 16384 elements.
 | ||||
| /// - bits [14, 31] The lower bound code point of the range. The upper bound of
 | ||||
| ///   the range is lower bound + size.
 | ||||
| inline constexpr uint32_t __entries[108] = { | ||||
|     0x0440005f /* 00001100 - 0000115f [   96] */, //
 | ||||
|     0x08c68001 /* 0000231a - 0000231b [    2] */, //
 | ||||
|     0x08ca4001 /* 00002329 - 0000232a [    2] */, //
 | ||||
|     0x08fa4003 /* 000023e9 - 000023ec [    4] */, //
 | ||||
|     0x08fc0000 /* 000023f0 - 000023f0 [    1] */, //
 | ||||
|     0x08fcc000 /* 000023f3 - 000023f3 [    1] */, //
 | ||||
|     0x097f4001 /* 000025fd - 000025fe [    2] */, //
 | ||||
|     0x09850001 /* 00002614 - 00002615 [    2] */, //
 | ||||
|     0x0992000b /* 00002648 - 00002653 [   12] */, //
 | ||||
|     0x099fc000 /* 0000267f - 0000267f [    1] */, //
 | ||||
|     0x09a4c000 /* 00002693 - 00002693 [    1] */, //
 | ||||
|     0x09a84000 /* 000026a1 - 000026a1 [    1] */, //
 | ||||
|     0x09aa8001 /* 000026aa - 000026ab [    2] */, //
 | ||||
|     0x09af4001 /* 000026bd - 000026be [    2] */, //
 | ||||
|     0x09b10001 /* 000026c4 - 000026c5 [    2] */, //
 | ||||
|     0x09b38000 /* 000026ce - 000026ce [    1] */, //
 | ||||
|     0x09b50000 /* 000026d4 - 000026d4 [    1] */, //
 | ||||
|     0x09ba8000 /* 000026ea - 000026ea [    1] */, //
 | ||||
|     0x09bc8001 /* 000026f2 - 000026f3 [    2] */, //
 | ||||
|     0x09bd4000 /* 000026f5 - 000026f5 [    1] */, //
 | ||||
|     0x09be8000 /* 000026fa - 000026fa [    1] */, //
 | ||||
|     0x09bf4000 /* 000026fd - 000026fd [    1] */, //
 | ||||
|     0x09c14000 /* 00002705 - 00002705 [    1] */, //
 | ||||
|     0x09c28001 /* 0000270a - 0000270b [    2] */, //
 | ||||
|     0x09ca0000 /* 00002728 - 00002728 [    1] */, //
 | ||||
|     0x09d30000 /* 0000274c - 0000274c [    1] */, //
 | ||||
|     0x09d38000 /* 0000274e - 0000274e [    1] */, //
 | ||||
|     0x09d4c002 /* 00002753 - 00002755 [    3] */, //
 | ||||
|     0x09d5c000 /* 00002757 - 00002757 [    1] */, //
 | ||||
|     0x09e54002 /* 00002795 - 00002797 [    3] */, //
 | ||||
|     0x09ec0000 /* 000027b0 - 000027b0 [    1] */, //
 | ||||
|     0x09efc000 /* 000027bf - 000027bf [    1] */, //
 | ||||
|     0x0ac6c001 /* 00002b1b - 00002b1c [    2] */, //
 | ||||
|     0x0ad40000 /* 00002b50 - 00002b50 [    1] */, //
 | ||||
|     0x0ad54000 /* 00002b55 - 00002b55 [    1] */, //
 | ||||
|     0x0ba00019 /* 00002e80 - 00002e99 [   26] */, //
 | ||||
|     0x0ba6c058 /* 00002e9b - 00002ef3 [   89] */, //
 | ||||
|     0x0bc000d5 /* 00002f00 - 00002fd5 [  214] */, //
 | ||||
|     0x0bfc000b /* 00002ff0 - 00002ffb [   12] */, //
 | ||||
|     0x0c00003e /* 00003000 - 0000303e [   63] */, //
 | ||||
|     0x0c104055 /* 00003041 - 00003096 [   86] */, //
 | ||||
|     0x0c264066 /* 00003099 - 000030ff [  103] */, //
 | ||||
|     0x0c41402a /* 00003105 - 0000312f [   43] */, //
 | ||||
|     0x0c4c405d /* 00003131 - 0000318e [   94] */, //
 | ||||
|     0x0c640053 /* 00003190 - 000031e3 [   84] */, //
 | ||||
|     0x0c7c002e /* 000031f0 - 0000321e [   47] */, //
 | ||||
|     0x0c880027 /* 00003220 - 00003247 [   40] */, //
 | ||||
|     0x0c943fff /* 00003250 - 0000724f [16384] */, //
 | ||||
|     0x1c94323c /* 00007250 - 0000a48c [12861] */, //
 | ||||
|     0x29240036 /* 0000a490 - 0000a4c6 [   55] */, //
 | ||||
|     0x2a58001c /* 0000a960 - 0000a97c [   29] */, //
 | ||||
|     0x2b002ba3 /* 0000ac00 - 0000d7a3 [11172] */, //
 | ||||
|     0x3e4001ff /* 0000f900 - 0000faff [  512] */, //
 | ||||
|     0x3f840009 /* 0000fe10 - 0000fe19 [   10] */, //
 | ||||
|     0x3f8c0022 /* 0000fe30 - 0000fe52 [   35] */, //
 | ||||
|     0x3f950012 /* 0000fe54 - 0000fe66 [   19] */, //
 | ||||
|     0x3f9a0003 /* 0000fe68 - 0000fe6b [    4] */, //
 | ||||
|     0x3fc0405f /* 0000ff01 - 0000ff60 [   96] */, //
 | ||||
|     0x3ff80006 /* 0000ffe0 - 0000ffe6 [    7] */, //
 | ||||
|     0x5bf80004 /* 00016fe0 - 00016fe4 [    5] */, //
 | ||||
|     0x5bfc0001 /* 00016ff0 - 00016ff1 [    2] */, //
 | ||||
|     0x5c0017f7 /* 00017000 - 000187f7 [ 6136] */, //
 | ||||
|     0x620004d5 /* 00018800 - 00018cd5 [ 1238] */, //
 | ||||
|     0x63400008 /* 00018d00 - 00018d08 [    9] */, //
 | ||||
|     0x6bfc0003 /* 0001aff0 - 0001aff3 [    4] */, //
 | ||||
|     0x6bfd4006 /* 0001aff5 - 0001affb [    7] */, //
 | ||||
|     0x6bff4001 /* 0001affd - 0001affe [    2] */, //
 | ||||
|     0x6c000122 /* 0001b000 - 0001b122 [  291] */, //
 | ||||
|     0x6c4c8000 /* 0001b132 - 0001b132 [    1] */, //
 | ||||
|     0x6c540002 /* 0001b150 - 0001b152 [    3] */, //
 | ||||
|     0x6c554000 /* 0001b155 - 0001b155 [    1] */, //
 | ||||
|     0x6c590003 /* 0001b164 - 0001b167 [    4] */, //
 | ||||
|     0x6c5c018b /* 0001b170 - 0001b2fb [  396] */, //
 | ||||
|     0x7c010000 /* 0001f004 - 0001f004 [    1] */, //
 | ||||
|     0x7c33c000 /* 0001f0cf - 0001f0cf [    1] */, //
 | ||||
|     0x7c638000 /* 0001f18e - 0001f18e [    1] */, //
 | ||||
|     0x7c644009 /* 0001f191 - 0001f19a [   10] */, //
 | ||||
|     0x7c800002 /* 0001f200 - 0001f202 [    3] */, //
 | ||||
|     0x7c84002b /* 0001f210 - 0001f23b [   44] */, //
 | ||||
|     0x7c900008 /* 0001f240 - 0001f248 [    9] */, //
 | ||||
|     0x7c940001 /* 0001f250 - 0001f251 [    2] */, //
 | ||||
|     0x7c980005 /* 0001f260 - 0001f265 [    6] */, //
 | ||||
|     0x7cc0034f /* 0001f300 - 0001f64f [  848] */, //
 | ||||
|     0x7da00045 /* 0001f680 - 0001f6c5 [   70] */, //
 | ||||
|     0x7db30000 /* 0001f6cc - 0001f6cc [    1] */, //
 | ||||
|     0x7db40002 /* 0001f6d0 - 0001f6d2 [    3] */, //
 | ||||
|     0x7db54002 /* 0001f6d5 - 0001f6d7 [    3] */, //
 | ||||
|     0x7db70003 /* 0001f6dc - 0001f6df [    4] */, //
 | ||||
|     0x7dbac001 /* 0001f6eb - 0001f6ec [    2] */, //
 | ||||
|     0x7dbd0008 /* 0001f6f4 - 0001f6fc [    9] */, //
 | ||||
|     0x7df8000b /* 0001f7e0 - 0001f7eb [   12] */, //
 | ||||
|     0x7dfc0000 /* 0001f7f0 - 0001f7f0 [    1] */, //
 | ||||
|     0x7e4000ff /* 0001f900 - 0001f9ff [  256] */, //
 | ||||
|     0x7e9c000c /* 0001fa70 - 0001fa7c [   13] */, //
 | ||||
|     0x7ea00008 /* 0001fa80 - 0001fa88 [    9] */, //
 | ||||
|     0x7ea4002d /* 0001fa90 - 0001fabd [   46] */, //
 | ||||
|     0x7eafc006 /* 0001fabf - 0001fac5 [    7] */, //
 | ||||
|     0x7eb3800d /* 0001face - 0001fadb [   14] */, //
 | ||||
|     0x7eb80008 /* 0001fae0 - 0001fae8 [    9] */, //
 | ||||
|     0x7ebc0008 /* 0001faf0 - 0001faf8 [    9] */, //
 | ||||
|     0x80003fff /* 00020000 - 00023fff [16384] */, //
 | ||||
|     0x90003fff /* 00024000 - 00027fff [16384] */, //
 | ||||
|     0xa0003fff /* 00028000 - 0002bfff [16384] */, //
 | ||||
|     0xb0003ffd /* 0002c000 - 0002fffd [16382] */, //
 | ||||
|     0xc0003fff /* 00030000 - 00033fff [16384] */, //
 | ||||
|     0xd0003fff /* 00034000 - 00037fff [16384] */, //
 | ||||
|     0xe0003fff /* 00038000 - 0003bfff [16384] */, //
 | ||||
|     0xf0003ffd /* 0003c000 - 0003fffd [16382] */}; | ||||
| 
 | ||||
| /// The upper bound entry of EastAsianWidth.txt.
 | ||||
| ///
 | ||||
| /// Values greater than this value may have more than 18 significant bits.
 | ||||
| /// They always have a width of 1. This property makes it possible to store
 | ||||
| /// the table in its compact form.
 | ||||
| inline constexpr uint32_t __table_upper_bound = 0x0003fffd; | ||||
| 
 | ||||
| /// Returns the estimated width of a Unicode code point.
 | ||||
| ///
 | ||||
| /// \pre The code point is a valid Unicode code point.
 | ||||
| [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int __estimated_width(const char32_t __code_point) noexcept { | ||||
|   // Since __table_upper_bound contains the unshifted range do the
 | ||||
|   // comparison without shifting.
 | ||||
|   if (__code_point > __table_upper_bound) [[unlikely]] | ||||
|     return 1; | ||||
| 
 | ||||
|   // When the code-point is less than the first element in the table
 | ||||
|   // the lookup is quite expensive. Since quite some scripts are in
 | ||||
|   // that range, it makes sense to validate that first.
 | ||||
|   // The std_format_spec_string_unicode benchmark gives a measurable
 | ||||
|   // improvement.
 | ||||
|   if (__code_point < (__entries[0] >> 14)) | ||||
|     return 1; | ||||
| 
 | ||||
|   ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 14) | 0x3fffu) - __entries; | ||||
|   if (__i == 0) | ||||
|     return 1; | ||||
| 
 | ||||
|   --__i; | ||||
|   uint32_t __upper_bound = (__entries[__i] >> 14) + (__entries[__i] & 0x3fffu); | ||||
|   return 1 + (__code_point <= __upper_bound); | ||||
| } | ||||
| 
 | ||||
| } // namespace __width_estimation_table
 | ||||
| 
 | ||||
| #endif //_LIBCPP_STD_VER >= 20
 | ||||
| 
 | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
| 
 | ||||
| #endif // _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue