Path: blob/main/contrib/llvm-project/libcxx/include/__format/buffer.h
35259 views
// -*- C++ -*-1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//89#ifndef _LIBCPP___FORMAT_BUFFER_H10#define _LIBCPP___FORMAT_BUFFER_H1112#include <__algorithm/copy_n.h>13#include <__algorithm/fill_n.h>14#include <__algorithm/max.h>15#include <__algorithm/min.h>16#include <__algorithm/ranges_copy_n.h>17#include <__algorithm/transform.h>18#include <__algorithm/unwrap_iter.h>19#include <__concepts/same_as.h>20#include <__config>21#include <__format/concepts.h>22#include <__format/enable_insertable.h>23#include <__format/format_to_n_result.h>24#include <__iterator/back_insert_iterator.h>25#include <__iterator/concepts.h>26#include <__iterator/incrementable_traits.h>27#include <__iterator/iterator_traits.h>28#include <__iterator/wrap_iter.h>29#include <__memory/addressof.h>30#include <__memory/allocate_at_least.h>31#include <__memory/allocator_traits.h>32#include <__memory/construct_at.h>33#include <__memory/ranges_construct_at.h>34#include <__memory/uninitialized_algorithms.h>35#include <__type_traits/add_pointer.h>36#include <__type_traits/conditional.h>37#include <__utility/exception_guard.h>38#include <__utility/move.h>39#include <cstddef>40#include <string_view>4142#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)43# pragma GCC system_header44#endif4546_LIBCPP_PUSH_MACROS47#include <__undef_macros>4849_LIBCPP_BEGIN_NAMESPACE_STD5051#if _LIBCPP_STD_VER >= 205253namespace __format {5455/// A "buffer" that handles writing to the proper iterator.56///57/// This helper is used together with the @ref back_insert_iterator to offer58/// type-erasure for the formatting functions. This reduces the number to59/// template instantiations.60template <__fmt_char_type _CharT>61class _LIBCPP_TEMPLATE_VIS __output_buffer {62public:63using value_type = _CharT;6465template <class _Tp>66_LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj)67: __ptr_(__ptr),68__capacity_(__capacity),69__flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }),70__obj_(__obj) {}7172_LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) {73__ptr_ = __ptr;74__capacity_ = __capacity;75}7677_LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; }7879// Used in std::back_insert_iterator.80_LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {81__ptr_[__size_++] = __c;8283// Profiling showed flushing after adding is more efficient than flushing84// when entering the function.85if (__size_ == __capacity_)86__flush();87}8889/// Copies the input __str to the buffer.90///91/// Since some of the input is generated by std::to_chars, there needs to be a92/// conversion when _CharT is wchar_t.93template <__fmt_char_type _InCharT>94_LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {95// When the underlying iterator is a simple iterator the __capacity_ is96// infinite. For a string or container back_inserter it isn't. This means97// that adding a large string to the buffer can cause some overhead. In that98// case a better approach could be:99// - flush the buffer100// - container.append(__str.begin(), __str.end());101// The same holds true for the fill.102// For transform it might be slightly harder, however the use case for103// transform is slightly less common; it converts hexadecimal values to104// upper case. For integral these strings are short.105// TODO FMT Look at the improvements above.106size_t __n = __str.size();107108__flush_on_overflow(__n);109if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).110std::copy_n(__str.data(), __n, std::addressof(__ptr_[__size_]));111__size_ += __n;112return;113}114115// The output doesn't fit in the internal buffer.116// Copy the data in "__capacity_" sized chunks.117_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");118const _InCharT* __first = __str.data();119do {120size_t __chunk = std::min(__n, __capacity_);121std::copy_n(__first, __chunk, std::addressof(__ptr_[__size_]));122__size_ = __chunk;123__first += __chunk;124__n -= __chunk;125__flush();126} while (__n);127}128129/// A std::transform wrapper.130///131/// Like @ref __copy it may need to do type conversion.132template <contiguous_iterator _Iterator,133class _UnaryOperation,134__fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>135_LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {136_LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");137138size_t __n = static_cast<size_t>(__last - __first);139__flush_on_overflow(__n);140if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).141std::transform(__first, __last, std::addressof(__ptr_[__size_]), std::move(__operation));142__size_ += __n;143return;144}145146// The output doesn't fit in the internal buffer.147// Transform the data in "__capacity_" sized chunks.148_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");149do {150size_t __chunk = std::min(__n, __capacity_);151std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);152__size_ = __chunk;153__first += __chunk;154__n -= __chunk;155__flush();156} while (__n);157}158159/// A \c fill_n wrapper.160_LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {161__flush_on_overflow(__n);162if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).163std::fill_n(std::addressof(__ptr_[__size_]), __n, __value);164__size_ += __n;165return;166}167168// The output doesn't fit in the internal buffer.169// Fill the buffer in "__capacity_" sized chunks.170_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");171do {172size_t __chunk = std::min(__n, __capacity_);173std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);174__size_ = __chunk;175__n -= __chunk;176__flush();177} while (__n);178}179180_LIBCPP_HIDE_FROM_ABI void __flush() {181__flush_(__ptr_, __size_, __obj_);182__size_ = 0;183}184185private:186_CharT* __ptr_;187size_t __capacity_;188size_t __size_{0};189void (*__flush_)(_CharT*, size_t, void*);190void* __obj_;191192/// Flushes the buffer when the output operation would overflow the buffer.193///194/// A simple approach for the overflow detection would be something along the195/// lines:196/// \code197/// // The internal buffer is large enough.198/// if (__n <= __capacity_) {199/// // Flush when we really would overflow.200/// if (__size_ + __n >= __capacity_)201/// __flush();202/// ...203/// }204/// \endcode205///206/// This approach works for all cases but one:207/// A __format_to_n_buffer_base where \ref __enable_direct_output is true.208/// In that case the \ref __capacity_ of the buffer changes during the first209/// \ref __flush. During that operation the output buffer switches from its210/// __writer_ to its __storage_. The \ref __capacity_ of the former depends211/// on the value of n, of the latter is a fixed size. For example:212/// - a format_to_n call with a 10'000 char buffer,213/// - the buffer is filled with 9'500 chars,214/// - adding 1'000 elements would overflow the buffer so the buffer gets215/// changed and the \ref __capacity_ decreases from 10'000 to216/// __buffer_size (256 at the time of writing).217///218/// This means that the \ref __flush for this class may need to copy a part of219/// the internal buffer to the proper output. In this example there will be220/// 500 characters that need this copy operation.221///222/// Note it would be more efficient to write 500 chars directly and then swap223/// the buffers. This would make the code more complex and \ref format_to_n is224/// not the most common use case. Therefore the optimization isn't done.225_LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) {226if (__size_ + __n >= __capacity_)227__flush();228}229};230231/// A storage using an internal buffer.232///233/// This storage is used when writing a single element to the output iterator234/// is expensive.235template <__fmt_char_type _CharT>236class _LIBCPP_TEMPLATE_VIS __internal_storage {237public:238_LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; }239240static constexpr size_t __buffer_size = 256 / sizeof(_CharT);241242private:243_CharT __buffer_[__buffer_size];244};245246/// A storage writing directly to the storage.247///248/// This requires the storage to be a contiguous buffer of \a _CharT.249/// Since the output is directly written to the underlying storage this class250/// is just an empty class.251template <__fmt_char_type _CharT>252class _LIBCPP_TEMPLATE_VIS __direct_storage {};253254template <class _OutIt, class _CharT>255concept __enable_direct_output =256__fmt_char_type<_CharT> &&257(same_as<_OutIt, _CharT*>258// TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an259// `#ifdef`.260|| same_as<_OutIt, __wrap_iter<_CharT*>>);261262/// Write policy for directly writing to the underlying output.263template <class _OutIt, __fmt_char_type _CharT>264class _LIBCPP_TEMPLATE_VIS __writer_direct {265public:266_LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it) : __out_it_(__out_it) {}267268_LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; }269270_LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) {271// _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator272// is adjusted.273__out_it_ += __n;274}275276private:277_OutIt __out_it_;278};279280/// Write policy for copying the buffer to the output.281template <class _OutIt, __fmt_char_type _CharT>282class _LIBCPP_TEMPLATE_VIS __writer_iterator {283public:284_LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it) : __out_it_{std::move(__out_it)} {}285286_LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); }287288_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {289__out_it_ = std::ranges::copy_n(__ptr, __n, std::move(__out_it_)).out;290}291292private:293_OutIt __out_it_;294};295296/// Concept to see whether a \a _Container is insertable.297///298/// The concept is used to validate whether multiple calls to a299/// \ref back_insert_iterator can be replace by a call to \c _Container::insert.300///301/// \note a \a _Container needs to opt-in to the concept by specializing302/// \ref __enable_insertable.303template <class _Container>304concept __insertable =305__enable_insertable<_Container> && __fmt_char_type<typename _Container::value_type> &&306requires(_Container& __t,307add_pointer_t<typename _Container::value_type> __first,308add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };309310/// Extract the container type of a \ref back_insert_iterator.311template <class _It>312struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container {313using type = void;314};315316template <__insertable _Container>317struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> {318using type = _Container;319};320321/// Write policy for inserting the buffer in a container.322template <class _Container>323class _LIBCPP_TEMPLATE_VIS __writer_container {324public:325using _CharT = typename _Container::value_type;326327_LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it)328: __container_{__out_it.__get_container()} {}329330_LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); }331332_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {333__container_->insert(__container_->end(), __ptr, __ptr + __n);334}335336private:337_Container* __container_;338};339340/// Selects the type of the writer used for the output iterator.341template <class _OutIt, class _CharT>342class _LIBCPP_TEMPLATE_VIS __writer_selector {343using _Container = typename __back_insert_iterator_container<_OutIt>::type;344345public:346using type =347conditional_t<!same_as<_Container, void>,348__writer_container<_Container>,349conditional_t<__enable_direct_output<_OutIt, _CharT>,350__writer_direct<_OutIt, _CharT>,351__writer_iterator<_OutIt, _CharT>>>;352};353354/// The generic formatting buffer.355template <class _OutIt, __fmt_char_type _CharT>356requires(output_iterator<_OutIt, const _CharT&>)357class _LIBCPP_TEMPLATE_VIS __format_buffer {358using _Storage =359conditional_t<__enable_direct_output<_OutIt, _CharT>, __direct_storage<_CharT>, __internal_storage<_CharT>>;360361public:362_LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)363requires(same_as<_Storage, __internal_storage<_CharT>>)364: __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(std::move(__out_it)) {}365366_LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)367requires(same_as<_Storage, __direct_storage<_CharT>>)368: __output_(std::__unwrap_iter(__out_it), size_t(-1), this), __writer_(std::move(__out_it)) {}369370_LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }371372_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); }373374_LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {375__output_.__flush();376return std::move(__writer_).__out_it();377}378379private:380_LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_;381__output_buffer<_CharT> __output_;382typename __writer_selector<_OutIt, _CharT>::type __writer_;383};384385/// A buffer that counts the number of insertions.386///387/// Since \ref formatted_size only needs to know the size, the output itself is388/// discarded.389template <__fmt_char_type _CharT>390class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer {391public:392_LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }393394_LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; }395396_LIBCPP_HIDE_FROM_ABI size_t __result() && {397__output_.__flush();398return __size_;399}400401private:402__internal_storage<_CharT> __storage_;403__output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};404size_t __size_{0};405};406407/// The base of a buffer that counts and limits the number of insertions.408template <class _OutIt, __fmt_char_type _CharT, bool>409requires(output_iterator<_OutIt, const _CharT&>)410struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base {411using _Size = iter_difference_t<_OutIt>;412413public:414_LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)415: __writer_(std::move(__out_it)), __max_size_(std::max(_Size(0), __max_size)) {}416417_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {418if (_Size(__size_) <= __max_size_)419__writer_.__flush(__ptr, std::min(_Size(__n), __max_size_ - __size_));420__size_ += __n;421}422423protected:424__internal_storage<_CharT> __storage_;425__output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};426typename __writer_selector<_OutIt, _CharT>::type __writer_;427428_Size __max_size_;429_Size __size_{0};430};431432/// The base of a buffer that counts and limits the number of insertions.433///434/// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true.435///436/// This class limits the size available to the direct writer so it will not437/// exceed the maximum number of code units.438template <class _OutIt, __fmt_char_type _CharT>439requires(output_iterator<_OutIt, const _CharT&>)440class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> {441using _Size = iter_difference_t<_OutIt>;442443public:444_LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)445: __output_(std::__unwrap_iter(__out_it), __max_size, this),446__writer_(std::move(__out_it)),447__max_size_(__max_size) {448if (__max_size <= 0) [[unlikely]]449__output_.__reset(__storage_.__begin(), __storage_.__buffer_size);450}451452_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {453// A __flush to the direct writer happens in the following occasions:454// - The format function has written the maximum number of allowed code455// units. At this point it's no longer valid to write to this writer. So456// switch to the internal storage. This internal storage doesn't need to457// be written anywhere so the __flush for that storage writes no output.458// - Like above, but the next "mass write" operation would overflow the459// buffer. In that case the buffer is pre-emptively switched. The still460// valid code units will be written separately.461// - The format_to_n function is finished. In this case there's no need to462// switch the buffer, but for simplicity the buffers are still switched.463// When the __max_size <= 0 the constructor already switched the buffers.464if (__size_ == 0 && __ptr != __storage_.__begin()) {465__writer_.__flush(__ptr, __n);466__output_.__reset(__storage_.__begin(), __storage_.__buffer_size);467} else if (__size_ < __max_size_) {468// Copies a part of the internal buffer to the output up to n characters.469// See __output_buffer<_CharT>::__flush_on_overflow for more information.470_Size __s = std::min(_Size(__n), __max_size_ - __size_);471std::copy_n(__ptr, __s, __writer_.__out_it());472__writer_.__flush(__ptr, __s);473}474475__size_ += __n;476}477478protected:479__internal_storage<_CharT> __storage_;480__output_buffer<_CharT> __output_;481__writer_direct<_OutIt, _CharT> __writer_;482483_Size __max_size_;484_Size __size_{0};485};486487/// The buffer that counts and limits the number of insertions.488template <class _OutIt, __fmt_char_type _CharT>489requires(output_iterator<_OutIt, const _CharT&>)490struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final491: public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> {492using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>;493using _Size = iter_difference_t<_OutIt>;494495public:496_LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size)497: _Base(std::move(__out_it), __max_size) {}498_LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); }499500_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {501this->__output_.__flush();502return {std::move(this->__writer_).__out_it(), this->__size_};503}504};505506// A dynamically growing buffer intended to be used for retargeting a context.507//508// P2286 Formatting ranges adds range formatting support. It allows the user to509// specify the minimum width for the entire formatted range. The width of the510// range is not known until the range is formatted. Formatting is done to an511// output_iterator so there's no guarantee it would be possible to add the fill512// to the front of the output. Instead the range is formatted to a temporary513// buffer and that buffer is formatted as a string.514//515// There is an issue with that approach, the format context used in516// std::formatter<T>::format contains the output iterator used as part of its517// type. So using this output iterator means there needs to be a new format518// context and the format arguments need to be retargeted to the new context.519// This retargeting is done by a basic_format_context specialized for the520// __iterator of this container.521//522// This class uses its own buffer management, since using vector523// would lead to a circular include with formatter for vector<bool>.524template <__fmt_char_type _CharT>525class _LIBCPP_TEMPLATE_VIS __retarget_buffer {526using _Alloc = allocator<_CharT>;527528public:529using value_type = _CharT;530531struct __iterator {532using difference_type = ptrdiff_t;533using value_type = _CharT;534535_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)536: __buffer_(std::addressof(__buffer)) {}537_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {538__buffer_->push_back(__c);539return *this;540}541_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {542__buffer_->push_back(__c);543return *this;544}545546_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }547_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }548_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }549__retarget_buffer* __buffer_;550};551552__retarget_buffer(const __retarget_buffer&) = delete;553__retarget_buffer& operator=(const __retarget_buffer&) = delete;554555_LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {556// When the initial size is very small a lot of resizes happen557// when elements added. So use a hard-coded minimum size.558//559// Note a size < 2 will not work560// - 0 there is no buffer, while push_back requires 1 empty element.561// - 1 multiplied by the grow factor is 1 and thus the buffer never562// grows.563auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT)));564__ptr_ = __result.ptr;565__capacity_ = __result.count;566}567568_LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {569ranges::destroy_n(__ptr_, __size_);570allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);571}572573_LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }574575_LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {576std::construct_at(__ptr_ + __size_, __c);577++__size_;578579if (__size_ == __capacity_)580__grow_buffer();581}582583template <__fmt_char_type _InCharT>584_LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {585size_t __n = __str.size();586if (__size_ + __n >= __capacity_)587// Push_back requires the buffer to have room for at least one character.588__grow_buffer(__size_ + __n + 1);589590std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);591__size_ += __n;592}593594template <contiguous_iterator _Iterator,595class _UnaryOperation,596__fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>597_LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {598_LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");599600size_t __n = static_cast<size_t>(__last - __first);601if (__size_ + __n >= __capacity_)602// Push_back requires the buffer to have room for at least one character.603__grow_buffer(__size_ + __n + 1);604605std::uninitialized_default_construct_n(__ptr_ + __size_, __n);606std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));607__size_ += __n;608}609610_LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {611if (__size_ + __n >= __capacity_)612// Push_back requires the buffer to have room for at least one character.613__grow_buffer(__size_ + __n + 1);614615std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);616__size_ += __n;617}618619_LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }620621private:622_LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }623624_LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {625_LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow");626auto __result = std::__allocate_at_least(__alloc_, __capacity);627auto __guard = std::__make_exception_guard([&] {628allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);629});630// This shouldn't throw, but just to be safe. Note that at -O1 this631// guard is optimized away so there is no runtime overhead.632std::uninitialized_move_n(__ptr_, __size_, __result.ptr);633__guard.__complete();634ranges::destroy_n(__ptr_, __size_);635allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);636637__ptr_ = __result.ptr;638__capacity_ = __result.count;639}640_LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;641_CharT* __ptr_;642size_t __capacity_;643size_t __size_{0};644};645646} // namespace __format647648#endif //_LIBCPP_STD_VER >= 20649650_LIBCPP_END_NAMESPACE_STD651652_LIBCPP_POP_MACROS653654#endif // _LIBCPP___FORMAT_BUFFER_H655656657