================ @@ -319,188 +353,222 @@ struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterato using type = _Container; }; -/// Write policy for inserting the buffer in a container. -template <class _Container> -class _LIBCPP_TEMPLATE_VIS __writer_container { +// A dynamically growing buffer. +template <__fmt_char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __allocating_buffer : public __output_buffer<_CharT> { public: - using _CharT = typename _Container::value_type; + __allocating_buffer(const __allocating_buffer&) = delete; + __allocating_buffer& operator=(const __allocating_buffer&) = delete; - _LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it) - : __container_{__out_it.__get_container()} {} + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __allocating_buffer() : __allocating_buffer{nullptr} {} - _LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); } + [[nodiscard]] + _LIBCPP_HIDE_FROM_ABI explicit __allocating_buffer(__max_output_size* __max_output_size) + : __output_buffer<_CharT>{__buffer_, __buffer_size_, __prepare_write, __max_output_size} {} - _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { - __container_->insert(__container_->end(), __ptr, __ptr + __n); + _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: - _Container* __container_; -}; + // 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_; -/// Selects the type of the writer used for the output iterator. -template <class _OutIt, class _CharT> -class _LIBCPP_TEMPLATE_VIS __writer_selector { - using _Container = typename __back_insert_iterator_container<_OutIt>::type; + // 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_]; -public: - using type = - conditional_t<!same_as<_Container, void>, - __writer_container<_Container>, - conditional_t<__enable_direct_output<_OutIt, _CharT>, - __writer_direct<_OutIt, _CharT>, - __writer_iterator<_OutIt, _CharT>>>; + _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); ---------------- ldionne wrote:
What we'd want here is roughly `std::__relocate(__ptr_, __ptr_ + this->__size(), __result.ptr)`. https://github.com/llvm/llvm-project/pull/108990 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits