Skip to content

Commit 08fe8cb

Browse files
committed
Speed-up and refactor move-assignment operator for vector<bool>
1 parent 7163603 commit 08fe8cb

File tree

3 files changed

+107
-9
lines changed

3 files changed

+107
-9
lines changed

libcxx/include/__vector/vector_bool.h

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ class _LIBCPP_TEMPLATE_VIS vector<bool, _Allocator> {
398398
__guard.__complete();
399399
}
400400

401+
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __copy_by_words(const vector& __v);
402+
401403
template <class _Iterator, class _Sentinel>
402404
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __assign_with_sentinel(_Iterator __first, _Sentinel __last);
403405

@@ -695,18 +697,23 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v
695697
}
696698
}
697699

700+
template <class _Allocator>
701+
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void vector<bool, _Allocator>::__copy_by_words(const vector& __v) {
702+
if (__v.__size_) {
703+
if (__v.__size_ > capacity()) {
704+
__vdeallocate();
705+
__vallocate(__v.__size_);
706+
}
707+
std::copy(__v.__begin_, __v.__begin_ + __external_cap_to_internal(__v.__size_), __begin_);
708+
}
709+
__size_ = __v.__size_;
710+
}
711+
698712
template <class _Allocator>
699713
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>& vector<bool, _Allocator>::operator=(const vector& __v) {
700714
if (this != std::addressof(__v)) {
701715
__copy_assign_alloc(__v);
702-
if (__v.__size_) {
703-
if (__v.__size_ > capacity()) {
704-
__vdeallocate();
705-
__vallocate(__v.__size_);
706-
}
707-
std::copy(__v.__begin_, __v.__begin_ + __external_cap_to_internal(__v.__size_), __begin_);
708-
}
709-
__size_ = __v.__size_;
716+
__copy_by_words(__v);
710717
}
711718
return *this;
712719
}
@@ -754,7 +761,7 @@ vector<bool, _Allocator>::operator=(vector&& __v)
754761
template <class _Allocator>
755762
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::__move_assign(vector& __c, false_type) {
756763
if (__alloc_ != __c.__alloc_)
757-
assign(__c.begin(), __c.end());
764+
__copy_by_words(__c);
758765
else
759766
__move_assign(__c, true_type());
760767
}

libcxx/test/benchmarks/containers/ContainerBenchmarks.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,20 @@ void BM_Assignment(benchmark::State& st, Container) {
5151
}
5252
}
5353

54+
template <class Container, class Allocator>
55+
void BM_Move_Assignment(benchmark::State& st, Container, Allocator) {
56+
auto size = st.range(0);
57+
Container c1(Allocator{1});
58+
Container c2(Allocator{2});
59+
c1.reserve(size);
60+
c2.resize(size);
61+
for (auto _ : st) {
62+
c1 = std::move(c2);
63+
DoNotOptimizeData(c1);
64+
DoNotOptimizeData(c2);
65+
}
66+
}
67+
5468
template <std::size_t... sz, typename Container, typename GenInputs>
5569
void BM_AssignInputIterIter(benchmark::State& st, Container c, GenInputs gen) {
5670
auto v = gen(1, sz...);
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11
10+
11+
#include <cstdint>
12+
#include <cstdlib>
13+
#include <cstring>
14+
#include <deque>
15+
#include <functional>
16+
#include <memory>
17+
#include <string>
18+
#include <vector>
19+
20+
#include "benchmark/benchmark.h"
21+
#include "ContainerBenchmarks.h"
22+
#include "../GenerateInput.h"
23+
24+
using namespace ContainerBenchmarks;
25+
26+
template <typename T, typename SIZE_TYPE = std::size_t, typename DIFF_TYPE = std::ptrdiff_t>
27+
class CustomSizedAllocator {
28+
template <typename U, typename Sz, typename Diff>
29+
friend class CustomSizedAllocator;
30+
31+
public:
32+
using value_type = T;
33+
using size_type = SIZE_TYPE;
34+
using difference_type = DIFF_TYPE;
35+
using propagate_on_container_swap = std::true_type;
36+
37+
explicit CustomSizedAllocator(int i = 0) : data_(i) {}
38+
39+
template <typename U, typename Sz, typename Diff>
40+
constexpr CustomSizedAllocator(const CustomSizedAllocator<U, Sz, Diff>& a) noexcept : data_(a.data_) {}
41+
42+
constexpr T* allocate(size_type n) {
43+
if (n > max_size())
44+
throw std::bad_array_new_length();
45+
return std::allocator<T>().allocate(n);
46+
}
47+
48+
constexpr void deallocate(T* p, size_type n) noexcept { std::allocator<T>().deallocate(p, n); }
49+
50+
constexpr size_type max_size() const noexcept { return std::numeric_limits<size_type>::max() / sizeof(value_type); }
51+
52+
int get() { return data_; }
53+
54+
private:
55+
int data_;
56+
57+
constexpr friend bool operator==(const CustomSizedAllocator& a, const CustomSizedAllocator& b) {
58+
return a.data_ == b.data_;
59+
}
60+
constexpr friend bool operator!=(const CustomSizedAllocator& a, const CustomSizedAllocator& b) {
61+
return a.data_ != b.data_;
62+
}
63+
};
64+
65+
BENCHMARK_CAPTURE(BM_Move_Assignment,
66+
vector_bool_uint32_t,
67+
std::vector<bool, CustomSizedAllocator<bool, std::uint32_t, std::int32_t>>{},
68+
CustomSizedAllocator<bool, std::uint32_t, std::int32_t>{})
69+
->Arg(5140480);
70+
71+
BENCHMARK_CAPTURE(BM_Move_Assignment,
72+
vector_bool_uint64_t,
73+
std::vector<bool, CustomSizedAllocator<bool, std::uint64_t, std::int64_t>>{},
74+
CustomSizedAllocator<bool, std::uint64_t, std::int64_t>{})
75+
->Arg(5140480);
76+
77+
BENCHMARK_MAIN();

0 commit comments

Comments
 (0)