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