Skip to content

Commit 96a7c9b

Browse files
authored
[libc++] Simplify vector<bool> fill constructors (#160521)
#119632 introduced a code size and performance regression. This was verified by running the included benchmark against trunk and trunk with #119632 reverted. Instead of actually reverting that patch, we can inline `__construct_at_end` into the few places it's used instead, simplifying the implementation further (by not handling special cases we never actually encounter). ``` Benchmark Baseline Candidate Difference % Difference ------------------------ ---------- ----------- ------------ -------------- BM_vector_bool_size_ctor 29.91 8.56 -21.35 -71.37 ```
1 parent 30402c7 commit 96a7c9b

File tree

2 files changed

+28
-19
lines changed

2 files changed

+28
-19
lines changed

libcxx/include/__vector/vector_bool.h

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,6 @@ class vector<bool, _Allocator> {
478478
return (__new_size + (__bits_per_word - 1)) & ~((size_type)__bits_per_word - 1);
479479
}
480480
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __recommend(size_type __new_size) const;
481-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_at_end(size_type __n, bool __x);
482481
template <class _InputIterator, class _Sentinel>
483482
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
484483
__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n);
@@ -567,20 +566,6 @@ vector<bool, _Allocator>::__recommend(size_type __new_size) const {
567566
return std::max<size_type>(2 * __cap, __align_it(__new_size));
568567
}
569568

570-
// Default constructs __n objects starting at __end_
571-
// Precondition: size() + __n <= capacity()
572-
// Postcondition: size() == size() + __n
573-
template <class _Allocator>
574-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
575-
vector<bool, _Allocator>::__construct_at_end(size_type __n, bool __x) {
576-
_LIBCPP_ASSERT_INTERNAL(
577-
capacity() >= size() + __n, "vector<bool>::__construct_at_end called with insufficient capacity");
578-
std::fill_n(end(), __n, __x);
579-
this->__size_ += __n;
580-
if (end().__ctz_ != 0) // Ensure uninitialized leading bits in the last word are set to zero
581-
std::fill_n(end(), __bits_per_word - end().__ctz_, 0);
582-
}
583-
584569
template <class _Allocator>
585570
template <class _InputIterator, class _Sentinel>
586571
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
@@ -613,7 +598,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n)
613598
: __begin_(nullptr), __size_(0), __cap_(0) {
614599
if (__n > 0) {
615600
__vallocate(__n);
616-
__construct_at_end(__n, false);
601+
std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0));
602+
__size_ = __n;
617603
}
618604
}
619605

@@ -623,7 +609,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, co
623609
: __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
624610
if (__n > 0) {
625611
__vallocate(__n);
626-
__construct_at_end(__n, false);
612+
std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0));
613+
__size_ = __n;
627614
}
628615
}
629616
#endif
@@ -633,7 +620,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, co
633620
: __begin_(nullptr), __size_(0), __cap_(0) {
634621
if (__n > 0) {
635622
__vallocate(__n);
636-
__construct_at_end(__n, __x);
623+
std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0) - __x);
624+
__size_ = __n;
637625
}
638626
}
639627

@@ -643,7 +631,8 @@ vector<bool, _Allocator>::vector(size_type __n, const value_type& __x, const all
643631
: __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
644632
if (__n > 0) {
645633
__vallocate(__n);
646-
__construct_at_end(__n, __x);
634+
std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0) - __x);
635+
__size_ = __n;
647636
}
648637
}
649638

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
#include <benchmark/benchmark.h>
10+
#include <vector>
11+
12+
static void BM_vector_bool_size_ctor(benchmark::State& state) {
13+
for (auto _ : state) {
14+
std::vector<bool> vec(100, true);
15+
benchmark::DoNotOptimize(vec);
16+
}
17+
}
18+
BENCHMARK(BM_vector_bool_size_ctor);
19+
20+
BENCHMARK_MAIN();

0 commit comments

Comments
 (0)