[llvm-branch-commits] [libcxx] [libc++][format][4/7] Improves std::format_to performance. (PR #101823)
Louis Dionne via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Aug 20 09:08:41 PDT 2024
================
@@ -722,6 +724,95 @@ class _LIBCPP_TEMPLATE_VIS __allocating_buffer : public __output_buffer<_CharT>
}
};
+// A buffer that directly writes to the underlying buffer.
+template <class _OutIt, __fmt_char_type _CharT>
+class _LIBCPP_TEMPLATE_VIS __direct_iterator_buffer : public __output_buffer<_CharT> {
+public:
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __direct_iterator_buffer(_OutIt __out_it)
+ : __output_buffer<_CharT>{std::__unwrap_iter(__out_it), __buffer_size, __prepare_write}, __out_it_(__out_it) {}
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return __out_it_ + this->__size(); }
+
+private:
+ // The function format_to expects a buffer large enough for the output. The
+ // function format_to_n has its own helper class that restricts the number of
+ // write options. So this function class can pretend to have an infinite
+ // buffer.
+ static constexpr size_t __buffer_size = -1;
+
+ _OutIt __out_it_;
+
+ _LIBCPP_HIDE_FROM_ABI static void
+ __prepare_write([[maybe_unused]] __output_buffer<_CharT>& __buffer, [[maybe_unused]] size_t __size_hint) {
+ std::__throw_length_error("__direct_iterator_buffer");
+ }
+};
+
+// A buffer that writes its output to the end of a container.
+template <class _OutIt, __fmt_char_type _CharT>
+class _LIBCPP_TEMPLATE_VIS __container_inserter_buffer : public __output_buffer<_CharT> {
+public:
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit __container_inserter_buffer(_OutIt __out_it)
+ : __output_buffer<_CharT>{__buffer_, __buffer_size, __prepare_write}, __container_{__out_it.__get_container()} {}
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto __out_it() && {
+ __container_->insert(__container_->end(), __buffer_, __buffer_ + this->__size());
+ return std::back_inserter(*__container_);
+ }
+
+private:
+ typename __back_insert_iterator_container<_OutIt>::type* __container_;
+
+ // This class uses a fixed size buffer and appends the elements in
+ // __buffer_size chunks. An alternative would be to use an allocating buffer
+ // and append the output in one write operation. Benchmarking showed no
+ // performance difference.
+ static constexpr size_t __buffer_size = 256;
+ _CharT __buffer_[__buffer_size];
+
+ _LIBCPP_HIDE_FROM_ABI void __prepare_write() {
+ __container_->insert(__container_->end(), __buffer_, __buffer_ + this->__size());
+ this->__buffer_flused();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static void
+ __prepare_write(__output_buffer<_CharT>& __buffer, [[maybe_unused]] size_t __size_hint) {
+ static_cast<__container_inserter_buffer<_OutIt, _CharT>&>(__buffer).__prepare_write();
+ }
+};
+
+// A buffer that writes to an iterator.
+//
+// Unlinke the __container_inserter_buffer this class' perfomance does benefit
----------------
ldionne wrote:
```suggestion
// Unlike the __container_inserter_buffer this class' performance does benefit
```
https://github.com/llvm/llvm-project/pull/101823
More information about the llvm-branch-commits
mailing list