Some careful work on buffer

This commit is contained in:
2024-12-08 23:58:43 +01:00
parent 72fe8dd2d6
commit af164f9af2
2 changed files with 101 additions and 4 deletions

View File

@ -3,6 +3,7 @@
#include "asl/meta.hpp" #include "asl/meta.hpp"
#include "asl/allocator.hpp" #include "asl/allocator.hpp"
#include "asl/annotations.hpp" #include "asl/annotations.hpp"
#include "asl/memory.hpp"
namespace asl namespace asl
{ {
@ -14,17 +15,47 @@ class buffer
T* m_data{}; T* m_data{};
isize_t m_capacity{}; isize_t m_capacity{};
// bit 63 : 0 = on heap, 1 = inline static constexpr size_t kOnHeapMask = 0x8000'0000'0000'0000ULL;
// bit 63 : 1 = on heap, 0 = inline
// bits [62:56] : size when inline // bits [62:56] : size when inline
// bits [52:0] : size when on heap // bits [62:0] : size when on heap
size_t m_size_encoded{}; size_t m_size_encoded_{};
ASL_NO_UNIQUE_ADDRESS Allocator m_allocator; ASL_NO_UNIQUE_ADDRESS Allocator m_allocator;
static_assert(align_of<T> <= align_of<T*>); static_assert(align_of<T> <= align_of<T*>);
static_assert(align_of<T*> == align_of<isize_t>); static_assert(align_of<T*> == align_of<isize_t>);
static_assert(align_of<T*> == align_of<size_t>); static_assert(align_of<T*> == align_of<size_t>);
constexpr size_t load_size_encoded() const
{
size_t s{};
asl::memcpy(&s, &m_size_encoded_, sizeof(size_t));
return s;
}
static constexpr bool is_on_heap(size_t size_encoded)
{
return (size_encoded & kOnHeapMask) != 0;
}
static constexpr isize_t decode_size(size_t size_encoded)
{
if constexpr (kInlineCapacity == 0)
{
return is_on_heap(size_encoded)
? static_cast<isize_t>(size_encoded & (~kOnHeapMask))
: 0;
}
else
{
return is_on_heap(size_encoded)
? static_cast<isize_t>(size_encoded & (~kOnHeapMask))
: static_cast<isize_t>(size_encoded >> 56);
}
}
public: public:
static constexpr isize_t kInlineCapacity = []() { static constexpr isize_t kInlineCapacity = []() {
@ -40,6 +71,54 @@ public:
explicit constexpr buffer(Allocator allocator) explicit constexpr buffer(Allocator allocator)
: m_allocator{ASL_MOVE(allocator)} : m_allocator{ASL_MOVE(allocator)}
{} {}
constexpr isize_t size() const
{
return decode_size(load_size_encoded());
}
constexpr isize_t capacity() const
{
if constexpr (kInlineCapacity == 0)
{
return m_capacity;
}
else
{
return is_on_heap(load_size_encoded())
? m_capacity
: kInlineCapacity;
}
}
// @Todo(C++23) Use deducing this
const T* data() const
{
if constexpr (kInlineCapacity == 0)
{
return m_data;
}
else
{
return is_on_heap(load_size_encoded())
? m_data
: reinterpret_cast<const T*>(this);
}
}
T* data()
{
if constexpr (kInlineCapacity == 0)
{
return m_data;
}
else
{
return is_on_heap(load_size_encoded())
? m_data
: reinterpret_cast<const T*>(this);
}
}
}; };
} // namespace asl } // namespace asl

View File

@ -2,7 +2,25 @@
#include <asl/testing/testing.hpp> #include <asl/testing/testing.hpp>
struct Big
{
uint64_t data[8];
};
static_assert(asl::buffer<int32_t>::kInlineCapacity == 5); static_assert(asl::buffer<int32_t>::kInlineCapacity == 5);
static_assert(asl::buffer<int64_t>::kInlineCapacity == 2); static_assert(asl::buffer<int64_t>::kInlineCapacity == 2);
static_assert(asl::buffer<char>::kInlineCapacity == 23); static_assert(asl::buffer<char>::kInlineCapacity == 23);
static_assert(asl::buffer<Big>::kInlineCapacity == 0);
ASL_TEST(default_size)
{
asl::buffer<int32_t> b1;
ASL_TEST_EXPECT(b1.size() == 0);
ASL_TEST_EXPECT(b1.capacity() == 5);
ASL_TEST_EXPECT(static_cast<const void*>(b1.data()) == &b1);
asl::buffer<Big> b2;
ASL_TEST_EXPECT(b2.size() == 0);
ASL_TEST_EXPECT(b2.capacity() == 0);
ASL_TEST_EXPECT(b2.data() == nullptr);
}