[libcxx-commits] [libcxx] [libc++] Optimize vector::emplace_back (PR #218658)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 25 04:20:22 PDT 2026


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/218658

None

>From 260eca17eb9e5974ade589c89a8650a956dabf33 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 25 Aug 2026 13:19:59 +0200
Subject: [PATCH] [libc++] Optimize vector::emplace_back

---
 libcxx/include/__vector/vector.h | 53 +++++++++++++++-----------------
 1 file changed, 25 insertions(+), 28 deletions(-)

diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index ebcfcc17d4b6d..4eae9314b4795 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -754,9 +754,6 @@ class _LIBCPP_WARN_UNUSED vector {
     __annotate_shrink(__old_size);
   }
 
-  template <class... _Args>
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI inline pointer __emplace_back_slow_path(_Args&&... __args);
-
   // The following functions are no-ops outside of AddressSanitizer mode.
   // We call annotations for every allocator, unless explicitly disabled.
   //
@@ -1071,34 +1068,25 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE
   }
 }
 
-template <class _Tp, class _Allocator>
-template <class... _Args>
-_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
-vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) {
-  _SplitBuffer __v(__recommend(size() + 1), size(), this->__layout_.__alloc());
-  //    __v.emplace_back(std::forward<_Args>(__args)...);
-  pointer __end = __v.end();
-  __alloc_traits::construct(this->__layout_.__alloc(), std::__to_address(__end), std::forward<_Args>(__args)...);
-  __v.__set_sentinel(++__end);
-  __layout_.__relocate(__v);
-  return __end;
-}
-
 // This makes the compiler inline `__else()` if `__cond` is known to be false. Currently LLVM doesn't do that without
 // the `__builtin_constant_p`, since it considers `__else` unlikely even through it's known to be run.
 // See https://llvm.org/PR154292
-template <class _If, class _Else>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __if_likely_else(bool __cond, _If __if, _Else __else) {
+template <class _If, class _Else, class... _Args>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 decltype(std::declval<_If>()(std::declval<_Args&&>()...))
+__if_likely_else(bool __cond, _If __if, _Else __else, _Args&&... __args) {
+  static_assert(
+      is_same<decltype(__if(std::forward<_Args>(__args)...)), decltype(__else(std::forward<_Args>(__args)...))>::value,
+      "Return type of if and else branch have to be the same type");
   if (__builtin_constant_p(__cond)) {
     if (__cond)
-      __if();
+      return __if(std::forward<_Args>(__args)...);
     else
-      __else();
+      return __else(std::forward<_Args>(__args)...);
   } else {
     if (__cond) [[__likely__]]
-      __if();
+      return __if(std::forward<_Args>(__args)...);
     else
-      __else();
+      return __else(std::forward<_Args>(__args)...);
   }
 }
 
@@ -1106,16 +1094,25 @@ template <class _Tp, class _Alloc>
 template <class... _Args>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Alloc>::__emplace_back_result_t
 vector<_Tp, _Alloc>::emplace_back(_Args&&... __args) {
-  pointer __end = __layout_.__end_ptr();
   std::__if_likely_else(
       size() != capacity(),
-      [&] {
-        __emplace_back_assume_capacity(std::forward<_Args>(__args)...);
-        ++__end;
+      [](vector& __self, _Args&&... __largs) static {
+        __self.__emplace_back_assume_capacity(std::forward<_Args>(__largs)...);
+        return __self.back();
+      },
+      [](vector& __self, _Args&&... __largs) static {
+        _SplitBuffer __v(__self.__recommend(__self.size() + 1), __self.size(), __self.__layout_.__alloc());
+        //    __v.emplace_back(std::forward<_Args>(__args)...);
+        pointer __end = __v.end();
+        __alloc_traits::construct(
+            __self.__layout_.__alloc(), std::__to_address(__end), std::forward<_Args>(__largs)...);
+        __v.__set_sentinel(++__end);
+        __self.__layout_.__relocate(__v);
+        return __self.back();
       },
-      [&] { __end = __emplace_back_slow_path(std::forward<_Args>(__args)...); });
+      *this,
+      std::forward<_Args>(__args)...);
 
-  __layout_.__set_bound_using_pointer(__end);
 #if _LIBCPP_STD_VER >= 17
   return back();
 #endif



More information about the libcxx-commits mailing list