Skip to content

Commit

Permalink
fixing #31, adding move with new alloc ctor (#38)
Browse files Browse the repository at this point in the history
* fixing #31, adding move with new alloc ctor

* formatting fixes
thirtytwobits authored Jun 20, 2023

Verified

This commit was signed with the committer’s verified signature.
snyk-bot Snyk bot
1 parent 0322ec6 commit 3c6718a
Showing 2 changed files with 151 additions and 65 deletions.
Original file line number Diff line number Diff line change
@@ -213,6 +213,19 @@ TYPED_TEST(VLACopyMoveTests, CopyConstruct)
EXPECT_EQ(subject, source);
}

// +---------------------------------------------------------------------------+

TYPED_TEST(VLACopyMoveTests, CopyConstructWithNewAllocator)
{
typename TypeParam::source_vla_type source{{0, 1, 0, 1, 0, 1, 0, 1, 0}, TypeParam::make_source_allocator()};
EXPECT_EQ(source.size(), 9);

typename TypeParam::subject_vla_type subject{source, TypeParam::make_source_allocator()};
EXPECT_EQ(source.size(), 9);
EXPECT_EQ(subject.size(), source.size());
EXPECT_EQ(subject, source);
}

// +---------------------------------------------------------------------------+
// | TEST CASES :: Copy Assignment
// +---------------------------------------------------------------------------+
@@ -286,6 +299,18 @@ TYPED_TEST(VLACopyMoveTests, MoveConstruct)
EXPECT_EQ(subject.size(), 9);
}

// +---------------------------------------------------------------------------+

TYPED_TEST(VLACopyMoveTests, MoveConstructWithNewAllocator)
{
typename TypeParam::source_vla_type source{{0, 1, 0, 1, 0, 1, 0, 1, 0}, TypeParam::make_source_allocator()};
EXPECT_EQ(source.size(), 9);

typename TypeParam::subject_vla_type subject{std::move(source), TypeParam::make_source_allocator()};
EXPECT_EQ(source.size(), 0);
EXPECT_EQ(subject.size(), 9);
}

// +---------------------------------------------------------------------------+
// | TEST CASES :: Move Assignment
// +---------------------------------------------------------------------------+
@@ -302,6 +327,8 @@ TYPED_TEST(VLACopyMoveTests, MoveAssign)
EXPECT_EQ(subject.size(), 9);
}

// +---------------------------------------------------------------------------+

TYPED_TEST(VLACopyMoveTests, MoveAssignWithAdequateCapacity)
{
typename TypeParam::subject_vla_type subject{TypeParam::make_subject_allocator()};
189 changes: 124 additions & 65 deletions include/cetl/variable_length_array.hpp
Original file line number Diff line number Diff line change
@@ -55,44 +55,6 @@ class VariableLengthArrayBase
///
using size_type = std::size_t;

constexpr VariableLengthArrayBase(
const allocator_type& alloc,
value_type* data,
size_type initial_capacity,
size_type size,
size_type max_size_max) noexcept(std::is_nothrow_copy_constructible<allocator_type>::value)
: alloc_(alloc)
, data_(data)
, capacity_(initial_capacity)
, size_(size)
, max_size_max_(max_size_max)
{
}

constexpr VariableLengthArrayBase(const VariableLengthArrayBase& rhs, const allocator_type& rhs_alloc) noexcept(
std::is_nothrow_copy_constructible<allocator_type>::value)
: alloc_(std::allocator_traits<allocator_type>::select_on_container_copy_construction(rhs_alloc))
, data_(nullptr)
, capacity_(0)
, size_(0)
, max_size_max_(rhs.max_size_max_)
{
}

constexpr VariableLengthArrayBase(VariableLengthArrayBase&& rhs) noexcept
: alloc_(std::move(rhs.alloc_))
, data_(std::move(rhs.data_))
, capacity_(rhs.capacity_)
, size_(rhs.size_)
, max_size_max_(rhs.max_size_max_)
{
static_assert(std::is_nothrow_move_constructible<allocator_type>::value,
"Allocator must be nothrow move constructible.");
rhs.size_ = 0;
rhs.capacity_ = 0;
rhs.data_ = nullptr;
}

private:
// +----------------------------------------------------------------------+
// | TYPE HELPERS
@@ -139,28 +101,15 @@ class VariableLengthArrayBase
std::allocator_traits<std::remove_reference_t<UAlloc>>::is_always_equal::value)>
{};

// +----------------------------------------------------------------------+
// If allocator propagates on copy assignment or is always equal. This
// is used to implement parts of the propagate_on_container_copy_assignment
// named requirement for allocators.
// See https://en.cppreference.com/w/cpp/named_req/Allocator
template <typename UAlloc>
struct is_pocca_or_is_always_equal
: public std::integral_constant<
bool,
(std::allocator_traits<std::remove_reference_t<UAlloc>>::propagate_on_container_copy_assignment::value ||
std::allocator_traits<std::remove_reference_t<UAlloc>>::is_always_equal::value)>
{};

protected:
// +----------------------------------------------------------------------+
// | Allocator move assignment
// +----------------------------------------------------------------------+
template <typename UAlloc>
constexpr bool move_assign_alloc(
UAlloc&& rhs,
typename std::enable_if<std::allocator_traits<
std::remove_reference_t<UAlloc>>::propagate_on_container_move_assignment::value>::type* =
typename std::enable_if_t<
std::allocator_traits<std::remove_reference_t<UAlloc>>::propagate_on_container_move_assignment::value>* =
nullptr) noexcept(is_pocma_or_is_always_equal<UAlloc>::value)
{
static_assert(std::is_nothrow_move_assignable<allocator_type>::value,
@@ -173,8 +122,8 @@ class VariableLengthArrayBase
template <typename UAlloc>
constexpr bool move_assign_alloc(
UAlloc&& rhs,
typename std::enable_if<!std::allocator_traits<
std::remove_reference_t<UAlloc>>::propagate_on_container_move_assignment::value>::type* =
typename std::enable_if_t<
!std::allocator_traits<std::remove_reference_t<UAlloc>>::propagate_on_container_move_assignment::value>* =
nullptr) noexcept(is_pocma_or_is_always_equal<UAlloc>::value)
{
// Cannot move assign so we have to do everything manually.
@@ -188,7 +137,7 @@ class VariableLengthArrayBase
template <typename UAlloc>
constexpr bool copy_assign_alloc(
const UAlloc& rhs,
typename std::enable_if<std::allocator_traits<UAlloc>::propagate_on_container_copy_assignment::value>::type* =
typename std::enable_if_t<std::allocator_traits<UAlloc>::propagate_on_container_copy_assignment::value>* =
nullptr) noexcept
{
static_assert(std::is_nothrow_copy_assignable<allocator_type>::value,
@@ -201,7 +150,7 @@ class VariableLengthArrayBase
template <typename UAlloc>
constexpr bool copy_assign_alloc(
const UAlloc& rhs,
typename std::enable_if<!std::allocator_traits<UAlloc>::propagate_on_container_copy_assignment::value>::type* =
typename std::enable_if_t<!std::allocator_traits<UAlloc>::propagate_on_container_copy_assignment::value>* =
nullptr) noexcept
{
(void) rhs;
@@ -217,14 +166,14 @@ class VariableLengthArrayBase
decltype(std::declval<U>().reallocate(std::declval<value_type*>(), std::size_t(), std::size_t()));

template <typename UAllocator>
static constexpr typename std::enable_if<is_detected<reallocate_operation, UAllocator>::value, value_type>::type*
static constexpr typename std::enable_if_t<is_detected<reallocate_operation, UAllocator>::value, value_type>*
reallocate(value_type* data, UAllocator& alloc, std::size_t old_object_count, std::size_t new_object_count)
{
return alloc.reallocate(data, old_object_count, new_object_count);
}

template <typename UAllocator>
static constexpr typename std::enable_if<!is_detected<reallocate_operation, UAllocator>::value, value_type>::type*
static constexpr typename std::enable_if_t<!is_detected<reallocate_operation, UAllocator>::value, value_type>*
reallocate(value_type* data, UAllocator& alloc, std::size_t old_object_count, std::size_t new_object_count)
{
(void) data;
@@ -553,7 +502,7 @@ class VariableLengthArrayBase
constexpr void move_assign_from(
VariableLengthArrayBase&& rhs,
const size_type rhs_max_size,
typename std::enable_if<is_pocma_or_is_always_equal<UAlloc>::value>::type* = nullptr) noexcept
typename std::enable_if_t<is_pocma_or_is_always_equal<UAlloc>::value>* = nullptr) noexcept
{
(void) rhs_max_size;

@@ -575,10 +524,9 @@ class VariableLengthArrayBase
}

template <typename UAlloc>
constexpr void move_assign_from(
VariableLengthArrayBase&& rhs,
const size_type rhs_max_size,
typename std::enable_if<!is_pocma_or_is_always_equal<UAlloc>::value>::type* = nullptr)
constexpr void move_assign_from(VariableLengthArrayBase&& rhs,
const size_type rhs_max_size,
typename std::enable_if_t<!is_pocma_or_is_always_equal<UAlloc>::value>* = nullptr)
{
if (this == &rhs)
{
@@ -804,6 +752,105 @@ class VariableLengthArrayBase
return capacity_ > capacity_before;
}

// +----------------------------------------------------------------------+
// | CONSTRUCTORS
// +----------------------------------------------------------------------+

constexpr VariableLengthArrayBase(
const allocator_type& alloc,
value_type* data,
size_type initial_capacity,
size_type size,
size_type max_size_max) noexcept(std::is_nothrow_copy_constructible<allocator_type>::value)
: alloc_(alloc)
, data_(data)
, capacity_(initial_capacity)
, size_(size)
, max_size_max_(max_size_max)
{
}

constexpr VariableLengthArrayBase(const VariableLengthArrayBase& rhs, const allocator_type& rhs_alloc) noexcept(
std::is_nothrow_copy_constructible<allocator_type>::value)
: alloc_(std::allocator_traits<allocator_type>::select_on_container_copy_construction(rhs_alloc))
, data_(nullptr)
, capacity_(0)
, size_(0)
, max_size_max_(rhs.max_size_max_)
{
}

constexpr VariableLengthArrayBase(VariableLengthArrayBase&& rhs) noexcept
: alloc_(std::move(rhs.alloc_))
, data_(std::move(rhs.data_))
, capacity_(rhs.capacity_)
, size_(rhs.size_)
, max_size_max_(rhs.max_size_max_)
{
static_assert(std::is_nothrow_move_constructible<allocator_type>::value,
"Allocator must be nothrow move constructible.");
rhs.size_ = 0;
rhs.capacity_ = 0;
rhs.data_ = nullptr;
}

template <typename UAlloc>
constexpr VariableLengthArrayBase(
VariableLengthArrayBase&& rhs,
const UAlloc& rhs_alloc,
typename std::enable_if_t<is_pocma_or_is_always_equal<UAlloc>::value>* = nullptr) noexcept
: alloc_(std::allocator_traits<UAlloc>::select_on_container_copy_construction(rhs_alloc))
, data_(std::move(rhs.data_))
, capacity_(rhs.capacity_)
, size_(rhs.size_)
, max_size_max_(rhs.max_size_max_)
{
static_assert(std::is_nothrow_copy_constructible<UAlloc>::value,
"Allocator must be nothrow copy constructible.");
rhs.size_ = 0;
rhs.capacity_ = 0;
rhs.data_ = nullptr;
}

template <typename UAlloc>
constexpr VariableLengthArrayBase(
VariableLengthArrayBase&& rhs,
const UAlloc& rhs_alloc,
typename std::enable_if_t<!is_pocma_or_is_always_equal<UAlloc>::value>* = nullptr) noexcept
: alloc_(std::allocator_traits<UAlloc>::select_on_container_copy_construction(rhs_alloc))
, data_{nullptr}
, capacity_(0)
, size_(0)
, max_size_max_(rhs.max_size_max_)
{
static_assert(std::is_nothrow_copy_constructible<UAlloc>::value,
"Allocator must be nothrow copy constructible.");
if (alloc_ == rhs.alloc_)
{
// The allocators may not always be equal, but they are this time.
data_ = std::move(rhs.data_);
capacity_ = rhs.capacity_;
size_ = rhs.size_;
}
else
{
// The allocators are not equal, so we need to move the data over
// manually.
if (rhs.size_ > 0)
{
data_ = std::allocator_traits<allocator_type>::allocate(alloc_, rhs.size_);
fast_forward_construct(data_, rhs.size_, rhs.data_, rhs.size_, alloc_);
}
capacity_ = rhs.capacity_;
size_ = rhs.size_;
}
rhs.size_ = 0;
rhs.capacity_ = 0;
rhs.data_ = nullptr;
}

~VariableLengthArrayBase() = default;

// +----------------------------------------------------------------------+
// | DATA MEMBERS
// +----------------------------------------------------------------------+
@@ -975,6 +1022,11 @@ class VariableLengthArray : protected VariableLengthArrayBase<T, Allocator>
return *this;
}

VariableLengthArray(VariableLengthArray&& rhs, const allocator_type& alloc) noexcept
: Base(std::move(rhs), alloc)
{
}

VariableLengthArray(VariableLengthArray&& rhs) noexcept
: Base(std::move(rhs))
{
@@ -993,7 +1045,7 @@ class VariableLengthArray : protected VariableLengthArrayBase<T, Allocator>
if (nullptr != data_)
{
// While deallocation is null-safe, we don't know if the allocator
// was move and is now in an invalid state.
// was moved and is now in an invalid state.
Base::fast_deallocate(data_, size_, capacity_, alloc_);
}
}
@@ -1742,6 +1794,13 @@ class VariableLengthArray<bool, Allocator> : protected VariableLengthArrayBase<u
rhs.last_byte_bit_fill_ = 0;
}

VariableLengthArray(VariableLengthArray&& rhs, const allocator_type& alloc) noexcept
: Base(std::move(rhs), alloc)
, last_byte_bit_fill_{rhs.last_byte_bit_fill_}
{
rhs.last_byte_bit_fill_ = 0;
}

VariableLengthArray& operator=(VariableLengthArray&& rhs) noexcept(
std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
std::allocator_traits<allocator_type>::is_always_equal::value)

0 comments on commit 3c6718a

Please sign in to comment.