181ad6265SDimitry Andric // -*- C++ -*-
281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
381ad6265SDimitry Andric //
481ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
581ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
681ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
781ad6265SDimitry Andric //
881ad6265SDimitry Andric //===----------------------------------------------------------------------===//
981ad6265SDimitry Andric 
1081ad6265SDimitry Andric #ifndef _LIBCPP___FORMAT_BUFFER_H
1181ad6265SDimitry Andric #define _LIBCPP___FORMAT_BUFFER_H
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #include <__algorithm/copy_n.h>
14bdd1243dSDimitry Andric #include <__algorithm/fill_n.h>
1581ad6265SDimitry Andric #include <__algorithm/max.h>
1681ad6265SDimitry Andric #include <__algorithm/min.h>
17bdd1243dSDimitry Andric #include <__algorithm/ranges_copy_n.h>
18bdd1243dSDimitry Andric #include <__algorithm/transform.h>
1981ad6265SDimitry Andric #include <__algorithm/unwrap_iter.h>
20bdd1243dSDimitry Andric #include <__concepts/same_as.h>
2181ad6265SDimitry Andric #include <__config>
22bdd1243dSDimitry Andric #include <__format/concepts.h>
2381ad6265SDimitry Andric #include <__format/enable_insertable.h>
2481ad6265SDimitry Andric #include <__format/format_to_n_result.h>
2581ad6265SDimitry Andric #include <__iterator/back_insert_iterator.h>
2681ad6265SDimitry Andric #include <__iterator/concepts.h>
2781ad6265SDimitry Andric #include <__iterator/incrementable_traits.h>
2881ad6265SDimitry Andric #include <__iterator/iterator_traits.h>
2981ad6265SDimitry Andric #include <__iterator/wrap_iter.h>
3006c3fb27SDimitry Andric #include <__memory/addressof.h>
3106c3fb27SDimitry Andric #include <__memory/allocate_at_least.h>
3206c3fb27SDimitry Andric #include <__memory/allocator_traits.h>
3306c3fb27SDimitry Andric #include <__memory/construct_at.h>
3406c3fb27SDimitry Andric #include <__memory/ranges_construct_at.h>
3506c3fb27SDimitry Andric #include <__memory/uninitialized_algorithms.h>
3606c3fb27SDimitry Andric #include <__type_traits/add_pointer.h>
3706c3fb27SDimitry Andric #include <__type_traits/conditional.h>
3806c3fb27SDimitry Andric #include <__utility/exception_guard.h>
3981ad6265SDimitry Andric #include <__utility/move.h>
4081ad6265SDimitry Andric #include <cstddef>
41bdd1243dSDimitry Andric #include <string_view>
4281ad6265SDimitry Andric 
4381ad6265SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
4481ad6265SDimitry Andric #  pragma GCC system_header
4581ad6265SDimitry Andric #endif
4681ad6265SDimitry Andric 
4781ad6265SDimitry Andric _LIBCPP_PUSH_MACROS
4881ad6265SDimitry Andric #include <__undef_macros>
4981ad6265SDimitry Andric 
5081ad6265SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
5181ad6265SDimitry Andric 
5206c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
5381ad6265SDimitry Andric 
5481ad6265SDimitry Andric namespace __format {
5581ad6265SDimitry Andric 
5681ad6265SDimitry Andric /// A "buffer" that handles writing to the proper iterator.
5781ad6265SDimitry Andric ///
5881ad6265SDimitry Andric /// This helper is used together with the @ref back_insert_iterator to offer
5981ad6265SDimitry Andric /// type-erasure for the formatting functions. This reduces the number to
6081ad6265SDimitry Andric /// template instantiations.
61bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
6281ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __output_buffer {
6381ad6265SDimitry Andric public:
6481ad6265SDimitry Andric   using value_type = _CharT;
6581ad6265SDimitry Andric 
6681ad6265SDimitry Andric   template <class _Tp>
__output_buffer(_CharT * __ptr,size_t __capacity,_Tp * __obj)67bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj)
68bdd1243dSDimitry Andric       : __ptr_(__ptr),
69bdd1243dSDimitry Andric         __capacity_(__capacity),
70bdd1243dSDimitry Andric         __flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }),
7181ad6265SDimitry Andric         __obj_(__obj) {}
7281ad6265SDimitry Andric 
__reset(_CharT * __ptr,size_t __capacity)73bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) {
7481ad6265SDimitry Andric     __ptr_      = __ptr;
7581ad6265SDimitry Andric     __capacity_ = __capacity;
7681ad6265SDimitry Andric   }
7781ad6265SDimitry Andric 
__make_output_iterator()78bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; }
7981ad6265SDimitry Andric 
80bdd1243dSDimitry Andric   // Used in std::back_insert_iterator.
push_back(_CharT __c)8181ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
8281ad6265SDimitry Andric     __ptr_[__size_++] = __c;
8381ad6265SDimitry Andric 
8481ad6265SDimitry Andric     // Profiling showed flushing after adding is more efficient than flushing
8581ad6265SDimitry Andric     // when entering the function.
8681ad6265SDimitry Andric     if (__size_ == __capacity_)
87bdd1243dSDimitry Andric       __flush();
8881ad6265SDimitry Andric   }
8981ad6265SDimitry Andric 
90bdd1243dSDimitry Andric   /// Copies the input __str to the buffer.
91bdd1243dSDimitry Andric   ///
92bdd1243dSDimitry Andric   /// Since some of the input is generated by std::to_chars, there needs to be a
93bdd1243dSDimitry Andric   /// conversion when _CharT is wchar_t.
94bdd1243dSDimitry Andric   template <__fmt_char_type _InCharT>
__copy(basic_string_view<_InCharT> __str)95bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
96bdd1243dSDimitry Andric     // When the underlying iterator is a simple iterator the __capacity_ is
97bdd1243dSDimitry Andric     // infinite. For a string or container back_inserter it isn't. This means
985f757f3fSDimitry Andric     // that adding a large string to the buffer can cause some overhead. In that
99bdd1243dSDimitry Andric     // case a better approach could be:
100bdd1243dSDimitry Andric     // - flush the buffer
101bdd1243dSDimitry Andric     // - container.append(__str.begin(), __str.end());
102bdd1243dSDimitry Andric     // The same holds true for the fill.
103bdd1243dSDimitry Andric     // For transform it might be slightly harder, however the use case for
104bdd1243dSDimitry Andric     // transform is slightly less common; it converts hexadecimal values to
105bdd1243dSDimitry Andric     // upper case. For integral these strings are short.
106bdd1243dSDimitry Andric     // TODO FMT Look at the improvements above.
107bdd1243dSDimitry Andric     size_t __n = __str.size();
108bdd1243dSDimitry Andric 
109bdd1243dSDimitry Andric     __flush_on_overflow(__n);
11006c3fb27SDimitry Andric     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
1115f757f3fSDimitry Andric       std::copy_n(__str.data(), __n, std::addressof(__ptr_[__size_]));
112bdd1243dSDimitry Andric       __size_ += __n;
113bdd1243dSDimitry Andric       return;
114bdd1243dSDimitry Andric     }
115bdd1243dSDimitry Andric 
116bdd1243dSDimitry Andric     // The output doesn't fit in the internal buffer.
117bdd1243dSDimitry Andric     // Copy the data in "__capacity_" sized chunks.
118*1db9f3b2SDimitry Andric     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
119bdd1243dSDimitry Andric     const _InCharT* __first = __str.data();
120bdd1243dSDimitry Andric     do {
1215f757f3fSDimitry Andric       size_t __chunk = std::min(__n, __capacity_);
1225f757f3fSDimitry Andric       std::copy_n(__first, __chunk, std::addressof(__ptr_[__size_]));
123bdd1243dSDimitry Andric       __size_ = __chunk;
124bdd1243dSDimitry Andric       __first += __chunk;
125bdd1243dSDimitry Andric       __n -= __chunk;
126bdd1243dSDimitry Andric       __flush();
127bdd1243dSDimitry Andric     } while (__n);
128bdd1243dSDimitry Andric   }
129bdd1243dSDimitry Andric 
130bdd1243dSDimitry Andric   /// A std::transform wrapper.
131bdd1243dSDimitry Andric   ///
132bdd1243dSDimitry Andric   /// Like @ref __copy it may need to do type conversion.
133cb14a3feSDimitry Andric   template <contiguous_iterator _Iterator,
134cb14a3feSDimitry Andric             class _UnaryOperation,
135cb14a3feSDimitry Andric             __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
__transform(_Iterator __first,_Iterator __last,_UnaryOperation __operation)136cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
137*1db9f3b2SDimitry Andric     _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
138bdd1243dSDimitry Andric 
139bdd1243dSDimitry Andric     size_t __n = static_cast<size_t>(__last - __first);
140bdd1243dSDimitry Andric     __flush_on_overflow(__n);
14106c3fb27SDimitry Andric     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
1425f757f3fSDimitry Andric       std::transform(__first, __last, std::addressof(__ptr_[__size_]), std::move(__operation));
143bdd1243dSDimitry Andric       __size_ += __n;
144bdd1243dSDimitry Andric       return;
145bdd1243dSDimitry Andric     }
146bdd1243dSDimitry Andric 
147bdd1243dSDimitry Andric     // The output doesn't fit in the internal buffer.
148bdd1243dSDimitry Andric     // Transform the data in "__capacity_" sized chunks.
149*1db9f3b2SDimitry Andric     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
150bdd1243dSDimitry Andric     do {
1515f757f3fSDimitry Andric       size_t __chunk = std::min(__n, __capacity_);
1525f757f3fSDimitry Andric       std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
153bdd1243dSDimitry Andric       __size_ = __chunk;
154bdd1243dSDimitry Andric       __first += __chunk;
155bdd1243dSDimitry Andric       __n -= __chunk;
156bdd1243dSDimitry Andric       __flush();
157bdd1243dSDimitry Andric     } while (__n);
158bdd1243dSDimitry Andric   }
159bdd1243dSDimitry Andric 
160bdd1243dSDimitry Andric   /// A \c fill_n wrapper.
__fill(size_t __n,_CharT __value)161bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
162bdd1243dSDimitry Andric     __flush_on_overflow(__n);
16306c3fb27SDimitry Andric     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
1645f757f3fSDimitry Andric       std::fill_n(std::addressof(__ptr_[__size_]), __n, __value);
165bdd1243dSDimitry Andric       __size_ += __n;
166bdd1243dSDimitry Andric       return;
167bdd1243dSDimitry Andric     }
168bdd1243dSDimitry Andric 
169bdd1243dSDimitry Andric     // The output doesn't fit in the internal buffer.
170bdd1243dSDimitry Andric     // Fill the buffer in "__capacity_" sized chunks.
171*1db9f3b2SDimitry Andric     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
172bdd1243dSDimitry Andric     do {
1735f757f3fSDimitry Andric       size_t __chunk = std::min(__n, __capacity_);
1745f757f3fSDimitry Andric       std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
175bdd1243dSDimitry Andric       __size_ = __chunk;
176bdd1243dSDimitry Andric       __n -= __chunk;
177bdd1243dSDimitry Andric       __flush();
178bdd1243dSDimitry Andric     } while (__n);
179bdd1243dSDimitry Andric   }
180bdd1243dSDimitry Andric 
__flush()181bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush() {
18281ad6265SDimitry Andric     __flush_(__ptr_, __size_, __obj_);
18381ad6265SDimitry Andric     __size_ = 0;
18481ad6265SDimitry Andric   }
18581ad6265SDimitry Andric 
18681ad6265SDimitry Andric private:
18781ad6265SDimitry Andric   _CharT* __ptr_;
18881ad6265SDimitry Andric   size_t __capacity_;
18981ad6265SDimitry Andric   size_t __size_{0};
19081ad6265SDimitry Andric   void (*__flush_)(_CharT*, size_t, void*);
19181ad6265SDimitry Andric   void* __obj_;
192bdd1243dSDimitry Andric 
193bdd1243dSDimitry Andric   /// Flushes the buffer when the output operation would overflow the buffer.
194bdd1243dSDimitry Andric   ///
195bdd1243dSDimitry Andric   /// A simple approach for the overflow detection would be something along the
196bdd1243dSDimitry Andric   /// lines:
197bdd1243dSDimitry Andric   /// \code
198bdd1243dSDimitry Andric   /// // The internal buffer is large enough.
199bdd1243dSDimitry Andric   /// if (__n <= __capacity_) {
200bdd1243dSDimitry Andric   ///   // Flush when we really would overflow.
201bdd1243dSDimitry Andric   ///   if (__size_ + __n >= __capacity_)
202bdd1243dSDimitry Andric   ///     __flush();
203bdd1243dSDimitry Andric   ///   ...
204bdd1243dSDimitry Andric   /// }
205bdd1243dSDimitry Andric   /// \endcode
206bdd1243dSDimitry Andric   ///
207bdd1243dSDimitry Andric   /// This approach works for all cases but one:
208bdd1243dSDimitry Andric   /// A __format_to_n_buffer_base where \ref __enable_direct_output is true.
209bdd1243dSDimitry Andric   /// In that case the \ref __capacity_ of the buffer changes during the first
210bdd1243dSDimitry Andric   /// \ref __flush. During that operation the output buffer switches from its
211bdd1243dSDimitry Andric   /// __writer_ to its __storage_. The \ref __capacity_ of the former depends
212bdd1243dSDimitry Andric   /// on the value of n, of the latter is a fixed size. For example:
213bdd1243dSDimitry Andric   /// - a format_to_n call with a 10'000 char buffer,
214bdd1243dSDimitry Andric   /// - the buffer is filled with 9'500 chars,
215bdd1243dSDimitry Andric   /// - adding 1'000 elements would overflow the buffer so the buffer gets
216bdd1243dSDimitry Andric   ///   changed and the \ref __capacity_ decreases from 10'000 to
217bdd1243dSDimitry Andric   ///   __buffer_size (256 at the time of writing).
218bdd1243dSDimitry Andric   ///
219bdd1243dSDimitry Andric   /// This means that the \ref __flush for this class may need to copy a part of
220bdd1243dSDimitry Andric   /// the internal buffer to the proper output. In this example there will be
221bdd1243dSDimitry Andric   /// 500 characters that need this copy operation.
222bdd1243dSDimitry Andric   ///
223bdd1243dSDimitry Andric   /// Note it would be more efficient to write 500 chars directly and then swap
224bdd1243dSDimitry Andric   /// the buffers. This would make the code more complex and \ref format_to_n is
225bdd1243dSDimitry Andric   /// not the most common use case. Therefore the optimization isn't done.
__flush_on_overflow(size_t __n)226bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) {
227bdd1243dSDimitry Andric     if (__size_ + __n >= __capacity_)
228bdd1243dSDimitry Andric       __flush();
229bdd1243dSDimitry Andric   }
23081ad6265SDimitry Andric };
23181ad6265SDimitry Andric 
23281ad6265SDimitry Andric /// A storage using an internal buffer.
23381ad6265SDimitry Andric ///
23481ad6265SDimitry Andric /// This storage is used when writing a single element to the output iterator
23581ad6265SDimitry Andric /// is expensive.
236bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
23781ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __internal_storage {
23881ad6265SDimitry Andric public:
__begin()239bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; }
24081ad6265SDimitry Andric 
24181ad6265SDimitry Andric   static constexpr size_t __buffer_size = 256 / sizeof(_CharT);
24281ad6265SDimitry Andric 
24381ad6265SDimitry Andric private:
24481ad6265SDimitry Andric   _CharT __buffer_[__buffer_size];
24581ad6265SDimitry Andric };
24681ad6265SDimitry Andric 
24781ad6265SDimitry Andric /// A storage writing directly to the storage.
24881ad6265SDimitry Andric ///
24981ad6265SDimitry Andric /// This requires the storage to be a contiguous buffer of \a _CharT.
25081ad6265SDimitry Andric /// Since the output is directly written to the underlying storage this class
25181ad6265SDimitry Andric /// is just an empty class.
252bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
25381ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __direct_storage {};
25481ad6265SDimitry Andric 
25581ad6265SDimitry Andric template <class _OutIt, class _CharT>
256cb14a3feSDimitry Andric concept __enable_direct_output =
257cb14a3feSDimitry Andric     __fmt_char_type<_CharT> &&
25881ad6265SDimitry Andric     (same_as<_OutIt, _CharT*>
25906c3fb27SDimitry Andric      // TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
26006c3fb27SDimitry Andric      // `#ifdef`.
261cb14a3feSDimitry Andric      || same_as<_OutIt, __wrap_iter<_CharT*>>);
26281ad6265SDimitry Andric 
26381ad6265SDimitry Andric /// Write policy for directly writing to the underlying output.
264bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT>
26581ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_direct {
26681ad6265SDimitry Andric public:
__writer_direct(_OutIt __out_it)267cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it) : __out_it_(__out_it) {}
26881ad6265SDimitry Andric 
__out_it()269bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; }
27081ad6265SDimitry Andric 
__flush(_CharT *,size_t __n)271bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) {
27281ad6265SDimitry Andric     // _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator
27381ad6265SDimitry Andric     // is adjusted.
274bdd1243dSDimitry Andric     __out_it_ += __n;
27581ad6265SDimitry Andric   }
27681ad6265SDimitry Andric 
27781ad6265SDimitry Andric private:
27881ad6265SDimitry Andric   _OutIt __out_it_;
27981ad6265SDimitry Andric };
28081ad6265SDimitry Andric 
28181ad6265SDimitry Andric /// Write policy for copying the buffer to the output.
282bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT>
28381ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_iterator {
28481ad6265SDimitry Andric public:
__writer_iterator(_OutIt __out_it)285cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it) : __out_it_{std::move(__out_it)} {}
28681ad6265SDimitry Andric 
__out_it()287bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); }
28881ad6265SDimitry Andric 
__flush(_CharT * __ptr,size_t __n)289bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
290bdd1243dSDimitry Andric     __out_it_ = std::ranges::copy_n(__ptr, __n, std::move(__out_it_)).out;
29181ad6265SDimitry Andric   }
29281ad6265SDimitry Andric 
29381ad6265SDimitry Andric private:
29481ad6265SDimitry Andric   _OutIt __out_it_;
29581ad6265SDimitry Andric };
29681ad6265SDimitry Andric 
29781ad6265SDimitry Andric /// Concept to see whether a \a _Container is insertable.
29881ad6265SDimitry Andric ///
29981ad6265SDimitry Andric /// The concept is used to validate whether multiple calls to a
30081ad6265SDimitry Andric /// \ref back_insert_iterator can be replace by a call to \c _Container::insert.
30181ad6265SDimitry Andric ///
30281ad6265SDimitry Andric /// \note a \a _Container needs to opt-in to the concept by specializing
30381ad6265SDimitry Andric /// \ref __enable_insertable.
30481ad6265SDimitry Andric template <class _Container>
30581ad6265SDimitry Andric concept __insertable =
306bdd1243dSDimitry Andric     __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)307cb14a3feSDimitry Andric     requires(_Container& __t,
308cb14a3feSDimitry Andric              add_pointer_t<typename _Container::value_type> __first,
30981ad6265SDimitry Andric              add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };
31081ad6265SDimitry Andric 
31181ad6265SDimitry Andric /// Extract the container type of a \ref back_insert_iterator.
31281ad6265SDimitry Andric template <class _It>
31381ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container {
31481ad6265SDimitry Andric   using type = void;
31581ad6265SDimitry Andric };
31681ad6265SDimitry Andric 
31781ad6265SDimitry Andric template <__insertable _Container>
31881ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> {
31981ad6265SDimitry Andric   using type = _Container;
32081ad6265SDimitry Andric };
32181ad6265SDimitry Andric 
32281ad6265SDimitry Andric /// Write policy for inserting the buffer in a container.
32381ad6265SDimitry Andric template <class _Container>
32481ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_container {
32581ad6265SDimitry Andric public:
32681ad6265SDimitry Andric   using _CharT = typename _Container::value_type;
32781ad6265SDimitry Andric 
32881ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it)
32981ad6265SDimitry Andric       : __container_{__out_it.__get_container()} {}
33081ad6265SDimitry Andric 
331bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); }
33281ad6265SDimitry Andric 
333bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
334bdd1243dSDimitry Andric     __container_->insert(__container_->end(), __ptr, __ptr + __n);
33581ad6265SDimitry Andric   }
33681ad6265SDimitry Andric 
33781ad6265SDimitry Andric private:
33881ad6265SDimitry Andric   _Container* __container_;
33981ad6265SDimitry Andric };
34081ad6265SDimitry Andric 
34181ad6265SDimitry Andric /// Selects the type of the writer used for the output iterator.
34281ad6265SDimitry Andric template <class _OutIt, class _CharT>
34381ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_selector {
34481ad6265SDimitry Andric   using _Container = typename __back_insert_iterator_container<_OutIt>::type;
34581ad6265SDimitry Andric 
34681ad6265SDimitry Andric public:
347cb14a3feSDimitry Andric   using type =
348cb14a3feSDimitry Andric       conditional_t<!same_as<_Container, void>,
349cb14a3feSDimitry Andric                     __writer_container<_Container>,
350cb14a3feSDimitry Andric                     conditional_t<__enable_direct_output<_OutIt, _CharT>,
351cb14a3feSDimitry Andric                                   __writer_direct<_OutIt, _CharT>,
35281ad6265SDimitry Andric                                   __writer_iterator<_OutIt, _CharT>>>;
35381ad6265SDimitry Andric };
35481ad6265SDimitry Andric 
35581ad6265SDimitry Andric /// The generic formatting buffer.
356bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT>
357cb14a3feSDimitry Andric   requires(output_iterator<_OutIt, const _CharT&>)
358cb14a3feSDimitry Andric class _LIBCPP_TEMPLATE_VIS __format_buffer {
35981ad6265SDimitry Andric   using _Storage =
360cb14a3feSDimitry Andric       conditional_t<__enable_direct_output<_OutIt, _CharT>, __direct_storage<_CharT>, __internal_storage<_CharT>>;
36181ad6265SDimitry Andric 
36281ad6265SDimitry Andric public:
36381ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
36481ad6265SDimitry Andric     requires(same_as<_Storage, __internal_storage<_CharT>>)
3655f757f3fSDimitry Andric       : __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(std::move(__out_it)) {}
36681ad6265SDimitry Andric 
367cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
368cb14a3feSDimitry Andric     requires(same_as<_Storage, __direct_storage<_CharT>>)
369cb14a3feSDimitry Andric       : __output_(std::__unwrap_iter(__out_it), size_t(-1), this), __writer_(std::move(__out_it)) {}
37081ad6265SDimitry Andric 
371bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
37281ad6265SDimitry Andric 
373bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); }
37481ad6265SDimitry Andric 
375bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {
376bdd1243dSDimitry Andric     __output_.__flush();
3775f757f3fSDimitry Andric     return std::move(__writer_).__out_it();
37881ad6265SDimitry Andric   }
37981ad6265SDimitry Andric 
38081ad6265SDimitry Andric private:
38181ad6265SDimitry Andric   _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_;
38281ad6265SDimitry Andric   __output_buffer<_CharT> __output_;
38381ad6265SDimitry Andric   typename __writer_selector<_OutIt, _CharT>::type __writer_;
38481ad6265SDimitry Andric };
38581ad6265SDimitry Andric 
38681ad6265SDimitry Andric /// A buffer that counts the number of insertions.
38781ad6265SDimitry Andric ///
38881ad6265SDimitry Andric /// Since \ref formatted_size only needs to know the size, the output itself is
38981ad6265SDimitry Andric /// discarded.
390bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
39181ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer {
39281ad6265SDimitry Andric public:
393bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
39481ad6265SDimitry Andric 
395bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; }
39681ad6265SDimitry Andric 
397bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI size_t __result() && {
398bdd1243dSDimitry Andric     __output_.__flush();
39981ad6265SDimitry Andric     return __size_;
40081ad6265SDimitry Andric   }
40181ad6265SDimitry Andric 
40281ad6265SDimitry Andric private:
40381ad6265SDimitry Andric   __internal_storage<_CharT> __storage_;
404bdd1243dSDimitry Andric   __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
40581ad6265SDimitry Andric   size_t __size_{0};
40681ad6265SDimitry Andric };
40781ad6265SDimitry Andric 
40881ad6265SDimitry Andric /// The base of a buffer that counts and limits the number of insertions.
409bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT, bool>
41081ad6265SDimitry Andric   requires(output_iterator<_OutIt, const _CharT&>)
41181ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base {
41281ad6265SDimitry Andric   using _Size = iter_difference_t<_OutIt>;
41381ad6265SDimitry Andric 
41481ad6265SDimitry Andric public:
415bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
4165f757f3fSDimitry Andric       : __writer_(std::move(__out_it)), __max_size_(std::max(_Size(0), __max_size)) {}
41781ad6265SDimitry Andric 
418bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
419bdd1243dSDimitry Andric     if (_Size(__size_) <= __max_size_)
4205f757f3fSDimitry Andric       __writer_.__flush(__ptr, std::min(_Size(__n), __max_size_ - __size_));
421bdd1243dSDimitry Andric     __size_ += __n;
42281ad6265SDimitry Andric   }
42381ad6265SDimitry Andric 
42481ad6265SDimitry Andric protected:
42581ad6265SDimitry Andric   __internal_storage<_CharT> __storage_;
426bdd1243dSDimitry Andric   __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
42781ad6265SDimitry Andric   typename __writer_selector<_OutIt, _CharT>::type __writer_;
42881ad6265SDimitry Andric 
429bdd1243dSDimitry Andric   _Size __max_size_;
43081ad6265SDimitry Andric   _Size __size_{0};
43181ad6265SDimitry Andric };
43281ad6265SDimitry Andric 
43381ad6265SDimitry Andric /// The base of a buffer that counts and limits the number of insertions.
43481ad6265SDimitry Andric ///
43581ad6265SDimitry Andric /// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true.
43681ad6265SDimitry Andric ///
437bdd1243dSDimitry Andric /// This class limits the size available to the direct writer so it will not
43881ad6265SDimitry Andric /// exceed the maximum number of code units.
439bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT>
44081ad6265SDimitry Andric   requires(output_iterator<_OutIt, const _CharT&>)
44181ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> {
44281ad6265SDimitry Andric   using _Size = iter_difference_t<_OutIt>;
44381ad6265SDimitry Andric 
44481ad6265SDimitry Andric public:
445bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
4465f757f3fSDimitry Andric       : __output_(std::__unwrap_iter(__out_it), __max_size, this),
4475f757f3fSDimitry Andric         __writer_(std::move(__out_it)),
448bdd1243dSDimitry Andric         __max_size_(__max_size) {
449bdd1243dSDimitry Andric     if (__max_size <= 0) [[unlikely]]
450bdd1243dSDimitry Andric       __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
45181ad6265SDimitry Andric   }
45281ad6265SDimitry Andric 
453bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
454bdd1243dSDimitry Andric     // A __flush to the direct writer happens in the following occasions:
45581ad6265SDimitry Andric     // - The format function has written the maximum number of allowed code
45681ad6265SDimitry Andric     //   units. At this point it's no longer valid to write to this writer. So
45781ad6265SDimitry Andric     //   switch to the internal storage. This internal storage doesn't need to
458bdd1243dSDimitry Andric     //   be written anywhere so the __flush for that storage writes no output.
459bdd1243dSDimitry Andric     // - Like above, but the next "mass write" operation would overflow the
460bdd1243dSDimitry Andric     //   buffer. In that case the buffer is pre-emptively switched. The still
461bdd1243dSDimitry Andric     //   valid code units will be written separately.
46281ad6265SDimitry Andric     // - The format_to_n function is finished. In this case there's no need to
46381ad6265SDimitry Andric     //   switch the buffer, but for simplicity the buffers are still switched.
464bdd1243dSDimitry Andric     // When the __max_size <= 0 the constructor already switched the buffers.
465bdd1243dSDimitry Andric     if (__size_ == 0 && __ptr != __storage_.__begin()) {
466bdd1243dSDimitry Andric       __writer_.__flush(__ptr, __n);
467bdd1243dSDimitry Andric       __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
468bdd1243dSDimitry Andric     } else if (__size_ < __max_size_) {
469bdd1243dSDimitry Andric       // Copies a part of the internal buffer to the output up to n characters.
470bdd1243dSDimitry Andric       // See __output_buffer<_CharT>::__flush_on_overflow for more information.
4715f757f3fSDimitry Andric       _Size __s = std::min(_Size(__n), __max_size_ - __size_);
472bdd1243dSDimitry Andric       std::copy_n(__ptr, __s, __writer_.__out_it());
473bdd1243dSDimitry Andric       __writer_.__flush(__ptr, __s);
47481ad6265SDimitry Andric     }
47581ad6265SDimitry Andric 
476bdd1243dSDimitry Andric     __size_ += __n;
47781ad6265SDimitry Andric   }
47881ad6265SDimitry Andric 
47981ad6265SDimitry Andric protected:
48081ad6265SDimitry Andric   __internal_storage<_CharT> __storage_;
48181ad6265SDimitry Andric   __output_buffer<_CharT> __output_;
48281ad6265SDimitry Andric   __writer_direct<_OutIt, _CharT> __writer_;
48381ad6265SDimitry Andric 
484bdd1243dSDimitry Andric   _Size __max_size_;
48581ad6265SDimitry Andric   _Size __size_{0};
48681ad6265SDimitry Andric };
48781ad6265SDimitry Andric 
48881ad6265SDimitry Andric /// The buffer that counts and limits the number of insertions.
489bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT>
49081ad6265SDimitry Andric   requires(output_iterator<_OutIt, const _CharT&>)
49181ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
49281ad6265SDimitry Andric     : public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> {
49381ad6265SDimitry Andric   using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>;
49481ad6265SDimitry Andric   using _Size = iter_difference_t<_OutIt>;
49581ad6265SDimitry Andric 
49681ad6265SDimitry Andric public:
497bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size)
4985f757f3fSDimitry Andric       : _Base(std::move(__out_it), __max_size) {}
499bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); }
50081ad6265SDimitry Andric 
501bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
502bdd1243dSDimitry Andric     this->__output_.__flush();
5035f757f3fSDimitry Andric     return {std::move(this->__writer_).__out_it(), this->__size_};
50481ad6265SDimitry Andric   }
50581ad6265SDimitry Andric };
506bdd1243dSDimitry Andric 
507bdd1243dSDimitry Andric // A dynamically growing buffer intended to be used for retargeting a context.
508bdd1243dSDimitry Andric //
509bdd1243dSDimitry Andric // P2286 Formatting ranges adds range formatting support. It allows the user to
510bdd1243dSDimitry Andric // specify the minimum width for the entire formatted range.  The width of the
511bdd1243dSDimitry Andric // range is not known until the range is formatted. Formatting is done to an
512bdd1243dSDimitry Andric // output_iterator so there's no guarantee it would be possible to add the fill
513bdd1243dSDimitry Andric // to the front of the output. Instead the range is formatted to a temporary
514bdd1243dSDimitry Andric // buffer and that buffer is formatted as a string.
515bdd1243dSDimitry Andric //
516bdd1243dSDimitry Andric // There is an issue with that approach, the format context used in
517bdd1243dSDimitry Andric // std::formatter<T>::format contains the output iterator used as part of its
518bdd1243dSDimitry Andric // type. So using this output iterator means there needs to be a new format
519bdd1243dSDimitry Andric // context and the format arguments need to be retargeted to the new context.
520bdd1243dSDimitry Andric // This retargeting is done by a basic_format_context specialized for the
521bdd1243dSDimitry Andric // __iterator of this container.
52206c3fb27SDimitry Andric //
52306c3fb27SDimitry Andric // This class uses its own buffer management, since using vector
52406c3fb27SDimitry Andric // would lead to a circular include with formatter for vector<bool>.
525bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
526bdd1243dSDimitry Andric class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
52706c3fb27SDimitry Andric   using _Alloc = allocator<_CharT>;
52806c3fb27SDimitry Andric 
529bdd1243dSDimitry Andric public:
530bdd1243dSDimitry Andric   using value_type = _CharT;
531bdd1243dSDimitry Andric 
532bdd1243dSDimitry Andric   struct __iterator {
533bdd1243dSDimitry Andric     using difference_type = ptrdiff_t;
53406c3fb27SDimitry Andric     using value_type      = _CharT;
535bdd1243dSDimitry Andric 
536bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
537bdd1243dSDimitry Andric         : __buffer_(std::addressof(__buffer)) {}
538bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {
539bdd1243dSDimitry Andric       __buffer_->push_back(__c);
540bdd1243dSDimitry Andric       return *this;
541bdd1243dSDimitry Andric     }
542bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {
543bdd1243dSDimitry Andric       __buffer_->push_back(__c);
544bdd1243dSDimitry Andric       return *this;
545bdd1243dSDimitry Andric     }
546bdd1243dSDimitry Andric 
547bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }
548bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }
549bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }
550bdd1243dSDimitry Andric     __retarget_buffer* __buffer_;
551bdd1243dSDimitry Andric   };
552bdd1243dSDimitry Andric 
55306c3fb27SDimitry Andric   __retarget_buffer(const __retarget_buffer&)            = delete;
55406c3fb27SDimitry Andric   __retarget_buffer& operator=(const __retarget_buffer&) = delete;
55506c3fb27SDimitry Andric 
55606c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {
55706c3fb27SDimitry Andric     // When the initial size is very small a lot of resizes happen
55806c3fb27SDimitry Andric     // when elements added. So use a hard-coded minimum size.
55906c3fb27SDimitry Andric     //
56006c3fb27SDimitry Andric     // Note a size < 2 will not work
56106c3fb27SDimitry Andric     // - 0 there is no buffer, while push_back requires 1 empty element.
56206c3fb27SDimitry Andric     // - 1 multiplied by the grow factor is 1 and thus the buffer never
56306c3fb27SDimitry Andric     //   grows.
56406c3fb27SDimitry Andric     auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT)));
56506c3fb27SDimitry Andric     __ptr_        = __result.ptr;
56606c3fb27SDimitry Andric     __capacity_   = __result.count;
56706c3fb27SDimitry Andric   }
56806c3fb27SDimitry Andric 
56906c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {
57006c3fb27SDimitry Andric     ranges::destroy_n(__ptr_, __size_);
57106c3fb27SDimitry Andric     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
57206c3fb27SDimitry Andric   }
573bdd1243dSDimitry Andric 
574bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
575bdd1243dSDimitry Andric 
57606c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
57706c3fb27SDimitry Andric     std::construct_at(__ptr_ + __size_, __c);
57806c3fb27SDimitry Andric     ++__size_;
57906c3fb27SDimitry Andric 
58006c3fb27SDimitry Andric     if (__size_ == __capacity_)
58106c3fb27SDimitry Andric       __grow_buffer();
58206c3fb27SDimitry Andric   }
583bdd1243dSDimitry Andric 
584bdd1243dSDimitry Andric   template <__fmt_char_type _InCharT>
585bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
58606c3fb27SDimitry Andric     size_t __n = __str.size();
58706c3fb27SDimitry Andric     if (__size_ + __n >= __capacity_)
58806c3fb27SDimitry Andric       // Push_back requires the buffer to have room for at least one character.
58906c3fb27SDimitry Andric       __grow_buffer(__size_ + __n + 1);
59006c3fb27SDimitry Andric 
59106c3fb27SDimitry Andric     std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);
59206c3fb27SDimitry Andric     __size_ += __n;
593bdd1243dSDimitry Andric   }
594bdd1243dSDimitry Andric 
595cb14a3feSDimitry Andric   template <contiguous_iterator _Iterator,
596cb14a3feSDimitry Andric             class _UnaryOperation,
597cb14a3feSDimitry Andric             __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
598cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
599*1db9f3b2SDimitry Andric     _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
60006c3fb27SDimitry Andric 
60106c3fb27SDimitry Andric     size_t __n = static_cast<size_t>(__last - __first);
60206c3fb27SDimitry Andric     if (__size_ + __n >= __capacity_)
60306c3fb27SDimitry Andric       // Push_back requires the buffer to have room for at least one character.
60406c3fb27SDimitry Andric       __grow_buffer(__size_ + __n + 1);
60506c3fb27SDimitry Andric 
60606c3fb27SDimitry Andric     std::uninitialized_default_construct_n(__ptr_ + __size_, __n);
60706c3fb27SDimitry Andric     std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));
60806c3fb27SDimitry Andric     __size_ += __n;
609bdd1243dSDimitry Andric   }
610bdd1243dSDimitry Andric 
61106c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
61206c3fb27SDimitry Andric     if (__size_ + __n >= __capacity_)
61306c3fb27SDimitry Andric       // Push_back requires the buffer to have room for at least one character.
61406c3fb27SDimitry Andric       __grow_buffer(__size_ + __n + 1);
615bdd1243dSDimitry Andric 
61606c3fb27SDimitry Andric     std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);
61706c3fb27SDimitry Andric     __size_ += __n;
61806c3fb27SDimitry Andric   }
61906c3fb27SDimitry Andric 
62006c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }
621bdd1243dSDimitry Andric 
622bdd1243dSDimitry Andric private:
62306c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
62406c3fb27SDimitry Andric 
62506c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
626*1db9f3b2SDimitry Andric     _LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow");
62706c3fb27SDimitry Andric     auto __result = std::__allocate_at_least(__alloc_, __capacity);
62806c3fb27SDimitry Andric     auto __guard  = std::__make_exception_guard([&] {
62906c3fb27SDimitry Andric       allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
63006c3fb27SDimitry Andric     });
63106c3fb27SDimitry Andric     // This shouldn't throw, but just to be safe. Note that at -O1 this
63206c3fb27SDimitry Andric     // guard is optimized away so there is no runtime overhead.
63306c3fb27SDimitry Andric     std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
63406c3fb27SDimitry Andric     __guard.__complete();
63506c3fb27SDimitry Andric     ranges::destroy_n(__ptr_, __size_);
63606c3fb27SDimitry Andric     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
63706c3fb27SDimitry Andric 
63806c3fb27SDimitry Andric     __ptr_      = __result.ptr;
63906c3fb27SDimitry Andric     __capacity_ = __result.count;
64006c3fb27SDimitry Andric   }
64106c3fb27SDimitry Andric   _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
64206c3fb27SDimitry Andric   _CharT* __ptr_;
64306c3fb27SDimitry Andric   size_t __capacity_;
64406c3fb27SDimitry Andric   size_t __size_{0};
645bdd1243dSDimitry Andric };
646bdd1243dSDimitry Andric 
64781ad6265SDimitry Andric } // namespace __format
64881ad6265SDimitry Andric 
64906c3fb27SDimitry Andric #endif //_LIBCPP_STD_VER >= 20
65081ad6265SDimitry Andric 
65181ad6265SDimitry Andric _LIBCPP_END_NAMESPACE_STD
65281ad6265SDimitry Andric 
65381ad6265SDimitry Andric _LIBCPP_POP_MACROS
65481ad6265SDimitry Andric 
65581ad6265SDimitry Andric #endif // _LIBCPP___FORMAT_BUFFER_H
656