2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___CXX03___FORMAT_BUFFER_H
11 #define _LIBCPP___CXX03___FORMAT_BUFFER_H
13 #include <__cxx03/__algorithm/copy_n.h>
14 #include <__cxx03/__algorithm/fill_n.h>
15 #include <__cxx03/__algorithm/max.h>
16 #include <__cxx03/__algorithm/min.h>
17 #include <__cxx03/__algorithm/ranges_copy_n.h>
18 #include <__cxx03/__algorithm/transform.h>
19 #include <__cxx03/__algorithm/unwrap_iter.h>
20 #include <__cxx03/__concepts/same_as.h>
21 #include <__cxx03/__config>
22 #include <__cxx03/__format/concepts.h>
23 #include <__cxx03/__format/enable_insertable.h>
24 #include <__cxx03/__format/format_to_n_result.h>
25 #include <__cxx03/__iterator/back_insert_iterator.h>
26 #include <__cxx03/__iterator/concepts.h>
27 #include <__cxx03/__iterator/incrementable_traits.h>
28 #include <__cxx03/__iterator/iterator_traits.h>
29 #include <__cxx03/__iterator/wrap_iter.h>
30 #include <__cxx03/__memory/addressof.h>
31 #include <__cxx03/__memory/allocate_at_least.h>
32 #include <__cxx03/__memory/allocator_traits.h>
33 #include <__cxx03/__memory/construct_at.h>
34 #include <__cxx03/__memory/ranges_construct_at.h>
35 #include <__cxx03/__memory/uninitialized_algorithms.h>
36 #include <__cxx03/__type_traits/add_pointer.h>
37 #include <__cxx03/__type_traits/conditional.h>
38 #include <__cxx03/__utility/exception_guard.h>
39 #include <__cxx03/__utility/move.h>
40 #include <__cxx03/cstddef>
41 #include <__cxx03/string_view>
43 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
44 # pragma GCC system_header
48 #include <__cxx03/__undef_macros>
50 _LIBCPP_BEGIN_NAMESPACE_STD
52 #if _LIBCPP_STD_VER >= 20
56 /// A "buffer" that handles writing to the proper iterator.
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
{
64 using value_type
= _CharT
;
67 _LIBCPP_HIDE_FROM_ABI
explicit __output_buffer(_CharT
* __ptr
, size_t __capacity
, _Tp
* __obj
)
69 __capacity_(__capacity
),
70 __flush_([](_CharT
* __p
, size_t __n
, void* __o
) { static_cast<_Tp
*>(__o
)->__flush(__p
, __n
); }),
73 _LIBCPP_HIDE_FROM_ABI
void __reset(_CharT
* __ptr
, size_t __capacity
) {
75 __capacity_
= __capacity
;
78 _LIBCPP_HIDE_FROM_ABI
auto __make_output_iterator() { return std::back_insert_iterator
{*this}; }
80 // Used in std::back_insert_iterator.
81 _LIBCPP_HIDE_FROM_ABI
void push_back(_CharT __c
) {
82 __ptr_
[__size_
++] = __c
;
84 // Profiling showed flushing after adding is more efficient than flushing
85 // when entering the function.
86 if (__size_
== __capacity_
)
90 /// Copies the input __str to the buffer.
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 // that adding a large string to 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();
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 std::copy_n(__str
.data(), __n
, std::addressof(__ptr_
[__size_
]));
116 // The output doesn't fit in the internal buffer.
117 // Copy the data in "__capacity_" sized chunks.
118 _LIBCPP_ASSERT_INTERNAL(__size_
== 0, "the buffer should be flushed by __flush_on_overflow");
119 const _InCharT
* __first
= __str
.data();
121 size_t __chunk
= std::min(__n
, __capacity_
);
122 std::copy_n(__first
, __chunk
, std::addressof(__ptr_
[__size_
]));
130 /// A std::transform wrapper.
132 /// Like @ref __copy it may need to do type conversion.
133 template <contiguous_iterator _Iterator
,
134 class _UnaryOperation
,
135 __fmt_char_type _InCharT
= typename iterator_traits
<_Iterator
>::value_type
>
136 _LIBCPP_HIDE_FROM_ABI
void __transform(_Iterator __first
, _Iterator __last
, _UnaryOperation __operation
) {
137 _LIBCPP_ASSERT_INTERNAL(__first
<= __last
, "not a valid range");
139 size_t __n
= static_cast<size_t>(__last
- __first
);
140 __flush_on_overflow(__n
);
141 if (__n
< __capacity_
) { // push_back requires the buffer to have room for at least one character (so use <).
142 std::transform(__first
, __last
, std::addressof(__ptr_
[__size_
]), std::move(__operation
));
147 // The output doesn't fit in the internal buffer.
148 // Transform the data in "__capacity_" sized chunks.
149 _LIBCPP_ASSERT_INTERNAL(__size_
== 0, "the buffer should be flushed by __flush_on_overflow");
151 size_t __chunk
= std::min(__n
, __capacity_
);
152 std::transform(__first
, __first
+ __chunk
, std::addressof(__ptr_
[__size_
]), __operation
);
160 /// A \c fill_n wrapper.
161 _LIBCPP_HIDE_FROM_ABI
void __fill(size_t __n
, _CharT __value
) {
162 __flush_on_overflow(__n
);
163 if (__n
< __capacity_
) { // push_back requires the buffer to have room for at least one character (so use <).
164 std::fill_n(std::addressof(__ptr_
[__size_
]), __n
, __value
);
169 // The output doesn't fit in the internal buffer.
170 // Fill the buffer in "__capacity_" sized chunks.
171 _LIBCPP_ASSERT_INTERNAL(__size_
== 0, "the buffer should be flushed by __flush_on_overflow");
173 size_t __chunk
= std::min(__n
, __capacity_
);
174 std::fill_n(std::addressof(__ptr_
[__size_
]), __chunk
, __value
);
181 _LIBCPP_HIDE_FROM_ABI
void __flush() {
182 __flush_(__ptr_
, __size_
, __obj_
);
190 void (*__flush_
)(_CharT
*, size_t, void*);
193 /// Flushes the buffer when the output operation would overflow the buffer.
195 /// A simple approach for the overflow detection would be something along the
198 /// // The internal buffer is large enough.
199 /// if (__n <= __capacity_) {
200 /// // Flush when we really would overflow.
201 /// if (__size_ + __n >= __capacity_)
207 /// This approach works for all cases but one:
208 /// A __format_to_n_buffer_base where \ref __enable_direct_output is true.
209 /// In that case the \ref __capacity_ of the buffer changes during the first
210 /// \ref __flush. During that operation the output buffer switches from its
211 /// __writer_ to its __storage_. The \ref __capacity_ of the former depends
212 /// on the value of n, of the latter is a fixed size. For example:
213 /// - a format_to_n call with a 10'000 char buffer,
214 /// - the buffer is filled with 9'500 chars,
215 /// - adding 1'000 elements would overflow the buffer so the buffer gets
216 /// changed and the \ref __capacity_ decreases from 10'000 to
217 /// __buffer_size (256 at the time of writing).
219 /// This means that the \ref __flush for this class may need to copy a part of
220 /// the internal buffer to the proper output. In this example there will be
221 /// 500 characters that need this copy operation.
223 /// Note it would be more efficient to write 500 chars directly and then swap
224 /// the buffers. This would make the code more complex and \ref format_to_n is
225 /// not the most common use case. Therefore the optimization isn't done.
226 _LIBCPP_HIDE_FROM_ABI
void __flush_on_overflow(size_t __n
) {
227 if (__size_
+ __n
>= __capacity_
)
232 /// A storage using an internal buffer.
234 /// This storage is used when writing a single element to the output iterator
236 template <__fmt_char_type _CharT
>
237 class _LIBCPP_TEMPLATE_VIS __internal_storage
{
239 _LIBCPP_HIDE_FROM_ABI _CharT
* __begin() { return __buffer_
; }
241 static constexpr size_t __buffer_size
= 256 / sizeof(_CharT
);
244 _CharT __buffer_
[__buffer_size
];
247 /// A storage writing directly to the storage.
249 /// This requires the storage to be a contiguous buffer of \a _CharT.
250 /// Since the output is directly written to the underlying storage this class
251 /// is just an empty class.
252 template <__fmt_char_type _CharT
>
253 class _LIBCPP_TEMPLATE_VIS __direct_storage
{};
255 template <class _OutIt
, class _CharT
>
256 concept __enable_direct_output
=
257 __fmt_char_type
<_CharT
> &&
258 (same_as
<_OutIt
, _CharT
*>
259 // TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
261 || same_as
<_OutIt
, __wrap_iter
<_CharT
*>>);
263 /// Write policy for directly writing to the underlying output.
264 template <class _OutIt
, __fmt_char_type _CharT
>
265 class _LIBCPP_TEMPLATE_VIS __writer_direct
{
267 _LIBCPP_HIDE_FROM_ABI
explicit __writer_direct(_OutIt __out_it
) : __out_it_(__out_it
) {}
269 _LIBCPP_HIDE_FROM_ABI _OutIt
__out_it() { return __out_it_
; }
271 _LIBCPP_HIDE_FROM_ABI
void __flush(_CharT
*, size_t __n
) {
272 // _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator
281 /// Write policy for copying the buffer to the output.
282 template <class _OutIt
, __fmt_char_type _CharT
>
283 class _LIBCPP_TEMPLATE_VIS __writer_iterator
{
285 _LIBCPP_HIDE_FROM_ABI
explicit __writer_iterator(_OutIt __out_it
) : __out_it_
{std::move(__out_it
)} {}
287 _LIBCPP_HIDE_FROM_ABI _OutIt
__out_it() && { return std::move(__out_it_
); }
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
;
297 /// Concept to see whether a \a _Container is insertable.
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.
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
,
308 add_pointer_t
<typename
_Container::value_type
> __first
,
309 add_pointer_t
<typename
_Container::value_type
> __last
) { __t
.insert(__t
.end(), __first
, __last
); };
311 /// Extract the container type of a \ref back_insert_iterator.
313 struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container
{
317 template <__insertable _Container
>
318 struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container
<back_insert_iterator
<_Container
>> {
319 using type
= _Container
;
322 /// Write policy for inserting the buffer in a container.
323 template <class _Container
>
324 class _LIBCPP_TEMPLATE_VIS __writer_container
{
326 using _CharT
= typename
_Container::value_type
;
328 _LIBCPP_HIDE_FROM_ABI
explicit __writer_container(back_insert_iterator
<_Container
> __out_it
)
329 : __container_
{__out_it
.__get_container()} {}
331 _LIBCPP_HIDE_FROM_ABI
auto __out_it() { return std::back_inserter(*__container_
); }
333 _LIBCPP_HIDE_FROM_ABI
void __flush(_CharT
* __ptr
, size_t __n
) {
334 __container_
->insert(__container_
->end(), __ptr
, __ptr
+ __n
);
338 _Container
* __container_
;
341 /// Selects the type of the writer used for the output iterator.
342 template <class _OutIt
, class _CharT
>
343 class _LIBCPP_TEMPLATE_VIS __writer_selector
{
344 using _Container
= typename __back_insert_iterator_container
<_OutIt
>::type
;
348 conditional_t
<!same_as
<_Container
, void>,
349 __writer_container
<_Container
>,
350 conditional_t
<__enable_direct_output
<_OutIt
, _CharT
>,
351 __writer_direct
<_OutIt
, _CharT
>,
352 __writer_iterator
<_OutIt
, _CharT
>>>;
355 /// The generic formatting buffer.
356 template <class _OutIt
, __fmt_char_type _CharT
>
357 requires(output_iterator
<_OutIt
, const _CharT
&>)
358 class _LIBCPP_TEMPLATE_VIS __format_buffer
{
360 conditional_t
<__enable_direct_output
<_OutIt
, _CharT
>, __direct_storage
<_CharT
>, __internal_storage
<_CharT
>>;
363 _LIBCPP_HIDE_FROM_ABI
explicit __format_buffer(_OutIt __out_it
)
364 requires(same_as
<_Storage
, __internal_storage
<_CharT
>>)
365 : __output_(__storage_
.__begin(), __storage_
.__buffer_size
, this), __writer_(std::move(__out_it
)) {}
367 _LIBCPP_HIDE_FROM_ABI
explicit __format_buffer(_OutIt __out_it
)
368 requires(same_as
<_Storage
, __direct_storage
<_CharT
>>)
369 : __output_(std::__unwrap_iter(__out_it
), size_t(-1), this), __writer_(std::move(__out_it
)) {}
371 _LIBCPP_HIDE_FROM_ABI
auto __make_output_iterator() { return __output_
.__make_output_iterator(); }
373 _LIBCPP_HIDE_FROM_ABI
void __flush(_CharT
* __ptr
, size_t __n
) { __writer_
.__flush(__ptr
, __n
); }
375 _LIBCPP_HIDE_FROM_ABI _OutIt
__out_it() && {
377 return std::move(__writer_
).__out_it();
381 _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_
;
382 __output_buffer
<_CharT
> __output_
;
383 typename __writer_selector
<_OutIt
, _CharT
>::type __writer_
;
386 /// A buffer that counts the number of insertions.
388 /// Since \ref formatted_size only needs to know the size, the output itself is
390 template <__fmt_char_type _CharT
>
391 class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer
{
393 _LIBCPP_HIDE_FROM_ABI
auto __make_output_iterator() { return __output_
.__make_output_iterator(); }
395 _LIBCPP_HIDE_FROM_ABI
void __flush(const _CharT
*, size_t __n
) { __size_
+= __n
; }
397 _LIBCPP_HIDE_FROM_ABI
size_t __result() && {
403 __internal_storage
<_CharT
> __storage_
;
404 __output_buffer
<_CharT
> __output_
{__storage_
.__begin(), __storage_
.__buffer_size
, this};
408 /// The base of a buffer that counts and limits the number of insertions.
409 template <class _OutIt
, __fmt_char_type _CharT
, bool>
410 requires(output_iterator
<_OutIt
, const _CharT
&>)
411 struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base
{
412 using _Size
= iter_difference_t
<_OutIt
>;
415 _LIBCPP_HIDE_FROM_ABI
explicit __format_to_n_buffer_base(_OutIt __out_it
, _Size __max_size
)
416 : __writer_(std::move(__out_it
)), __max_size_(std::max(_Size(0), __max_size
)) {}
418 _LIBCPP_HIDE_FROM_ABI
void __flush(_CharT
* __ptr
, size_t __n
) {
419 if (_Size(__size_
) <= __max_size_
)
420 __writer_
.__flush(__ptr
, std::min(_Size(__n
), __max_size_
- __size_
));
425 __internal_storage
<_CharT
> __storage_
;
426 __output_buffer
<_CharT
> __output_
{__storage_
.__begin(), __storage_
.__buffer_size
, this};
427 typename __writer_selector
<_OutIt
, _CharT
>::type __writer_
;
433 /// The base of a buffer that counts and limits the number of insertions.
435 /// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true.
437 /// This class limits the size available to the direct writer so it will not
438 /// exceed the maximum number of code units.
439 template <class _OutIt
, __fmt_char_type _CharT
>
440 requires(output_iterator
<_OutIt
, const _CharT
&>)
441 class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base
<_OutIt
, _CharT
, true> {
442 using _Size
= iter_difference_t
<_OutIt
>;
445 _LIBCPP_HIDE_FROM_ABI
explicit __format_to_n_buffer_base(_OutIt __out_it
, _Size __max_size
)
446 : __output_(std::__unwrap_iter(__out_it
), __max_size
, this),
447 __writer_(std::move(__out_it
)),
448 __max_size_(__max_size
) {
449 if (__max_size
<= 0) [[unlikely
]]
450 __output_
.__reset(__storage_
.__begin(), __storage_
.__buffer_size
);
453 _LIBCPP_HIDE_FROM_ABI
void __flush(_CharT
* __ptr
, size_t __n
) {
454 // A __flush to the direct writer happens in the following occasions:
455 // - The format function has written the maximum number of allowed code
456 // units. At this point it's no longer valid to write to this writer. So
457 // switch to the internal storage. This internal storage doesn't need to
458 // be written anywhere so the __flush for that storage writes no output.
459 // - Like above, but the next "mass write" operation would overflow the
460 // buffer. In that case the buffer is pre-emptively switched. The still
461 // valid code units will be written separately.
462 // - The format_to_n function is finished. In this case there's no need to
463 // switch the buffer, but for simplicity the buffers are still switched.
464 // When the __max_size <= 0 the constructor already switched the buffers.
465 if (__size_
== 0 && __ptr
!= __storage_
.__begin()) {
466 __writer_
.__flush(__ptr
, __n
);
467 __output_
.__reset(__storage_
.__begin(), __storage_
.__buffer_size
);
468 } else if (__size_
< __max_size_
) {
469 // Copies a part of the internal buffer to the output up to n characters.
470 // See __output_buffer<_CharT>::__flush_on_overflow for more information.
471 _Size __s
= std::min(_Size(__n
), __max_size_
- __size_
);
472 std::copy_n(__ptr
, __s
, __writer_
.__out_it());
473 __writer_
.__flush(__ptr
, __s
);
480 __internal_storage
<_CharT
> __storage_
;
481 __output_buffer
<_CharT
> __output_
;
482 __writer_direct
<_OutIt
, _CharT
> __writer_
;
488 /// The buffer that counts and limits the number of insertions.
489 template <class _OutIt
, __fmt_char_type _CharT
>
490 requires(output_iterator
<_OutIt
, const _CharT
&>)
491 struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
492 : public __format_to_n_buffer_base
< _OutIt
, _CharT
, __enable_direct_output
<_OutIt
, _CharT
>> {
493 using _Base
= __format_to_n_buffer_base
<_OutIt
, _CharT
, __enable_direct_output
<_OutIt
, _CharT
>>;
494 using _Size
= iter_difference_t
<_OutIt
>;
497 _LIBCPP_HIDE_FROM_ABI
explicit __format_to_n_buffer(_OutIt __out_it
, _Size __max_size
)
498 : _Base(std::move(__out_it
), __max_size
) {}
499 _LIBCPP_HIDE_FROM_ABI
auto __make_output_iterator() { return this->__output_
.__make_output_iterator(); }
501 _LIBCPP_HIDE_FROM_ABI format_to_n_result
<_OutIt
> __result() && {
502 this->__output_
.__flush();
503 return {std::move(this->__writer_
).__out_it(), this->__size_
};
507 // A dynamically growing buffer intended to be used for retargeting a context.
509 // P2286 Formatting ranges adds range formatting support. It allows the user to
510 // specify the minimum width for the entire formatted range. The width of the
511 // range is not known until the range is formatted. Formatting is done to an
512 // output_iterator so there's no guarantee it would be possible to add the fill
513 // to the front of the output. Instead the range is formatted to a temporary
514 // buffer and that buffer is formatted as a string.
516 // There is an issue with that approach, the format context used in
517 // std::formatter<T>::format contains the output iterator used as part of its
518 // type. So using this output iterator means there needs to be a new format
519 // context and the format arguments need to be retargeted to the new context.
520 // This retargeting is done by a basic_format_context specialized for the
521 // __iterator of this container.
523 // This class uses its own buffer management, since using vector
524 // would lead to a circular include with formatter for vector<bool>.
525 template <__fmt_char_type _CharT
>
526 class _LIBCPP_TEMPLATE_VIS __retarget_buffer
{
527 using _Alloc
= allocator
<_CharT
>;
530 using value_type
= _CharT
;
533 using difference_type
= ptrdiff_t;
534 using value_type
= _CharT
;
536 _LIBCPP_HIDE_FROM_ABI
constexpr explicit __iterator(__retarget_buffer
& __buffer
)
537 : __buffer_(std::addressof(__buffer
)) {}
538 _LIBCPP_HIDE_FROM_ABI
constexpr __iterator
& operator=(const _CharT
& __c
) {
539 __buffer_
->push_back(__c
);
542 _LIBCPP_HIDE_FROM_ABI
constexpr __iterator
& operator=(_CharT
&& __c
) {
543 __buffer_
->push_back(__c
);
547 _LIBCPP_HIDE_FROM_ABI
constexpr __iterator
& operator*() { return *this; }
548 _LIBCPP_HIDE_FROM_ABI
constexpr __iterator
& operator++() { return *this; }
549 _LIBCPP_HIDE_FROM_ABI
constexpr __iterator
operator++(int) { return *this; }
550 __retarget_buffer
* __buffer_
;
553 __retarget_buffer(const __retarget_buffer
&) = delete;
554 __retarget_buffer
& operator=(const __retarget_buffer
&) = delete;
556 _LIBCPP_HIDE_FROM_ABI
explicit __retarget_buffer(size_t __size_hint
) {
557 // When the initial size is very small a lot of resizes happen
558 // when elements added. So use a hard-coded minimum size.
560 // Note a size < 2 will not work
561 // - 0 there is no buffer, while push_back requires 1 empty element.
562 // - 1 multiplied by the grow factor is 1 and thus the buffer never
564 auto __result
= std::__allocate_at_least(__alloc_
, std::max(__size_hint
, 256 / sizeof(_CharT
)));
565 __ptr_
= __result
.ptr
;
566 __capacity_
= __result
.count
;
569 _LIBCPP_HIDE_FROM_ABI
~__retarget_buffer() {
570 ranges::destroy_n(__ptr_
, __size_
);
571 allocator_traits
<_Alloc
>::deallocate(__alloc_
, __ptr_
, __capacity_
);
574 _LIBCPP_HIDE_FROM_ABI __iterator
__make_output_iterator() { return __iterator
{*this}; }
576 _LIBCPP_HIDE_FROM_ABI
void push_back(_CharT __c
) {
577 std::construct_at(__ptr_
+ __size_
, __c
);
580 if (__size_
== __capacity_
)
584 template <__fmt_char_type _InCharT
>
585 _LIBCPP_HIDE_FROM_ABI
void __copy(basic_string_view
<_InCharT
> __str
) {
586 size_t __n
= __str
.size();
587 if (__size_
+ __n
>= __capacity_
)
588 // Push_back requires the buffer to have room for at least one character.
589 __grow_buffer(__size_
+ __n
+ 1);
591 std::uninitialized_copy_n(__str
.data(), __n
, __ptr_
+ __size_
);
595 template <contiguous_iterator _Iterator
,
596 class _UnaryOperation
,
597 __fmt_char_type _InCharT
= typename iterator_traits
<_Iterator
>::value_type
>
598 _LIBCPP_HIDE_FROM_ABI
void __transform(_Iterator __first
, _Iterator __last
, _UnaryOperation __operation
) {
599 _LIBCPP_ASSERT_INTERNAL(__first
<= __last
, "not a valid range");
601 size_t __n
= static_cast<size_t>(__last
- __first
);
602 if (__size_
+ __n
>= __capacity_
)
603 // Push_back requires the buffer to have room for at least one character.
604 __grow_buffer(__size_
+ __n
+ 1);
606 std::uninitialized_default_construct_n(__ptr_
+ __size_
, __n
);
607 std::transform(__first
, __last
, __ptr_
+ __size_
, std::move(__operation
));
611 _LIBCPP_HIDE_FROM_ABI
void __fill(size_t __n
, _CharT __value
) {
612 if (__size_
+ __n
>= __capacity_
)
613 // Push_back requires the buffer to have room for at least one character.
614 __grow_buffer(__size_
+ __n
+ 1);
616 std::uninitialized_fill_n(__ptr_
+ __size_
, __n
, __value
);
620 _LIBCPP_HIDE_FROM_ABI basic_string_view
<_CharT
> __view() { return {__ptr_
, __size_
}; }
623 _LIBCPP_HIDE_FROM_ABI
void __grow_buffer() { __grow_buffer(__capacity_
* 1.6); }
625 _LIBCPP_HIDE_FROM_ABI
void __grow_buffer(size_t __capacity
) {
626 _LIBCPP_ASSERT_INTERNAL(__capacity
> __capacity_
, "the buffer must grow");
627 auto __result
= std::__allocate_at_least(__alloc_
, __capacity
);
628 auto __guard
= std::__make_exception_guard([&] {
629 allocator_traits
<_Alloc
>::deallocate(__alloc_
, __result
.ptr
, __result
.count
);
631 // This shouldn't throw, but just to be safe. Note that at -O1 this
632 // guard is optimized away so there is no runtime overhead.
633 std::uninitialized_move_n(__ptr_
, __size_
, __result
.ptr
);
634 __guard
.__complete();
635 ranges::destroy_n(__ptr_
, __size_
);
636 allocator_traits
<_Alloc
>::deallocate(__alloc_
, __ptr_
, __capacity_
);
638 __ptr_
= __result
.ptr
;
639 __capacity_
= __result
.count
;
641 _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_
;
647 } // namespace __format
649 #endif //_LIBCPP_STD_VER >= 20
651 _LIBCPP_END_NAMESPACE_STD
655 #endif // _LIBCPP___CXX03___FORMAT_BUFFER_H