Some careful work on buffer
This commit is contained in:
@ -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,10 +15,12 @@ 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;
|
||||||
|
|
||||||
@ -25,6 +28,34 @@ class buffer
|
|||||||
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
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user