xref: /freebsd-src/contrib/llvm-project/libcxx/include/__format/buffer.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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>
30*06c3fb27SDimitry Andric #include <__memory/addressof.h>
31*06c3fb27SDimitry Andric #include <__memory/allocate_at_least.h>
32*06c3fb27SDimitry Andric #include <__memory/allocator_traits.h>
33*06c3fb27SDimitry Andric #include <__memory/construct_at.h>
34*06c3fb27SDimitry Andric #include <__memory/ranges_construct_at.h>
35*06c3fb27SDimitry Andric #include <__memory/uninitialized_algorithms.h>
36*06c3fb27SDimitry Andric #include <__type_traits/add_pointer.h>
37*06c3fb27SDimitry Andric #include <__type_traits/conditional.h>
38*06c3fb27SDimitry 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 
52*06c3fb27SDimitry 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>
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 
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 
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.
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>
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
98bdd1243dSDimitry Andric     // adding a large string the 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);
110*06c3fb27SDimitry Andric     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
111bdd1243dSDimitry Andric       _VSTD::copy_n(__str.data(), __n, _VSTD::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*06c3fb27SDimitry Andric     _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
119bdd1243dSDimitry Andric     const _InCharT* __first = __str.data();
120bdd1243dSDimitry Andric     do {
121bdd1243dSDimitry Andric       size_t __chunk = _VSTD::min(__n, __capacity_);
122bdd1243dSDimitry Andric       _VSTD::copy_n(__first, __chunk, _VSTD::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.
133bdd1243dSDimitry Andric   template <__fmt_char_type _InCharT, class _UnaryOperation>
134bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) {
135*06c3fb27SDimitry Andric     _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
136bdd1243dSDimitry Andric 
137bdd1243dSDimitry Andric     size_t __n = static_cast<size_t>(__last - __first);
138bdd1243dSDimitry Andric     __flush_on_overflow(__n);
139*06c3fb27SDimitry Andric     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
140bdd1243dSDimitry Andric       _VSTD::transform(__first, __last, _VSTD::addressof(__ptr_[__size_]), _VSTD::move(__operation));
141bdd1243dSDimitry Andric       __size_ += __n;
142bdd1243dSDimitry Andric       return;
143bdd1243dSDimitry Andric     }
144bdd1243dSDimitry Andric 
145bdd1243dSDimitry Andric     // The output doesn't fit in the internal buffer.
146bdd1243dSDimitry Andric     // Transform the data in "__capacity_" sized chunks.
147*06c3fb27SDimitry Andric     _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
148bdd1243dSDimitry Andric     do {
149bdd1243dSDimitry Andric       size_t __chunk = _VSTD::min(__n, __capacity_);
150bdd1243dSDimitry Andric       _VSTD::transform(__first, __first + __chunk, _VSTD::addressof(__ptr_[__size_]), __operation);
151bdd1243dSDimitry Andric       __size_ = __chunk;
152bdd1243dSDimitry Andric       __first += __chunk;
153bdd1243dSDimitry Andric       __n -= __chunk;
154bdd1243dSDimitry Andric       __flush();
155bdd1243dSDimitry Andric     } while (__n);
156bdd1243dSDimitry Andric   }
157bdd1243dSDimitry Andric 
158bdd1243dSDimitry Andric   /// A \c fill_n wrapper.
159bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
160bdd1243dSDimitry Andric     __flush_on_overflow(__n);
161*06c3fb27SDimitry Andric     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
162bdd1243dSDimitry Andric       _VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __n, __value);
163bdd1243dSDimitry Andric       __size_ += __n;
164bdd1243dSDimitry Andric       return;
165bdd1243dSDimitry Andric     }
166bdd1243dSDimitry Andric 
167bdd1243dSDimitry Andric     // The output doesn't fit in the internal buffer.
168bdd1243dSDimitry Andric     // Fill the buffer in "__capacity_" sized chunks.
169*06c3fb27SDimitry Andric     _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
170bdd1243dSDimitry Andric     do {
171bdd1243dSDimitry Andric       size_t __chunk = _VSTD::min(__n, __capacity_);
172bdd1243dSDimitry Andric       _VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __chunk, __value);
173bdd1243dSDimitry Andric       __size_ = __chunk;
174bdd1243dSDimitry Andric       __n -= __chunk;
175bdd1243dSDimitry Andric       __flush();
176bdd1243dSDimitry Andric     } while (__n);
177bdd1243dSDimitry Andric   }
178bdd1243dSDimitry Andric 
179bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush() {
18081ad6265SDimitry Andric     __flush_(__ptr_, __size_, __obj_);
18181ad6265SDimitry Andric     __size_ = 0;
18281ad6265SDimitry Andric   }
18381ad6265SDimitry Andric 
18481ad6265SDimitry Andric private:
18581ad6265SDimitry Andric   _CharT* __ptr_;
18681ad6265SDimitry Andric   size_t __capacity_;
18781ad6265SDimitry Andric   size_t __size_{0};
18881ad6265SDimitry Andric   void (*__flush_)(_CharT*, size_t, void*);
18981ad6265SDimitry Andric   void* __obj_;
190bdd1243dSDimitry Andric 
191bdd1243dSDimitry Andric   /// Flushes the buffer when the output operation would overflow the buffer.
192bdd1243dSDimitry Andric   ///
193bdd1243dSDimitry Andric   /// A simple approach for the overflow detection would be something along the
194bdd1243dSDimitry Andric   /// lines:
195bdd1243dSDimitry Andric   /// \code
196bdd1243dSDimitry Andric   /// // The internal buffer is large enough.
197bdd1243dSDimitry Andric   /// if (__n <= __capacity_) {
198bdd1243dSDimitry Andric   ///   // Flush when we really would overflow.
199bdd1243dSDimitry Andric   ///   if (__size_ + __n >= __capacity_)
200bdd1243dSDimitry Andric   ///     __flush();
201bdd1243dSDimitry Andric   ///   ...
202bdd1243dSDimitry Andric   /// }
203bdd1243dSDimitry Andric   /// \endcode
204bdd1243dSDimitry Andric   ///
205bdd1243dSDimitry Andric   /// This approach works for all cases but one:
206bdd1243dSDimitry Andric   /// A __format_to_n_buffer_base where \ref __enable_direct_output is true.
207bdd1243dSDimitry Andric   /// In that case the \ref __capacity_ of the buffer changes during the first
208bdd1243dSDimitry Andric   /// \ref __flush. During that operation the output buffer switches from its
209bdd1243dSDimitry Andric   /// __writer_ to its __storage_. The \ref __capacity_ of the former depends
210bdd1243dSDimitry Andric   /// on the value of n, of the latter is a fixed size. For example:
211bdd1243dSDimitry Andric   /// - a format_to_n call with a 10'000 char buffer,
212bdd1243dSDimitry Andric   /// - the buffer is filled with 9'500 chars,
213bdd1243dSDimitry Andric   /// - adding 1'000 elements would overflow the buffer so the buffer gets
214bdd1243dSDimitry Andric   ///   changed and the \ref __capacity_ decreases from 10'000 to
215bdd1243dSDimitry Andric   ///   __buffer_size (256 at the time of writing).
216bdd1243dSDimitry Andric   ///
217bdd1243dSDimitry Andric   /// This means that the \ref __flush for this class may need to copy a part of
218bdd1243dSDimitry Andric   /// the internal buffer to the proper output. In this example there will be
219bdd1243dSDimitry Andric   /// 500 characters that need this copy operation.
220bdd1243dSDimitry Andric   ///
221bdd1243dSDimitry Andric   /// Note it would be more efficient to write 500 chars directly and then swap
222bdd1243dSDimitry Andric   /// the buffers. This would make the code more complex and \ref format_to_n is
223bdd1243dSDimitry Andric   /// not the most common use case. Therefore the optimization isn't done.
224bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) {
225bdd1243dSDimitry Andric     if (__size_ + __n >= __capacity_)
226bdd1243dSDimitry Andric       __flush();
227bdd1243dSDimitry Andric   }
22881ad6265SDimitry Andric };
22981ad6265SDimitry Andric 
23081ad6265SDimitry Andric /// A storage using an internal buffer.
23181ad6265SDimitry Andric ///
23281ad6265SDimitry Andric /// This storage is used when writing a single element to the output iterator
23381ad6265SDimitry Andric /// is expensive.
234bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
23581ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __internal_storage {
23681ad6265SDimitry Andric public:
237bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; }
23881ad6265SDimitry Andric 
23981ad6265SDimitry Andric   static constexpr size_t __buffer_size = 256 / sizeof(_CharT);
24081ad6265SDimitry Andric 
24181ad6265SDimitry Andric private:
24281ad6265SDimitry Andric   _CharT __buffer_[__buffer_size];
24381ad6265SDimitry Andric };
24481ad6265SDimitry Andric 
24581ad6265SDimitry Andric /// A storage writing directly to the storage.
24681ad6265SDimitry Andric ///
24781ad6265SDimitry Andric /// This requires the storage to be a contiguous buffer of \a _CharT.
24881ad6265SDimitry Andric /// Since the output is directly written to the underlying storage this class
24981ad6265SDimitry Andric /// is just an empty class.
250bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
25181ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __direct_storage {};
25281ad6265SDimitry Andric 
25381ad6265SDimitry Andric template <class _OutIt, class _CharT>
254bdd1243dSDimitry Andric concept __enable_direct_output = __fmt_char_type<_CharT> &&
25581ad6265SDimitry Andric     (same_as<_OutIt, _CharT*>
256*06c3fb27SDimitry Andric      // TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
257*06c3fb27SDimitry Andric      // `#ifdef`.
25881ad6265SDimitry Andric      || same_as<_OutIt, __wrap_iter<_CharT*>>
25981ad6265SDimitry Andric     );
26081ad6265SDimitry Andric 
26181ad6265SDimitry Andric /// Write policy for directly writing to the underlying output.
262bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT>
26381ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_direct {
26481ad6265SDimitry Andric public:
26581ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it)
26681ad6265SDimitry Andric       : __out_it_(__out_it) {}
26781ad6265SDimitry Andric 
268bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; }
26981ad6265SDimitry Andric 
270bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) {
27181ad6265SDimitry Andric     // _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator
27281ad6265SDimitry Andric     // is adjusted.
273bdd1243dSDimitry Andric     __out_it_ += __n;
27481ad6265SDimitry Andric   }
27581ad6265SDimitry Andric 
27681ad6265SDimitry Andric private:
27781ad6265SDimitry Andric   _OutIt __out_it_;
27881ad6265SDimitry Andric };
27981ad6265SDimitry Andric 
28081ad6265SDimitry Andric /// Write policy for copying the buffer to the output.
281bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT>
28281ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_iterator {
28381ad6265SDimitry Andric public:
28481ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it)
28581ad6265SDimitry Andric       : __out_it_{_VSTD::move(__out_it)} {}
28681ad6265SDimitry Andric 
287bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); }
28881ad6265SDimitry Andric 
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> &&
30781ad6265SDimitry Andric     requires(_Container& __t, add_pointer_t<typename _Container::value_type> __first,
30881ad6265SDimitry Andric              add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };
30981ad6265SDimitry Andric 
31081ad6265SDimitry Andric /// Extract the container type of a \ref back_insert_iterator.
31181ad6265SDimitry Andric template <class _It>
31281ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container {
31381ad6265SDimitry Andric   using type = void;
31481ad6265SDimitry Andric };
31581ad6265SDimitry Andric 
31681ad6265SDimitry Andric template <__insertable _Container>
31781ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> {
31881ad6265SDimitry Andric   using type = _Container;
31981ad6265SDimitry Andric };
32081ad6265SDimitry Andric 
32181ad6265SDimitry Andric /// Write policy for inserting the buffer in a container.
32281ad6265SDimitry Andric template <class _Container>
32381ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_container {
32481ad6265SDimitry Andric public:
32581ad6265SDimitry Andric   using _CharT = typename _Container::value_type;
32681ad6265SDimitry Andric 
32781ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it)
32881ad6265SDimitry Andric       : __container_{__out_it.__get_container()} {}
32981ad6265SDimitry Andric 
330bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); }
33181ad6265SDimitry Andric 
332bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
333bdd1243dSDimitry Andric     __container_->insert(__container_->end(), __ptr, __ptr + __n);
33481ad6265SDimitry Andric   }
33581ad6265SDimitry Andric 
33681ad6265SDimitry Andric private:
33781ad6265SDimitry Andric   _Container* __container_;
33881ad6265SDimitry Andric };
33981ad6265SDimitry Andric 
34081ad6265SDimitry Andric /// Selects the type of the writer used for the output iterator.
34181ad6265SDimitry Andric template <class _OutIt, class _CharT>
34281ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_selector {
34381ad6265SDimitry Andric   using _Container = typename __back_insert_iterator_container<_OutIt>::type;
34481ad6265SDimitry Andric 
34581ad6265SDimitry Andric public:
34681ad6265SDimitry Andric   using type = conditional_t<!same_as<_Container, void>, __writer_container<_Container>,
34781ad6265SDimitry Andric                              conditional_t<__enable_direct_output<_OutIt, _CharT>, __writer_direct<_OutIt, _CharT>,
34881ad6265SDimitry Andric                                            __writer_iterator<_OutIt, _CharT>>>;
34981ad6265SDimitry Andric };
35081ad6265SDimitry Andric 
35181ad6265SDimitry Andric /// The generic formatting buffer.
352bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT>
35381ad6265SDimitry Andric requires(output_iterator<_OutIt, const _CharT&>) class _LIBCPP_TEMPLATE_VIS
35481ad6265SDimitry Andric     __format_buffer {
35581ad6265SDimitry Andric   using _Storage =
35681ad6265SDimitry Andric       conditional_t<__enable_direct_output<_OutIt, _CharT>,
35781ad6265SDimitry Andric                     __direct_storage<_CharT>, __internal_storage<_CharT>>;
35881ad6265SDimitry Andric 
35981ad6265SDimitry Andric public:
36081ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
36181ad6265SDimitry Andric     requires(same_as<_Storage, __internal_storage<_CharT>>)
362bdd1243dSDimitry Andric       : __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(_VSTD::move(__out_it)) {}
36381ad6265SDimitry Andric 
36481ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) requires(
36581ad6265SDimitry Andric       same_as<_Storage, __direct_storage<_CharT>>)
36681ad6265SDimitry Andric       : __output_(_VSTD::__unwrap_iter(__out_it), size_t(-1), this),
36781ad6265SDimitry Andric         __writer_(_VSTD::move(__out_it)) {}
36881ad6265SDimitry Andric 
369bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
37081ad6265SDimitry Andric 
371bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); }
37281ad6265SDimitry Andric 
373bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {
374bdd1243dSDimitry Andric     __output_.__flush();
375bdd1243dSDimitry Andric     return _VSTD::move(__writer_).__out_it();
37681ad6265SDimitry Andric   }
37781ad6265SDimitry Andric 
37881ad6265SDimitry Andric private:
37981ad6265SDimitry Andric   _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_;
38081ad6265SDimitry Andric   __output_buffer<_CharT> __output_;
38181ad6265SDimitry Andric   typename __writer_selector<_OutIt, _CharT>::type __writer_;
38281ad6265SDimitry Andric };
38381ad6265SDimitry Andric 
38481ad6265SDimitry Andric /// A buffer that counts the number of insertions.
38581ad6265SDimitry Andric ///
38681ad6265SDimitry Andric /// Since \ref formatted_size only needs to know the size, the output itself is
38781ad6265SDimitry Andric /// discarded.
388bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
38981ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer {
39081ad6265SDimitry Andric public:
391bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
39281ad6265SDimitry Andric 
393bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; }
39481ad6265SDimitry Andric 
395bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI size_t __result() && {
396bdd1243dSDimitry Andric     __output_.__flush();
39781ad6265SDimitry Andric     return __size_;
39881ad6265SDimitry Andric   }
39981ad6265SDimitry Andric 
40081ad6265SDimitry Andric private:
40181ad6265SDimitry Andric   __internal_storage<_CharT> __storage_;
402bdd1243dSDimitry Andric   __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
40381ad6265SDimitry Andric   size_t __size_{0};
40481ad6265SDimitry Andric };
40581ad6265SDimitry Andric 
40681ad6265SDimitry Andric /// The base of a buffer that counts and limits the number of insertions.
407bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT, bool>
40881ad6265SDimitry Andric   requires(output_iterator<_OutIt, const _CharT&>)
40981ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base {
41081ad6265SDimitry Andric   using _Size = iter_difference_t<_OutIt>;
41181ad6265SDimitry Andric 
41281ad6265SDimitry Andric public:
413bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
414bdd1243dSDimitry Andric       : __writer_(_VSTD::move(__out_it)), __max_size_(_VSTD::max(_Size(0), __max_size)) {}
41581ad6265SDimitry Andric 
416bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
417bdd1243dSDimitry Andric     if (_Size(__size_) <= __max_size_)
418bdd1243dSDimitry Andric       __writer_.__flush(__ptr, _VSTD::min(_Size(__n), __max_size_ - __size_));
419bdd1243dSDimitry Andric     __size_ += __n;
42081ad6265SDimitry Andric   }
42181ad6265SDimitry Andric 
42281ad6265SDimitry Andric protected:
42381ad6265SDimitry Andric   __internal_storage<_CharT> __storage_;
424bdd1243dSDimitry Andric   __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
42581ad6265SDimitry Andric   typename __writer_selector<_OutIt, _CharT>::type __writer_;
42681ad6265SDimitry Andric 
427bdd1243dSDimitry Andric   _Size __max_size_;
42881ad6265SDimitry Andric   _Size __size_{0};
42981ad6265SDimitry Andric };
43081ad6265SDimitry Andric 
43181ad6265SDimitry Andric /// The base of a buffer that counts and limits the number of insertions.
43281ad6265SDimitry Andric ///
43381ad6265SDimitry Andric /// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true.
43481ad6265SDimitry Andric ///
435bdd1243dSDimitry Andric /// This class limits the size available to the direct writer so it will not
43681ad6265SDimitry Andric /// exceed the maximum number of code units.
437bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT>
43881ad6265SDimitry Andric   requires(output_iterator<_OutIt, const _CharT&>)
43981ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> {
44081ad6265SDimitry Andric   using _Size = iter_difference_t<_OutIt>;
44181ad6265SDimitry Andric 
44281ad6265SDimitry Andric public:
443bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
444bdd1243dSDimitry Andric       : __output_(_VSTD::__unwrap_iter(__out_it), __max_size, this),
445bdd1243dSDimitry Andric         __writer_(_VSTD::move(__out_it)),
446bdd1243dSDimitry Andric         __max_size_(__max_size) {
447bdd1243dSDimitry Andric     if (__max_size <= 0) [[unlikely]]
448bdd1243dSDimitry Andric       __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
44981ad6265SDimitry Andric   }
45081ad6265SDimitry Andric 
451bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
452bdd1243dSDimitry Andric     // A __flush to the direct writer happens in the following occasions:
45381ad6265SDimitry Andric     // - The format function has written the maximum number of allowed code
45481ad6265SDimitry Andric     //   units. At this point it's no longer valid to write to this writer. So
45581ad6265SDimitry Andric     //   switch to the internal storage. This internal storage doesn't need to
456bdd1243dSDimitry Andric     //   be written anywhere so the __flush for that storage writes no output.
457bdd1243dSDimitry Andric     // - Like above, but the next "mass write" operation would overflow the
458bdd1243dSDimitry Andric     //   buffer. In that case the buffer is pre-emptively switched. The still
459bdd1243dSDimitry Andric     //   valid code units will be written separately.
46081ad6265SDimitry Andric     // - The format_to_n function is finished. In this case there's no need to
46181ad6265SDimitry Andric     //   switch the buffer, but for simplicity the buffers are still switched.
462bdd1243dSDimitry Andric     // When the __max_size <= 0 the constructor already switched the buffers.
463bdd1243dSDimitry Andric     if (__size_ == 0 && __ptr != __storage_.__begin()) {
464bdd1243dSDimitry Andric       __writer_.__flush(__ptr, __n);
465bdd1243dSDimitry Andric       __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
466bdd1243dSDimitry Andric     } else if (__size_ < __max_size_) {
467bdd1243dSDimitry Andric       // Copies a part of the internal buffer to the output up to n characters.
468bdd1243dSDimitry Andric       // See __output_buffer<_CharT>::__flush_on_overflow for more information.
469bdd1243dSDimitry Andric       _Size __s = _VSTD::min(_Size(__n), __max_size_ - __size_);
470bdd1243dSDimitry Andric       std::copy_n(__ptr, __s, __writer_.__out_it());
471bdd1243dSDimitry Andric       __writer_.__flush(__ptr, __s);
47281ad6265SDimitry Andric     }
47381ad6265SDimitry Andric 
474bdd1243dSDimitry Andric     __size_ += __n;
47581ad6265SDimitry Andric   }
47681ad6265SDimitry Andric 
47781ad6265SDimitry Andric protected:
47881ad6265SDimitry Andric   __internal_storage<_CharT> __storage_;
47981ad6265SDimitry Andric   __output_buffer<_CharT> __output_;
48081ad6265SDimitry Andric   __writer_direct<_OutIt, _CharT> __writer_;
48181ad6265SDimitry Andric 
482bdd1243dSDimitry Andric   _Size __max_size_;
48381ad6265SDimitry Andric   _Size __size_{0};
48481ad6265SDimitry Andric };
48581ad6265SDimitry Andric 
48681ad6265SDimitry Andric /// The buffer that counts and limits the number of insertions.
487bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT>
48881ad6265SDimitry Andric   requires(output_iterator<_OutIt, const _CharT&>)
48981ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
49081ad6265SDimitry Andric     : public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> {
49181ad6265SDimitry Andric   using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>;
49281ad6265SDimitry Andric   using _Size = iter_difference_t<_OutIt>;
49381ad6265SDimitry Andric 
49481ad6265SDimitry Andric public:
495bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size)
496bdd1243dSDimitry Andric       : _Base(_VSTD::move(__out_it), __max_size) {}
497bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); }
49881ad6265SDimitry Andric 
499bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
500bdd1243dSDimitry Andric     this->__output_.__flush();
501bdd1243dSDimitry Andric     return {_VSTD::move(this->__writer_).__out_it(), this->__size_};
50281ad6265SDimitry Andric   }
50381ad6265SDimitry Andric };
504bdd1243dSDimitry Andric 
505bdd1243dSDimitry Andric // A dynamically growing buffer intended to be used for retargeting a context.
506bdd1243dSDimitry Andric //
507bdd1243dSDimitry Andric // P2286 Formatting ranges adds range formatting support. It allows the user to
508bdd1243dSDimitry Andric // specify the minimum width for the entire formatted range.  The width of the
509bdd1243dSDimitry Andric // range is not known until the range is formatted. Formatting is done to an
510bdd1243dSDimitry Andric // output_iterator so there's no guarantee it would be possible to add the fill
511bdd1243dSDimitry Andric // to the front of the output. Instead the range is formatted to a temporary
512bdd1243dSDimitry Andric // buffer and that buffer is formatted as a string.
513bdd1243dSDimitry Andric //
514bdd1243dSDimitry Andric // There is an issue with that approach, the format context used in
515bdd1243dSDimitry Andric // std::formatter<T>::format contains the output iterator used as part of its
516bdd1243dSDimitry Andric // type. So using this output iterator means there needs to be a new format
517bdd1243dSDimitry Andric // context and the format arguments need to be retargeted to the new context.
518bdd1243dSDimitry Andric // This retargeting is done by a basic_format_context specialized for the
519bdd1243dSDimitry Andric // __iterator of this container.
520*06c3fb27SDimitry Andric //
521*06c3fb27SDimitry Andric // This class uses its own buffer management, since using vector
522*06c3fb27SDimitry Andric // would lead to a circular include with formatter for vector<bool>.
523bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
524bdd1243dSDimitry Andric class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
525*06c3fb27SDimitry Andric   using _Alloc = allocator<_CharT>;
526*06c3fb27SDimitry Andric 
527bdd1243dSDimitry Andric public:
528bdd1243dSDimitry Andric   using value_type = _CharT;
529bdd1243dSDimitry Andric 
530bdd1243dSDimitry Andric   struct __iterator {
531bdd1243dSDimitry Andric     using difference_type = ptrdiff_t;
532*06c3fb27SDimitry Andric     using value_type      = _CharT;
533bdd1243dSDimitry Andric 
534bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
535bdd1243dSDimitry Andric         : __buffer_(std::addressof(__buffer)) {}
536bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {
537bdd1243dSDimitry Andric       __buffer_->push_back(__c);
538bdd1243dSDimitry Andric       return *this;
539bdd1243dSDimitry Andric     }
540bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {
541bdd1243dSDimitry Andric       __buffer_->push_back(__c);
542bdd1243dSDimitry Andric       return *this;
543bdd1243dSDimitry Andric     }
544bdd1243dSDimitry Andric 
545bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }
546bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }
547bdd1243dSDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }
548bdd1243dSDimitry Andric     __retarget_buffer* __buffer_;
549bdd1243dSDimitry Andric   };
550bdd1243dSDimitry Andric 
551*06c3fb27SDimitry Andric   __retarget_buffer(const __retarget_buffer&)            = delete;
552*06c3fb27SDimitry Andric   __retarget_buffer& operator=(const __retarget_buffer&) = delete;
553*06c3fb27SDimitry Andric 
554*06c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {
555*06c3fb27SDimitry Andric     // When the initial size is very small a lot of resizes happen
556*06c3fb27SDimitry Andric     // when elements added. So use a hard-coded minimum size.
557*06c3fb27SDimitry Andric     //
558*06c3fb27SDimitry Andric     // Note a size < 2 will not work
559*06c3fb27SDimitry Andric     // - 0 there is no buffer, while push_back requires 1 empty element.
560*06c3fb27SDimitry Andric     // - 1 multiplied by the grow factor is 1 and thus the buffer never
561*06c3fb27SDimitry Andric     //   grows.
562*06c3fb27SDimitry Andric     auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT)));
563*06c3fb27SDimitry Andric     __ptr_        = __result.ptr;
564*06c3fb27SDimitry Andric     __capacity_   = __result.count;
565*06c3fb27SDimitry Andric   }
566*06c3fb27SDimitry Andric 
567*06c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {
568*06c3fb27SDimitry Andric     ranges::destroy_n(__ptr_, __size_);
569*06c3fb27SDimitry Andric     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
570*06c3fb27SDimitry Andric   }
571bdd1243dSDimitry Andric 
572bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
573bdd1243dSDimitry Andric 
574*06c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
575*06c3fb27SDimitry Andric     std::construct_at(__ptr_ + __size_, __c);
576*06c3fb27SDimitry Andric     ++__size_;
577*06c3fb27SDimitry Andric 
578*06c3fb27SDimitry Andric     if (__size_ == __capacity_)
579*06c3fb27SDimitry Andric       __grow_buffer();
580*06c3fb27SDimitry Andric   }
581bdd1243dSDimitry Andric 
582bdd1243dSDimitry Andric   template <__fmt_char_type _InCharT>
583bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
584*06c3fb27SDimitry Andric     size_t __n = __str.size();
585*06c3fb27SDimitry Andric     if (__size_ + __n >= __capacity_)
586*06c3fb27SDimitry Andric       // Push_back requires the buffer to have room for at least one character.
587*06c3fb27SDimitry Andric       __grow_buffer(__size_ + __n + 1);
588*06c3fb27SDimitry Andric 
589*06c3fb27SDimitry Andric     std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);
590*06c3fb27SDimitry Andric     __size_ += __n;
591bdd1243dSDimitry Andric   }
592bdd1243dSDimitry Andric 
593bdd1243dSDimitry Andric   template <__fmt_char_type _InCharT, class _UnaryOperation>
594bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) {
595*06c3fb27SDimitry Andric     _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
596*06c3fb27SDimitry Andric 
597*06c3fb27SDimitry Andric     size_t __n = static_cast<size_t>(__last - __first);
598*06c3fb27SDimitry Andric     if (__size_ + __n >= __capacity_)
599*06c3fb27SDimitry Andric       // Push_back requires the buffer to have room for at least one character.
600*06c3fb27SDimitry Andric       __grow_buffer(__size_ + __n + 1);
601*06c3fb27SDimitry Andric 
602*06c3fb27SDimitry Andric     std::uninitialized_default_construct_n(__ptr_ + __size_, __n);
603*06c3fb27SDimitry Andric     std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));
604*06c3fb27SDimitry Andric     __size_ += __n;
605bdd1243dSDimitry Andric   }
606bdd1243dSDimitry Andric 
607*06c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
608*06c3fb27SDimitry Andric     if (__size_ + __n >= __capacity_)
609*06c3fb27SDimitry Andric       // Push_back requires the buffer to have room for at least one character.
610*06c3fb27SDimitry Andric       __grow_buffer(__size_ + __n + 1);
611bdd1243dSDimitry Andric 
612*06c3fb27SDimitry Andric     std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);
613*06c3fb27SDimitry Andric     __size_ += __n;
614*06c3fb27SDimitry Andric   }
615*06c3fb27SDimitry Andric 
616*06c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }
617bdd1243dSDimitry Andric 
618bdd1243dSDimitry Andric private:
619*06c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
620*06c3fb27SDimitry Andric 
621*06c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
622*06c3fb27SDimitry Andric     _LIBCPP_ASSERT_UNCATEGORIZED(__capacity > __capacity_, "the buffer must grow");
623*06c3fb27SDimitry Andric     auto __result = std::__allocate_at_least(__alloc_, __capacity);
624*06c3fb27SDimitry Andric     auto __guard  = std::__make_exception_guard([&] {
625*06c3fb27SDimitry Andric       allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
626*06c3fb27SDimitry Andric     });
627*06c3fb27SDimitry Andric     // This shouldn't throw, but just to be safe. Note that at -O1 this
628*06c3fb27SDimitry Andric     // guard is optimized away so there is no runtime overhead.
629*06c3fb27SDimitry Andric     std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
630*06c3fb27SDimitry Andric     __guard.__complete();
631*06c3fb27SDimitry Andric     ranges::destroy_n(__ptr_, __size_);
632*06c3fb27SDimitry Andric     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
633*06c3fb27SDimitry Andric 
634*06c3fb27SDimitry Andric     __ptr_      = __result.ptr;
635*06c3fb27SDimitry Andric     __capacity_ = __result.count;
636*06c3fb27SDimitry Andric   }
637*06c3fb27SDimitry Andric   _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
638*06c3fb27SDimitry Andric   _CharT* __ptr_;
639*06c3fb27SDimitry Andric   size_t __capacity_;
640*06c3fb27SDimitry Andric   size_t __size_{0};
641bdd1243dSDimitry Andric };
642bdd1243dSDimitry Andric 
64381ad6265SDimitry Andric } // namespace __format
64481ad6265SDimitry Andric 
645*06c3fb27SDimitry Andric #endif //_LIBCPP_STD_VER >= 20
64681ad6265SDimitry Andric 
64781ad6265SDimitry Andric _LIBCPP_END_NAMESPACE_STD
64881ad6265SDimitry Andric 
64981ad6265SDimitry Andric _LIBCPP_POP_MACROS
65081ad6265SDimitry Andric 
65181ad6265SDimitry Andric #endif // _LIBCPP___FORMAT_BUFFER_H
652