From 22131693e1892c5477c998ab63bf476d152b17cb Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Wed, 1 Jan 2025 19:18:19 +0100 Subject: Implement move constructor for buffer --- asl/box.hpp | 2 +- asl/buffer.hpp | 21 +++++++++--------- asl/maybe_uninit.hpp | 2 +- asl/memory.hpp | 8 +++---- asl/option.hpp | 2 +- asl/testing/testing.cpp | 8 +++++++ asl/tests/buffer_tests.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++++ asl/tests/test_types.hpp | 1 + 8 files changed, 82 insertions(+), 17 deletions(-) diff --git a/asl/box.hpp b/asl/box.hpp index 198fada..491338f 100644 --- a/asl/box.hpp +++ b/asl/box.hpp @@ -58,7 +58,7 @@ public: { if (m_ptr != nullptr) { - destruct(m_ptr); + destroy(m_ptr); m_alloc.dealloc(m_ptr, layout::of()); m_ptr = nullptr; } diff --git a/asl/buffer.hpp b/asl/buffer.hpp index 9020a99..84284bc 100644 --- a/asl/buffer.hpp +++ b/asl/buffer.hpp @@ -100,9 +100,8 @@ private: constexpr void set_size(isize_t new_size) { - ASL_ASSERT(new_size >= 0); - ASL_ASSERT_RELEASE(new_size <= capacity()); - if (kInlineCapacity == 0 || is_on_heap()) + ASL_ASSERT(new_size >= 0 && new_size <= capacity()); + if (is_on_heap()) { store_size_encoded(encode_size_heap(new_size)); } @@ -124,22 +123,23 @@ public: { if (other.is_on_heap()) { - // @Todo Test this - destroy(); m_data = other.m_data; m_capacity = other.m_capacity; - set_size(other.size()); + store_size_encoded(other.load_size_encoded()); } else if (trivially_move_constructible) { - // @Todo Test this - destroy(); asl::memcpy(this, &other, kInlineRegionSize); } else { - // @Todo + isize_t n = other.size(); + ASL_ASSERT(n <= kInlineCapacity); + relocate_uninit_n(data(), other.data(), n); + set_size_inline(n); } + + other.set_size_inline(0); } ~buffer() @@ -171,7 +171,7 @@ public: isize_t current_size = size(); if (current_size == 0) { return; } - destruct_n(data(), current_size); + destroy_n(data(), current_size); set_size(0); } @@ -185,6 +185,7 @@ public: auto current_layout = layout::array(m_capacity); m_allocator.dealloc(m_data, current_layout); } + set_size_inline(0); } } diff --git a/asl/maybe_uninit.hpp b/asl/maybe_uninit.hpp index cedd96f..e59cfe0 100644 --- a/asl/maybe_uninit.hpp +++ b/asl/maybe_uninit.hpp @@ -53,7 +53,7 @@ public: // @Safety Must be called only when in initialized state. constexpr void uninit_unsafe() & { - destruct(init_ptr_unsafe()); + destroy(init_ptr_unsafe()); } }; diff --git a/asl/memory.hpp b/asl/memory.hpp index 0441c8c..cfc7057 100644 --- a/asl/memory.hpp +++ b/asl/memory.hpp @@ -36,7 +36,7 @@ constexpr T* construct_at(void* ptr, Args&&... args) } template -constexpr void destruct(T* data) +constexpr void destroy(T* data) { if constexpr (!trivially_destructible) { @@ -45,13 +45,13 @@ constexpr void destruct(T* data) } template -constexpr void destruct_n(T* data, isize_t n) +constexpr void destroy_n(T* data, isize_t n) { if constexpr (!trivially_destructible) { for (isize_t i = 0; i < n; ++i) { - destruct(data + i); + destroy(data + i); } } } @@ -71,7 +71,7 @@ constexpr void relocate_uninit_n(T* to, T* from, isize_t n) // NOLINTNEXTLINE(*-pointer-arithmetic) construct_at(to + i, ASL_MOVE(from[i])); } - destruct_n(from, n); + destroy_n(from, n); } } diff --git a/asl/option.hpp b/asl/option.hpp index 8deed69..b87a5ab 100644 --- a/asl/option.hpp +++ b/asl/option.hpp @@ -383,7 +383,7 @@ public: } else { - destruct(&m_payload); + destroy(&m_payload); construct_at(&m_payload, niche{}); } } diff --git a/asl/testing/testing.cpp b/asl/testing/testing.cpp index 405df34..aff6a74 100644 --- a/asl/testing/testing.cpp +++ b/asl/testing/testing.cpp @@ -38,6 +38,8 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) { int fail = 0; int pass = 0; + + asl::testing::Test* failed_head = nullptr; for (auto* it = g_head; it != nullptr; it = it->m_next) { @@ -55,6 +57,8 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) { asl::eprint(RED("[ FAILED ]") " {}\n", it->m_case_name); fail += 1; + + it->m_next = asl::exchange(failed_head, it); } } @@ -67,6 +71,10 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) else { asl::eprint(RED("[ FAILED ]") " {} test(s) failed\n", fail); + for (auto* it = failed_head; it != nullptr; it = it->m_next) + { + asl::eprint(RED("[ FAILED ]") " {}\n", it->m_case_name); + } } return fail; diff --git a/asl/tests/buffer_tests.cpp b/asl/tests/buffer_tests.cpp index 15cc391..556eb2c 100644 --- a/asl/tests/buffer_tests.cpp +++ b/asl/tests/buffer_tests.cpp @@ -228,3 +228,58 @@ ASL_TEST(clear_destructor_heap) ASL_TEST_EXPECT(d1 == true); ASL_TEST_EXPECT(d2 == true); } + +ASL_TEST(move_construct_from_heap) +{ + bool d[3]{}; + asl::buffer buf; + buf.push(&d[0]); + buf.push(&d[1]); + buf.push(&d[2]); + + { + asl::buffer buf2(ASL_MOVE(buf)); + ASL_TEST_EXPECT(buf2.size() == 3); + ASL_TEST_EXPECT(d[0] == false); + ASL_TEST_EXPECT(d[1] == false); + ASL_TEST_EXPECT(d[2] == false); + } + + ASL_TEST_EXPECT(buf.size() == 0); + ASL_TEST_EXPECT(d[0] == true); + ASL_TEST_EXPECT(d[1] == true); + ASL_TEST_EXPECT(d[2] == true); +} + +ASL_TEST(move_construct_inline_trivial) +{ + asl::buffer buf; + buf.push(1U); + buf.push(2U); + + asl::buffer buf2(ASL_MOVE(buf)); + ASL_TEST_EXPECT(buf2[0] == 1U); + ASL_TEST_EXPECT(buf2[1] == 2U); + + ASL_TEST_EXPECT(buf2.size() == 2); + ASL_TEST_EXPECT(buf.size() == 0); +} + +ASL_TEST(move_construct_from_inline_non_trivial) +{ + bool d[2]{}; + asl::buffer buf; + buf.push(&d[0]); + buf.push(&d[1]); + + { + asl::buffer buf2(ASL_MOVE(buf)); + ASL_TEST_EXPECT(buf2.size() == 2); + ASL_TEST_EXPECT(d[0] == false); + ASL_TEST_EXPECT(d[1] == false); + } + + ASL_TEST_EXPECT(buf.size() == 0); + ASL_TEST_EXPECT(d[0] == true); + ASL_TEST_EXPECT(d[1] == true); +} diff --git a/asl/tests/test_types.hpp b/asl/tests/test_types.hpp index f91afb3..1bcf72f 100644 --- a/asl/tests/test_types.hpp +++ b/asl/tests/test_types.hpp @@ -82,6 +82,7 @@ struct DestructorObserver { if (destroyed != nullptr) { + ASL_ASSERT_RELEASE(*destroyed == false); *destroyed = true; } } -- cgit