From b73295b5f3c2afeea3f44838ee103d5df1f0dafd Mon Sep 17 00:00:00 2001 From: Gene Harvey Date: Fri, 27 Dec 2024 17:50:32 -0600 Subject: [PATCH] Unify algorithm for copy-assignment Also, tighten up the move-assignment algorithm. --- source/include/gch/small_vector.hpp | 678 +++++++++++++++++----------- 1 file changed, 403 insertions(+), 275 deletions(-) diff --git a/source/include/gch/small_vector.hpp b/source/include/gch/small_vector.hpp index c864ff0..6a48036 100644 --- a/source/include/gch/small_vector.hpp +++ b/source/include/gch/small_vector.hpp @@ -2233,9 +2233,9 @@ namespace gch template struct small_vector_data_base { - Pointer data_ptr; - SizeT capacity; - SizeT size; + Pointer m_data_ptr; + SizeT m_capacity; + SizeT m_size; }; template @@ -2612,7 +2612,7 @@ namespace gch void set_data_ptr (ptr data_ptr) noexcept { - m_data.data_ptr = data_ptr; + m_data.m_data_ptr = data_ptr; } GCH_CPP20_CONSTEXPR @@ -2620,23 +2620,23 @@ namespace gch set_capacity (size_ty capacity) noexcept { assert (InlineCapacity <= capacity && "capacity must be greater than InlineCapacity."); - m_data.capacity = static_cast (capacity); + m_data.m_capacity = static_cast (capacity); } GCH_CPP20_CONSTEXPR void set_size (size_ty size) noexcept { - m_data.size = static_cast (size); + m_data.m_size = static_cast (size); } GCH_CPP20_CONSTEXPR void set_data (ptr data_ptr, size_ty capacity, size_ty size) noexcept { - m_data.data_ptr = data_ptr; - m_data.capacity = static_cast (capacity); - m_data.size = static_cast (size); + m_data.m_data_ptr = data_ptr; + m_data.m_capacity = static_cast (capacity); + m_data.m_size = static_cast (size); } GCH_CPP20_CONSTEXPR @@ -2721,10 +2721,96 @@ namespace gch return unchecked_calculate_new_capacity (minimum_required_capacity); } - template + template + GCH_CPP20_CONSTEXPR + void + copy_elements_equal_or_non_propagated_allocators ( + const small_vector_base& other + ) + { + if (get_size () < other.get_size ()) + { + // There are more elements in `other`. + // Overwrite the existing range and uninitialized-move the rest. + auto other_pivot = other.ptr_at (get_size ()); + copy_range (other.begin_ptr (), other_pivot, begin_ptr ()); + uninitialized_copy (other_pivot, other.end_ptr (), end_ptr ()); + } + else + { + // There are fewer elements in `other`. + // Overwrite part of the existing range and destroy the rest + auto new_end = copy_range (other.begin_ptr (), other.end_ptr (), begin_ptr ()); + destroy_range (new_end, end_ptr ()); + } + } + + template ::value>::type * = nullptr> + GCH_CPP20_CONSTEXPR + void + copy_elements_unequal_and_propagated_allocators ( + cptr first, + cptr last, + alloc_interface& alloc + ) + { + destroy_range (begin_ptr (), end_ptr ()); + alloc.uninitialized_copy (first, last, begin_ptr ()); + } + + template ::value>::type * = nullptr> + GCH_CPP20_CONSTEXPR + void + copy_elements_unequal_and_propagated_allocators ( + cptr first, + cptr last, + alloc_interface& alloc + ) + { + ptr l_pivot; + cptr r_pivot; + size_ty range_size = internal_range_length (first, last); + + if (get_size () < range_size) + { + // There are more elements in `other`. + // Uninitialized-copy first, then replace element-by-element backwards. + l_pivot = end_ptr (); + r_pivot = unchecked_next (first, get_size ()); + alloc.uninitialized_copy (r_pivot, last, l_pivot); + } + else + { + // There are fewer elements in `other`. + // Destroy the tail, then replace element-by-element backwards. + l_pivot = ptr_at (range_size); + r_pivot = last; + destroy_range (l_pivot, end_ptr ()); + } + + ptr l_ptr = l_pivot; + GCH_TRY + { + for (cptr r_ptr = r_pivot; ! (l_ptr == begin_ptr ()); ) + { + destroy (--l_ptr); + alloc.construct (l_ptr, *--r_ptr); + } + } + GCH_CATCH (...) + { + alloc.destroy_range (unchecked_next (l_ptr), ptr_at (range_size)); + set_size (internal_range_length (begin_ptr (), l_ptr)); + GCH_THROW; + } + } + + template GCH_CPP20_CONSTEXPR small_vector_base& - copy_assign_default (const small_vector_base& other) + copy_assign_equal_or_non_propagated_allocators (const small_vector_base& other) { if (get_capacity () < other.get_size ()) { @@ -2742,119 +2828,226 @@ namespace gch GCH_THROW; } - reset_data (new_data_ptr, new_capacity, other.get_size ()); + wipe (); + set_data_ptr (new_data_ptr); + set_capacity (new_capacity); } - else + else if (other.get_size () <= InlineCapacity && has_allocation ()) { - if (get_size () < other.get_size ()) - { - // No reallocation, partially in uninitialized space. - std::copy_n (other.begin_ptr (), get_size (), begin_ptr ()); - uninitialized_copy (other.ptr_at (get_size ()), other.end_ptr (), end_ptr ()); - } - else - { - destroy_range (copy_range (other.begin_ptr (), other.end_ptr (), begin_ptr ()), - end_ptr ()); - } + // Eagerly move into inline storage. - // data_ptr and capacity do not change in this case. - set_size (other.get_size ()); + ptr new_data_ptr = storage_ptr (); +#ifdef GCH_LIB_IS_CONSTANT_EVALUATED + if (std::is_constant_evaluated ()) + new_data_ptr = alloc_interface::allocate (InlineCapacity); +#endif + + uninitialized_copy (other.begin_ptr (), other.end_ptr (), new_data_ptr); + destroy_range (begin_ptr (), end_ptr ()); + deallocate (begin_ptr (), get_capacity ()); + set_data_ptr (new_data_ptr); + set_capacity (InlineCapacity); } + else + copy_elements_equal_or_non_propagated_allocators (other); + set_size (other.get_size ()); alloc_interface::maybe_copy (other); return *this; } - template ::propagate_on_container_copy_assignment::value - &&! allocators_always_equal::value - >::type * = nullptr> + template GCH_CPP20_CONSTEXPR small_vector_base& - copy_assign (const small_vector_base& other) + copy_assign_unequal_and_propagated_allocators (const small_vector_base& other) { - if (other.allocator_ref () == allocator_ref ()) - return copy_assign_default (other); - - // Avoid using `select_on_container_copy_construction` here. - alloc_interface new_alloc (other.allocator_ref ()); + // Note: We have to create a new alloc_interface here because `other` is const. + alloc_interface alloc { other.allocator_ref () }; if (InlineCapacity < other.get_size ()) { - const size_ty new_capacity = other.get_size (); - const ptr new_data_ptr = new_alloc.allocate_with_hint ( + const size_ty new_capacity = calculate_new_capacity (InlineCapacity, other.get_size ()); + const ptr new_data_ptr = alloc.allocate_with_hint ( new_capacity, - other.allocation_end_ptr ()); + other.allocation_end_ptr () + ); GCH_TRY { - new_alloc.uninitialized_copy (other.begin_ptr (), other.end_ptr (), new_data_ptr); + alloc.uninitialized_copy (other.begin_ptr (), other.end_ptr (), new_data_ptr); } GCH_CATCH (...) { - new_alloc.deallocate (new_data_ptr, new_capacity); + alloc.deallocate (new_data_ptr, new_capacity); GCH_THROW; } - reset_data (new_data_ptr, new_capacity, other.get_size ()); + wipe (); + set_data_ptr (new_data_ptr); + set_capacity (new_capacity); } - else + else if (has_allocation ()) { - if (has_allocation ()) - { + ptr new_data_ptr = storage_ptr (); #ifdef GCH_LIB_IS_CONSTANT_EVALUATED - ptr new_data_ptr; - if (std::is_constant_evaluated ()) - new_data_ptr = new_alloc.allocate (InlineCapacity); - else - new_data_ptr = storage_ptr (); -#else - const ptr new_data_ptr = storage_ptr (); + if (std::is_constant_evaluated ()) + new_data_ptr = alloc.allocate (InlineCapacity); #endif - new_alloc.uninitialized_copy (other.begin_ptr (), other.end_ptr (), new_data_ptr); - destroy_range (begin_ptr (), end_ptr ()); - deallocate (begin_ptr (), get_capacity ()); - set_capacity (InlineCapacity); - set_data_ptr (new_data_ptr); - } - else - { - destroy_range (begin_ptr (), end_ptr ()); - GCH_TRY - { - new_alloc.uninitialized_copy (other.begin_ptr (), other.end_ptr (), begin_ptr ()); - } - GCH_CATCH (...) - { - set_size (0); - GCH_THROW; - } - } - set_size (other.get_size ()); + alloc.uninitialized_copy (other.begin_ptr (), other.end_ptr (), new_data_ptr); + destroy_range (begin_ptr (), end_ptr ()); + deallocate (begin_ptr (), get_capacity ()); + set_data_ptr (new_data_ptr); + set_capacity (InlineCapacity); + } + else + { + copy_elements_unequal_and_propagated_allocators ( + other.begin_ptr (), + other.end_ptr (), + alloc + ); } - alloc_interface::operator= (std::move (new_alloc)); + set_size (other.get_size ()); + alloc_interface::operator= (std::move (alloc)); return *this; } - template ::propagate_on_container_copy_assignment::value || allocators_always_equal::value >::type * = nullptr> GCH_CPP20_CONSTEXPR small_vector_base& - copy_assign (const small_vector_base& other) + copy_assign (const small_vector_base& other) + { + return copy_assign_equal_or_non_propagated_allocators (other); + } + + template ::propagate_on_container_copy_assignment::value + &&! allocators_always_equal::value + >::type * = nullptr> + GCH_CPP20_CONSTEXPR + small_vector_base& + copy_assign (const small_vector_base& other) + { + if (allocator_ref () == other.allocator_ref ()) + return copy_assign_equal_or_non_propagated_allocators (other); + return copy_assign_unequal_and_propagated_allocators (other); + } + + template + GCH_CPP20_CONSTEXPR + void + move_elements_equal_or_non_propagated_allocators (small_vector_base& other) + { + if (get_size () < other.get_size ()) + { + // There are more elements in `other`. + // Overwrite the existing range and uninitialized-move the rest. + ptr other_pivot = other.ptr_at (get_size ()); + std::move (other.begin_ptr (), other_pivot, begin_ptr ()); + uninitialized_move (other_pivot, other.end_ptr (), end_ptr ()); + } + else + { + // There are fewer elements in `other`. + // Overwrite part of the existing range and destroy the rest + ptr new_end = std::move (other.begin_ptr (), other.end_ptr (), begin_ptr ()); + destroy_range (new_end, end_ptr ()); + } + } + + template ::value>::type * = nullptr> + GCH_CPP20_CONSTEXPR + void + move_elements_unequal_and_propagated_allocators (small_vector_base& other) + { + destroy_range (begin_ptr (), end_ptr ()); + other.uninitialized_move (other.begin_ptr (), other.end_ptr (), begin_ptr ()); + } + + template ::value>::type * = nullptr> + GCH_CPP20_CONSTEXPR + void + move_elements_unequal_and_propagated_allocators (small_vector_base& other) + { + ptr l_pivot, r_pivot; + + if (get_size () < other.get_size ()) + { + // There are more elements in `other`. + // Uninitialized-move first, then replace element-by-element backwards. + l_pivot = end_ptr (); + r_pivot = other.ptr_at (get_size ()); + other.uninitialized_move (r_pivot, other.end_ptr (), l_pivot); + } + else + { + // There are fewer elements in `other`. + // Destroy the tail, then replace element-by-element backwards. + l_pivot = ptr_at (other.get_size ()); + r_pivot = other.end_ptr (); + destroy_range (l_pivot, end_ptr ()); + } + + ptr l_ptr = l_pivot; + GCH_TRY + { + for (ptr r_ptr = r_pivot; ! (l_ptr == begin_ptr ()); ) + { + destroy (--l_ptr); + other.construct (l_ptr, std::move (*--r_ptr)); + } + } + GCH_CATCH (...) + { + other.destroy_range (unchecked_next (l_ptr), ptr_at (other.get_size ())); + set_size (internal_range_length (begin_ptr (), l_ptr)); + GCH_THROW; + } + } + + template ::value>::type * = nullptr> + GCH_CPP20_CONSTEXPR + void + move_elements (small_vector_base& other) + { + return move_elements_equal_or_non_propagated_allocators (other); + } + + template ::value>::type * = nullptr> + GCH_CPP20_CONSTEXPR + void + move_elements (small_vector_base& other) + { + if (allocator_ref () == other.allocator_ref ()) + return move_elements_equal_or_non_propagated_allocators (other); + return move_elements_unequal_and_propagated_allocators (other); + } + + template + GCH_CPP20_CONSTEXPR + small_vector_base& + move_assign_pointer (small_vector_base& other) noexcept { - return copy_assign_default (other); + reset_data (other.begin_ptr (), other.get_capacity (), other.get_size ()); + other.set_default (); + alloc_interface::maybe_move (std::move (other)); + return *this; } template GCH_CPP20_CONSTEXPR small_vector_base& - move_assign_unequal_and_non_propagated_allocators (small_vector_base& other) + move_assign_equal_or_non_propagated_allocators (small_vector_base& other) { if (get_capacity () < other.get_size ()) { @@ -2872,26 +3065,30 @@ namespace gch GCH_THROW; } - reset_data (new_data_ptr, new_capacity, other.get_size ()); + wipe (); + set_data_ptr (new_data_ptr); + set_capacity (new_capacity); } - else + else if (has_allocation () && other.get_size () <= InlineCapacity) { - move_elements_equal_or_non_propagated_allocators (other); + // Eagerly move into inline storage if `other` is small enough. - // data_ptr and capacity do not change in this case - set_size (other.get_size ()); - } + ptr new_data_ptr = storage_ptr (); +#ifdef GCH_LIB_IS_CONSTANT_EVALUATED + if (std::is_constant_evaluated ()) + new_data_ptr = this->allocate (InlineCapacity); +#endif - return *this; - } + uninitialized_move (other.begin_ptr (), other.end_ptr (), new_data_ptr); + destroy_range (begin_ptr (), end_ptr ()); + deallocate (begin_ptr (), get_capacity ()); + set_data_ptr (new_data_ptr); + set_capacity (InlineCapacity); + } + else + move_elements_equal_or_non_propagated_allocators (other); - template ::type * = nullptr> - GCH_CPP20_CONSTEXPR - small_vector_base& - move_assign_equal_or_propagated_allocators (small_vector_base& other) noexcept - { - reset_data (other.begin_ptr (), other.get_capacity (), other.get_size ()); - other.set_default (); + set_size (other.get_size ()); alloc_interface::maybe_move (std::move (other)); return *this; } @@ -2899,110 +3096,127 @@ namespace gch template GCH_CPP20_CONSTEXPR small_vector_base& - move_assign_equal_or_propagated_allocators (small_vector_base& other) + move_assign_unequal_and_propagated_allocators (small_vector_base& other) { - if (other.has_allocation () && InlineCapacity < other.get_capacity ()) - { - reset_data (other.begin_ptr (), other.get_capacity (), other.get_size ()); - other.set_default (); - } - else if (other.get_size () <= InlineCapacity) + if (InlineCapacity < other.get_size ()) { - // Eagerly move into inline storage. + const size_ty new_capacity = calculate_new_capacity (InlineCapacity, other.get_size ()); + const ptr new_data_ptr = other.allocate_with_hint ( + new_capacity, + other.allocation_end_ptr () + ); - if (has_allocation ()) + GCH_TRY { -#ifdef GCH_LIB_IS_CONSTANT_EVALUATED - ptr new_data_ptr; - if (std::is_constant_evaluated ()) - new_data_ptr = other.allocate (InlineCapacity); - else - new_data_ptr = storage_ptr (); -#else - const ptr new_data_ptr = storage_ptr (); -#endif - other.uninitialized_move (other.begin_ptr (), other.end_ptr (), new_data_ptr); - reset_data (new_data_ptr, InlineCapacity, other.get_size ()); } - else + GCH_CATCH (...) { - move_elements (other); - set_size (other.get_size ()); + other.deallocate (new_data_ptr, new_capacity); + GCH_THROW; } + + wipe (); + set_data_ptr (new_data_ptr); + set_capacity (new_capacity); } - else + else if (has_allocation ()) { - bool needs_propagation = - std::allocator_traits::propagate_on_container_move_assignment::value - &&! allocators_always_equal::value - &&! (allocator_ref () == other.allocator_ref ()); - size_ty target_capacity; - if (needs_propagation) - target_capacity = InlineCapacity; - else - target_capacity = get_capacity (); - - if (target_capacity < other.get_size ()) - { - // If we can't move the pointer over, then we will have to move element-by-element. - // - // Note: We use `allocate_with_hint` here to bypass the assert in `unchecked_allocate`. - size_ty new_capacity = calculate_new_capacity (target_capacity,other.get_size ()); - ptr new_data_ptr = other.allocate_with_hint ( - new_capacity, - other.allocation_end_ptr () - ); - - GCH_TRY - { - other.uninitialized_move (other.begin_ptr (), other.end_ptr (), new_data_ptr); - } - GCH_CATCH (...) - { - other.deallocate (new_data_ptr, new_capacity); - GCH_THROW; - } + ptr new_data_ptr = storage_ptr (); +#ifdef GCH_LIB_IS_CONSTANT_EVALUATED + if (std::is_constant_evaluated ()) + new_data_ptr = other.allocate (InlineCapacity); +#endif - reset_data (new_data_ptr, new_capacity, other.get_size ()); - } - else - { - move_elements (other); - set_size (other.get_size ()); - } + other.uninitialized_move (other.begin_ptr (), other.end_ptr (), new_data_ptr); + destroy_range (begin_ptr (), end_ptr ()); + deallocate (begin_ptr (), get_capacity ()); + set_data_ptr (new_data_ptr); + set_capacity (InlineCapacity); } + else + move_elements_unequal_and_propagated_allocators (other); - alloc_interface::maybe_move (std::move (other)); + set_size (other.get_size ()); + alloc_interface::operator= (std::move (other)); return *this; } + template ::type * = nullptr> + GCH_CPP20_CONSTEXPR + small_vector_base& + move_assign_equal_allocators (small_vector_base& other) + { + return move_assign_pointer (other); + } + + template + GCH_CPP20_CONSTEXPR + small_vector_base& + move_assign_equal_allocators (small_vector_base& other) + { + if (other.has_allocation () && InlineCapacity < other.get_capacity ()) + return move_assign_pointer (other); + else + return move_assign_equal_or_non_propagated_allocators (other); + } + + template ::propagate_on_container_move_assignment::value + >::type* = nullptr> + GCH_CPP20_CONSTEXPR + small_vector_base& + move_assign_unequal_allocators (small_vector_base& other) + { + return move_assign_pointer (other); + } + template ::propagate_on_container_move_assignment::value - || allocators_always_equal::value - ) + std::allocator_traits::propagate_on_container_move_assignment::value >::type * = nullptr> GCH_CPP20_CONSTEXPR small_vector_base& - move_assign (small_vector_base& other) + move_assign_unequal_allocators (small_vector_base& other) { - return move_assign_equal_or_propagated_allocators (other); + if (other.has_allocation () && InlineCapacity < other.get_capacity ()) + return move_assign_pointer (other); + else + return move_assign_unequal_and_propagated_allocators (other); } template ::propagate_on_container_move_assignment::value - || allocators_always_equal::value - ) + ! std::allocator_traits::propagate_on_container_move_assignment::value >::type * = nullptr> GCH_CPP20_CONSTEXPR small_vector_base& + move_assign_unequal_allocators (small_vector_base& other) + { + // We cannot move an allocation pointer in this case, so go directly to the inner function. + return move_assign_equal_or_non_propagated_allocators (other); + } + + template ::value>::type * = nullptr> + GCH_CPP20_CONSTEXPR + small_vector_base& + move_assign (small_vector_base& other) + { + return move_assign_equal_allocators (other); + } + + template ::value>::type * = nullptr> + GCH_CPP20_CONSTEXPR + small_vector_base& move_assign (small_vector_base& other) { if (allocator_ref () == other.allocator_ref ()) - return move_assign_equal_or_propagated_allocators (other); - return move_assign_unequal_and_non_propagated_allocators (other); + return move_assign_equal_allocators (other); + return move_assign_unequal_allocators (other); } template - void - move_elements_equal_or_non_propagated_allocators (small_vector_base& other) - { - if (get_size () < other.get_size ()) - { - // There are more elements in `other`. - // Overwrite the existing range and uninitialized move the rest. - ptr other_pivot = other.ptr_at (get_size ()); - std::move (other.begin_ptr (), other_pivot, begin_ptr ()); - uninitialized_move (other_pivot, other.end_ptr (), end_ptr ()); - } - else - { - // fewer elements in other - // overwrite part of the existing range and destroy the rest - ptr new_end = std::move (other.begin_ptr (), other.end_ptr (), begin_ptr ()); - destroy_range (new_end, end_ptr ()); - } - } - - template ::value>::type * = nullptr> - void - move_elements_unequal_and_propagated_allocators (small_vector_base& other) - { - destroy_range (begin_ptr (), end_ptr ()); - other.uninitialized_move (other.begin_ptr (), other.end_ptr (), begin_ptr ()); - } - - template ::value>::type * = nullptr> - void - move_elements_unequal_and_propagated_allocators (small_vector_base& other) - { - ptr l_pivot, r_pivot; - - if (get_size () < other.get_size ()) - { - // There are more elements in `other`. - // Uninitialized move first, then replace element-by-element backwards. - l_pivot = end_ptr (); - r_pivot = other.ptr_at (get_size ()); - other.uninitialized_move (r_pivot, other.end_ptr (), l_pivot); - } - else - { - // There are fewer elements in `other`. - // Overwrite part of the existing range and destroy the tail. - l_pivot = ptr_at (other.get_size ()); - r_pivot = other.end_ptr (); - destroy_range (l_pivot, end_ptr ()); - } - - ptr l_ptr = l_pivot; - GCH_TRY - { - for (ptr r_ptr = r_pivot; ! (l_ptr == begin_ptr ()); ) - { - destroy (--l_ptr); - other.construct (l_ptr, std::move (*--r_ptr)); - } - } - GCH_CATCH (...) - { - other.destroy_range (unchecked_next (l_ptr), ptr_at (other.get_size ())); - set_size (internal_range_length (begin_ptr (), l_ptr)); - GCH_THROW; - } - } - - template ::value>::type * = nullptr> - void - move_elements (small_vector_base& other) - { - return move_elements_equal_or_non_propagated_allocators (other); - } - - template ::value>::type * = nullptr> - void - move_elements (small_vector_base& other) - { - if (allocator_ref () == other.allocator_ref ()) - return move_elements_equal_or_non_propagated_allocators (other); - return move_elements_unequal_and_propagated_allocators (other); - } - template GCH_CPP20_CONSTEXPR void @@ -4512,7 +4637,7 @@ namespace gch else swap_elements_equal_or_non_propagated_allocators (other); - swap (m_data.size, other.m_data.size); + swap (m_data.m_size, other.m_data.m_size); } template ::type * = nullptr> @@ -4521,9 +4646,9 @@ namespace gch swap_equal_or_propagated_allocators (small_vector_base& other) { using std::swap; - swap (m_data.data_ptr, other.m_data.data_ptr); - swap (m_data.capacity, other.m_data.capacity); - swap (m_data.size, other.m_data.size); + swap (m_data.m_data_ptr, other.m_data.m_data_ptr); + swap (m_data.m_capacity, other.m_data.m_capacity); + swap (m_data.m_size, other.m_data.m_size); alloc_interface::maybe_swap (other); } @@ -4536,7 +4661,8 @@ namespace gch static_assert (LessEqualI <= InlineCapacity, "should not be instantiated"); assert ( - allocator_ref () == other.allocator_ref () + allocators_always_equal::value + || allocator_ref () == other.allocator_ref () || std::allocator_traits::propagate_on_container_swap::value ); @@ -4544,21 +4670,18 @@ namespace gch { if (InlineCapacity < other.get_capacity ()) { - swap (m_data.data_ptr, other.m_data.data_ptr); - swap (m_data.capacity, other.m_data.capacity); + // Note: This is always the branch that will run when constant-evaluated. + swap (m_data.m_data_ptr, other.m_data.m_data_ptr); + swap (m_data.m_capacity, other.m_data.m_capacity); } else { // Move the elements of `other` into inline storage. // Give our pointer to `other`. + ptr new_data_ptr = storage_ptr (); #ifdef GCH_LIB_IS_CONSTANT_EVALUATED - ptr new_data_ptr; if (std::is_constant_evaluated ()) - new_data_ptr = other.allocate (InlineCapacity); - else - new_data_ptr = storage_ptr (); -#else - const ptr new_data_ptr = storage_ptr (); + new_data_ptr = this->allocate (InlineCapacity); #endif other.uninitialized_move (other.begin_ptr (), other.end_ptr (), new_data_ptr); @@ -4573,14 +4696,15 @@ namespace gch } else if (InlineCapacity < other.get_capacity ()) { - // Note: This will never be constant evaluated because both are always allocated. + // This implies that `other` is allocated, and that we can use its pointer. + size_ty new_capacity = LessEqualI; ptr new_data_ptr = other.storage_ptr (); // Check to see if we can store our elements in the inline storage of `other`. if (LessEqualI < get_size ()) { - new_capacity = get_size (); + new_capacity = other.calculate_new_capacity (LessEqualI, get_size ()); new_data_ptr = alloc_interface::allocate_with_hint ( new_capacity, allocation_end_ptr () @@ -4609,7 +4733,7 @@ namespace gch else if (LessEqualI < get_size ()) { // We have too many elements to store in `other`. Allocate a new buffer. - size_ty new_capacity = get_size (); + size_ty new_capacity = other.calculate_new_capacity(LessEqualI, get_size ()); ptr new_data_ptr = alloc_interface::allocate_with_hint ( new_capacity, other.allocation_end_ptr () @@ -4662,7 +4786,7 @@ namespace gch else swap_elements (other); - swap (m_data.size, other.m_data.size); + swap (m_data.m_size, other.m_data.m_size); alloc_interface::maybe_swap (other); } @@ -4901,14 +5025,14 @@ namespace gch size_ty get_capacity (void) const noexcept { - return m_data.capacity; + return m_data.m_capacity; } GCH_NODISCARD constexpr size_ty get_size (void) const noexcept { - return m_data.size; + return m_data.m_size; } GCH_NODISCARD constexpr @@ -4922,7 +5046,7 @@ namespace gch ptr begin_ptr (void) noexcept { - return m_data.data_ptr; + return m_data.m_data_ptr; } GCH_NODISCARD @@ -4930,7 +5054,7 @@ namespace gch cptr begin_ptr (void) const noexcept { - return m_data.data_ptr; + return m_data.m_data_ptr; } GCH_NODISCARD GCH_CPP14_CONSTEXPR @@ -4986,6 +5110,10 @@ namespace gch ptr storage_ptr (void) noexcept { +//#ifdef GCH_LIB_IS_CONSTANT_EVALUATED +// if (std::is_constant_evaluated ()) +// return nullptr; +//#endif return m_data.storage (); }