xref: /llvm-project/libcxx/include/__cxx03/__format/buffer.h (revision ce7771902dc50d900de639d499a60486b83f70e0)
1e78f53d1SNikolas Klauser // -*- C++ -*-
2e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===//
3e78f53d1SNikolas Klauser //
4e78f53d1SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5e78f53d1SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
6e78f53d1SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7e78f53d1SNikolas Klauser //
8e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===//
9e78f53d1SNikolas Klauser 
10*ce777190SNikolas Klauser #ifndef _LIBCPP___CXX03___FORMAT_BUFFER_H
11*ce777190SNikolas Klauser #define _LIBCPP___CXX03___FORMAT_BUFFER_H
12e78f53d1SNikolas Klauser 
1373fbae83SNikolas Klauser #include <__cxx03/__algorithm/copy_n.h>
1473fbae83SNikolas Klauser #include <__cxx03/__algorithm/fill_n.h>
1573fbae83SNikolas Klauser #include <__cxx03/__algorithm/max.h>
1673fbae83SNikolas Klauser #include <__cxx03/__algorithm/min.h>
1773fbae83SNikolas Klauser #include <__cxx03/__algorithm/ranges_copy_n.h>
1873fbae83SNikolas Klauser #include <__cxx03/__algorithm/transform.h>
1973fbae83SNikolas Klauser #include <__cxx03/__algorithm/unwrap_iter.h>
2073fbae83SNikolas Klauser #include <__cxx03/__concepts/same_as.h>
2173fbae83SNikolas Klauser #include <__cxx03/__config>
2273fbae83SNikolas Klauser #include <__cxx03/__format/concepts.h>
2373fbae83SNikolas Klauser #include <__cxx03/__format/enable_insertable.h>
2473fbae83SNikolas Klauser #include <__cxx03/__format/format_to_n_result.h>
2573fbae83SNikolas Klauser #include <__cxx03/__iterator/back_insert_iterator.h>
2673fbae83SNikolas Klauser #include <__cxx03/__iterator/concepts.h>
2773fbae83SNikolas Klauser #include <__cxx03/__iterator/incrementable_traits.h>
2873fbae83SNikolas Klauser #include <__cxx03/__iterator/iterator_traits.h>
2973fbae83SNikolas Klauser #include <__cxx03/__iterator/wrap_iter.h>
3073fbae83SNikolas Klauser #include <__cxx03/__memory/addressof.h>
3173fbae83SNikolas Klauser #include <__cxx03/__memory/allocate_at_least.h>
3273fbae83SNikolas Klauser #include <__cxx03/__memory/allocator_traits.h>
3373fbae83SNikolas Klauser #include <__cxx03/__memory/construct_at.h>
3473fbae83SNikolas Klauser #include <__cxx03/__memory/ranges_construct_at.h>
3573fbae83SNikolas Klauser #include <__cxx03/__memory/uninitialized_algorithms.h>
3673fbae83SNikolas Klauser #include <__cxx03/__type_traits/add_pointer.h>
3773fbae83SNikolas Klauser #include <__cxx03/__type_traits/conditional.h>
3873fbae83SNikolas Klauser #include <__cxx03/__utility/exception_guard.h>
3973fbae83SNikolas Klauser #include <__cxx03/__utility/move.h>
4073fbae83SNikolas Klauser #include <__cxx03/cstddef>
4173fbae83SNikolas Klauser #include <__cxx03/string_view>
42e78f53d1SNikolas Klauser 
43e78f53d1SNikolas Klauser #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
44e78f53d1SNikolas Klauser #  pragma GCC system_header
45e78f53d1SNikolas Klauser #endif
46e78f53d1SNikolas Klauser 
47e78f53d1SNikolas Klauser _LIBCPP_PUSH_MACROS
4873fbae83SNikolas Klauser #include <__cxx03/__undef_macros>
49e78f53d1SNikolas Klauser 
50e78f53d1SNikolas Klauser _LIBCPP_BEGIN_NAMESPACE_STD
51e78f53d1SNikolas Klauser 
52e78f53d1SNikolas Klauser #if _LIBCPP_STD_VER >= 20
53e78f53d1SNikolas Klauser 
54e78f53d1SNikolas Klauser namespace __format {
55e78f53d1SNikolas Klauser 
56e78f53d1SNikolas Klauser /// A "buffer" that handles writing to the proper iterator.
57e78f53d1SNikolas Klauser ///
58e78f53d1SNikolas Klauser /// This helper is used together with the @ref back_insert_iterator to offer
59e78f53d1SNikolas Klauser /// type-erasure for the formatting functions. This reduces the number to
60e78f53d1SNikolas Klauser /// template instantiations.
61e78f53d1SNikolas Klauser template <__fmt_char_type _CharT>
62e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __output_buffer {
63e78f53d1SNikolas Klauser public:
64e78f53d1SNikolas Klauser   using value_type = _CharT;
65e78f53d1SNikolas Klauser 
66e78f53d1SNikolas Klauser   template <class _Tp>
67e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj)
68e78f53d1SNikolas Klauser       : __ptr_(__ptr),
69e78f53d1SNikolas Klauser         __capacity_(__capacity),
70e78f53d1SNikolas Klauser         __flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }),
71e78f53d1SNikolas Klauser         __obj_(__obj) {}
72e78f53d1SNikolas Klauser 
73e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) {
74e78f53d1SNikolas Klauser     __ptr_      = __ptr;
75e78f53d1SNikolas Klauser     __capacity_ = __capacity;
76e78f53d1SNikolas Klauser   }
77e78f53d1SNikolas Klauser 
78e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; }
79e78f53d1SNikolas Klauser 
80e78f53d1SNikolas Klauser   // Used in std::back_insert_iterator.
81e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
82e78f53d1SNikolas Klauser     __ptr_[__size_++] = __c;
83e78f53d1SNikolas Klauser 
84e78f53d1SNikolas Klauser     // Profiling showed flushing after adding is more efficient than flushing
85e78f53d1SNikolas Klauser     // when entering the function.
86e78f53d1SNikolas Klauser     if (__size_ == __capacity_)
87e78f53d1SNikolas Klauser       __flush();
88e78f53d1SNikolas Klauser   }
89e78f53d1SNikolas Klauser 
90e78f53d1SNikolas Klauser   /// Copies the input __str to the buffer.
91e78f53d1SNikolas Klauser   ///
92e78f53d1SNikolas Klauser   /// Since some of the input is generated by std::to_chars, there needs to be a
93e78f53d1SNikolas Klauser   /// conversion when _CharT is wchar_t.
94e78f53d1SNikolas Klauser   template <__fmt_char_type _InCharT>
95e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
96e78f53d1SNikolas Klauser     // When the underlying iterator is a simple iterator the __capacity_ is
97e78f53d1SNikolas Klauser     // infinite. For a string or container back_inserter it isn't. This means
98e78f53d1SNikolas Klauser     // that adding a large string to the buffer can cause some overhead. In that
99e78f53d1SNikolas Klauser     // case a better approach could be:
100e78f53d1SNikolas Klauser     // - flush the buffer
101e78f53d1SNikolas Klauser     // - container.append(__str.begin(), __str.end());
102e78f53d1SNikolas Klauser     // The same holds true for the fill.
103e78f53d1SNikolas Klauser     // For transform it might be slightly harder, however the use case for
104e78f53d1SNikolas Klauser     // transform is slightly less common; it converts hexadecimal values to
105e78f53d1SNikolas Klauser     // upper case. For integral these strings are short.
106e78f53d1SNikolas Klauser     // TODO FMT Look at the improvements above.
107e78f53d1SNikolas Klauser     size_t __n = __str.size();
108e78f53d1SNikolas Klauser 
109e78f53d1SNikolas Klauser     __flush_on_overflow(__n);
110e78f53d1SNikolas Klauser     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
111e78f53d1SNikolas Klauser       std::copy_n(__str.data(), __n, std::addressof(__ptr_[__size_]));
112e78f53d1SNikolas Klauser       __size_ += __n;
113e78f53d1SNikolas Klauser       return;
114e78f53d1SNikolas Klauser     }
115e78f53d1SNikolas Klauser 
116e78f53d1SNikolas Klauser     // The output doesn't fit in the internal buffer.
117e78f53d1SNikolas Klauser     // Copy the data in "__capacity_" sized chunks.
118e78f53d1SNikolas Klauser     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
119e78f53d1SNikolas Klauser     const _InCharT* __first = __str.data();
120e78f53d1SNikolas Klauser     do {
121e78f53d1SNikolas Klauser       size_t __chunk = std::min(__n, __capacity_);
122e78f53d1SNikolas Klauser       std::copy_n(__first, __chunk, std::addressof(__ptr_[__size_]));
123e78f53d1SNikolas Klauser       __size_ = __chunk;
124e78f53d1SNikolas Klauser       __first += __chunk;
125e78f53d1SNikolas Klauser       __n -= __chunk;
126e78f53d1SNikolas Klauser       __flush();
127e78f53d1SNikolas Klauser     } while (__n);
128e78f53d1SNikolas Klauser   }
129e78f53d1SNikolas Klauser 
130e78f53d1SNikolas Klauser   /// A std::transform wrapper.
131e78f53d1SNikolas Klauser   ///
132e78f53d1SNikolas Klauser   /// Like @ref __copy it may need to do type conversion.
133e78f53d1SNikolas Klauser   template <contiguous_iterator _Iterator,
134e78f53d1SNikolas Klauser             class _UnaryOperation,
135e78f53d1SNikolas Klauser             __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
136e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
137e78f53d1SNikolas Klauser     _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
138e78f53d1SNikolas Klauser 
139e78f53d1SNikolas Klauser     size_t __n = static_cast<size_t>(__last - __first);
140e78f53d1SNikolas Klauser     __flush_on_overflow(__n);
141e78f53d1SNikolas Klauser     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
142e78f53d1SNikolas Klauser       std::transform(__first, __last, std::addressof(__ptr_[__size_]), std::move(__operation));
143e78f53d1SNikolas Klauser       __size_ += __n;
144e78f53d1SNikolas Klauser       return;
145e78f53d1SNikolas Klauser     }
146e78f53d1SNikolas Klauser 
147e78f53d1SNikolas Klauser     // The output doesn't fit in the internal buffer.
148e78f53d1SNikolas Klauser     // Transform the data in "__capacity_" sized chunks.
149e78f53d1SNikolas Klauser     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
150e78f53d1SNikolas Klauser     do {
151e78f53d1SNikolas Klauser       size_t __chunk = std::min(__n, __capacity_);
152e78f53d1SNikolas Klauser       std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
153e78f53d1SNikolas Klauser       __size_ = __chunk;
154e78f53d1SNikolas Klauser       __first += __chunk;
155e78f53d1SNikolas Klauser       __n -= __chunk;
156e78f53d1SNikolas Klauser       __flush();
157e78f53d1SNikolas Klauser     } while (__n);
158e78f53d1SNikolas Klauser   }
159e78f53d1SNikolas Klauser 
160e78f53d1SNikolas Klauser   /// A \c fill_n wrapper.
161e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
162e78f53d1SNikolas Klauser     __flush_on_overflow(__n);
163e78f53d1SNikolas Klauser     if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
164e78f53d1SNikolas Klauser       std::fill_n(std::addressof(__ptr_[__size_]), __n, __value);
165e78f53d1SNikolas Klauser       __size_ += __n;
166e78f53d1SNikolas Klauser       return;
167e78f53d1SNikolas Klauser     }
168e78f53d1SNikolas Klauser 
169e78f53d1SNikolas Klauser     // The output doesn't fit in the internal buffer.
170e78f53d1SNikolas Klauser     // Fill the buffer in "__capacity_" sized chunks.
171e78f53d1SNikolas Klauser     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
172e78f53d1SNikolas Klauser     do {
173e78f53d1SNikolas Klauser       size_t __chunk = std::min(__n, __capacity_);
174e78f53d1SNikolas Klauser       std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
175e78f53d1SNikolas Klauser       __size_ = __chunk;
176e78f53d1SNikolas Klauser       __n -= __chunk;
177e78f53d1SNikolas Klauser       __flush();
178e78f53d1SNikolas Klauser     } while (__n);
179e78f53d1SNikolas Klauser   }
180e78f53d1SNikolas Klauser 
181e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __flush() {
182e78f53d1SNikolas Klauser     __flush_(__ptr_, __size_, __obj_);
183e78f53d1SNikolas Klauser     __size_ = 0;
184e78f53d1SNikolas Klauser   }
185e78f53d1SNikolas Klauser 
186e78f53d1SNikolas Klauser private:
187e78f53d1SNikolas Klauser   _CharT* __ptr_;
188e78f53d1SNikolas Klauser   size_t __capacity_;
189e78f53d1SNikolas Klauser   size_t __size_{0};
190e78f53d1SNikolas Klauser   void (*__flush_)(_CharT*, size_t, void*);
191e78f53d1SNikolas Klauser   void* __obj_;
192e78f53d1SNikolas Klauser 
193e78f53d1SNikolas Klauser   /// Flushes the buffer when the output operation would overflow the buffer.
194e78f53d1SNikolas Klauser   ///
195e78f53d1SNikolas Klauser   /// A simple approach for the overflow detection would be something along the
196e78f53d1SNikolas Klauser   /// lines:
197e78f53d1SNikolas Klauser   /// \code
198e78f53d1SNikolas Klauser   /// // The internal buffer is large enough.
199e78f53d1SNikolas Klauser   /// if (__n <= __capacity_) {
200e78f53d1SNikolas Klauser   ///   // Flush when we really would overflow.
201e78f53d1SNikolas Klauser   ///   if (__size_ + __n >= __capacity_)
202e78f53d1SNikolas Klauser   ///     __flush();
203e78f53d1SNikolas Klauser   ///   ...
204e78f53d1SNikolas Klauser   /// }
205e78f53d1SNikolas Klauser   /// \endcode
206e78f53d1SNikolas Klauser   ///
207e78f53d1SNikolas Klauser   /// This approach works for all cases but one:
208e78f53d1SNikolas Klauser   /// A __format_to_n_buffer_base where \ref __enable_direct_output is true.
209e78f53d1SNikolas Klauser   /// In that case the \ref __capacity_ of the buffer changes during the first
210e78f53d1SNikolas Klauser   /// \ref __flush. During that operation the output buffer switches from its
211e78f53d1SNikolas Klauser   /// __writer_ to its __storage_. The \ref __capacity_ of the former depends
212e78f53d1SNikolas Klauser   /// on the value of n, of the latter is a fixed size. For example:
213e78f53d1SNikolas Klauser   /// - a format_to_n call with a 10'000 char buffer,
214e78f53d1SNikolas Klauser   /// - the buffer is filled with 9'500 chars,
215e78f53d1SNikolas Klauser   /// - adding 1'000 elements would overflow the buffer so the buffer gets
216e78f53d1SNikolas Klauser   ///   changed and the \ref __capacity_ decreases from 10'000 to
217e78f53d1SNikolas Klauser   ///   __buffer_size (256 at the time of writing).
218e78f53d1SNikolas Klauser   ///
219e78f53d1SNikolas Klauser   /// This means that the \ref __flush for this class may need to copy a part of
220e78f53d1SNikolas Klauser   /// the internal buffer to the proper output. In this example there will be
221e78f53d1SNikolas Klauser   /// 500 characters that need this copy operation.
222e78f53d1SNikolas Klauser   ///
223e78f53d1SNikolas Klauser   /// Note it would be more efficient to write 500 chars directly and then swap
224e78f53d1SNikolas Klauser   /// the buffers. This would make the code more complex and \ref format_to_n is
225e78f53d1SNikolas Klauser   /// not the most common use case. Therefore the optimization isn't done.
226e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) {
227e78f53d1SNikolas Klauser     if (__size_ + __n >= __capacity_)
228e78f53d1SNikolas Klauser       __flush();
229e78f53d1SNikolas Klauser   }
230e78f53d1SNikolas Klauser };
231e78f53d1SNikolas Klauser 
232e78f53d1SNikolas Klauser /// A storage using an internal buffer.
233e78f53d1SNikolas Klauser ///
234e78f53d1SNikolas Klauser /// This storage is used when writing a single element to the output iterator
235e78f53d1SNikolas Klauser /// is expensive.
236e78f53d1SNikolas Klauser template <__fmt_char_type _CharT>
237e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __internal_storage {
238e78f53d1SNikolas Klauser public:
239e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; }
240e78f53d1SNikolas Klauser 
241e78f53d1SNikolas Klauser   static constexpr size_t __buffer_size = 256 / sizeof(_CharT);
242e78f53d1SNikolas Klauser 
243e78f53d1SNikolas Klauser private:
244e78f53d1SNikolas Klauser   _CharT __buffer_[__buffer_size];
245e78f53d1SNikolas Klauser };
246e78f53d1SNikolas Klauser 
247e78f53d1SNikolas Klauser /// A storage writing directly to the storage.
248e78f53d1SNikolas Klauser ///
249e78f53d1SNikolas Klauser /// This requires the storage to be a contiguous buffer of \a _CharT.
250e78f53d1SNikolas Klauser /// Since the output is directly written to the underlying storage this class
251e78f53d1SNikolas Klauser /// is just an empty class.
252e78f53d1SNikolas Klauser template <__fmt_char_type _CharT>
253e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __direct_storage {};
254e78f53d1SNikolas Klauser 
255e78f53d1SNikolas Klauser template <class _OutIt, class _CharT>
256e78f53d1SNikolas Klauser concept __enable_direct_output =
257e78f53d1SNikolas Klauser     __fmt_char_type<_CharT> &&
258e78f53d1SNikolas Klauser     (same_as<_OutIt, _CharT*>
259e78f53d1SNikolas Klauser      // TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
260e78f53d1SNikolas Klauser      // `#ifdef`.
261e78f53d1SNikolas Klauser      || same_as<_OutIt, __wrap_iter<_CharT*>>);
262e78f53d1SNikolas Klauser 
263e78f53d1SNikolas Klauser /// Write policy for directly writing to the underlying output.
264e78f53d1SNikolas Klauser template <class _OutIt, __fmt_char_type _CharT>
265e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __writer_direct {
266e78f53d1SNikolas Klauser public:
267e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it) : __out_it_(__out_it) {}
268e78f53d1SNikolas Klauser 
269e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; }
270e78f53d1SNikolas Klauser 
271e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) {
272e78f53d1SNikolas Klauser     // _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator
273e78f53d1SNikolas Klauser     // is adjusted.
274e78f53d1SNikolas Klauser     __out_it_ += __n;
275e78f53d1SNikolas Klauser   }
276e78f53d1SNikolas Klauser 
277e78f53d1SNikolas Klauser private:
278e78f53d1SNikolas Klauser   _OutIt __out_it_;
279e78f53d1SNikolas Klauser };
280e78f53d1SNikolas Klauser 
281e78f53d1SNikolas Klauser /// Write policy for copying the buffer to the output.
282e78f53d1SNikolas Klauser template <class _OutIt, __fmt_char_type _CharT>
283e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __writer_iterator {
284e78f53d1SNikolas Klauser public:
285e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it) : __out_it_{std::move(__out_it)} {}
286e78f53d1SNikolas Klauser 
287e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); }
288e78f53d1SNikolas Klauser 
289e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
290e78f53d1SNikolas Klauser     __out_it_ = std::ranges::copy_n(__ptr, __n, std::move(__out_it_)).out;
291e78f53d1SNikolas Klauser   }
292e78f53d1SNikolas Klauser 
293e78f53d1SNikolas Klauser private:
294e78f53d1SNikolas Klauser   _OutIt __out_it_;
295e78f53d1SNikolas Klauser };
296e78f53d1SNikolas Klauser 
297e78f53d1SNikolas Klauser /// Concept to see whether a \a _Container is insertable.
298e78f53d1SNikolas Klauser ///
299e78f53d1SNikolas Klauser /// The concept is used to validate whether multiple calls to a
300e78f53d1SNikolas Klauser /// \ref back_insert_iterator can be replace by a call to \c _Container::insert.
301e78f53d1SNikolas Klauser ///
302e78f53d1SNikolas Klauser /// \note a \a _Container needs to opt-in to the concept by specializing
303e78f53d1SNikolas Klauser /// \ref __enable_insertable.
304e78f53d1SNikolas Klauser template <class _Container>
305e78f53d1SNikolas Klauser concept __insertable =
306e78f53d1SNikolas Klauser     __enable_insertable<_Container> && __fmt_char_type<typename _Container::value_type> &&
307e78f53d1SNikolas Klauser     requires(_Container& __t,
308e78f53d1SNikolas Klauser              add_pointer_t<typename _Container::value_type> __first,
309e78f53d1SNikolas Klauser              add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };
310e78f53d1SNikolas Klauser 
311e78f53d1SNikolas Klauser /// Extract the container type of a \ref back_insert_iterator.
312e78f53d1SNikolas Klauser template <class _It>
313e78f53d1SNikolas Klauser struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container {
314e78f53d1SNikolas Klauser   using type = void;
315e78f53d1SNikolas Klauser };
316e78f53d1SNikolas Klauser 
317e78f53d1SNikolas Klauser template <__insertable _Container>
318e78f53d1SNikolas Klauser struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> {
319e78f53d1SNikolas Klauser   using type = _Container;
320e78f53d1SNikolas Klauser };
321e78f53d1SNikolas Klauser 
322e78f53d1SNikolas Klauser /// Write policy for inserting the buffer in a container.
323e78f53d1SNikolas Klauser template <class _Container>
324e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __writer_container {
325e78f53d1SNikolas Klauser public:
326e78f53d1SNikolas Klauser   using _CharT = typename _Container::value_type;
327e78f53d1SNikolas Klauser 
328e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it)
329e78f53d1SNikolas Klauser       : __container_{__out_it.__get_container()} {}
330e78f53d1SNikolas Klauser 
331e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); }
332e78f53d1SNikolas Klauser 
333e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
334e78f53d1SNikolas Klauser     __container_->insert(__container_->end(), __ptr, __ptr + __n);
335e78f53d1SNikolas Klauser   }
336e78f53d1SNikolas Klauser 
337e78f53d1SNikolas Klauser private:
338e78f53d1SNikolas Klauser   _Container* __container_;
339e78f53d1SNikolas Klauser };
340e78f53d1SNikolas Klauser 
341e78f53d1SNikolas Klauser /// Selects the type of the writer used for the output iterator.
342e78f53d1SNikolas Klauser template <class _OutIt, class _CharT>
343e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __writer_selector {
344e78f53d1SNikolas Klauser   using _Container = typename __back_insert_iterator_container<_OutIt>::type;
345e78f53d1SNikolas Klauser 
346e78f53d1SNikolas Klauser public:
347e78f53d1SNikolas Klauser   using type =
348e78f53d1SNikolas Klauser       conditional_t<!same_as<_Container, void>,
349e78f53d1SNikolas Klauser                     __writer_container<_Container>,
350e78f53d1SNikolas Klauser                     conditional_t<__enable_direct_output<_OutIt, _CharT>,
351e78f53d1SNikolas Klauser                                   __writer_direct<_OutIt, _CharT>,
352e78f53d1SNikolas Klauser                                   __writer_iterator<_OutIt, _CharT>>>;
353e78f53d1SNikolas Klauser };
354e78f53d1SNikolas Klauser 
355e78f53d1SNikolas Klauser /// The generic formatting buffer.
356e78f53d1SNikolas Klauser template <class _OutIt, __fmt_char_type _CharT>
357e78f53d1SNikolas Klauser   requires(output_iterator<_OutIt, const _CharT&>)
358e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __format_buffer {
359e78f53d1SNikolas Klauser   using _Storage =
360e78f53d1SNikolas Klauser       conditional_t<__enable_direct_output<_OutIt, _CharT>, __direct_storage<_CharT>, __internal_storage<_CharT>>;
361e78f53d1SNikolas Klauser 
362e78f53d1SNikolas Klauser public:
363e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
364e78f53d1SNikolas Klauser     requires(same_as<_Storage, __internal_storage<_CharT>>)
365e78f53d1SNikolas Klauser       : __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(std::move(__out_it)) {}
366e78f53d1SNikolas Klauser 
367e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
368e78f53d1SNikolas Klauser     requires(same_as<_Storage, __direct_storage<_CharT>>)
369e78f53d1SNikolas Klauser       : __output_(std::__unwrap_iter(__out_it), size_t(-1), this), __writer_(std::move(__out_it)) {}
370e78f53d1SNikolas Klauser 
371e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
372e78f53d1SNikolas Klauser 
373e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); }
374e78f53d1SNikolas Klauser 
375e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {
376e78f53d1SNikolas Klauser     __output_.__flush();
377e78f53d1SNikolas Klauser     return std::move(__writer_).__out_it();
378e78f53d1SNikolas Klauser   }
379e78f53d1SNikolas Klauser 
380e78f53d1SNikolas Klauser private:
381e78f53d1SNikolas Klauser   _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_;
382e78f53d1SNikolas Klauser   __output_buffer<_CharT> __output_;
383e78f53d1SNikolas Klauser   typename __writer_selector<_OutIt, _CharT>::type __writer_;
384e78f53d1SNikolas Klauser };
385e78f53d1SNikolas Klauser 
386e78f53d1SNikolas Klauser /// A buffer that counts the number of insertions.
387e78f53d1SNikolas Klauser ///
388e78f53d1SNikolas Klauser /// Since \ref formatted_size only needs to know the size, the output itself is
389e78f53d1SNikolas Klauser /// discarded.
390e78f53d1SNikolas Klauser template <__fmt_char_type _CharT>
391e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer {
392e78f53d1SNikolas Klauser public:
393e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
394e78f53d1SNikolas Klauser 
395e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; }
396e78f53d1SNikolas Klauser 
397e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI size_t __result() && {
398e78f53d1SNikolas Klauser     __output_.__flush();
399e78f53d1SNikolas Klauser     return __size_;
400e78f53d1SNikolas Klauser   }
401e78f53d1SNikolas Klauser 
402e78f53d1SNikolas Klauser private:
403e78f53d1SNikolas Klauser   __internal_storage<_CharT> __storage_;
404e78f53d1SNikolas Klauser   __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
405e78f53d1SNikolas Klauser   size_t __size_{0};
406e78f53d1SNikolas Klauser };
407e78f53d1SNikolas Klauser 
408e78f53d1SNikolas Klauser /// The base of a buffer that counts and limits the number of insertions.
409e78f53d1SNikolas Klauser template <class _OutIt, __fmt_char_type _CharT, bool>
410e78f53d1SNikolas Klauser   requires(output_iterator<_OutIt, const _CharT&>)
411e78f53d1SNikolas Klauser struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base {
412e78f53d1SNikolas Klauser   using _Size = iter_difference_t<_OutIt>;
413e78f53d1SNikolas Klauser 
414e78f53d1SNikolas Klauser public:
415e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
416e78f53d1SNikolas Klauser       : __writer_(std::move(__out_it)), __max_size_(std::max(_Size(0), __max_size)) {}
417e78f53d1SNikolas Klauser 
418e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
419e78f53d1SNikolas Klauser     if (_Size(__size_) <= __max_size_)
420e78f53d1SNikolas Klauser       __writer_.__flush(__ptr, std::min(_Size(__n), __max_size_ - __size_));
421e78f53d1SNikolas Klauser     __size_ += __n;
422e78f53d1SNikolas Klauser   }
423e78f53d1SNikolas Klauser 
424e78f53d1SNikolas Klauser protected:
425e78f53d1SNikolas Klauser   __internal_storage<_CharT> __storage_;
426e78f53d1SNikolas Klauser   __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
427e78f53d1SNikolas Klauser   typename __writer_selector<_OutIt, _CharT>::type __writer_;
428e78f53d1SNikolas Klauser 
429e78f53d1SNikolas Klauser   _Size __max_size_;
430e78f53d1SNikolas Klauser   _Size __size_{0};
431e78f53d1SNikolas Klauser };
432e78f53d1SNikolas Klauser 
433e78f53d1SNikolas Klauser /// The base of a buffer that counts and limits the number of insertions.
434e78f53d1SNikolas Klauser ///
435e78f53d1SNikolas Klauser /// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true.
436e78f53d1SNikolas Klauser ///
437e78f53d1SNikolas Klauser /// This class limits the size available to the direct writer so it will not
438e78f53d1SNikolas Klauser /// exceed the maximum number of code units.
439e78f53d1SNikolas Klauser template <class _OutIt, __fmt_char_type _CharT>
440e78f53d1SNikolas Klauser   requires(output_iterator<_OutIt, const _CharT&>)
441e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> {
442e78f53d1SNikolas Klauser   using _Size = iter_difference_t<_OutIt>;
443e78f53d1SNikolas Klauser 
444e78f53d1SNikolas Klauser public:
445e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
446e78f53d1SNikolas Klauser       : __output_(std::__unwrap_iter(__out_it), __max_size, this),
447e78f53d1SNikolas Klauser         __writer_(std::move(__out_it)),
448e78f53d1SNikolas Klauser         __max_size_(__max_size) {
449e78f53d1SNikolas Klauser     if (__max_size <= 0) [[unlikely]]
450e78f53d1SNikolas Klauser       __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
451e78f53d1SNikolas Klauser   }
452e78f53d1SNikolas Klauser 
453e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
454e78f53d1SNikolas Klauser     // A __flush to the direct writer happens in the following occasions:
455e78f53d1SNikolas Klauser     // - The format function has written the maximum number of allowed code
456e78f53d1SNikolas Klauser     //   units. At this point it's no longer valid to write to this writer. So
457e78f53d1SNikolas Klauser     //   switch to the internal storage. This internal storage doesn't need to
458e78f53d1SNikolas Klauser     //   be written anywhere so the __flush for that storage writes no output.
459e78f53d1SNikolas Klauser     // - Like above, but the next "mass write" operation would overflow the
460e78f53d1SNikolas Klauser     //   buffer. In that case the buffer is pre-emptively switched. The still
461e78f53d1SNikolas Klauser     //   valid code units will be written separately.
462e78f53d1SNikolas Klauser     // - The format_to_n function is finished. In this case there's no need to
463e78f53d1SNikolas Klauser     //   switch the buffer, but for simplicity the buffers are still switched.
464e78f53d1SNikolas Klauser     // When the __max_size <= 0 the constructor already switched the buffers.
465e78f53d1SNikolas Klauser     if (__size_ == 0 && __ptr != __storage_.__begin()) {
466e78f53d1SNikolas Klauser       __writer_.__flush(__ptr, __n);
467e78f53d1SNikolas Klauser       __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
468e78f53d1SNikolas Klauser     } else if (__size_ < __max_size_) {
469e78f53d1SNikolas Klauser       // Copies a part of the internal buffer to the output up to n characters.
470e78f53d1SNikolas Klauser       // See __output_buffer<_CharT>::__flush_on_overflow for more information.
471e78f53d1SNikolas Klauser       _Size __s = std::min(_Size(__n), __max_size_ - __size_);
472e78f53d1SNikolas Klauser       std::copy_n(__ptr, __s, __writer_.__out_it());
473e78f53d1SNikolas Klauser       __writer_.__flush(__ptr, __s);
474e78f53d1SNikolas Klauser     }
475e78f53d1SNikolas Klauser 
476e78f53d1SNikolas Klauser     __size_ += __n;
477e78f53d1SNikolas Klauser   }
478e78f53d1SNikolas Klauser 
479e78f53d1SNikolas Klauser protected:
480e78f53d1SNikolas Klauser   __internal_storage<_CharT> __storage_;
481e78f53d1SNikolas Klauser   __output_buffer<_CharT> __output_;
482e78f53d1SNikolas Klauser   __writer_direct<_OutIt, _CharT> __writer_;
483e78f53d1SNikolas Klauser 
484e78f53d1SNikolas Klauser   _Size __max_size_;
485e78f53d1SNikolas Klauser   _Size __size_{0};
486e78f53d1SNikolas Klauser };
487e78f53d1SNikolas Klauser 
488e78f53d1SNikolas Klauser /// The buffer that counts and limits the number of insertions.
489e78f53d1SNikolas Klauser template <class _OutIt, __fmt_char_type _CharT>
490e78f53d1SNikolas Klauser   requires(output_iterator<_OutIt, const _CharT&>)
491e78f53d1SNikolas Klauser struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
492e78f53d1SNikolas Klauser     : public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> {
493e78f53d1SNikolas Klauser   using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>;
494e78f53d1SNikolas Klauser   using _Size = iter_difference_t<_OutIt>;
495e78f53d1SNikolas Klauser 
496e78f53d1SNikolas Klauser public:
497e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size)
498e78f53d1SNikolas Klauser       : _Base(std::move(__out_it), __max_size) {}
499e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); }
500e78f53d1SNikolas Klauser 
501e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
502e78f53d1SNikolas Klauser     this->__output_.__flush();
503e78f53d1SNikolas Klauser     return {std::move(this->__writer_).__out_it(), this->__size_};
504e78f53d1SNikolas Klauser   }
505e78f53d1SNikolas Klauser };
506e78f53d1SNikolas Klauser 
507e78f53d1SNikolas Klauser // A dynamically growing buffer intended to be used for retargeting a context.
508e78f53d1SNikolas Klauser //
509e78f53d1SNikolas Klauser // P2286 Formatting ranges adds range formatting support. It allows the user to
510e78f53d1SNikolas Klauser // specify the minimum width for the entire formatted range.  The width of the
511e78f53d1SNikolas Klauser // range is not known until the range is formatted. Formatting is done to an
512e78f53d1SNikolas Klauser // output_iterator so there's no guarantee it would be possible to add the fill
513e78f53d1SNikolas Klauser // to the front of the output. Instead the range is formatted to a temporary
514e78f53d1SNikolas Klauser // buffer and that buffer is formatted as a string.
515e78f53d1SNikolas Klauser //
516e78f53d1SNikolas Klauser // There is an issue with that approach, the format context used in
517e78f53d1SNikolas Klauser // std::formatter<T>::format contains the output iterator used as part of its
518e78f53d1SNikolas Klauser // type. So using this output iterator means there needs to be a new format
519e78f53d1SNikolas Klauser // context and the format arguments need to be retargeted to the new context.
520e78f53d1SNikolas Klauser // This retargeting is done by a basic_format_context specialized for the
521e78f53d1SNikolas Klauser // __iterator of this container.
522e78f53d1SNikolas Klauser //
523e78f53d1SNikolas Klauser // This class uses its own buffer management, since using vector
524e78f53d1SNikolas Klauser // would lead to a circular include with formatter for vector<bool>.
525e78f53d1SNikolas Klauser template <__fmt_char_type _CharT>
526e78f53d1SNikolas Klauser class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
527e78f53d1SNikolas Klauser   using _Alloc = allocator<_CharT>;
528e78f53d1SNikolas Klauser 
529e78f53d1SNikolas Klauser public:
530e78f53d1SNikolas Klauser   using value_type = _CharT;
531e78f53d1SNikolas Klauser 
532e78f53d1SNikolas Klauser   struct __iterator {
533e78f53d1SNikolas Klauser     using difference_type = ptrdiff_t;
534e78f53d1SNikolas Klauser     using value_type      = _CharT;
535e78f53d1SNikolas Klauser 
536e78f53d1SNikolas Klauser     _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
537e78f53d1SNikolas Klauser         : __buffer_(std::addressof(__buffer)) {}
538e78f53d1SNikolas Klauser     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {
539e78f53d1SNikolas Klauser       __buffer_->push_back(__c);
540e78f53d1SNikolas Klauser       return *this;
541e78f53d1SNikolas Klauser     }
542e78f53d1SNikolas Klauser     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {
543e78f53d1SNikolas Klauser       __buffer_->push_back(__c);
544e78f53d1SNikolas Klauser       return *this;
545e78f53d1SNikolas Klauser     }
546e78f53d1SNikolas Klauser 
547e78f53d1SNikolas Klauser     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }
548e78f53d1SNikolas Klauser     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }
549e78f53d1SNikolas Klauser     _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }
550e78f53d1SNikolas Klauser     __retarget_buffer* __buffer_;
551e78f53d1SNikolas Klauser   };
552e78f53d1SNikolas Klauser 
553e78f53d1SNikolas Klauser   __retarget_buffer(const __retarget_buffer&)            = delete;
554e78f53d1SNikolas Klauser   __retarget_buffer& operator=(const __retarget_buffer&) = delete;
555e78f53d1SNikolas Klauser 
556e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {
557e78f53d1SNikolas Klauser     // When the initial size is very small a lot of resizes happen
558e78f53d1SNikolas Klauser     // when elements added. So use a hard-coded minimum size.
559e78f53d1SNikolas Klauser     //
560e78f53d1SNikolas Klauser     // Note a size < 2 will not work
561e78f53d1SNikolas Klauser     // - 0 there is no buffer, while push_back requires 1 empty element.
562e78f53d1SNikolas Klauser     // - 1 multiplied by the grow factor is 1 and thus the buffer never
563e78f53d1SNikolas Klauser     //   grows.
564e78f53d1SNikolas Klauser     auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT)));
565e78f53d1SNikolas Klauser     __ptr_        = __result.ptr;
566e78f53d1SNikolas Klauser     __capacity_   = __result.count;
567e78f53d1SNikolas Klauser   }
568e78f53d1SNikolas Klauser 
569e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {
570e78f53d1SNikolas Klauser     ranges::destroy_n(__ptr_, __size_);
571e78f53d1SNikolas Klauser     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
572e78f53d1SNikolas Klauser   }
573e78f53d1SNikolas Klauser 
574e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
575e78f53d1SNikolas Klauser 
576e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
577e78f53d1SNikolas Klauser     std::construct_at(__ptr_ + __size_, __c);
578e78f53d1SNikolas Klauser     ++__size_;
579e78f53d1SNikolas Klauser 
580e78f53d1SNikolas Klauser     if (__size_ == __capacity_)
581e78f53d1SNikolas Klauser       __grow_buffer();
582e78f53d1SNikolas Klauser   }
583e78f53d1SNikolas Klauser 
584e78f53d1SNikolas Klauser   template <__fmt_char_type _InCharT>
585e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
586e78f53d1SNikolas Klauser     size_t __n = __str.size();
587e78f53d1SNikolas Klauser     if (__size_ + __n >= __capacity_)
588e78f53d1SNikolas Klauser       // Push_back requires the buffer to have room for at least one character.
589e78f53d1SNikolas Klauser       __grow_buffer(__size_ + __n + 1);
590e78f53d1SNikolas Klauser 
591e78f53d1SNikolas Klauser     std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);
592e78f53d1SNikolas Klauser     __size_ += __n;
593e78f53d1SNikolas Klauser   }
594e78f53d1SNikolas Klauser 
595e78f53d1SNikolas Klauser   template <contiguous_iterator _Iterator,
596e78f53d1SNikolas Klauser             class _UnaryOperation,
597e78f53d1SNikolas Klauser             __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
598e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
599e78f53d1SNikolas Klauser     _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
600e78f53d1SNikolas Klauser 
601e78f53d1SNikolas Klauser     size_t __n = static_cast<size_t>(__last - __first);
602e78f53d1SNikolas Klauser     if (__size_ + __n >= __capacity_)
603e78f53d1SNikolas Klauser       // Push_back requires the buffer to have room for at least one character.
604e78f53d1SNikolas Klauser       __grow_buffer(__size_ + __n + 1);
605e78f53d1SNikolas Klauser 
606e78f53d1SNikolas Klauser     std::uninitialized_default_construct_n(__ptr_ + __size_, __n);
607e78f53d1SNikolas Klauser     std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));
608e78f53d1SNikolas Klauser     __size_ += __n;
609e78f53d1SNikolas Klauser   }
610e78f53d1SNikolas Klauser 
611e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
612e78f53d1SNikolas Klauser     if (__size_ + __n >= __capacity_)
613e78f53d1SNikolas Klauser       // Push_back requires the buffer to have room for at least one character.
614e78f53d1SNikolas Klauser       __grow_buffer(__size_ + __n + 1);
615e78f53d1SNikolas Klauser 
616e78f53d1SNikolas Klauser     std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);
617e78f53d1SNikolas Klauser     __size_ += __n;
618e78f53d1SNikolas Klauser   }
619e78f53d1SNikolas Klauser 
620e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }
621e78f53d1SNikolas Klauser 
622e78f53d1SNikolas Klauser private:
623e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
624e78f53d1SNikolas Klauser 
625e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
626e78f53d1SNikolas Klauser     _LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow");
627e78f53d1SNikolas Klauser     auto __result = std::__allocate_at_least(__alloc_, __capacity);
628e78f53d1SNikolas Klauser     auto __guard  = std::__make_exception_guard([&] {
629e78f53d1SNikolas Klauser       allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
630e78f53d1SNikolas Klauser     });
631e78f53d1SNikolas Klauser     // This shouldn't throw, but just to be safe. Note that at -O1 this
632e78f53d1SNikolas Klauser     // guard is optimized away so there is no runtime overhead.
633e78f53d1SNikolas Klauser     std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
634e78f53d1SNikolas Klauser     __guard.__complete();
635e78f53d1SNikolas Klauser     ranges::destroy_n(__ptr_, __size_);
636e78f53d1SNikolas Klauser     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
637e78f53d1SNikolas Klauser 
638e78f53d1SNikolas Klauser     __ptr_      = __result.ptr;
639e78f53d1SNikolas Klauser     __capacity_ = __result.count;
640e78f53d1SNikolas Klauser   }
641e78f53d1SNikolas Klauser   _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
642e78f53d1SNikolas Klauser   _CharT* __ptr_;
643e78f53d1SNikolas Klauser   size_t __capacity_;
644e78f53d1SNikolas Klauser   size_t __size_{0};
645e78f53d1SNikolas Klauser };
646e78f53d1SNikolas Klauser 
647e78f53d1SNikolas Klauser } // namespace __format
648e78f53d1SNikolas Klauser 
649e78f53d1SNikolas Klauser #endif //_LIBCPP_STD_VER >= 20
650e78f53d1SNikolas Klauser 
651e78f53d1SNikolas Klauser _LIBCPP_END_NAMESPACE_STD
652e78f53d1SNikolas Klauser 
653e78f53d1SNikolas Klauser _LIBCPP_POP_MACROS
654e78f53d1SNikolas Klauser 
655*ce777190SNikolas Klauser #endif // _LIBCPP___CXX03___FORMAT_BUFFER_H
656