Implement copy move & assign for buffer

This commit is contained in:
2025-01-02 19:37:41 +01:00
parent 12b864491f
commit a9f254dcea
3 changed files with 145 additions and 3 deletions

View File

@ -5,6 +5,7 @@
#include "asl/annotations.hpp" #include "asl/annotations.hpp"
#include "asl/memory.hpp" #include "asl/memory.hpp"
#include "asl/assert.hpp" #include "asl/assert.hpp"
#include "asl/span.hpp"
namespace asl namespace asl
{ {
@ -141,7 +142,7 @@ private:
isize_t other_n = other.size(); isize_t other_n = other.size();
isize_t this_n = size(); isize_t this_n = size();
resize_uninit(other_n); resize_uninit(other_n);
if (other_n < this_n) if (other_n <= this_n)
{ {
relocate_assign_n(data(), other.data(), other_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: public:
constexpr buffer() requires default_constructible<Allocator> = default; constexpr buffer() requires default_constructible<Allocator> = default;
@ -175,13 +196,30 @@ public:
: m_allocator{ASL_MOVE(allocator)} : 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) constexpr buffer(buffer&& other)
requires moveable<T>
: buffer(ASL_MOVE(other.m_allocator)) : buffer(ASL_MOVE(other.m_allocator))
{ {
move_from_other(ASL_MOVE(other), false); 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) constexpr buffer& operator=(buffer&& other)
requires moveable<T>
{ {
if (&other == this) { return *this; } if (&other == this) { return *this; }
move_from_other(ASL_MOVE(other), true); move_from_other(ASL_MOVE(other), true);
@ -193,8 +231,6 @@ public:
destroy(); destroy();
} }
// @Todo Copy constructor & assignment
constexpr isize_t size() const constexpr isize_t size() const
{ {
return decode_size(load_size_encoded()); 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 // @Todo(C++23) Use deducing this
constexpr T& operator[](isize_t i) constexpr T& operator[](isize_t i)
{ {

View File

@ -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> template<move_constructible T>
constexpr void relocate_uninit_n(T* to, T* from, isize_t n) constexpr void relocate_uninit_n(T* to, T* from, isize_t n)
{ {

View File

@ -469,3 +469,64 @@ ASL_TEST(move_assign_from_inline_incompatible_allocator)
ASL_TEST_EXPECT(d[4] == true); ASL_TEST_EXPECT(d[4] == true);
ASL_TEST_EXPECT(d[5] == 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);
}