Back to home page

EIC code displayed by LXR

 
 

    


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

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___CXX03___FORMAT_BUFFER_H
0011 #define _LIBCPP___CXX03___FORMAT_BUFFER_H
0012 
0013 #include <__cxx03/__algorithm/copy_n.h>
0014 #include <__cxx03/__algorithm/fill_n.h>
0015 #include <__cxx03/__algorithm/max.h>
0016 #include <__cxx03/__algorithm/min.h>
0017 #include <__cxx03/__algorithm/ranges_copy_n.h>
0018 #include <__cxx03/__algorithm/transform.h>
0019 #include <__cxx03/__algorithm/unwrap_iter.h>
0020 #include <__cxx03/__concepts/same_as.h>
0021 #include <__cxx03/__config>
0022 #include <__cxx03/__format/concepts.h>
0023 #include <__cxx03/__format/enable_insertable.h>
0024 #include <__cxx03/__format/format_to_n_result.h>
0025 #include <__cxx03/__iterator/back_insert_iterator.h>
0026 #include <__cxx03/__iterator/concepts.h>
0027 #include <__cxx03/__iterator/incrementable_traits.h>
0028 #include <__cxx03/__iterator/iterator_traits.h>
0029 #include <__cxx03/__iterator/wrap_iter.h>
0030 #include <__cxx03/__memory/addressof.h>
0031 #include <__cxx03/__memory/allocate_at_least.h>
0032 #include <__cxx03/__memory/allocator_traits.h>
0033 #include <__cxx03/__memory/construct_at.h>
0034 #include <__cxx03/__memory/ranges_construct_at.h>
0035 #include <__cxx03/__memory/uninitialized_algorithms.h>
0036 #include <__cxx03/__type_traits/add_pointer.h>
0037 #include <__cxx03/__type_traits/conditional.h>
0038 #include <__cxx03/__utility/exception_guard.h>
0039 #include <__cxx03/__utility/move.h>
0040 #include <__cxx03/cstddef>
0041 #include <__cxx03/string_view>
0042 
0043 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0044 #  pragma GCC system_header
0045 #endif
0046 
0047 _LIBCPP_PUSH_MACROS
0048 #include <__cxx03/__undef_macros>
0049 
0050 _LIBCPP_BEGIN_NAMESPACE_STD
0051 
0052 #if _LIBCPP_STD_VER >= 20
0053 
0054 namespace __format {
0055 
0056 /// A "buffer" that handles writing to the proper iterator.
0057 ///
0058 /// This helper is used together with the @ref back_insert_iterator to offer
0059 /// type-erasure for the formatting functions. This reduces the number to
0060 /// template instantiations.
0061 template <__fmt_char_type _CharT>
0062 class _LIBCPP_TEMPLATE_VIS __output_buffer {
0063 public:
0064   using value_type = _CharT;
0065 
0066   template <class _Tp>
0067   _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj)
0068       : __ptr_(__ptr),
0069         __capacity_(__capacity),
0070         __flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }),
0071         __obj_(__obj) {}
0072 
0073   _LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) {
0074     __ptr_      = __ptr;
0075     __capacity_ = __capacity;
0076   }
0077 
0078   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; }
0079 
0080   // Used in std::back_insert_iterator.
0081   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
0082     __ptr_[__size_++] = __c;
0083 
0084     // Profiling showed flushing after adding is more efficient than flushing
0085     // when entering the function.
0086     if (__size_ == __capacity_)
0087       __flush();
0088   }
0089 
0090   /// Copies the input __str to the buffer.
0091   ///
0092   /// Since some of the input is generated by std::to_chars, there needs to be a
0093   /// conversion when _CharT is wchar_t.
0094   template <__fmt_char_type _InCharT>
0095   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
0096     // When the underlying iterator is a simple iterator the __capacity_ is
0097     // infinite. For a string or container back_inserter it isn't. This means
0098     // that adding a large string to the buffer can cause some overhead. In that
0099     // case a better approach could be:
0100     // - flush the buffer
0101     // - container.append(__str.begin(), __str.end());
0102     // The same holds true for the fill.
0103     // For transform it might be slightly harder, however the use case for
0104     // transform is slightly less common; it converts hexadecimal values to
0105     // upper case. For integral these strings are short.
0106     // TODO FMT Look at the improvements above.
0107     size_t __n = __str.size();
0108 
0109     __flush_on_overflow(__n);
0110     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
0111       std::copy_n(__str.data(), __n, std::addressof(__ptr_[__size_]));
0112       __size_ += __n;
0113       return;
0114     }
0115 
0116     // The output doesn't fit in the internal buffer.
0117     // Copy the data in "__capacity_" sized chunks.
0118     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
0119     const _InCharT* __first = __str.data();
0120     do {
0121       size_t __chunk = std::min(__n, __capacity_);
0122       std::copy_n(__first, __chunk, std::addressof(__ptr_[__size_]));
0123       __size_ = __chunk;
0124       __first += __chunk;
0125       __n -= __chunk;
0126       __flush();
0127     } while (__n);
0128   }
0129 
0130   /// A std::transform wrapper.
0131   ///
0132   /// Like @ref __copy it may need to do type conversion.
0133   template <contiguous_iterator _Iterator,
0134             class _UnaryOperation,
0135             __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
0136   _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
0137     _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
0138 
0139     size_t __n = static_cast<size_t>(__last - __first);
0140     __flush_on_overflow(__n);
0141     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
0142       std::transform(__first, __last, std::addressof(__ptr_[__size_]), std::move(__operation));
0143       __size_ += __n;
0144       return;
0145     }
0146 
0147     // The output doesn't fit in the internal buffer.
0148     // Transform the data in "__capacity_" sized chunks.
0149     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
0150     do {
0151       size_t __chunk = std::min(__n, __capacity_);
0152       std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
0153       __size_ = __chunk;
0154       __first += __chunk;
0155       __n -= __chunk;
0156       __flush();
0157     } while (__n);
0158   }
0159 
0160   /// A \c fill_n wrapper.
0161   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
0162     __flush_on_overflow(__n);
0163     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
0164       std::fill_n(std::addressof(__ptr_[__size_]), __n, __value);
0165       __size_ += __n;
0166       return;
0167     }
0168 
0169     // The output doesn't fit in the internal buffer.
0170     // Fill the buffer in "__capacity_" sized chunks.
0171     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
0172     do {
0173       size_t __chunk = std::min(__n, __capacity_);
0174       std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
0175       __size_ = __chunk;
0176       __n -= __chunk;
0177       __flush();
0178     } while (__n);
0179   }
0180 
0181   _LIBCPP_HIDE_FROM_ABI void __flush() {
0182     __flush_(__ptr_, __size_, __obj_);
0183     __size_ = 0;
0184   }
0185 
0186 private:
0187   _CharT* __ptr_;
0188   size_t __capacity_;
0189   size_t __size_{0};
0190   void (*__flush_)(_CharT*, size_t, void*);
0191   void* __obj_;
0192 
0193   /// Flushes the buffer when the output operation would overflow the buffer.
0194   ///
0195   /// A simple approach for the overflow detection would be something along the
0196   /// lines:
0197   /// \code
0198   /// // The internal buffer is large enough.
0199   /// if (__n <= __capacity_) {
0200   ///   // Flush when we really would overflow.
0201   ///   if (__size_ + __n >= __capacity_)
0202   ///     __flush();
0203   ///   ...
0204   /// }
0205   /// \endcode
0206   ///
0207   /// This approach works for all cases but one:
0208   /// A __format_to_n_buffer_base where \ref __enable_direct_output is true.
0209   /// In that case the \ref __capacity_ of the buffer changes during the first
0210   /// \ref __flush. During that operation the output buffer switches from its
0211   /// __writer_ to its __storage_. The \ref __capacity_ of the former depends
0212   /// on the value of n, of the latter is a fixed size. For example:
0213   /// - a format_to_n call with a 10'000 char buffer,
0214   /// - the buffer is filled with 9'500 chars,
0215   /// - adding 1'000 elements would overflow the buffer so the buffer gets
0216   ///   changed and the \ref __capacity_ decreases from 10'000 to
0217   ///   __buffer_size (256 at the time of writing).
0218   ///
0219   /// This means that the \ref __flush for this class may need to copy a part of
0220   /// the internal buffer to the proper output. In this example there will be
0221   /// 500 characters that need this copy operation.
0222   ///
0223   /// Note it would be more efficient to write 500 chars directly and then swap
0224   /// the buffers. This would make the code more complex and \ref format_to_n is
0225   /// not the most common use case. Therefore the optimization isn't done.
0226   _LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) {
0227     if (__size_ + __n >= __capacity_)
0228       __flush();
0229   }
0230 };
0231 
0232 /// A storage using an internal buffer.
0233 ///
0234 /// This storage is used when writing a single element to the output iterator
0235 /// is expensive.
0236 template <__fmt_char_type _CharT>
0237 class _LIBCPP_TEMPLATE_VIS __internal_storage {
0238 public:
0239   _LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; }
0240 
0241   static constexpr size_t __buffer_size = 256 / sizeof(_CharT);
0242 
0243 private:
0244   _CharT __buffer_[__buffer_size];
0245 };
0246 
0247 /// A storage writing directly to the storage.
0248 ///
0249 /// This requires the storage to be a contiguous buffer of \a _CharT.
0250 /// Since the output is directly written to the underlying storage this class
0251 /// is just an empty class.
0252 template <__fmt_char_type _CharT>
0253 class _LIBCPP_TEMPLATE_VIS __direct_storage {};
0254 
0255 template <class _OutIt, class _CharT>
0256 concept __enable_direct_output =
0257     __fmt_char_type<_CharT> &&
0258     (same_as<_OutIt, _CharT*>
0259      // TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
0260      // `#ifdef`.
0261      || same_as<_OutIt, __wrap_iter<_CharT*>>);
0262 
0263 /// Write policy for directly writing to the underlying output.
0264 template <class _OutIt, __fmt_char_type _CharT>
0265 class _LIBCPP_TEMPLATE_VIS __writer_direct {
0266 public:
0267   _LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it) : __out_it_(__out_it) {}
0268 
0269   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; }
0270 
0271   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) {
0272     // _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator
0273     // is adjusted.
0274     __out_it_ += __n;
0275   }
0276 
0277 private:
0278   _OutIt __out_it_;
0279 };
0280 
0281 /// Write policy for copying the buffer to the output.
0282 template <class _OutIt, __fmt_char_type _CharT>
0283 class _LIBCPP_TEMPLATE_VIS __writer_iterator {
0284 public:
0285   _LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it) : __out_it_{std::move(__out_it)} {}
0286 
0287   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); }
0288 
0289   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
0290     __out_it_ = std::ranges::copy_n(__ptr, __n, std::move(__out_it_)).out;
0291   }
0292 
0293 private:
0294   _OutIt __out_it_;
0295 };
0296 
0297 /// Concept to see whether a \a _Container is insertable.
0298 ///
0299 /// The concept is used to validate whether multiple calls to a
0300 /// \ref back_insert_iterator can be replace by a call to \c _Container::insert.
0301 ///
0302 /// \note a \a _Container needs to opt-in to the concept by specializing
0303 /// \ref __enable_insertable.
0304 template <class _Container>
0305 concept __insertable =
0306     __enable_insertable<_Container> && __fmt_char_type<typename _Container::value_type> &&
0307     requires(_Container& __t,
0308              add_pointer_t<typename _Container::value_type> __first,
0309              add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };
0310 
0311 /// Extract the container type of a \ref back_insert_iterator.
0312 template <class _It>
0313 struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container {
0314   using type = void;
0315 };
0316 
0317 template <__insertable _Container>
0318 struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> {
0319   using type = _Container;
0320 };
0321 
0322 /// Write policy for inserting the buffer in a container.
0323 template <class _Container>
0324 class _LIBCPP_TEMPLATE_VIS __writer_container {
0325 public:
0326   using _CharT = typename _Container::value_type;
0327 
0328   _LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it)
0329       : __container_{__out_it.__get_container()} {}
0330 
0331   _LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); }
0332 
0333   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
0334     __container_->insert(__container_->end(), __ptr, __ptr + __n);
0335   }
0336 
0337 private:
0338   _Container* __container_;
0339 };
0340 
0341 /// Selects the type of the writer used for the output iterator.
0342 template <class _OutIt, class _CharT>
0343 class _LIBCPP_TEMPLATE_VIS __writer_selector {
0344   using _Container = typename __back_insert_iterator_container<_OutIt>::type;
0345 
0346 public:
0347   using type =
0348       conditional_t<!same_as<_Container, void>,
0349                     __writer_container<_Container>,
0350                     conditional_t<__enable_direct_output<_OutIt, _CharT>,
0351                                   __writer_direct<_OutIt, _CharT>,
0352                                   __writer_iterator<_OutIt, _CharT>>>;
0353 };
0354 
0355 /// The generic formatting buffer.
0356 template <class _OutIt, __fmt_char_type _CharT>
0357   requires(output_iterator<_OutIt, const _CharT&>)
0358 class _LIBCPP_TEMPLATE_VIS __format_buffer {
0359   using _Storage =
0360       conditional_t<__enable_direct_output<_OutIt, _CharT>, __direct_storage<_CharT>, __internal_storage<_CharT>>;
0361 
0362 public:
0363   _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
0364     requires(same_as<_Storage, __internal_storage<_CharT>>)
0365       : __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(std::move(__out_it)) {}
0366 
0367   _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
0368     requires(same_as<_Storage, __direct_storage<_CharT>>)
0369       : __output_(std::__unwrap_iter(__out_it), size_t(-1), this), __writer_(std::move(__out_it)) {}
0370 
0371   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
0372 
0373   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); }
0374 
0375   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {
0376     __output_.__flush();
0377     return std::move(__writer_).__out_it();
0378   }
0379 
0380 private:
0381   _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_;
0382   __output_buffer<_CharT> __output_;
0383   typename __writer_selector<_OutIt, _CharT>::type __writer_;
0384 };
0385 
0386 /// A buffer that counts the number of insertions.
0387 ///
0388 /// Since \ref formatted_size only needs to know the size, the output itself is
0389 /// discarded.
0390 template <__fmt_char_type _CharT>
0391 class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer {
0392 public:
0393   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
0394 
0395   _LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; }
0396 
0397   _LIBCPP_HIDE_FROM_ABI size_t __result() && {
0398     __output_.__flush();
0399     return __size_;
0400   }
0401 
0402 private:
0403   __internal_storage<_CharT> __storage_;
0404   __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
0405   size_t __size_{0};
0406 };
0407 
0408 /// The base of a buffer that counts and limits the number of insertions.
0409 template <class _OutIt, __fmt_char_type _CharT, bool>
0410   requires(output_iterator<_OutIt, const _CharT&>)
0411 struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base {
0412   using _Size = iter_difference_t<_OutIt>;
0413 
0414 public:
0415   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
0416       : __writer_(std::move(__out_it)), __max_size_(std::max(_Size(0), __max_size)) {}
0417 
0418   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
0419     if (_Size(__size_) <= __max_size_)
0420       __writer_.__flush(__ptr, std::min(_Size(__n), __max_size_ - __size_));
0421     __size_ += __n;
0422   }
0423 
0424 protected:
0425   __internal_storage<_CharT> __storage_;
0426   __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
0427   typename __writer_selector<_OutIt, _CharT>::type __writer_;
0428 
0429   _Size __max_size_;
0430   _Size __size_{0};
0431 };
0432 
0433 /// The base of a buffer that counts and limits the number of insertions.
0434 ///
0435 /// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true.
0436 ///
0437 /// This class limits the size available to the direct writer so it will not
0438 /// exceed the maximum number of code units.
0439 template <class _OutIt, __fmt_char_type _CharT>
0440   requires(output_iterator<_OutIt, const _CharT&>)
0441 class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> {
0442   using _Size = iter_difference_t<_OutIt>;
0443 
0444 public:
0445   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
0446       : __output_(std::__unwrap_iter(__out_it), __max_size, this),
0447         __writer_(std::move(__out_it)),
0448         __max_size_(__max_size) {
0449     if (__max_size <= 0) [[unlikely]]
0450       __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
0451   }
0452 
0453   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
0454     // A __flush to the direct writer happens in the following occasions:
0455     // - The format function has written the maximum number of allowed code
0456     //   units. At this point it's no longer valid to write to this writer. So
0457     //   switch to the internal storage. This internal storage doesn't need to
0458     //   be written anywhere so the __flush for that storage writes no output.
0459     // - Like above, but the next "mass write" operation would overflow the
0460     //   buffer. In that case the buffer is pre-emptively switched. The still
0461     //   valid code units will be written separately.
0462     // - The format_to_n function is finished. In this case there's no need to
0463     //   switch the buffer, but for simplicity the buffers are still switched.
0464     // When the __max_size <= 0 the constructor already switched the buffers.
0465     if (__size_ == 0 && __ptr != __storage_.__begin()) {
0466       __writer_.__flush(__ptr, __n);
0467       __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
0468     } else if (__size_ < __max_size_) {
0469       // Copies a part of the internal buffer to the output up to n characters.
0470       // See __output_buffer<_CharT>::__flush_on_overflow for more information.
0471       _Size __s = std::min(_Size(__n), __max_size_ - __size_);
0472       std::copy_n(__ptr, __s, __writer_.__out_it());
0473       __writer_.__flush(__ptr, __s);
0474     }
0475 
0476     __size_ += __n;
0477   }
0478 
0479 protected:
0480   __internal_storage<_CharT> __storage_;
0481   __output_buffer<_CharT> __output_;
0482   __writer_direct<_OutIt, _CharT> __writer_;
0483 
0484   _Size __max_size_;
0485   _Size __size_{0};
0486 };
0487 
0488 /// The buffer that counts and limits the number of insertions.
0489 template <class _OutIt, __fmt_char_type _CharT>
0490   requires(output_iterator<_OutIt, const _CharT&>)
0491 struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
0492     : public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> {
0493   using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>;
0494   using _Size = iter_difference_t<_OutIt>;
0495 
0496 public:
0497   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size)
0498       : _Base(std::move(__out_it), __max_size) {}
0499   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); }
0500 
0501   _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
0502     this->__output_.__flush();
0503     return {std::move(this->__writer_).__out_it(), this->__size_};
0504   }
0505 };
0506 
0507 // A dynamically growing buffer intended to be used for retargeting a context.
0508 //
0509 // P2286 Formatting ranges adds range formatting support. It allows the user to
0510 // specify the minimum width for the entire formatted range.  The width of the
0511 // range is not known until the range is formatted. Formatting is done to an
0512 // output_iterator so there's no guarantee it would be possible to add the fill
0513 // to the front of the output. Instead the range is formatted to a temporary
0514 // buffer and that buffer is formatted as a string.
0515 //
0516 // There is an issue with that approach, the format context used in
0517 // std::formatter<T>::format contains the output iterator used as part of its
0518 // type. So using this output iterator means there needs to be a new format
0519 // context and the format arguments need to be retargeted to the new context.
0520 // This retargeting is done by a basic_format_context specialized for the
0521 // __iterator of this container.
0522 //
0523 // This class uses its own buffer management, since using vector
0524 // would lead to a circular include with formatter for vector<bool>.
0525 template <__fmt_char_type _CharT>
0526 class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
0527   using _Alloc = allocator<_CharT>;
0528 
0529 public:
0530   using value_type = _CharT;
0531 
0532   struct __iterator {
0533     using difference_type = ptrdiff_t;
0534     using value_type      = _CharT;
0535 
0536     _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
0537         : __buffer_(std::addressof(__buffer)) {}
0538     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {
0539       __buffer_->push_back(__c);
0540       return *this;
0541     }
0542     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {
0543       __buffer_->push_back(__c);
0544       return *this;
0545     }
0546 
0547     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }
0548     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }
0549     _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }
0550     __retarget_buffer* __buffer_;
0551   };
0552 
0553   __retarget_buffer(const __retarget_buffer&)            = delete;
0554   __retarget_buffer& operator=(const __retarget_buffer&) = delete;
0555 
0556   _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {
0557     // When the initial size is very small a lot of resizes happen
0558     // when elements added. So use a hard-coded minimum size.
0559     //
0560     // Note a size < 2 will not work
0561     // - 0 there is no buffer, while push_back requires 1 empty element.
0562     // - 1 multiplied by the grow factor is 1 and thus the buffer never
0563     //   grows.
0564     auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT)));
0565     __ptr_        = __result.ptr;
0566     __capacity_   = __result.count;
0567   }
0568 
0569   _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {
0570     ranges::destroy_n(__ptr_, __size_);
0571     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
0572   }
0573 
0574   _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
0575 
0576   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
0577     std::construct_at(__ptr_ + __size_, __c);
0578     ++__size_;
0579 
0580     if (__size_ == __capacity_)
0581       __grow_buffer();
0582   }
0583 
0584   template <__fmt_char_type _InCharT>
0585   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
0586     size_t __n = __str.size();
0587     if (__size_ + __n >= __capacity_)
0588       // Push_back requires the buffer to have room for at least one character.
0589       __grow_buffer(__size_ + __n + 1);
0590 
0591     std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);
0592     __size_ += __n;
0593   }
0594 
0595   template <contiguous_iterator _Iterator,
0596             class _UnaryOperation,
0597             __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
0598   _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
0599     _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
0600 
0601     size_t __n = static_cast<size_t>(__last - __first);
0602     if (__size_ + __n >= __capacity_)
0603       // Push_back requires the buffer to have room for at least one character.
0604       __grow_buffer(__size_ + __n + 1);
0605 
0606     std::uninitialized_default_construct_n(__ptr_ + __size_, __n);
0607     std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));
0608     __size_ += __n;
0609   }
0610 
0611   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
0612     if (__size_ + __n >= __capacity_)
0613       // Push_back requires the buffer to have room for at least one character.
0614       __grow_buffer(__size_ + __n + 1);
0615 
0616     std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);
0617     __size_ += __n;
0618   }
0619 
0620   _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }
0621 
0622 private:
0623   _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
0624 
0625   _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
0626     _LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow");
0627     auto __result = std::__allocate_at_least(__alloc_, __capacity);
0628     auto __guard  = std::__make_exception_guard([&] {
0629       allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
0630     });
0631     // This shouldn't throw, but just to be safe. Note that at -O1 this
0632     // guard is optimized away so there is no runtime overhead.
0633     std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
0634     __guard.__complete();
0635     ranges::destroy_n(__ptr_, __size_);
0636     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
0637 
0638     __ptr_      = __result.ptr;
0639     __capacity_ = __result.count;
0640   }
0641   _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
0642   _CharT* __ptr_;
0643   size_t __capacity_;
0644   size_t __size_{0};
0645 };
0646 
0647 } // namespace __format
0648 
0649 #endif //_LIBCPP_STD_VER >= 20
0650 
0651 _LIBCPP_END_NAMESPACE_STD
0652 
0653 _LIBCPP_POP_MACROS
0654 
0655 #endif // _LIBCPP___CXX03___FORMAT_BUFFER_H