Skip to content

Commit 05bd927

Browse files
committed
Speed-up copy/move-ctors for vector<bool>
1 parent f75c846 commit 05bd927

File tree

3 files changed

+83
-11
lines changed

3 files changed

+83
-11
lines changed

libcxx/include/__vector/vector_bool.h

Lines changed: 17 additions & 11 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 __alloc_and_copy(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

@@ -674,25 +676,30 @@ vector<bool, _Allocator>::vector(initializer_list<value_type> __il, const alloca
674676

675677
#endif // _LIBCPP_CXX03_LANG
676678

679+
// This function copies each storage word as a whole, which is substantially more efficient than copying
680+
// individual bits within each word
681+
template <class _Allocator>
682+
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void vector<bool, _Allocator>::__alloc_and_copy(const vector& __v) {
683+
if (__v.__size_) {
684+
__vallocate(__v.__size_);
685+
std::copy(__v.__begin_, __v.__begin_ + __external_cap_to_internal(__v.__size_), __begin_);
686+
}
687+
__size_ = __v.__size_;
688+
}
689+
677690
template <class _Allocator>
678691
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v)
679692
: __begin_(nullptr),
680693
__size_(0),
681694
__cap_(0),
682695
__alloc_(__storage_traits::select_on_container_copy_construction(__v.__alloc_)) {
683-
if (__v.size() > 0) {
684-
__vallocate(__v.size());
685-
__construct_at_end(__v.begin(), __v.end(), __v.size());
686-
}
696+
__alloc_and_copy(__v);
687697
}
688698

689699
template <class _Allocator>
690700
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v, const allocator_type& __a)
691701
: __begin_(nullptr), __size_(0), __cap_(0), __alloc_(__a) {
692-
if (__v.size() > 0) {
693-
__vallocate(__v.size());
694-
__construct_at_end(__v.begin(), __v.end(), __v.size());
695-
}
702+
__alloc_and_copy(__v);
696703
}
697704

698705
template <class _Allocator>
@@ -737,9 +744,8 @@ vector<bool, _Allocator>::vector(vector&& __v, const __type_identity_t<allocator
737744
this->__cap_ = __v.__cap_;
738745
__v.__begin_ = nullptr;
739746
__v.__cap_ = __v.__size_ = 0;
740-
} else if (__v.size() > 0) {
741-
__vallocate(__v.size());
742-
__construct_at_end(__v.begin(), __v.end(), __v.size());
747+
} else {
748+
__alloc_and_copy(__v);
743749
}
744750
}
745751

libcxx/test/benchmarks/containers/ContainerBenchmarks.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,36 @@ void BM_CopyConstruct(benchmark::State& st, Container) {
3939
}
4040
}
4141

42+
template <class Container>
43+
void BM_MoveConstruct(benchmark::State& st, Container) {
44+
auto size = st.range(0);
45+
Container c(size);
46+
for (auto _ : st) {
47+
auto v = std::move(c);
48+
DoNotOptimizeData(v);
49+
}
50+
}
51+
52+
template <class Container, class Allocator>
53+
void BM_CopyConstruct_Alloc(benchmark::State& st, Container, Allocator a) {
54+
auto size = st.range(0);
55+
Container c(size);
56+
for (auto _ : st) {
57+
Container v(c, a);
58+
DoNotOptimizeData(v);
59+
}
60+
}
61+
62+
template <class Container, class Allocator>
63+
void BM_MoveConstruct_Alloc(benchmark::State& st, Container, Allocator a) {
64+
auto size = st.range(0);
65+
Container c(size);
66+
for (auto _ : st) {
67+
Container v(std::move(c), a);
68+
DoNotOptimizeData(v);
69+
}
70+
}
71+
4272
template <class Container>
4373
void BM_Assignment(benchmark::State& st, Container) {
4474
auto size = st.range(0);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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, c++14, c++17, c++20
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+
#include "test_allocator.h"
24+
25+
using namespace ContainerBenchmarks;
26+
27+
BENCHMARK_CAPTURE(BM_CopyConstruct, vector_bool, std::vector<bool>{})->Arg(5140480);
28+
BENCHMARK_CAPTURE(BM_MoveConstruct, vector_bool, std::vector<bool>{})->Arg(5140480);
29+
BENCHMARK_CAPTURE(
30+
BM_CopyConstruct_Alloc, vector_bool, std::vector<bool, test_allocator<bool>>(), test_allocator<bool>(3))
31+
->Arg(5140480);
32+
BENCHMARK_CAPTURE(
33+
BM_MoveConstruct_Alloc, vector_bool, std::vector<bool, test_allocator<bool>>(), test_allocator<bool>(3))
34+
->Arg(5140480);
35+
36+
BENCHMARK_MAIN();

0 commit comments

Comments
 (0)