xref: /freebsd/contrib/llvm-project/libcxx/include/__format/buffer.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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.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.h>
33 #include <__memory/allocator_traits.h>
34 #include <__memory/construct_at.h>
35 #include <__memory/destroy.h>
36 #include <__memory/uninitialized_algorithms.h>
37 #include <__type_traits/add_pointer.h>
38 #include <__type_traits/conditional.h>
39 #include <__utility/exception_guard.h>
40 #include <__utility/move.h>
41 #include <stdexcept>
42 #include <string_view>
43 
44 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
45 #  pragma GCC system_header
46 #endif
47 
48 _LIBCPP_PUSH_MACROS
49 #include <__undef_macros>
50 
51 _LIBCPP_BEGIN_NAMESPACE_STD
52 
53 #if _LIBCPP_STD_VER >= 20
54 
55 namespace __format {
56 
57 // A helper to limit the total size of code units written.
58 class _LIBCPP_HIDE_FROM_ABI __max_output_size {
59 public:
__max_output_size(size_t __max_size)60   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __max_output_size(size_t __max_size) : __max_size_{__max_size} {}
61 
62   // This function adjusts the size of a (bulk) write operations. It ensures the
63   // number of code units written by a __output_buffer never exceeds
64   // __max_size_ code units.
__write_request(size_t __code_units)65   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __write_request(size_t __code_units) {
66     size_t __result =
67         __code_units_written_ < __max_size_ ? std::min(__code_units, __max_size_ - __code_units_written_) : 0;
68     __code_units_written_ += __code_units;
69     return __result;
70   }
71 
__code_units_written()72   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __code_units_written() const noexcept { return __code_units_written_; }
73 
74 private:
75   size_t __max_size_;
76   // The code units that would have been written if there was no limit.
77   // format_to_n returns this value.
78   size_t __code_units_written_{0};
79 };
80 
81 /// A "buffer" that handles writing to the proper iterator.
82 ///
83 /// This helper is used together with the @ref back_insert_iterator to offer
84 /// type-erasure for the formatting functions. This reduces the number to
85 /// template instantiations.
86 ///
87 /// The design is the following:
88 /// - There is an external object that connects the buffer to the output.
89 /// - This buffer object:
90 ///   - inherits publicly from this class.
91 ///   - has a static or dynamic buffer.
92 ///   - has a static member function to make space in its buffer write
93 ///     operations. This can be done by increasing the size of the internal
94 ///     buffer or by writing the contents of the buffer to the output iterator.
95 ///
96 ///     This member function is a constructor argument, so its name is not
97 ///     fixed. The code uses the name __prepare_write.
98 /// - The number of output code units can be limited by a __max_output_size
99 ///   object. This is used in format_to_n This object:
100 ///   - Contains the maximum number of code units to be written.
101 ///   - Contains the number of code units that are requested to be written.
102 ///     This number is returned to the user of format_to_n.
103 ///   - The write functions call the object's __request_write member function.
104 ///     This function:
105 ///     - Updates the number of code units that are requested to be written.
106 ///     - Returns the number of code units that can be written without
107 ///       exceeding the maximum number of code units to be written.
108 ///
109 /// Documentation for the buffer usage members:
110 /// - __ptr_
111 ///   The start of the buffer.
112 /// - __capacity_
113 ///   The number of code units that can be written. This means
114 ///   [__ptr_, __ptr_ + __capacity_) is a valid range to write to.
115 /// - __size_
116 ///   The number of code units written in the buffer. The next code unit will
117 ///   be written at __ptr_ + __size_. This __size_ may NOT contain the total
118 ///   number of code units written by the __output_buffer. Whether or not it
119 ///   does depends on the sub-class used. Typically the total number of code
120 ///   units written is not interesting. It is interesting for format_to_n which
121 ///   has its own way to track this number.
122 ///
123 /// Documentation for the modifying buffer operations:
124 /// The subclasses have a function with the following signature:
125 ///
126 ///   static void __prepare_write(
127 ///     __output_buffer<_CharT>& __buffer, size_t __code_units);
128 ///
129 /// This function is called when a write function writes more code units than
130 /// the buffer's available space. When an __max_output_size object is provided
131 /// the number of code units is the number of code units returned from
132 /// __max_output_size::__request_write function.
133 ///
134 /// - The __buffer contains *this. Since the class containing this function
135 ///   inherits from __output_buffer it's safe to cast it to the subclass being
136 ///   used.
137 /// - The __code_units is the number of code units the caller will write + 1.
138 ///   - This value does not take the available space of the buffer into account.
139 ///   - The push_back function is more efficient when writing before resizing,
140 ///     this means the buffer should always have room for one code unit. Hence
141 ///     the + 1 is the size.
142 /// - When the function returns there is room for at least one additional code
143 ///   unit. There is no requirement there is room for __code_units code units:
144 ///   - The class has some "bulk" operations. For example, __copy which copies
145 ///     the contents of a basic_string_view to the output. If the sub-class has
146 ///     a fixed size buffer the size of the basic_string_view may be larger
147 ///     than the buffer. In that case it's impossible to honor the requested
148 ///     size.
149 ///   - When the buffer has room for at least one code unit the function may be
150 ///     a no-op.
151 /// - When the function makes space for more code units it uses one for these
152 ///   functions to signal the change:
153 ///   - __buffer_flushed()
154 ///     - This function is typically used for a fixed sized buffer.
155 ///     - The current contents of [__ptr_, __ptr_ + __size_) have been
156 ///       processed.
157 ///     - __ptr_ remains unchanged.
158 ///     - __capacity_ remains unchanged.
159 ///     - __size_ will be set to 0.
160 ///   - __buffer_moved(_CharT* __ptr, size_t __capacity)
161 ///     - This function is typically used for a dynamic sized buffer. There the
162 ///       location of the buffer changes due to reallocations.
163 ///     - __ptr_ will be set to __ptr. (This value may be the old value of
164 ///       __ptr_).
165 ///     - __capacity_ will be set to __capacity. (This value may be the old
166 ///       value of __capacity_).
167 ///     - __size_ remains unchanged,
168 ///     - The range [__ptr, __ptr + __size_) contains the original data of the
169 ///       range [__ptr_, __ptr_ + __size_).
170 ///
171 /// The push_back function expects a valid buffer and a capacity of at least 1.
172 /// This means:
173 /// - The class is constructed with a valid buffer,
174 /// - __buffer_moved is called with a valid buffer is used before the first
175 ///   write operation,
176 /// - no write function is ever called, or
177 /// - the class is constructed with a __max_output_size object with __max_size 0.
178 ///
179 /// The latter option allows formatted_size to use the output buffer without
180 /// ever writing anything to the buffer.
181 template <__fmt_char_type _CharT>
182 class __output_buffer {
183 public:
184   using value_type _LIBCPP_NODEBUG           = _CharT;
185   using __prepare_write_type _LIBCPP_NODEBUG = void (*)(__output_buffer<_CharT>&, size_t);
186 
187   [[nodiscard]]
__output_buffer(_CharT * __ptr,size_t __capacity,__prepare_write_type __function)188   _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, __prepare_write_type __function)
189       : __output_buffer{__ptr, __capacity, __function, nullptr} {}
190 
__output_buffer(_CharT * __ptr,size_t __capacity,__prepare_write_type __function,__max_output_size * __max_output_size)191   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(
192       _CharT* __ptr, size_t __capacity, __prepare_write_type __function, __max_output_size* __max_output_size)
193       : __ptr_(__ptr), __capacity_(__capacity), __prepare_write_(__function), __max_output_size_(__max_output_size) {}
194 
__buffer_flushed()195   _LIBCPP_HIDE_FROM_ABI void __buffer_flushed() { __size_ = 0; }
196 
__buffer_moved(_CharT * __ptr,size_t __capacity)197   _LIBCPP_HIDE_FROM_ABI void __buffer_moved(_CharT* __ptr, size_t __capacity) {
198     __ptr_      = __ptr;
199     __capacity_ = __capacity;
200   }
201 
__make_output_iterator()202   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; }
203 
204   // Used in std::back_insert_iterator.
push_back(_CharT __c)205   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
206     if (__max_output_size_ && __max_output_size_->__write_request(1) == 0)
207       return;
208 
209     _LIBCPP_ASSERT_INTERNAL(
210         __ptr_ && __size_ < __capacity_ && __available() >= 1, "attempted to write outside the buffer");
211 
212     __ptr_[__size_++] = __c;
213 
214     // Profiling showed flushing after adding is more efficient than flushing
215     // when entering the function.
216     if (__size_ == __capacity_)
217       __prepare_write(0);
218   }
219 
220   /// Copies the input __str to the buffer.
221   ///
222   /// Since some of the input is generated by std::to_chars, there needs to be a
223   /// conversion when _CharT is wchar_t.
224   template <__fmt_char_type _InCharT>
__copy(basic_string_view<_InCharT> __str)225   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
226     // When the underlying iterator is a simple iterator the __capacity_ is
227     // infinite. For a string or container back_inserter it isn't. This means
228     // that adding a large string to the buffer can cause some overhead. In that
229     // case a better approach could be:
230     // - flush the buffer
231     // - container.append(__str.begin(), __str.end());
232     // The same holds true for the fill.
233     // For transform it might be slightly harder, however the use case for
234     // transform is slightly less common; it converts hexadecimal values to
235     // upper case. For integral these strings are short.
236     // TODO FMT Look at the improvements above.
237     size_t __n = __str.size();
238     if (__max_output_size_) {
239       __n = __max_output_size_->__write_request(__n);
240       if (__n == 0)
241         return;
242     }
243 
244     const _InCharT* __first = __str.data();
245     do {
246       __prepare_write(__n);
247       size_t __chunk = std::min(__n, __available());
248       std::copy_n(__first, __chunk, std::addressof(__ptr_[__size_]));
249       __size_ += __chunk;
250       __first += __chunk;
251       __n -= __chunk;
252     } while (__n);
253   }
254 
255   /// A std::transform wrapper.
256   ///
257   /// Like @ref __copy it may need to do type conversion.
258   template <contiguous_iterator _Iterator,
259             class _UnaryOperation,
260             __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
__transform(_Iterator __first,_Iterator __last,_UnaryOperation __operation)261   _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
262     _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
263 
264     size_t __n = static_cast<size_t>(__last - __first);
265     if (__max_output_size_) {
266       __n = __max_output_size_->__write_request(__n);
267       if (__n == 0)
268         return;
269     }
270 
271     do {
272       __prepare_write(__n);
273       size_t __chunk = std::min(__n, __available());
274       std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
275       __size_ += __chunk;
276       __first += __chunk;
277       __n -= __chunk;
278     } while (__n);
279   }
280 
281   /// A \c fill_n wrapper.
__fill(size_t __n,_CharT __value)282   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
283     if (__max_output_size_) {
284       __n = __max_output_size_->__write_request(__n);
285       if (__n == 0)
286         return;
287     }
288 
289     do {
290       __prepare_write(__n);
291       size_t __chunk = std::min(__n, __available());
292       std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
293       __size_ += __chunk;
294       __n -= __chunk;
295     } while (__n);
296   }
297 
__capacity()298   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __capacity() const { return __capacity_; }
__size()299   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __size() const { return __size_; }
300 
301 private:
302   _CharT* __ptr_;
303   size_t __capacity_;
304   size_t __size_{0};
305   void (*__prepare_write_)(__output_buffer<_CharT>&, size_t);
306   __max_output_size* __max_output_size_;
307 
__available()308   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __available() const { return __capacity_ - __size_; }
309 
__prepare_write(size_t __code_units)310   _LIBCPP_HIDE_FROM_ABI void __prepare_write(size_t __code_units) {
311     // Always have space for one additional code unit. This is a precondition of the push_back function.
312     __code_units += 1;
313     if (__available() < __code_units)
314       __prepare_write_(*this, __code_units + 1);
315   }
316 };
317 
318 template <class _OutIt, class _CharT>
319 concept __enable_direct_output =
320     __fmt_char_type<_CharT> &&
321     (same_as<_OutIt, _CharT*>
322      // TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
323      // `#ifdef`.
324      || same_as<_OutIt, __wrap_iter<_CharT*>>);
325 
326 /// Concept to see whether a \a _Container is insertable.
327 ///
328 /// The concept is used to validate whether multiple calls to a
329 /// \ref back_insert_iterator can be replace by a call to \c _Container::insert.
330 ///
331 /// \note a \a _Container needs to opt-in to the concept by specializing
332 /// \ref __enable_insertable.
333 template <class _Container>
334 concept __insertable =
335     __enable_insertable<_Container> && __fmt_char_type<typename _Container::value_type> &&
requires(_Container & __t,add_pointer_t<typename _Container::value_type> __first,add_pointer_t<typename _Container::value_type> __last)336     requires(_Container& __t,
337              add_pointer_t<typename _Container::value_type> __first,
338              add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };
339 
340 /// Extract the container type of a \ref back_insert_iterator.
341 template <class _It>
342 struct __back_insert_iterator_container {
343   using type _LIBCPP_NODEBUG = void;
344 };
345 
346 template <__insertable _Container>
347 struct __back_insert_iterator_container<back_insert_iterator<_Container>> {
348   using type _LIBCPP_NODEBUG = _Container;
349 };
350 
351 // A dynamically growing buffer.
352 template <__fmt_char_type _CharT>
353 class __allocating_buffer : public __output_buffer<_CharT> {
354 public:
355   __allocating_buffer(const __allocating_buffer&)            = delete;
356   __allocating_buffer& operator=(const __allocating_buffer&) = delete;
357 
358   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __allocating_buffer() : __allocating_buffer{nullptr} {}
359 
360   [[nodiscard]]
361   _LIBCPP_HIDE_FROM_ABI explicit __allocating_buffer(__max_output_size* __max_output_size)
362       : __output_buffer<_CharT>{__small_buffer_, __buffer_size_, __prepare_write, __max_output_size} {}
363 
364   _LIBCPP_HIDE_FROM_ABI ~__allocating_buffer() {
365     if (__ptr_ != __small_buffer_)
366       _Alloc{}.deallocate(__ptr_, this->__capacity());
367   }
368 
369   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, this->__size()}; }
370 
371 private:
372   using _Alloc _LIBCPP_NODEBUG = allocator<_CharT>;
373 
374   // Since allocating is expensive the class has a small internal buffer. When
375   // its capacity is exceeded a dynamic buffer will be allocated.
376   static constexpr size_t __buffer_size_ = 256;
377   _CharT __small_buffer_[__buffer_size_];
378 
379   _CharT* __ptr_{__small_buffer_};
380 
381   _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
382     if (__capacity < __buffer_size_)
383       return;
384 
385     _LIBCPP_ASSERT_INTERNAL(__capacity > this->__capacity(), "the buffer must grow");
386 
387     // _CharT is an implicit lifetime type so can be used without explicit
388     // construction or destruction.
389     _Alloc __alloc;
390     auto __result = std::__allocate_at_least(__alloc, __capacity);
391     std::copy_n(__ptr_, this->__size(), __result.ptr);
392     if (__ptr_ != __small_buffer_)
393       __alloc.deallocate(__ptr_, this->__capacity());
394 
395     __ptr_ = __result.ptr;
396     this->__buffer_moved(__ptr_, __result.count);
397   }
398 
399   _LIBCPP_HIDE_FROM_ABI void __prepare_write(size_t __size_hint) {
400     __grow_buffer(std::max<size_t>(this->__capacity() + __size_hint, this->__capacity() * 1.6));
401   }
402 
403   _LIBCPP_HIDE_FROM_ABI static void __prepare_write(__output_buffer<_CharT>& __buffer, size_t __size_hint) {
404     static_cast<__allocating_buffer<_CharT>&>(__buffer).__prepare_write(__size_hint);
405   }
406 };
407 
408 // A buffer that directly writes to the underlying buffer.
409 template <class _OutIt, __fmt_char_type _CharT>
410 class __direct_iterator_buffer : public __output_buffer<_CharT> {
411 public:
412   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __direct_iterator_buffer(_OutIt __out_it)
413       : __direct_iterator_buffer{__out_it, nullptr} {}
414 
415   [[nodiscard]]
416   _LIBCPP_HIDE_FROM_ABI explicit __direct_iterator_buffer(_OutIt __out_it, __max_output_size* __max_output_size)
417       : __output_buffer<_CharT>{std::__unwrap_iter(__out_it), __buffer_size, __prepare_write, __max_output_size},
418         __out_it_(__out_it) {}
419 
420   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return __out_it_ + this->__size(); }
421 
422 private:
423   // The function format_to expects a buffer large enough for the output. The
424   // function format_to_n has its own helper class that restricts the number of
425   // write options. So this function class can pretend to have an infinite
426   // buffer.
427   static constexpr size_t __buffer_size = -1;
428 
429   _OutIt __out_it_;
430 
431   _LIBCPP_HIDE_FROM_ABI static void
432   __prepare_write([[maybe_unused]] __output_buffer<_CharT>& __buffer, [[maybe_unused]] size_t __size_hint) {
433     std::__throw_length_error("__direct_iterator_buffer");
434   }
435 };
436 
437 // A buffer that writes its output to the end of a container.
438 template <class _OutIt, __fmt_char_type _CharT>
439 class __container_inserter_buffer : public __output_buffer<_CharT> {
440 public:
441   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __container_inserter_buffer(_OutIt __out_it)
442       : __container_inserter_buffer{__out_it, nullptr} {}
443 
444   [[nodiscard]]
445   _LIBCPP_HIDE_FROM_ABI explicit __container_inserter_buffer(_OutIt __out_it, __max_output_size* __max_output_size)
446       : __output_buffer<_CharT>{__small_buffer_, __buffer_size, __prepare_write, __max_output_size},
447         __container_{__out_it.__get_container()} {}
448 
449   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto __out_it() && {
450     __container_->insert(__container_->end(), __small_buffer_, __small_buffer_ + this->__size());
451     return std::back_inserter(*__container_);
452   }
453 
454 private:
455   typename __back_insert_iterator_container<_OutIt>::type* __container_;
456 
457   // This class uses a fixed size buffer and appends the elements in
458   // __buffer_size chunks. An alternative would be to use an allocating buffer
459   // and append the output in a single write operation. Benchmarking showed no
460   // performance difference.
461   static constexpr size_t __buffer_size = 256;
462   _CharT __small_buffer_[__buffer_size];
463 
464   _LIBCPP_HIDE_FROM_ABI void __prepare_write() {
465     __container_->insert(__container_->end(), __small_buffer_, __small_buffer_ + this->__size());
466     this->__buffer_flushed();
467   }
468 
469   _LIBCPP_HIDE_FROM_ABI static void
470   __prepare_write(__output_buffer<_CharT>& __buffer, [[maybe_unused]] size_t __size_hint) {
471     static_cast<__container_inserter_buffer<_OutIt, _CharT>&>(__buffer).__prepare_write();
472   }
473 };
474 
475 // A buffer that writes to an iterator.
476 //
477 // Unlike the __container_inserter_buffer this class' performance does benefit
478 // from allocating and then inserting.
479 template <class _OutIt, __fmt_char_type _CharT>
480 class __iterator_buffer : public __allocating_buffer<_CharT> {
481 public:
482   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __iterator_buffer(_OutIt __out_it)
483       : __allocating_buffer<_CharT>{}, __out_it_{std::move(__out_it)} {}
484 
485   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __iterator_buffer(_OutIt __out_it, __max_output_size* __max_output_size)
486       : __allocating_buffer<_CharT>{__max_output_size}, __out_it_{std::move(__out_it)} {}
487 
488   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto __out_it() && {
489     return std::ranges::copy(this->__view(), std::move(__out_it_)).out;
490   }
491 
492 private:
493   _OutIt __out_it_;
494 };
495 
496 // Selects the type of the buffer used for the output iterator.
497 template <class _OutIt, __fmt_char_type _CharT>
498 class __buffer_selector {
499   using _Container _LIBCPP_NODEBUG = __back_insert_iterator_container<_OutIt>::type;
500 
501 public:
502   using type _LIBCPP_NODEBUG =
503       conditional_t<!same_as<_Container, void>,
504                     __container_inserter_buffer<_OutIt, _CharT>,
505                     conditional_t<__enable_direct_output<_OutIt, _CharT>,
506                                   __direct_iterator_buffer<_OutIt, _CharT>,
507                                   __iterator_buffer<_OutIt, _CharT>>>;
508 };
509 
510 // A buffer that counts and limits the number of insertions.
511 template <class _OutIt, __fmt_char_type _CharT>
512 class __format_to_n_buffer : private __buffer_selector<_OutIt, _CharT>::type {
513 public:
514   using _Base _LIBCPP_NODEBUG = __buffer_selector<_OutIt, _CharT>::type;
515 
516   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __format_to_n_buffer(_OutIt __out_it, iter_difference_t<_OutIt> __n)
517       : _Base{std::move(__out_it), std::addressof(__max_output_size_)},
518         __max_output_size_{__n < 0 ? size_t{0} : static_cast<size_t>(__n)} {}
519 
520   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return _Base::__make_output_iterator(); }
521 
522   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
523     return {static_cast<_Base&&>(*this).__out_it(),
524             static_cast<iter_difference_t<_OutIt>>(__max_output_size_.__code_units_written())};
525   }
526 
527 private:
528   __max_output_size __max_output_size_;
529 };
530 
531 // A buffer that counts the number of insertions.
532 //
533 // Since formatted_size only needs to know the size, the output itself is
534 // discarded.
535 template <__fmt_char_type _CharT>
536 class __formatted_size_buffer : private __output_buffer<_CharT> {
537 public:
538   using _Base _LIBCPP_NODEBUG = __output_buffer<_CharT>;
539 
540   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __formatted_size_buffer()
541       : _Base{nullptr, 0, __prepare_write, std::addressof(__max_output_size_)} {}
542 
543   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return _Base::__make_output_iterator(); }
544 
545   // This function does not need to be r-value qualified, however this is
546   // consistent with similar objects.
547   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __result() && { return __max_output_size_.__code_units_written(); }
548 
549 private:
550   __max_output_size __max_output_size_{0};
551 
552   _LIBCPP_HIDE_FROM_ABI static void
553   __prepare_write([[maybe_unused]] __output_buffer<_CharT>& __buffer, [[maybe_unused]] size_t __size_hint) {
554     // Note this function does not satisfy the requirement of giving a 1 code unit buffer.
555     _LIBCPP_ASSERT_INTERNAL(
556         false, "Since __max_output_size_.__max_size_ == 0 there should never be call to this function.");
557   }
558 };
559 
560 // A dynamically growing buffer intended to be used for retargeting a context.
561 //
562 // P2286 Formatting ranges adds range formatting support. It allows the user to
563 // specify the minimum width for the entire formatted range.  The width of the
564 // range is not known until the range is formatted. Formatting is done to an
565 // output_iterator so there's no guarantee it would be possible to add the fill
566 // to the front of the output. Instead the range is formatted to a temporary
567 // buffer and that buffer is formatted as a string.
568 //
569 // There is an issue with that approach, the format context used in
570 // std::formatter<T>::format contains the output iterator used as part of its
571 // type. So using this output iterator means there needs to be a new format
572 // context and the format arguments need to be retargeted to the new context.
573 // This retargeting is done by a basic_format_context specialized for the
574 // __iterator of this container.
575 //
576 // This class uses its own buffer management, since using vector
577 // would lead to a circular include with formatter for vector<bool>.
578 template <__fmt_char_type _CharT>
579 class __retarget_buffer {
580   using _Alloc _LIBCPP_NODEBUG = allocator<_CharT>;
581 
582 public:
583   using value_type _LIBCPP_NODEBUG = _CharT;
584 
585   struct __iterator {
586     using difference_type _LIBCPP_NODEBUG = ptrdiff_t;
587     using value_type _LIBCPP_NODEBUG      = _CharT;
588 
589     _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
590         : __buffer_(std::addressof(__buffer)) {}
591     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {
592       __buffer_->push_back(__c);
593       return *this;
594     }
595     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {
596       __buffer_->push_back(__c);
597       return *this;
598     }
599 
600     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }
601     _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }
602     _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }
603     __retarget_buffer* __buffer_;
604   };
605 
606   __retarget_buffer(const __retarget_buffer&)            = delete;
607   __retarget_buffer& operator=(const __retarget_buffer&) = delete;
608 
609   _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {
610     // When the initial size is very small a lot of resizes happen
611     // when elements added. So use a hard-coded minimum size.
612     //
613     // Note a size < 2 will not work
614     // - 0 there is no buffer, while push_back requires 1 empty element.
615     // - 1 multiplied by the grow factor is 1 and thus the buffer never
616     //   grows.
617     auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT)));
618     __ptr_        = __result.ptr;
619     __capacity_   = __result.count;
620   }
621 
622   _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {
623     std::destroy_n(__ptr_, __size_);
624     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
625   }
626 
627   _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
628 
629   _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
630     std::construct_at(__ptr_ + __size_, __c);
631     ++__size_;
632 
633     if (__size_ == __capacity_)
634       __grow_buffer();
635   }
636 
637   template <__fmt_char_type _InCharT>
638   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
639     size_t __n = __str.size();
640     if (__size_ + __n >= __capacity_)
641       // Push_back requires the buffer to have room for at least one character.
642       __grow_buffer(__size_ + __n + 1);
643 
644     std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);
645     __size_ += __n;
646   }
647 
648   template <contiguous_iterator _Iterator,
649             class _UnaryOperation,
650             __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
651   _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
652     _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
653 
654     size_t __n = static_cast<size_t>(__last - __first);
655     if (__size_ + __n >= __capacity_)
656       // Push_back requires the buffer to have room for at least one character.
657       __grow_buffer(__size_ + __n + 1);
658 
659     std::uninitialized_default_construct_n(__ptr_ + __size_, __n);
660     std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));
661     __size_ += __n;
662   }
663 
664   _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
665     if (__size_ + __n >= __capacity_)
666       // Push_back requires the buffer to have room for at least one character.
667       __grow_buffer(__size_ + __n + 1);
668 
669     std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);
670     __size_ += __n;
671   }
672 
673   _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }
674 
675 private:
676   _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
677 
678   _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
679     _LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow");
680     auto __result = std::__allocate_at_least(__alloc_, __capacity);
681     auto __guard  = std::__make_exception_guard([&] {
682       allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
683     });
684     // This shouldn't throw, but just to be safe. Note that at -O1 this
685     // guard is optimized away so there is no runtime overhead.
686     std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
687     __guard.__complete();
688     std::destroy_n(__ptr_, __size_);
689     allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
690 
691     __ptr_      = __result.ptr;
692     __capacity_ = __result.count;
693   }
694   _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
695   _CharT* __ptr_;
696   size_t __capacity_;
697   size_t __size_{0};
698 };
699 
700 } // namespace __format
701 
702 #endif // _LIBCPP_STD_VER >= 20
703 
704 _LIBCPP_END_NAMESPACE_STD
705 
706 _LIBCPP_POP_MACROS
707 
708 #endif // _LIBCPP___FORMAT_BUFFER_H
709