From a9f254dcea5cc73112ba4df96ceaf48a33fae216 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Thu, 2 Jan 2025 19:37:41 +0100 Subject: Implement copy move & assign for buffer --- asl/buffer.hpp | 53 +++++++++++++++++++++++++++++++++++++--- asl/memory.hpp | 34 ++++++++++++++++++++++++++ asl/tests/buffer_tests.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 3 deletions(-) (limited to 'asl') diff --git a/asl/buffer.hpp b/asl/buffer.hpp index ca371d2..eab0a2e 100644 --- a/asl/buffer.hpp +++ b/asl/buffer.hpp @@ -5,6 +5,7 @@ #include "asl/annotations.hpp" #include "asl/memory.hpp" #include "asl/assert.hpp" +#include "asl/span.hpp" namespace asl { @@ -141,7 +142,7 @@ private: isize_t other_n = other.size(); isize_t this_n = size(); resize_uninit(other_n); - if (other_n < this_n) + if (other_n <= this_n) { relocate_assign_n(data(), other.data(), other_n); } @@ -168,6 +169,26 @@ private: } } + void copy_range(span to_copy) + { + isize_t this_size = size(); + isize_t new_size = to_copy.size(); + + resize_uninit(to_copy.size()); + ASL_ASSERT(capacity() >= new_size); + ASL_ASSERT(size() == to_copy.size()); + + if (new_size <= this_size) + { + copy_assign_n(data(), to_copy.data(), new_size); + } + else + { + copy_assign_n(data(), to_copy.data(), this_size); + copy_uninit_n(data() + this_size, to_copy.data() + this_size, new_size - this_size); + } + } + public: constexpr buffer() requires default_constructible = default; @@ -175,13 +196,30 @@ public: : m_allocator{ASL_MOVE(allocator)} {} + constexpr buffer(const buffer& other) + requires copy_constructible && copyable + : m_allocator{other.m_allocator} + { + copy_range(other); + } + constexpr buffer(buffer&& other) + requires moveable : buffer(ASL_MOVE(other.m_allocator)) { move_from_other(ASL_MOVE(other), false); } + + constexpr buffer& operator=(const buffer& other) + requires copyable + { + if (&other == this) { return *this; } + copy_range(other); + return *this; + } constexpr buffer& operator=(buffer&& other) + requires moveable { if (&other == this) { return *this; } move_from_other(ASL_MOVE(other), true); @@ -193,8 +231,6 @@ public: destroy(); } - // @Todo Copy constructor & assignment - constexpr isize_t size() const { return decode_size(load_size_encoded()); @@ -307,6 +343,17 @@ public: } } + // @Todo(C++23) Deducing this + operator span() const // NOLINT(*-explicit-conversions) + { + return span{data(), size()}; + } + + operator span() // NOLINT(*-explicit-conversions) + { + return span{data(), size()}; + } + // @Todo(C++23) Use deducing this constexpr T& operator[](isize_t i) { diff --git a/asl/memory.hpp b/asl/memory.hpp index 1209bf6..209f1d1 100644 --- a/asl/memory.hpp +++ b/asl/memory.hpp @@ -56,6 +56,40 @@ constexpr void destroy_n(T* data, isize_t n) } } +template +constexpr void copy_uninit_n(T* to, const T* from, isize_t n) +{ + if constexpr (trivially_copy_constructible) + { + memcpy(to, from, size_of * n); + } + else + { + for (isize_t i = 0; i < n; ++i) + { + // NOLINTNEXTLINE(*-pointer-arithmetic) + construct_at(to + i, from[i]); + } + } +} + +template +constexpr void copy_assign_n(T* to, const T* from, isize_t n) +{ + if constexpr (trivially_copy_constructible) + { + memcpy(to, from, size_of * n); + } + else + { + for (isize_t i = 0; i < n; ++i) + { + // NOLINTNEXTLINE(*-pointer-arithmetic) + to[i] = from[i]; + } + } +} + template constexpr void relocate_uninit_n(T* to, T* from, isize_t n) { diff --git a/asl/tests/buffer_tests.cpp b/asl/tests/buffer_tests.cpp index 1a08554..ad26c96 100644 --- a/asl/tests/buffer_tests.cpp +++ b/asl/tests/buffer_tests.cpp @@ -469,3 +469,64 @@ ASL_TEST(move_assign_from_inline_incompatible_allocator) ASL_TEST_EXPECT(d[4] == true); ASL_TEST_EXPECT(d[5] == true); } + +ASL_TEST(copy_construct_inline) +{ + asl::buffer buf; + buf.push(0); + buf.push(1); + buf.push(2); + + asl::buffer buf2{buf}; + + ASL_TEST_EXPECT(buf.size() == buf2.size()); + ASL_TEST_EXPECT(buf.size() == 3); + ASL_TEST_EXPECT(buf[0] == 0); + ASL_TEST_EXPECT(buf[1] == 1); + ASL_TEST_EXPECT(buf[2] == 2); + ASL_TEST_EXPECT(buf2[0] == 0); + ASL_TEST_EXPECT(buf2[1] == 1); + ASL_TEST_EXPECT(buf2[2] == 2); +} + +ASL_TEST(copy_assign_into_smaller) +{ + asl::buffer buf; + buf.push(0); + buf.push(1); + buf.push(2); + + asl::buffer buf2; + buf2.push(4); + + buf2 = buf; + + ASL_TEST_EXPECT(buf.size() == 3); + ASL_TEST_EXPECT(buf2.size() == 3); + + ASL_TEST_EXPECT(buf[0] == 0); + ASL_TEST_EXPECT(buf[1] == 1); + ASL_TEST_EXPECT(buf[2] == 2); + ASL_TEST_EXPECT(buf2[0] == 0); + ASL_TEST_EXPECT(buf2[1] == 1); + ASL_TEST_EXPECT(buf2[2] == 2); +} + +ASL_TEST(copy_assign_into_larger) +{ + asl::buffer buf; + buf.push(0); + buf.push(1); + buf.push(2); + + asl::buffer buf2; + buf2.push(4); + + buf = buf2; + + ASL_TEST_EXPECT(buf.size() == 1); + ASL_TEST_EXPECT(buf2.size() == 1); + + ASL_TEST_EXPECT(buf[0] == 4); + ASL_TEST_EXPECT(buf2[0] == 4); +} -- cgit