Skip to content

Commit

Permalink
add move for zero sized any in any case (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
kelbon authored Feb 14, 2024
1 parent 278c272 commit 56143f5
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 20 deletions.
47 changes: 28 additions & 19 deletions include/anyany/anyany.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ struct basic_any : construct_interface<basic_any<Alloc, SooS, Methods...>, Metho
using aa_polymorphic_tag = int;

private:
static AA_CONSTEVAL_CPP20 size_t soo_buffer_size() noexcept {
static AA_CONSTEVAL_CPP20 size_t soo_buffer_size() noexcept {
// needs atleast sizeof(std::size_t) in buffer(SooS)
// to store allocated size for passing it into deallocate(ptr, n)
static_assert(SooS == 0 || SooS >= sizeof(size_t),
Expand Down Expand Up @@ -1174,7 +1174,7 @@ struct basic_any : construct_interface<basic_any<Alloc, SooS, Methods...>, Metho
template <typename Method>
static constexpr bool has_method = noexport::contains_v<Method, Methods...>;
static constexpr bool has_copy = has_method<copy_with<Alloc, SooS>>;
static constexpr bool has_move = noexport::has_move<Methods...>;
static constexpr bool has_move = noexport::has_move<Methods...> || SooS == 0;

static_assert(noexport::is_byte_like_v<typename alloc_traits::value_type>);
static_assert(std::is_nothrow_copy_constructible_v<Alloc>, "C++ Standard requires it");
Expand Down Expand Up @@ -1384,6 +1384,10 @@ struct basic_any : construct_interface<basic_any<Alloc, SooS, Methods...>, Metho

// observe

constexpr explicit operator bool() const noexcept {
return has_value();
}

enum : bool { is_always_stable_pointers = SooS == 0 };

// returns true if poly_ptr/ref to this basic_any will not be invalidated after move
Expand Down Expand Up @@ -1411,27 +1415,32 @@ struct basic_any : construct_interface<basic_any<Alloc, SooS, Methods...>, Metho
return invoke<noexport::some_copy_method<Methods...>>(*this).move_fn;
}
// precodition - has_value() == false
template <bool MemoryMaybeReused = true, typename Other>
void move_value_from(Other& other) noexcept(MemoryMaybeReused) {
template <bool MemoryMaybeReused = true, typename... OtherMethods>
void move_value_from(basic_any<Alloc, SooS, OtherMethods...>& other) noexcept(MemoryMaybeReused) {
if (!other.has_value())
return;
// `move` is noexcept (invariant of small state)
// `move` also 'relocate' i.e. calls dctor of value(for remove invoke<destroy> in future)
if (!other.memory_allocated()) {
other.get_move_fn()(other.value_ptr, value_ptr);
if constexpr (SooS == 0) {
value_ptr = std::exchange(other.value_ptr, other.data);
size_allocated = other.size_allocated;
} else {
if constexpr (MemoryMaybeReused) {
value_ptr = std::exchange(other.value_ptr, other.data);
size_allocated = other.size_allocated;
} else {
value_ptr = alloc.allocate(other.size_allocated);
size_allocated = other.size_allocated;
scope_failure free_memory{[&] {
alloc.deallocate(reinterpret_cast<alloc_pointer_type>(value_ptr), other.size_allocated);
value_ptr = data;
}};
// `move` is noexcept (invariant of small state)
// `move` also 'relocate' i.e. calls dctor of value(for remove invoke<destroy> in future)
if (!other.memory_allocated()) {
other.get_move_fn()(other.value_ptr, value_ptr);
free_memory.no_longer_needed();
} else {
if constexpr (MemoryMaybeReused) {
value_ptr = std::exchange(other.value_ptr, other.data);
size_allocated = other.size_allocated;
} else {
value_ptr = alloc.allocate(other.size_allocated);
size_allocated = other.size_allocated;
scope_failure free_memory{[&] {
alloc.deallocate(reinterpret_cast<alloc_pointer_type>(value_ptr), other.size_allocated);
value_ptr = data;
}};
other.get_move_fn()(other.value_ptr, value_ptr);
free_memory.no_longer_needed();
}
}
}
vtable_ptr = subtable_ptr<Methods...>(other.vtable_ptr);
Expand Down
16 changes: 15 additions & 1 deletion tests/test_anyany.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,20 @@ TEST(non_default_constructible_allocs) {
return 0;
}

TEST(zero_sized_any) {
using test_t = aa::basic_any_with<aa::default_allocator, 0>;
test_t val = 5;
auto val2 = std::move(val);
error_if(!val2.is_stable_pointers());
error_if(!val2);
error_if(!!val);
std::swap(val, val2);
error_if(!val.is_stable_pointers());
error_if(!val);
error_if(!!val2);
return error_count;
}

int main() {
fwd_declare(5);
std::cout << "C++ standard: " << __cplusplus << std::endl;
Expand Down Expand Up @@ -1571,5 +1585,5 @@ int main() {
TESTtype_descriptor_and_plugins_interaction() + TESTspecial_member_functions() + TESTptr_behavior() +
TESTtransmutate_ctors() + TESTstateful() + TESTsubtable_ptr() + TESTmaterialize() +
TESTruntime_reflection() + TESTcustom_unique_ptr() + TESTstrange_allocs() +
TESTalways_allocated_any() + TESTnon_default_constructible_allocs();
TESTalways_allocated_any() + TESTnon_default_constructible_allocs() + TESTzero_sized_any();
}

0 comments on commit 56143f5

Please sign in to comment.