Skip to content

Commit 2c1decb

Browse files
authored
[libc++] Don't instantiate __split_buffer with an allocator reference (#171651)
Allocators should be extremely cheap, if not free, to copy. Furthermore, we have requirements on allocator types that copies must compare equal, and that move and copy must be the same. Hence, taking an allocator by reference should not provide benefits beyond making a copy of it. However, taking the allocator by reference leads to complexity in __split_buffer, which can be removed if we stop using that pattern.
1 parent 15df9e7 commit 2c1decb

File tree

3 files changed

+45
-50
lines changed

3 files changed

+45
-50
lines changed

libcxx/include/__split_buffer

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
#include <__type_traits/is_swappable.h>
3434
#include <__type_traits/is_trivially_destructible.h>
3535
#include <__type_traits/is_trivially_relocatable.h>
36-
#include <__type_traits/remove_reference.h>
3736
#include <__utility/forward.h>
3837
#include <__utility/move.h>
3938

@@ -54,8 +53,7 @@ class __split_buffer_pointer_layout {
5453
protected:
5554
using value_type = _Tp;
5655
using allocator_type = _Allocator;
57-
using __alloc_rr _LIBCPP_NODEBUG = __libcpp_remove_reference_t<allocator_type>;
58-
using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<__alloc_rr>;
56+
using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>;
5957
using reference = value_type&;
6058
using const_reference = const value_type&;
6159
using size_type = typename __alloc_traits::size_type;
@@ -159,9 +157,9 @@ public:
159157
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { return *(__end_ - 1); }
160158

161159
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(
162-
__split_buffer_pointer_layout<__split_buffer<value_type, __alloc_rr&, __split_buffer_pointer_layout>,
160+
__split_buffer_pointer_layout<__split_buffer<value_type, allocator_type, __split_buffer_pointer_layout>,
163161
value_type,
164-
__alloc_rr&>& __other) _NOEXCEPT {
162+
allocator_type>& __other) _NOEXCEPT {
165163
std::swap(__front_cap_, __other.__front_cap_);
166164
std::swap(__begin_, __other.__begin_);
167165
std::swap(__back_cap_, __other.__back_cap_);
@@ -207,8 +205,7 @@ class __split_buffer_size_layout {
207205
protected:
208206
using value_type = _Tp;
209207
using allocator_type = _Allocator;
210-
using __alloc_rr _LIBCPP_NODEBUG = __libcpp_remove_reference_t<allocator_type>;
211-
using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<__alloc_rr>;
208+
using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>;
212209
using reference = value_type&;
213210
using const_reference = const value_type&;
214211
using size_type = typename __alloc_traits::size_type;
@@ -316,9 +313,9 @@ public:
316313
}
317314

318315
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(
319-
__split_buffer_pointer_layout<__split_buffer<value_type, __alloc_rr&, __split_buffer_pointer_layout>,
316+
__split_buffer_pointer_layout<__split_buffer<value_type, allocator_type, __split_buffer_pointer_layout>,
320317
value_type,
321-
__alloc_rr&>& __other) _NOEXCEPT {
318+
allocator_type>& __other) _NOEXCEPT {
322319
std::swap(__front_cap_, __other.__front_cap_);
323320
std::swap(__begin_, __other.__begin_);
324321
std::swap(__cap_, __other.__cap_);
@@ -386,8 +383,7 @@ private:
386383
// protected:
387384
// using value_type = _Tp;
388385
// using allocator_type = _Allocator;
389-
// using __alloc_rr = __libcpp_remove_reference_t<allocator_type>;
390-
// using __alloc_traits = allocator_traits<__alloc_rr>;
386+
// using __alloc_traits = allocator_traits<allocator_type>;
391387
// using reference = value_type&;
392388
// using const_reference = const value_type&;
393389
// using size_type = typename __alloc_traits::size_type;
@@ -462,7 +458,6 @@ public:
462458
using __base_type::__set_sentinel;
463459
using __base_type::__set_valid_range;
464460

465-
using typename __base_type::__alloc_rr;
466461
using typename __base_type::__alloc_traits;
467462
using typename __base_type::allocator_type;
468463
using typename __base_type::const_iterator;
@@ -489,18 +484,18 @@ public:
489484

490485
_LIBCPP_HIDE_FROM_ABI __split_buffer() = default;
491486

492-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a) : __base_type(__a) {}
487+
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(allocator_type& __a) : __base_type(__a) {}
493488

494-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const __alloc_rr& __a)
489+
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const allocator_type& __a)
495490
: __base_type(__a) {}
496491

497492
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
498-
__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a);
493+
__split_buffer(size_type __cap, size_type __start, allocator_type& __a);
499494

500495
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c)
501496
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
502497

503-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c, const __alloc_rr& __a);
498+
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c, const allocator_type& __a);
504499

505500
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer& operator=(__split_buffer&& __c)
506501
_NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value &&
@@ -560,7 +555,7 @@ public:
560555
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last, true_type) _NOEXCEPT;
561556

562557
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer& __x)
563-
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>);
558+
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<allocator_type>);
564559

565560
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const {
566561
if (__front_cap() == nullptr) {
@@ -589,7 +584,7 @@ public:
589584
}
590585

591586
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
592-
__swap_without_allocator(__split_buffer<value_type, __alloc_rr&, _Layout>& __other) _NOEXCEPT {
587+
__swap_without_allocator(__split_buffer<value_type, allocator_type, _Layout>& __other) _NOEXCEPT {
593588
__base_type::__swap_without_allocator(__other);
594589
}
595590

@@ -653,7 +648,7 @@ template <class _Tp, class _Allocator, template <class, class, class> class _Lay
653648
template <class _Iterator, class _Sentinel>
654649
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
655650
__split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) {
656-
__alloc_rr& __a = __get_allocator();
651+
allocator_type& __a = __get_allocator();
657652
for (; __first != __last; ++__first) {
658653
if (__back_spare() == 0) {
659654
size_type __old_cap = capacity();
@@ -718,7 +713,7 @@ __split_buffer<_Tp, _Allocator, _Layout>::__destruct_at_end(pointer __new_last,
718713

719714
template <class _Tp, class _Allocator, template <class, class, class> class _Layout>
720715
_LIBCPP_CONSTEXPR_SINCE_CXX20
721-
__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a)
716+
__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(size_type __cap, size_type __start, allocator_type& __a)
722717
: __base_type(__a) {
723718
_LIBCPP_ASSERT_INTERNAL(__cap >= __start, "can't have a start point outside the capacity");
724719
if (__cap > 0) {
@@ -748,7 +743,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator, _Layout>::__split_
748743

749744
template <class _Tp, class _Allocator, template <class, class, class> class _Layout>
750745
_LIBCPP_CONSTEXPR_SINCE_CXX20
751-
__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a)
746+
__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(__split_buffer&& __c, const allocator_type& __a)
752747
: __base_type(__a) {
753748
if (__a == __c.__get_allocator()) {
754749
__set_data(__c.__front_cap());
@@ -781,7 +776,7 @@ __split_buffer<_Tp, _Allocator, _Layout>::operator=(__split_buffer&& __c)
781776

782777
template <class _Tp, class _Allocator, template <class, class, class> class _Layout>
783778
_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::swap(__split_buffer& __x)
784-
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>) {
779+
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<allocator_type>) {
785780
__base_type::swap(__x);
786781
}
787782

@@ -791,7 +786,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::shr
791786
#if _LIBCPP_HAS_EXCEPTIONS
792787
try {
793788
#endif // _LIBCPP_HAS_EXCEPTIONS
794-
__split_buffer<value_type, __alloc_rr&, _Layout> __t(size(), 0, __get_allocator());
789+
__split_buffer<value_type, allocator_type, _Layout> __t(size(), 0, __get_allocator());
795790
if (__t.capacity() < capacity()) {
796791
__t.__construct_at_end(move_iterator<pointer>(begin()), move_iterator<pointer>(end()));
797792
__t.__set_sentinel(size());
@@ -818,7 +813,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::emp
818813
__set_valid_range(std::move_backward(begin(), __end, __new_end), __new_end);
819814
} else {
820815
size_type __c = std::max<size_type>(2 * capacity(), 1);
821-
__split_buffer<value_type, __alloc_rr&, _Layout> __t(__c, (__c + 3) / 4, __get_allocator());
816+
__split_buffer<value_type, allocator_type, _Layout> __t(__c, (__c + 3) / 4, __get_allocator());
822817
__t.__construct_at_end(move_iterator<pointer>(begin()), move_iterator<pointer>(__end));
823818
__base_type::__swap_without_allocator(__t);
824819
}
@@ -840,7 +835,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::emp
840835
__set_valid_range(begin() - __d, __end);
841836
} else {
842837
size_type __c = std::max<size_type>(2 * capacity(), 1);
843-
__split_buffer<value_type, __alloc_rr&, _Layout> __t(__c, __c / 4, __get_allocator());
838+
__split_buffer<value_type, allocator_type, _Layout> __t(__c, __c / 4, __get_allocator());
844839
__t.__construct_at_end(move_iterator<pointer>(begin()), move_iterator<pointer>(__end));
845840
__base_type::__swap_without_allocator(__t);
846841
}

libcxx/include/__vector/vector.h

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -687,9 +687,9 @@ class vector {
687687
}
688688

689689
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
690-
__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v);
690+
__swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v);
691691
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer
692-
__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v, pointer __p);
692+
__swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v, pointer __p);
693693
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
694694
__move_range(pointer __from_s, pointer __from_e, pointer __to);
695695
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign(vector& __c, true_type)
@@ -810,7 +810,7 @@ class vector {
810810
return __p;
811811
}
812812

813-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer<_Tp, allocator_type&>& __sb) {
813+
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer<_Tp, allocator_type>& __sb) {
814814
auto __vector_begin = __begin_;
815815
auto __vector_sentinel = __end_;
816816
auto __vector_cap = __cap_;
@@ -855,7 +855,7 @@ vector(from_range_t, _Range&&, _Alloc = _Alloc()) -> vector<ranges::range_value_
855855
// function has a strong exception guarantee.
856856
template <class _Tp, class _Allocator>
857857
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
858-
vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v) {
858+
vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v) {
859859
__annotate_delete();
860860
auto __new_begin = __v.begin() - size();
861861
std::__uninitialized_allocator_relocate(
@@ -874,7 +874,7 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, a
874874
// function has a strong exception guarantee if __begin_ == __p || __end_ == __p.
875875
template <class _Tp, class _Allocator>
876876
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
877-
vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v, pointer __p) {
877+
vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v, pointer __p) {
878878
__annotate_delete();
879879
pointer __ret = __v.begin();
880880

@@ -1074,7 +1074,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::reserve(size_type __
10741074
if (__n > capacity()) {
10751075
if (__n > max_size())
10761076
this->__throw_length_error();
1077-
__split_buffer<value_type, allocator_type&> __v(__n, size(), this->__alloc_);
1077+
__split_buffer<value_type, allocator_type> __v(__n, size(), this->__alloc_);
10781078
__swap_out_circular_buffer(__v);
10791079
}
10801080
}
@@ -1085,7 +1085,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE
10851085
#if _LIBCPP_HAS_EXCEPTIONS
10861086
try {
10871087
#endif // _LIBCPP_HAS_EXCEPTIONS
1088-
__split_buffer<value_type, allocator_type&> __v(size(), size(), this->__alloc_);
1088+
__split_buffer<value_type, allocator_type> __v(size(), size(), this->__alloc_);
10891089
// The Standard mandates shrink_to_fit() does not increase the capacity.
10901090
// With equal capacity keep the existing buffer. This avoids extra work
10911091
// due to swapping the elements.
@@ -1102,7 +1102,7 @@ template <class _Tp, class _Allocator>
11021102
template <class... _Args>
11031103
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
11041104
vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) {
1105-
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), size(), this->__alloc_);
1105+
__split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), size(), this->__alloc_);
11061106
// __v.emplace_back(std::forward<_Args>(__args)...);
11071107
pointer __end = __v.end();
11081108
__alloc_traits::construct(this->__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...);
@@ -1205,7 +1205,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x)
12051205
*__p = *__xr;
12061206
}
12071207
} else {
1208-
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
1208+
__split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
12091209
__v.emplace_back(__x);
12101210
__p = __swap_out_circular_buffer(__v, __p);
12111211
}
@@ -1224,7 +1224,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) {
12241224
*__p = std::move(__x);
12251225
}
12261226
} else {
1227-
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
1227+
__split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
12281228
__v.emplace_back(std::move(__x));
12291229
__p = __swap_out_circular_buffer(__v, __p);
12301230
}
@@ -1245,7 +1245,7 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) {
12451245
*__p = std::move(__tmp.get());
12461246
}
12471247
} else {
1248-
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
1248+
__split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
12491249
__v.emplace_back(std::forward<_Args>(__args)...);
12501250
__p = __swap_out_circular_buffer(__v, __p);
12511251
}
@@ -1273,7 +1273,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_
12731273
std::fill_n(__p, __n, *__xr);
12741274
}
12751275
} else {
1276-
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
1276+
__split_buffer<value_type, allocator_type> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
12771277
__v.__construct_at_end(__n, __x);
12781278
__p = __swap_out_circular_buffer(__v, __p);
12791279
}
@@ -1294,11 +1294,11 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
12941294
if (__first == __last)
12951295
(void)std::rotate(__p, __old_last, this->__end_);
12961296
else {
1297-
__split_buffer<value_type, allocator_type&> __v(__alloc_);
1297+
__split_buffer<value_type, allocator_type> __v(__alloc_);
12981298
auto __guard = std::__make_exception_guard(
12991299
_AllocatorDestroyRangeReverse<allocator_type, pointer>(__alloc_, __old_last, this->__end_));
13001300
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
1301-
__split_buffer<value_type, allocator_type&> __merged(
1301+
__split_buffer<value_type, allocator_type> __merged(
13021302
__recommend(size() + __v.size()), __off, __alloc_); // has `__off` positions available at the front
13031303
std::__uninitialized_allocator_relocate(
13041304
__alloc_, std::__to_address(__old_last), std::__to_address(this->__end_), std::__to_address(__merged.end()));
@@ -1344,7 +1344,7 @@ vector<_Tp, _Allocator>::__insert_with_size(
13441344
__insert_assign_n_unchecked<_AlgPolicy>(std::move(__first), __n, __p);
13451345
}
13461346
} else {
1347-
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
1347+
__split_buffer<value_type, allocator_type> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
13481348
__v.__construct_at_end_with_size(std::move(__first), __n);
13491349
__p = __swap_out_circular_buffer(__v, __p);
13501350
}
@@ -1359,7 +1359,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
13591359
if (__new_size <= capacity()) {
13601360
__construct_at_end(__new_size - __current_size);
13611361
} else {
1362-
__split_buffer<value_type, allocator_type&> __v(__recommend(__new_size), __current_size, __alloc_);
1362+
__split_buffer<value_type, allocator_type> __v(__recommend(__new_size), __current_size, __alloc_);
13631363
__v.__construct_at_end(__new_size - __current_size);
13641364
__swap_out_circular_buffer(__v);
13651365
}
@@ -1375,7 +1375,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
13751375
if (__new_size <= capacity())
13761376
__construct_at_end(__new_size - __current_size, __x);
13771377
else {
1378-
__split_buffer<value_type, allocator_type&> __v(__recommend(__new_size), __current_size, __alloc_);
1378+
__split_buffer<value_type, allocator_type> __v(__recommend(__new_size), __current_size, __alloc_);
13791379
__v.__construct_at_end(__new_size - __current_size, __x);
13801380
__swap_out_circular_buffer(__v);
13811381
}

0 commit comments

Comments
 (0)