summaryrefslogtreecommitdiff
path: root/asl
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2024-12-08 23:58:43 +0100
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2024-12-20 15:35:58 +0100
commitaf164f9af26d0c64d2e8210039b99e4f191acdaa (patch)
tree85bf7c0703bd03f88ec99d4f5a9f9931471da2b0 /asl
parent72fe8dd2d6d6a3a5592646950a4e43b9a79ed9b4 (diff)
Some careful work on buffer
Diffstat (limited to 'asl')
-rw-r--r--asl/buffer.hpp87
-rw-r--r--asl/tests/buffer_tests.cpp18
2 files changed, 101 insertions, 4 deletions
diff --git a/asl/buffer.hpp b/asl/buffer.hpp
index abf29fe..b45d5d8 100644
--- a/asl/buffer.hpp
+++ b/asl/buffer.hpp
@@ -3,6 +3,7 @@
#include "asl/meta.hpp"
#include "asl/allocator.hpp"
#include "asl/annotations.hpp"
+#include "asl/memory.hpp"
namespace asl
{
@@ -14,17 +15,47 @@ class buffer
T* m_data{};
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 [52:0] : size when on heap
- size_t m_size_encoded{};
+ // bits [62:0] : size when on heap
+ size_t m_size_encoded_{};
ASL_NO_UNIQUE_ADDRESS Allocator m_allocator;
static_assert(align_of<T> <= align_of<T*>);
static_assert(align_of<T*> == align_of<isize_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:
static constexpr isize_t kInlineCapacity = []() {
@@ -40,6 +71,54 @@ public:
explicit constexpr buffer(Allocator 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
diff --git a/asl/tests/buffer_tests.cpp b/asl/tests/buffer_tests.cpp
index 133a549..2d23b2f 100644
--- a/asl/tests/buffer_tests.cpp
+++ b/asl/tests/buffer_tests.cpp
@@ -2,7 +2,25 @@
#include <asl/testing/testing.hpp>
+struct Big
+{
+ uint64_t data[8];
+};
+
static_assert(asl::buffer<int32_t>::kInlineCapacity == 5);
static_assert(asl::buffer<int64_t>::kInlineCapacity == 2);
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);
+}