================ @@ -499,11 +652,78 @@ struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); } _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && { - this->__output_.__flush(); + this->__output_.__flush(0); return {std::move(this->__writer_).__out_it(), this->__size_}; } }; +// ***** ***** ***** LLVM-20 classes ***** ***** ***** + +// A dynamically growing buffer. +template <__fmt_char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __allocating_buffer : public __output_buffer<_CharT> { +public: + __allocating_buffer(const __allocating_buffer&) = delete; + __allocating_buffer& operator=(const __allocating_buffer&) = delete; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __allocating_buffer() + : __output_buffer<_CharT>{__buffer_, __buffer_size_, __prepare_write} {} + + _LIBCPP_HIDE_FROM_ABI ~__allocating_buffer() { + if (__ptr_ != __buffer_) { + ranges::destroy_n(__ptr_, this->__size()); + allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, this->__capacity()); + } + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, this->__size()}; } + +private: + // At the moment the allocator is hard-code. There might be reasons to have + // an allocator trait in the future. This ensures forward compatibility. + using _Alloc = allocator<_CharT>; + _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_; + + // Since allocating is expensive the class has a small internal buffer. When + // its capacity is exceeded a dynamic buffer will be allocated. + static constexpr size_t __buffer_size_ = 256; + _CharT __buffer_[__buffer_size_]; + _CharT* __ptr_{__buffer_}; + + _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) { + if (__capacity < __buffer_size_) + return; + + _LIBCPP_ASSERT_INTERNAL(__capacity > this->__capacity(), "the buffer must grow"); + auto __result = std::__allocate_at_least(__alloc_, __capacity); + auto __guard = std::__make_exception_guard([&] { + allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count); + }); + // This shouldn't throw, but just to be safe. Note that at -O1 this + // guard is optimized away so there is no runtime overhead. + new (__result.ptr) _CharT[__result.count]; + std::copy_n(__ptr_, this->__size(), __result.ptr); + __guard.__complete(); + if (__ptr_ != __buffer_) { + ranges::destroy_n(__ptr_, this->__capacity()); + allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, this->__capacity()); + } ---------------- ldionne wrote:
```suggestion auto __guard = std::__make_exception_guard([&] { allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count); }); // This shouldn't throw, but just to be safe. Note that at -O1 this // guard is optimized away so there is no runtime overhead. std::__uninitialized_allocator_relocate(__alloc_, __ptr_, __ptr_ + this->__size(), __result.ptr); __guard.__complete(); if (__ptr_ != __buffer_) { allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, this->__capacity()); } ``` https://github.com/llvm/llvm-project/pull/101817 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits