Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // -*- C++ -*-
0002 //===----------------------------------------------------------------------===//
0003 //
0004 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0005 // See https://llvm.org/LICENSE.txt for license information.
0006 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0007 //
0008 //===----------------------------------------------------------------------===//
0009 
0010 #ifndef _LIBCPP___FORMAT_BUFFER_H
0011 #define _LIBCPP___FORMAT_BUFFER_H
0012 
0013 #include <__algorithm/copy_n.h>
0014 #include <__algorithm/fill_n.h>
0015 #include <__algorithm/max.h>
0016 #include <__algorithm/min.h>
0017 #include <__algorithm/ranges_copy.h>
0018 #include <__algorithm/ranges_copy_n.h>
0019 #include <__algorithm/transform.h>
0020 #include <__algorithm/unwrap_iter.h>
0021 #include <__concepts/same_as.h>
0022 #include <__config>
0023 #include <__format/concepts.h>
0024 #include <__format/enable_insertable.h>
0025 #include <__format/format_to_n_result.h>
0026 #include <__iterator/back_insert_iterator.h>
0027 #include <__iterator/concepts.h>
0028 #include <__iterator/incrementable_traits.h>
0029 #include <__iterator/iterator_traits.h>
0030 #include <__iterator/wrap_iter.h>
0031 #include <__memory/addressof.h>
0032 #include <__memory/allocate_at_least.h>
0033 #include <__memory/allocator.h>
0034 #include <__memory/allocator_traits.h>
0035 #include <__memory/construct_at.h>
0036 #include <__memory/ranges_construct_at.h>
0037 #include <__memory/uninitialized_algorithms.h>
0038 #include <__type_traits/add_pointer.h>
0039 #include <__type_traits/conditional.h>
0040 #include <__utility/exception_guard.h>
0041 #include <__utility/move.h>
0042 #include <stdexcept>
0043 #include <string_view>
0044 
0045 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0046 #  pragma GCC system_header
0047 #endif
0048 
0049 _LIBCPP_PUSH_MACROS
0050 #include <__undef_macros>
0051 
0052 _LIBCPP_BEGIN_NAMESPACE_STD
0053 
0054 #if _LIBCPP_STD_VER >= 20
0055 
0056 namespace __format {
0057 
0058 // A helper to limit the total size of code units written.
0059 class _LIBCPP_HIDE_FROM_ABI __max_output_size {
0060 public:
0061   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __max_output_size(size_t __max_size) : __max_size_{__max_size} {}
0062 
0063   // This function adjusts the size of a (bulk) write operations. It ensures the
0064   // number of code units written by a __output_buffer never exceeds
0065   // __max_size_ code units.
0066   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __write_request(size_t __code_units) {
0067     size_t __result =
0068         __code_units_written_ < __max_size_ ? std::min(__code_units, __max_size_ - __code_units_written_) : 0;
0069     __code_units_written_ += __code_units;
0070     return __result;
0071   }
0072 
0073   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __code_units_written() const noexcept { return __code_units_written_; }
0074 
0075 private:
0076   size_t __max_size_;
0077   // The code units that would have been written if there was no limit.
0078   // format_to_n returns this value.
0079   size_t __code_units_written_{0};
0080 };
0081 
0082 /// A "buffer" that handles writing to the proper iterator.
0083 ///
0084 /// This helper is used together with the @ref back_insert_iterator to offer
0085 /// type-erasure for the formatting functions. This reduces the number to
0086 /// template instantiations.
0087 ///
0088 /// The design is the following:
0089 /// - There is an external object that connects the buffer to the output.
0090 /// - This buffer object:
0091 ///   - inherits publicly from this class.
0092 ///   - has a static or dynamic buffer.
0093 ///   - has a static member function to make space in its buffer write
0094 ///     operations. This can be done by increasing the size of the internal
0095 ///     buffer or by writing the contents of the buffer to the output iterator.
0096 ///
0097 ///     This member function is a constructor argument, so its name is not
0098 ///     fixed. The code uses the name __prepare_write.
0099 /// - The number of output code units can be limited by a __max_output_size
0100 ///   object. This is used in format_to_n This object:
0101 ///   - Contains the maximum number of code units to be written.
0102 ///   - Contains the number of code units that are requested to be written.
0103 ///     This number is returned to the user of format_to_n.
0104 ///   - The write functions call the object's __request_write member function.
0105 ///     This function:
0106 ///     - Updates the number of code units that are requested to be written.
0107 ///     - Returns the number of code units that can be written without
0108 ///       exceeding the maximum number of code units to be written.
0109 ///
0110 /// Documentation for the buffer usage members:
0111 /// - __ptr_
0112 ///   The start of the buffer.
0113 /// - __capacity_
0114 ///   The number of code units that can be written. This means
0115 ///   [__ptr_, __ptr_ + __capacity_) is a valid range to write to.
0116 /// - __size_
0117 ///   The number of code units written in the buffer. The next code unit will
0118 ///   be written at __ptr_ + __size_. This __size_ may NOT contain the total
0119 ///   number of code units written by the __output_buffer. Whether or not it
0120 ///   does depends on the sub-class used. Typically the total number of code
0121 ///   units written is not interesting. It is interesting for format_to_n which
0122 ///   has its own way to track this number.
0123 ///
0124 /// Documentation for the modifying buffer operations:
0125 /// The subclasses have a function with the following signature:
0126 ///
0127 ///   static void __prepare_write(
0128 ///     __output_buffer<_CharT>& __buffer, size_t __code_units);
0129 ///
0130 /// This function is called when a write function writes more code units than
0131 /// the buffer's available space. When an __max_output_size object is provided
0132 /// the number of code units is the number of code units returned from
0133 /// __max_output_size::__request_write function.
0134 ///
0135 /// - The __buffer contains *this. Since the class containing this function
0136 ///   inherits from __output_buffer it's safe to cast it to the subclass being
0137 ///   used.
0138 /// - The __code_units is the number of code units the caller will write + 1.
0139 ///   - This value does not take the available space of the buffer into account.
0140 ///   - The push_back function is more efficient when writing before resizing,
0141 ///     this means the buffer should always have room for one code unit. Hence
0142 ///     the + 1 is the size.
0143 /// - When the function returns there is room for at least one additional code
0144 ///   unit. There is no requirement there is room for __code_units code units:
0145 ///   - The class has some "bulk" operations. For example, __copy which copies
0146 ///     the contents of a basic_string_view to the output. If the sub-class has
0147 ///     a fixed size buffer the size of the basic_string_view may be larger
0148 ///     than the buffer. In that case it's impossible to honor the requested
0149 ///     size.
0150 ///   - When the buffer has room for at least one code unit the function may be
0151 ///     a no-op.
0152 /// - When the function makes space for more code units it uses one for these
0153 ///   functions to signal the change:
0154 ///   - __buffer_flushed()
0155 ///     - This function is typically used for a fixed sized buffer.
0156 ///     - The current contents of [__ptr_, __ptr_ + __size_) have been
0157 ///       processed.
0158 ///     - __ptr_ remains unchanged.
0159 ///     - __capacity_ remains unchanged.
0160 ///     - __size_ will be set to 0.
0161 ///   - __buffer_moved(_CharT* __ptr, size_t __capacity)
0162 ///     - This function is typically used for a dynamic sized buffer. There the
0163 ///       location of the buffer changes due to reallocations.
0164 ///     - __ptr_ will be set to __ptr. (This value may be the old value of
0165 ///       __ptr_).
0166 ///     - __capacity_ will be set to __capacity. (This value may be the old
0167 ///       value of __capacity_).
0168 ///     - __size_ remains unchanged,
0169 ///     - The range [__ptr, __ptr + __size_) contains the original data of the
0170 ///       range [__ptr_, __ptr_ + __size_).
0171 ///
0172 /// The push_back function expects a valid buffer and a capacity of at least 1.
0173 /// This means:
0174 /// - The class is constructed with a valid buffer,
0175 /// - __buffer_moved is called with a valid buffer is used before the first
0176 ///   write operation,
0177 /// - no write function is ever called, or
0178 /// - the class is constructed with a __max_output_size object with __max_size 0.
0179 ///
0180 /// The latter option allows formatted_size to use the output buffer without
0181 /// ever writing anything to the buffer.
0182 template <__fmt_char_type _CharT>
0183 class _LIBCPP_TEMPLATE_VIS __output_buffer {
0184 public:
0185   using value_type _LIBCPP_NODEBUG           = _CharT;
0186   using __prepare_write_type _LIBCPP_NODEBUG = void (*)(__output_buffer<_CharT>&, size_t);
0187 
0188   [[nodiscard]]
0189   _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, __prepare_write_type __function)
0190       : __output_buffer{__ptr, __capacity, __function, nullptr} {}
0191 
0192   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(
0193       _CharT* __ptr, size_t __capacity, __prepare_write_type __function, __max_output_size* __max_output_size)
0194       : __ptr_(__ptr), __capacity_(__capacity), __prepare_write_(__function), __max_output_size_(__max_output_size) {}
0195 
0196   _LIBCPP_HIDE_FROM_ABI void __buffer_flushed() { __size_ = 0; }
0197 
0198   _LIBCPP_HIDE_FROM_ABI void __buffer_moved(_CharT* __ptr, size_t __capacity) {
0199     __ptr_      = __ptr;
0200     __capacity_ = __capacity;
0201   }
0202 
0203   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; }
0204 
0205   // Used in std::back_insert_iterator.
0206   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
0207     if (__max_output_size_ && __max_output_size_->__write_request(1) == 0)
0208       return;
0209 
0210     _LIBCPP_ASSERT_INTERNAL(
0211         __ptr_ && __size_ < __capacity_ && __available() >= 1, "attempted to write outside the buffer");
0212 
0213     __ptr_[__size_++] = __c;
0214 
0215     // Profiling showed flushing after adding is more efficient than flushing
0216     // when entering the function.
0217     if (__size_ == __capacity_)
0218       __prepare_write(0);
0219   }
0220 
0221   /// Copies the input __str to the buffer.
0222   ///
0223   /// Since some of the input is generated by std::to_chars, there needs to be a
0224   /// conversion when _CharT is wchar_t.
0225   template <__fmt_char_type _InCharT>
0226   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
0227     // When the underlying iterator is a simple iterator the __capacity_ is
0228     // infinite. For a string or container back_inserter it isn't. This means
0229     // that adding a large string to the buffer can cause some overhead. In that
0230     // case a better approach could be:
0231     // - flush the buffer
0232     // - container.append(__str.begin(), __str.end());
0233     // The same holds true for the fill.
0234     // For transform it might be slightly harder, however the use case for
0235     // transform is slightly less common; it converts hexadecimal values to
0236     // upper case. For integral these strings are short.
0237     // TODO FMT Look at the improvements above.
0238     size_t __n = __str.size();
0239     if (__max_output_size_) {
0240       __n = __max_output_size_->__write_request(__n);
0241       if (__n == 0)
0242         return;
0243     }
0244 
0245     const _InCharT* __first = __str.data();
0246     do {
0247       __prepare_write(__n);
0248       size_t __chunk = std::min(__n, __available());
0249       std::copy_n(__first, __chunk, std::addressof(__ptr_[__size_]));
0250       __size_ += __chunk;
0251       __first += __chunk;
0252       __n -= __chunk;
0253     } while (__n);
0254   }
0255 
0256   /// A std::transform wrapper.
0257   ///
0258   /// Like @ref __copy it may need to do type conversion.
0259   template <contiguous_iterator _Iterator,
0260             class _UnaryOperation,
0261             __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
0262   _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
0263     _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
0264 
0265     size_t __n = static_cast<size_t>(__last - __first);
0266     if (__max_output_size_) {
0267       __n = __max_output_size_->__write_request(__n);
0268       if (__n == 0)
0269         return;
0270     }
0271 
0272     do {
0273       __prepare_write(__n);
0274       size_t __chunk = std::min(__n, __available());
0275       std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
0276       __size_ += __chunk;
0277       __first += __chunk;
0278       __n -= __chunk;
0279     } while (__n);
0280   }
0281 
0282   /// A \c fill_n wrapper.
0283   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
0284     if (__max_output_size_) {
0285       __n = __max_output_size_->__write_request(__n);
0286       if (__n == 0)
0287         return;
0288     }
0289 
0290     do {
0291       __prepare_write(__n);
0292       size_t __chunk = std::min(__n, __available());
0293       std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
0294       __size_ += __chunk;
0295       __n -= __chunk;
0296     } while (__n);
0297   }
0298 
0299   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __capacity() const { return __capacity_; }
0300   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __size() const { return __size_; }
0301 
0302 private:
0303   _CharT* __ptr_;
0304   size_t __capacity_;
0305   size_t __size_{0};
0306   void (*__prepare_write_)(__output_buffer<_CharT>&, size_t);
0307   __max_output_size* __max_output_size_;
0308 
0309   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __available() const { return __capacity_ - __size_; }
0310 
0311   _LIBCPP_HIDE_FROM_ABI void __prepare_write(size_t __code_units) {
0312     // Always have space for one additional code unit. This is a precondition of the push_back function.
0313     __code_units += 1;
0314     if (__available() < __code_units)
0315       __prepare_write_(*this, __code_units + 1);
0316   }
0317 };
0318 
0319 template <class _OutIt, class _CharT>
0320 concept __enable_direct_output =
0321     __fmt_char_type<_CharT> &&
0322     (same_as<_OutIt, _CharT*>
0323      // TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
0324      // `#ifdef`.
0325      || same_as<_OutIt, __wrap_iter<_CharT*>>);
0326 
0327 /// Concept to see whether a \a _Container is insertable.
0328 ///
0329 /// The concept is used to validate whether multiple calls to a
0330 /// \ref back_insert_iterator can be replace by a call to \c _Container::insert.
0331 ///
0332 /// \note a \a _Container needs to opt-in to the concept by specializing
0333 /// \ref __enable_insertable.
0334 template <class _Container>
0335 concept __insertable =
0336     __enable_insertable<_Container> && __fmt_char_type<typename _Container::value_type> &&
0337     requires(_Container& __t,
0338              add_pointer_t<typename _Container::value_type> __first,
0339              add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };
0340 
0341 /// Extract the container type of a \ref back_insert_iterator.
0342 template <class _It>
0343 struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container {
0344   using type _LIBCPP_NODEBUG = void;
0345 };
0346 
0347 template <__insertable _Container>
0348 struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> {
0349   using type _LIBCPP_NODEBUG = _Container;
0350 };
0351 
0352 // A dynamically growing buffer.
0353 template <__fmt_char_type _CharT>
0354 class _LIBCPP_TEMPLATE_VIS __allocating_buffer : public __output_buffer<_CharT> {
0355 public:
0356   __allocating_buffer(const __allocating_buffer&)            = delete;
0357   __allocating_buffer& operator=(const __allocating_buffer&) = delete;
0358 
0359   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __allocating_buffer() : __allocating_buffer{nullptr} {}
0360 
0361   [[nodiscard]]
0362   _LIBCPP_HIDE_FROM_ABI explicit __allocating_buffer(__max_output_size* __max_output_size)
0363       : __output_buffer<_CharT>{__small_buffer_, __buffer_size_, __prepare_write, __max_output_size} {}
0364 
0365   _LIBCPP_HIDE_FROM_ABI ~__allocating_buffer() {
0366     if (__ptr_ != __small_buffer_)
0367       _Alloc{}.deallocate(__ptr_, this->__capacity());
0368   }
0369 
0370   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, this->__size()}; }
0371 
0372 private:
0373   using _Alloc _LIBCPP_NODEBUG = allocator<_CharT>;
0374 
0375   // Since allocating is expensive the class has a small internal buffer. When
0376   // its capacity is exceeded a dynamic buffer will be allocated.
0377   static constexpr size_t __buffer_size_ = 256;
0378   _CharT __small_buffer_[__buffer_size_];
0379 
0380   _CharT* __ptr_{__small_buffer_};
0381 
0382   _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
0383     if (__capacity < __buffer_size_)
0384       return;
0385 
0386     _LIBCPP_ASSERT_INTERNAL(__capacity > this->__capacity(), "the buffer must grow");
0387 
0388     // _CharT is an implicit lifetime type so can be used without explicit
0389     // construction or destruction.
0390     _Alloc __alloc;
0391     auto __result = std::__allocate_at_least(__alloc, __capacity);
0392     std::copy_n(__ptr_, this->__size(), __result.ptr);
0393     if (__ptr_ != __small_buffer_)
0394       __alloc.deallocate(__ptr_, this->__capacity());
0395 
0396     __ptr_ = __result.ptr;
0397     this->__buffer_moved(__ptr_, __result.count);
0398   }
0399 
0400   _LIBCPP_HIDE_FROM_ABI void __prepare_write(size_t __size_hint) {
0401     __grow_buffer(std::max<size_t>(this->__capacity() + __size_hint, this->__capacity() * 1.6));
0402   }
0403 
0404   _LIBCPP_HIDE_FROM_ABI static void __prepare_write(__output_buffer<_CharT>& __buffer, size_t __size_hint) {
0405     static_cast<__allocating_buffer<_CharT>&>(__buffer).__prepare_write(__size_hint);
0406   }
0407 };
0408 
0409 // A buffer that directly writes to the underlying buffer.
0410 template <class _OutIt, __fmt_char_type _CharT>
0411 class _LIBCPP_TEMPLATE_VIS __direct_iterator_buffer : public __output_buffer<_CharT> {
0412 public:
0413   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __direct_iterator_buffer(_OutIt __out_it)
0414       : __direct_iterator_buffer{__out_it, nullptr} {}
0415 
0416   [[nodiscard]]
0417   _LIBCPP_HIDE_FROM_ABI explicit __direct_iterator_buffer(_OutIt __out_it, __max_output_size* __max_output_size)
0418       : __output_buffer<_CharT>{std::__unwrap_iter(__out_it), __buffer_size, __prepare_write, __max_output_size},
0419         __out_it_(__out_it) {}
0420 
0421   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return __out_it_ + this->__size(); }
0422 
0423 private:
0424   // The function format_to expects a buffer large enough for the output. The
0425   // function format_to_n has its own helper class that restricts the number of
0426   // write options. So this function class can pretend to have an infinite
0427   // buffer.
0428   static constexpr size_t __buffer_size = -1;
0429 
0430   _OutIt __out_it_;
0431 
0432   _LIBCPP_HIDE_FROM_ABI static void
0433   __prepare_write([[maybe_unused]] __output_buffer<_CharT>& __buffer, [[maybe_unused]] size_t __size_hint) {
0434     std::__throw_length_error("__direct_iterator_buffer");
0435   }
0436 };
0437 
0438 // A buffer that writes its output to the end of a container.
0439 template <class _OutIt, __fmt_char_type _CharT>
0440 class _LIBCPP_TEMPLATE_VIS __container_inserter_buffer : public __output_buffer<_CharT> {
0441 public:
0442   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __container_inserter_buffer(_OutIt __out_it)
0443       : __container_inserter_buffer{__out_it, nullptr} {}
0444 
0445   [[nodiscard]]
0446   _LIBCPP_HIDE_FROM_ABI explicit __container_inserter_buffer(_OutIt __out_it, __max_output_size* __max_output_size)
0447       : __output_buffer<_CharT>{__small_buffer_, __buffer_size, __prepare_write, __max_output_size},
0448         __container_{__out_it.__get_container()} {}
0449 
0450   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto __out_it() && {
0451     __container_->insert(__container_->end(), __small_buffer_, __small_buffer_ + this->__size());
0452     return std::back_inserter(*__container_);
0453   }
0454 
0455 private:
0456   typename __back_insert_iterator_container<_OutIt>::type* __container_;
0457 
0458   // This class uses a fixed size buffer and appends the elements in
0459   // __buffer_size chunks. An alternative would be to use an allocating buffer
0460   // and append the output in a single write operation. Benchmarking showed no
0461   // performance difference.
0462   static constexpr size_t __buffer_size = 256;
0463   _CharT __small_buffer_[__buffer_size];
0464 
0465   _LIBCPP_HIDE_FROM_ABI void __prepare_write() {
0466     __container_->insert(__container_->end(), __small_buffer_, __small_buffer_ + this->__size());
0467     this->__buffer_flushed();
0468   }
0469 
0470   _LIBCPP_HIDE_FROM_ABI static void
0471   __prepare_write(__output_buffer<_CharT>& __buffer, [[maybe_unused]] size_t __size_hint) {
0472     static_cast<__container_inserter_buffer<_OutIt, _CharT>&>(__buffer).__prepare_write();
0473   }
0474 };
0475 
0476 // A buffer that writes to an iterator.
0477 //
0478 // Unlike the __container_inserter_buffer this class' performance does benefit
0479 // from allocating and then inserting.
0480 template <class _OutIt, __fmt_char_type _CharT>
0481 class _LIBCPP_TEMPLATE_VIS __iterator_buffer : public __allocating_buffer<_CharT> {
0482 public:
0483   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __iterator_buffer(_OutIt __out_it)
0484       : __allocating_buffer<_CharT>{}, __out_it_{std::move(__out_it)} {}
0485 
0486   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __iterator_buffer(_OutIt __out_it, __max_output_size* __max_output_size)
0487       : __allocating_buffer<_CharT>{__max_output_size}, __out_it_{std::move(__out_it)} {}
0488 
0489   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto __out_it() && {
0490     return std::ranges::copy(this->__view(), std::move(__out_it_)).out;
0491   }
0492 
0493 private:
0494   _OutIt __out_it_;
0495 };
0496 
0497 // Selects the type of the buffer used for the output iterator.
0498 template <class _OutIt, __fmt_char_type _CharT>
0499 class _LIBCPP_TEMPLATE_VIS __buffer_selector {
0500   using _Container _LIBCPP_NODEBUG = __back_insert_iterator_container<_OutIt>::type;
0501 
0502 public:
0503   using type _LIBCPP_NODEBUG =
0504       conditional_t<!same_as<_Container, void>,
0505                     __container_inserter_buffer<_OutIt, _CharT>,
0506                     conditional_t<__enable_direct_output<_OutIt, _CharT>,
0507                                   __direct_iterator_buffer<_OutIt, _CharT>,
0508                                   __iterator_buffer<_OutIt, _CharT>>>;
0509 };
0510 
0511 // A buffer that counts and limits the number of insertions.
0512 template <class _OutIt, __fmt_char_type _CharT>
0513 class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer : private __buffer_selector<_OutIt, _CharT>::type {
0514 public:
0515   using _Base _LIBCPP_NODEBUG = __buffer_selector<_OutIt, _CharT>::type;
0516 
0517   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __format_to_n_buffer(_OutIt __out_it, iter_difference_t<_OutIt> __n)
0518       : _Base{std::move(__out_it), std::addressof(__max_output_size_)},
0519         __max_output_size_{__n < 0 ? size_t{0} : static_cast<size_t>(__n)} {}
0520 
0521   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return _Base::__make_output_iterator(); }
0522 
0523   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
0524     return {static_cast<_Base&&>(*this).__out_it(),
0525             static_cast<iter_difference_t<_OutIt>>(__max_output_size_.__code_units_written())};
0526   }
0527 
0528 private:
0529   __max_output_size __max_output_size_;
0530 };
0531 
0532 // A buffer that counts the number of insertions.
0533 //
0534 // Since formatted_size only needs to know the size, the output itself is
0535 // discarded.
0536 template <__fmt_char_type _CharT>
0537 class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer : private __output_buffer<_CharT> {
0538 public:
0539   using _Base _LIBCPP_NODEBUG = __output_buffer<_CharT>;
0540 
0541   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __formatted_size_buffer()
0542       : _Base{nullptr, 0, __prepare_write, std::addressof(__max_output_size_)} {}
0543 
0544   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return _Base::__make_output_iterator(); }
0545 
0546   // This function does not need to be r-value qualified, however this is
0547   // consistent with similar objects.
0548   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __result() && { return __max_output_size_.__code_units_written(); }
0549 
0550 private:
0551   __max_output_size __max_output_size_{0};
0552 
0553   _LIBCPP_HIDE_FROM_ABI static void
0554   __prepare_write([[maybe_unused]] __output_buffer<_CharT>& __buffer, [[maybe_unused]] size_t __size_hint) {
0555     // Note this function does not satisfy the requirement of giving a 1 code unit buffer.
0556     _LIBCPP_ASSERT_INTERNAL(
0557         false, "Since __max_output_size_.__max_size_ == 0 there should never be call to this function.");
0558   }
0559 };
0560 
0561 // A dynamically growing buffer intended to be used for retargeting a context.
0562 //
0563 // P2286 Formatting ranges adds range formatting support. It allows the user to
0564 // specify the minimum width for the entire formatted range.  The width of the
0565 // range is not known until the range is formatted. Formatting is done to an
0566 // output_iterator so there's no guarantee it would be possible to add the fill
0567 // to the front of the output. Instead the range is formatted to a temporary
0568 // buffer and that buffer is formatted as a string.
0569 //
0570 // There is an issue with that approach, the format context used in
0571 // std::formatter<T>::format contains the output iterator used as part of its
0572 // type. So using this output iterator means there needs to be a new format
0573 // context and the format arguments need to be retargeted to the new context.
0574 // This retargeting is done by a basic_format_context specialized for the
0575 // __iterator of this container.
0576 //
0577 // This class uses its own buffer management, since using vector
0578 // would lead to a circular include with formatter for vector<bool>.
0579 template <__fmt_char_type _CharT>
0580 class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
0581   using _Alloc _LIBCPP_NODEBUG = allocator<_CharT>;
0582 
0583 public:
0584   using value_type _LIBCPP_NODEBUG = _CharT;
0585 
0586   struct __iterator {
0587     using difference_type _LIBCPP_NODEBUG = ptrdiff_t;
0588     using value_type _LIBCPP_NODEBUG      = _CharT;
0589 
0590     _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
0591         : __buffer_(std::addressof(__buffer)) {}
0592     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {
0593       __buffer_->push_back(__c);
0594       return *this;
0595     }
0596     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {
0597       __buffer_->push_back(__c);
0598       return *this;
0599     }
0600 
0601     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }
0602     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }
0603     _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }
0604     __retarget_buffer* __buffer_;
0605   };
0606 
0607   __retarget_buffer(const __retarget_buffer&)            = delete;
0608   __retarget_buffer& operator=(const __retarget_buffer&) = delete;
0609 
0610   _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {
0611     // When the initial size is very small a lot of resizes happen
0612     // when elements added. So use a hard-coded minimum size.
0613     //
0614     // Note a size < 2 will not work
0615     // - 0 there is no buffer, while push_back requires 1 empty element.
0616     // - 1 multiplied by the grow factor is 1 and thus the buffer never
0617     //   grows.
0618     auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT)));
0619     __ptr_        = __result.ptr;
0620     __capacity_   = __result.count;
0621   }
0622 
0623   _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {
0624     ranges::destroy_n(__ptr_, __size_);
0625     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
0626   }
0627 
0628   _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
0629 
0630   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
0631     std::construct_at(__ptr_ + __size_, __c);
0632     ++__size_;
0633 
0634     if (__size_ == __capacity_)
0635       __grow_buffer();
0636   }
0637 
0638   template <__fmt_char_type _InCharT>
0639   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
0640     size_t __n = __str.size();
0641     if (__size_ + __n >= __capacity_)
0642       // Push_back requires the buffer to have room for at least one character.
0643       __grow_buffer(__size_ + __n + 1);
0644 
0645     std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);
0646     __size_ += __n;
0647   }
0648 
0649   template <contiguous_iterator _Iterator,
0650             class _UnaryOperation,
0651             __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
0652   _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
0653     _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
0654 
0655     size_t __n = static_cast<size_t>(__last - __first);
0656     if (__size_ + __n >= __capacity_)
0657       // Push_back requires the buffer to have room for at least one character.
0658       __grow_buffer(__size_ + __n + 1);
0659 
0660     std::uninitialized_default_construct_n(__ptr_ + __size_, __n);
0661     std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));
0662     __size_ += __n;
0663   }
0664 
0665   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
0666     if (__size_ + __n >= __capacity_)
0667       // Push_back requires the buffer to have room for at least one character.
0668       __grow_buffer(__size_ + __n + 1);
0669 
0670     std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);
0671     __size_ += __n;
0672   }
0673 
0674   _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }
0675 
0676 private:
0677   _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
0678 
0679   _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
0680     _LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow");
0681     auto __result = std::__allocate_at_least(__alloc_, __capacity);
0682     auto __guard  = std::__make_exception_guard([&] {
0683       allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
0684     });
0685     // This shouldn't throw, but just to be safe. Note that at -O1 this
0686     // guard is optimized away so there is no runtime overhead.
0687     std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
0688     __guard.__complete();
0689     ranges::destroy_n(__ptr_, __size_);
0690     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
0691 
0692     __ptr_      = __result.ptr;
0693     __capacity_ = __result.count;
0694   }
0695   _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
0696   _CharT* __ptr_;
0697   size_t __capacity_;
0698   size_t __size_{0};
0699 };
0700 
0701 } // namespace __format
0702 
0703 #endif // _LIBCPP_STD_VER >= 20
0704 
0705 _LIBCPP_END_NAMESPACE_STD
0706 
0707 _LIBCPP_POP_MACROS
0708 
0709 #endif // _LIBCPP___FORMAT_BUFFER_H