Skip to content

Commit 42c5224

Browse files
committed
Speed-up copy/move-ctors for vector<bool>
1 parent 1c4341d commit 42c5224

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
@@ -417,6 +417,8 @@ class _LIBCPP_TEMPLATE_VIS vector<bool, _Allocator> {
417417
__guard.__complete();
418418
}
419419

420+
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __alloc_and_copy(const vector& __v);
421+
420422
template <class _Iterator, class _Sentinel>
421423
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __assign_with_sentinel(_Iterator __first, _Sentinel __last);
422424

@@ -695,25 +697,30 @@ vector<bool, _Allocator>::vector(initializer_list<value_type> __il, const alloca
695697

696698
#endif // _LIBCPP_CXX03_LANG
697699

700+
// This function copies each storage word as a whole, which is substantially more efficient than copying
701+
// individual bits within each word
702+
template <class _Allocator>
703+
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void vector<bool, _Allocator>::__alloc_and_copy(const vector& __v) {
704+
if (__v.__size_) {
705+
__vallocate(__v.__size_);
706+
std::copy(__v.__begin_, __v.__begin_ + __external_cap_to_internal(__v.__size_), __begin_);
707+
}
708+
__size_ = __v.__size_;
709+
}
710+
698711
template <class _Allocator>
699712
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v)
700713
: __begin_(nullptr),
701714
__size_(0),
702715
__cap_(0),
703716
__alloc_(__storage_traits::select_on_container_copy_construction(__v.__alloc_)) {
704-
if (__v.size() > 0) {
705-
__vallocate(__v.size());
706-
__construct_at_end(__v.begin(), __v.end(), __v.size());
707-
}
717+
__alloc_and_copy(__v);
708718
}
709719

710720
template <class _Allocator>
711721
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v, const allocator_type& __a)
712722
: __begin_(nullptr), __size_(0), __cap_(0), __alloc_(__a) {
713-
if (__v.size() > 0) {
714-
__vallocate(__v.size());
715-
__construct_at_end(__v.begin(), __v.end(), __v.size());
716-
}
723+
__alloc_and_copy(__v);
717724
}
718725

719726
template <class _Allocator>
@@ -758,9 +765,8 @@ vector<bool, _Allocator>::vector(vector&& __v, const __type_identity_t<allocator
758765
this->__cap_ = __v.__cap_;
759766
__v.__begin_ = nullptr;
760767
__v.__cap_ = __v.__size_ = 0;
761-
} else if (__v.size() > 0) {
762-
__vallocate(__v.size());
763-
__construct_at_end(__v.begin(), __v.end(), __v.size());
768+
} else {
769+
__alloc_and_copy(__v);
764770
}
765771
}
766772

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)