[libcxx-commits] [libcxx] 03c7b93 - [libc++][format] Removes vector dependency.

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Sun Apr 30 04:33:52 PDT 2023


Author: Mark de Wever
Date: 2023-04-30T13:33:44+02:00
New Revision: 03c7b93aab35106834b6c8dac097ea6bd401ba1e

URL: https://github.com/llvm/llvm-project/commit/03c7b93aab35106834b6c8dac097ea6bd401ba1e
DIFF: https://github.com/llvm/llvm-project/commit/03c7b93aab35106834b6c8dac097ea6bd401ba1e.diff

LOG: [libc++][format] Removes vector dependency.

During the review of D140653 it was suggested to use vector in
__retarget_buffer instead of manually managing the memory. Due to the
requirements of the Standard it turns out format needs to include vector
leading to a cycle. Therefore switching back to manual memory
management.

This is a preparation to fix https://llvm.org/PR61314

Reviewed By: #libc, ldionne

Differential Revision: https://reviews.llvm.org/D148826

Added: 
    

Modified: 
    libcxx/include/__format/buffer.h
    libcxx/test/libcxx/transitive_includes/cxx03.csv
    libcxx/test/libcxx/transitive_includes/cxx11.csv
    libcxx/test/libcxx/transitive_includes/cxx14.csv
    libcxx/test/libcxx/transitive_includes/cxx17.csv
    libcxx/test/libcxx/transitive_includes/cxx20.csv
    libcxx/test/libcxx/transitive_includes/cxx2b.csv

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h
index 16db88aec7fbe..e74ca8f579d42 100644
--- a/libcxx/include/__format/buffer.h
+++ b/libcxx/include/__format/buffer.h
@@ -28,12 +28,17 @@
 #include <__iterator/iterator_traits.h>
 #include <__iterator/wrap_iter.h>
 #include <__memory/addressof.h>
+#include <__memory/allocate_at_least.h>
+#include <__memory/allocator_traits.h>
+#include <__memory/construct_at.h>
+#include <__memory/ranges_construct_at.h>
+#include <__memory/uninitialized_algorithms.h>
 #include <__type_traits/add_pointer.h>
 #include <__type_traits/conditional.h>
+#include <__utility/exception_guard.h>
 #include <__utility/move.h>
 #include <cstddef>
 #include <string_view>
-#include <vector>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -512,8 +517,13 @@ struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
 // context and the format arguments need to be retargeted to the new context.
 // This retargeting is done by a basic_format_context specialized for the
 // __iterator of this container.
+//
+// This class uses its own buffer management, since using vector
+// would lead to a circular include with formatter for vector<bool>.
 template <__fmt_char_type _CharT>
 class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
+  using _Alloc = allocator<_CharT>;
+
 public:
   using value_type = _CharT;
 
@@ -537,31 +547,89 @@ class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
     __retarget_buffer* __buffer_;
   };
 
-  _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) { __buffer_.reserve(__size_hint); }
+  __retarget_buffer(const __retarget_buffer&)            = delete;
+  __retarget_buffer& operator=(const __retarget_buffer&) = delete;
+
+  _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {
+    auto __result = std::__allocate_at_least(__alloc_, __size_hint ? __size_hint : 256 / sizeof(_CharT));
+    __ptr_        = __result.ptr;
+    __capacity_   = __result.count;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {
+    ranges::destroy_n(__ptr_, __size_);
+    allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
+  }
 
   _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
 
-  _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) { __buffer_.push_back(__c); }
+  _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
+    std::construct_at(__ptr_ + __size_, __c);
+    ++__size_;
+
+    if (__size_ == __capacity_)
+      __grow_buffer();
+  }
 
   template <__fmt_char_type _InCharT>
   _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
-    __buffer_.insert(__buffer_.end(), __str.begin(), __str.end());
+    size_t __n = __str.size();
+    if (__size_ + __n >= __capacity_)
+      // Push_back requires the buffer to have room for at least one character.
+      __grow_buffer(__size_ + __n + 1);
+
+    std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);
+    __size_ += __n;
   }
 
   template <__fmt_char_type _InCharT, class _UnaryOperation>
   _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) {
     _LIBCPP_ASSERT(__first <= __last, "not a valid range");
-    std::transform(__first, __last, std::back_inserter(__buffer_), std::move(__operation));
+
+    size_t __n = static_cast<size_t>(__last - __first);
+    if (__size_ + __n >= __capacity_)
+      // Push_back requires the buffer to have room for at least one character.
+      __grow_buffer(__size_ + __n + 1);
+
+    std::uninitialized_default_construct_n(__ptr_ + __size_, __n);
+    std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));
+    __size_ += __n;
   }
 
-  _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) { __buffer_.insert(__buffer_.end(), __n, __value); }
+  _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
+    if (__size_ + __n >= __capacity_)
+      // Push_back requires the buffer to have room for at least one character.
+      __grow_buffer(__size_ + __n + 1);
+
+    std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);
+    __size_ += __n;
+  }
 
-  _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__buffer_.data(), __buffer_.size()}; }
+  _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }
 
 private:
-  // Use vector instead of string to avoid adding zeros after every append
-  // operation. The buffer is exposed as a string_view and not as a c-string.
-  vector<_CharT> __buffer_;
+  _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
+
+  _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
+    _LIBCPP_ASSERT(__capacity > __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. Not that at -O1 this
+    // guard is optimized away so there is no runtime overhead.
+    std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
+    __guard.__complete();
+    ranges::destroy_n(__ptr_, __size_);
+    allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
+
+    __ptr_      = __result.ptr;
+    __capacity_ = __result.count;
+  }
+  _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
+  _CharT* __ptr_;
+  size_t __capacity_;
+  size_t __size_{0};
 };
 
 } // namespace __format

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index efb07e748f562..e5aee81cc70d8 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -333,7 +333,6 @@ format stdexcept
 format string
 format string_view
 format tuple
-format vector
 format version
 forward_list algorithm
 forward_list atomic
@@ -869,7 +868,6 @@ thread string_view
 thread system_error
 thread tuple
 thread type_traits
-thread vector
 thread version
 tuple compare
 tuple cstddef

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 0cd572f402906..f696ff6c2b152 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -333,7 +333,6 @@ format stdexcept
 format string
 format string_view
 format tuple
-format vector
 format version
 forward_list algorithm
 forward_list atomic
@@ -870,7 +869,6 @@ thread string_view
 thread system_error
 thread tuple
 thread type_traits
-thread vector
 thread version
 tuple compare
 tuple cstddef

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index a0d7ff076dcd8..5e7d9ca2700bf 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -335,7 +335,6 @@ format stdexcept
 format string
 format string_view
 format tuple
-format vector
 format version
 forward_list algorithm
 forward_list atomic
@@ -872,7 +871,6 @@ thread string_view
 thread system_error
 thread tuple
 thread type_traits
-thread vector
 thread version
 tuple compare
 tuple cstddef

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index a0d7ff076dcd8..5e7d9ca2700bf 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -335,7 +335,6 @@ format stdexcept
 format string
 format string_view
 format tuple
-format vector
 format version
 forward_list algorithm
 forward_list atomic
@@ -872,7 +871,6 @@ thread string_view
 thread system_error
 thread tuple
 thread type_traits
-thread vector
 thread version
 tuple compare
 tuple cstddef

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 57a75bd9959b8..a96081233f326 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -127,7 +127,6 @@ chrono string
 chrono string_view
 chrono tuple
 chrono type_traits
-chrono vector
 chrono version
 cinttypes cstdint
 cmath type_traits
@@ -343,7 +342,6 @@ format stdexcept
 format string
 format string_view
 format tuple
-format vector
 format version
 forward_list algorithm
 forward_list atomic
@@ -878,7 +876,6 @@ thread string_view
 thread system_error
 thread tuple
 thread type_traits
-thread vector
 thread version
 tuple compare
 tuple cstddef

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx2b.csv b/libcxx/test/libcxx/transitive_includes/cxx2b.csv
index aa2161fe38fbd..3f5758630f348 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx2b.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx2b.csv
@@ -71,6 +71,7 @@ chrono ctime
 chrono initializer_list
 chrono limits
 chrono locale
+chrono new
 chrono optional
 chrono ostream
 chrono ratio
@@ -79,7 +80,6 @@ chrono stdexcept
 chrono string
 chrono string_view
 chrono tuple
-chrono vector
 chrono version
 cinttypes cstdint
 cmath version
@@ -225,6 +225,7 @@ format cstdlib
 format initializer_list
 format limits
 format locale
+format new
 format optional
 format queue
 format stack
@@ -232,7 +233,6 @@ format stdexcept
 format string
 format string_view
 format tuple
-format vector
 format version
 forward_list compare
 forward_list cstddef
@@ -582,12 +582,12 @@ thread ctime
 thread iosfwd
 thread limits
 thread locale
+thread new
 thread ratio
 thread stdexcept
 thread string
 thread string_view
 thread tuple
-thread vector
 thread version
 tuple compare
 tuple cstddef


        


More information about the libcxx-commits mailing list