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