Skip to content

Commit

Permalink
[aa_inplace_vector] Swap allocators even in the UB case, for the sake…
Browse files Browse the repository at this point in the history
… of argument
  • Loading branch information
Quuxplusone committed Oct 8, 2024
1 parent 5791ae1 commit 8bf9f3f
Showing 1 changed file with 33 additions and 9 deletions.
42 changes: 33 additions & 9 deletions include/sg14/aa_inplace_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ struct ipv_alloc_holder {
ipv_alloc_holder& operator=(ipv_alloc_holder&&) noexcept = default;
~ipv_alloc_holder() noexcept = default;
constexpr const Alloc& get_allocator_() const { return alloc_; }
constexpr void copy_allocator_(ipv_alloc_holder& rhs) { alloc_ = rhs.alloc_; }
constexpr void move_allocator_(ipv_alloc_holder& rhs) { alloc_ = std::move(rhs.alloc_); }
constexpr void swap_allocators_(ipv_alloc_holder& rhs) { using std::swap; swap(alloc_, rhs.alloc_); }
};

template<class T>
Expand All @@ -308,6 +311,9 @@ struct ipv_alloc_holder<std::allocator<T>> {
explicit ipv_alloc_holder() = default;
constexpr explicit ipv_alloc_holder(const Alloc&) {}
static constexpr Alloc get_allocator_() { return Alloc(); }
constexpr void copy_allocator_(ipv_alloc_holder&) { }
constexpr void move_allocator_(ipv_alloc_holder&) { }
static constexpr void swap_allocators_(ipv_alloc_holder&) { }
};

template<class T, size_t N, class size_type>
Expand Down Expand Up @@ -361,6 +367,9 @@ struct SG14_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF((sg14::aaipv::be_trivially_r
using ipv_data_holder<T, N, typename std::allocator_traits<Alloc>::size_type>::set_size_;
using ipv_data_holder<T, N, typename std::allocator_traits<Alloc>::size_type>::swap_sizes_;
using ipv_alloc_holder<Alloc>::get_allocator_;
using ipv_alloc_holder<Alloc>::copy_allocator_;
using ipv_alloc_holder<Alloc>::move_allocator_;
using ipv_alloc_holder<Alloc>::swap_allocators_;

// There is a feature-test macro for "conditionally trivial SMFs," namely
// (__cpp_concepts >= 202002L); but in fact neither GCC 11.4 nor AppleClang 15
Expand Down Expand Up @@ -478,6 +487,8 @@ struct SG14_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF((sg14::aaipv::be_trivially_r
{
if constexpr (std::allocator_traits<Alloc>::propagate_on_container_copy_assignment::value && !std::allocator_traits<Alloc>::is_always_equal::value) {
SG14_INPLACE_VECTOR_ASSERT_PRECONDITION(this->get_allocator_() == rhs.get_allocator_(), "operator= tried to propagate an unequal allocator; this is UB");
// This line is redundant, since the allocators are supposed to be equal.
copy_allocator_(rhs);
}
if (this == std::addressof(rhs)) {
// do nothing
Expand All @@ -495,6 +506,8 @@ struct SG14_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF((sg14::aaipv::be_trivially_r
{
if constexpr (std::allocator_traits<Alloc>::propagate_on_container_move_assignment::value && !std::allocator_traits<Alloc>::is_always_equal::value) {
SG14_INPLACE_VECTOR_ASSERT_PRECONDITION(this->get_allocator_() == rhs.get_allocator_(), "operator= tried to propagate an unequal allocator; this is UB");
// This line is redundant, since the allocators are supposed to be equal.
move_allocator_(rhs);
}
if (this == std::addressof(rhs)) {
// do nothing
Expand Down Expand Up @@ -536,21 +549,32 @@ struct SG14_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF((sg14::aaipv::be_trivially_r

static constexpr void swap_(ipvbase& a, ipvbase& b) noexcept(SwapIsNoexcept)
{
if constexpr (std::allocator_traits<Alloc>::propagate_on_container_swap::value && !std::allocator_traits<Alloc>::is_always_equal::value) {
SG14_INPLACE_VECTOR_ASSERT_PRECONDITION(a.get_allocator_() == b.get_allocator_(), "swap tried to swap unequal allocators; this is UB");
}
if (a.size_ < b.size_) {
swap_(b, a);
} else {
if constexpr (std::allocator_traits<Alloc>::propagate_on_container_swap::value && !std::allocator_traits<Alloc>::is_always_equal::value) {
SG14_INPLACE_VECTOR_ASSERT_PRECONDITION(a.get_allocator_() == b.get_allocator_(), "swap tried to swap unequal allocators; this is UB");
// This line is redundant, since the allocators are supposed to be equal.
a.swap_allocators_(b);
}
std::swap_ranges(a.data_, a.data_ + b.size_, b.data_);
#if defined(__cpp_lib_trivially_relocatable)
size_t n = a.size_;
a.set_size_(b.size_);
sg14::aaipv::uninitialized_relocate_a(a.get_allocator_(), a.data_ + b.size_, a.data_ + n, b.data_ + b.size_);
b.set_size_(n);
if constexpr (std::is_trivially_relocatable_v<T> &&
sg14::aaipv::has_trivial_construct<Alloc, T, T&&>::value &&
sg14::aaipv::has_trivial_destroy<Alloc, T>::value) {
size_t n = a.size_;
a.set_size_(b.size_);
std::uninitialized_relocate(a.data_ + b.size_, a.data_ + n, b.data_ + b.size_);
b.set_size_(n);
return;
}
#else
sg14::aaipv::uninitialized_move_a(a.get_allocator_(), a.data_ + b.size_, a.data_ + a.size_, b.data_ + b.size_);
sg14::aaipv::destroy_a(a.get_allocator_(), a.data_ + b.size_, a.data_ + a.size_);
sg14::aaipv::uninitialized_move_a(b.get_allocator_(), a.data_ + b.size_, a.data_ + a.size_, b.data_ + b.size_);
if constexpr (std::allocator_traits<Alloc>::propagate_on_container_swap::value && !std::allocator_traits<Alloc>::is_always_equal::value) {
sg14::aaipv::destroy_a(b.get_allocator_(), a.data_ + b.size_, a.data_ + a.size_);
} else {
sg14::aaipv::destroy_a(a.get_allocator_(), a.data_ + b.size_, a.data_ + a.size_);
}
a.swap_sizes_(b);
#endif
}
Expand Down

0 comments on commit 8bf9f3f

Please sign in to comment.