summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2025-01-02 19:37:41 +0100
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2025-01-02 19:46:23 +0100
commita9f254dcea5cc73112ba4df96ceaf48a33fae216 (patch)
treed735d931cc99a47123118b7ceed326331f326055
parent12b864491fe9750e9fbe09e354374bb441941761 (diff)
Implement copy move & assign for buffer
-rw-r--r--asl/buffer.hpp53
-rw-r--r--asl/memory.hpp34
-rw-r--r--asl/tests/buffer_tests.cpp61
3 files changed, 145 insertions, 3 deletions
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<const T> 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<Allocator> = default;
@@ -175,13 +196,30 @@ public:
: m_allocator{ASL_MOVE(allocator)}
{}
+ constexpr buffer(const buffer& other)
+ requires copy_constructible<Allocator> && copyable<T>
+ : m_allocator{other.m_allocator}
+ {
+ copy_range(other);
+ }
+
constexpr buffer(buffer&& other)
+ requires moveable<T>
: buffer(ASL_MOVE(other.m_allocator))
{
move_from_other(ASL_MOVE(other), false);
}
+
+ constexpr buffer& operator=(const buffer& other)
+ requires copyable<T>
+ {
+ if (&other == this) { return *this; }
+ copy_range(other);
+ return *this;
+ }
constexpr buffer& operator=(buffer&& other)
+ requires moveable<T>
{
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 T>() const // NOLINT(*-explicit-conversions)
+ {
+ return span<const T>{data(), size()};
+ }
+
+ operator span<T>() // NOLINT(*-explicit-conversions)
+ {
+ return span<T>{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<copy_constructible T>
+constexpr void copy_uninit_n(T* to, const T* from, isize_t n)
+{
+ if constexpr (trivially_copy_constructible<T>)
+ {
+ memcpy(to, from, size_of<T> * n);
+ }
+ else
+ {
+ for (isize_t i = 0; i < n; ++i)
+ {
+ // NOLINTNEXTLINE(*-pointer-arithmetic)
+ construct_at<T>(to + i, from[i]);
+ }
+ }
+}
+
+template<copy_assignable T>
+constexpr void copy_assign_n(T* to, const T* from, isize_t n)
+{
+ if constexpr (trivially_copy_constructible<T>)
+ {
+ memcpy(to, from, size_of<T> * n);
+ }
+ else
+ {
+ for (isize_t i = 0; i < n; ++i)
+ {
+ // NOLINTNEXTLINE(*-pointer-arithmetic)
+ to[i] = from[i];
+ }
+ }
+}
+
template<move_constructible T>
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<int> buf;
+ buf.push(0);
+ buf.push(1);
+ buf.push(2);
+
+ asl::buffer<int> 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<int> buf;
+ buf.push(0);
+ buf.push(1);
+ buf.push(2);
+
+ asl::buffer<int> 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<int> buf;
+ buf.push(0);
+ buf.push(1);
+ buf.push(2);
+
+ asl::buffer<int> 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);
+}