Add reserve_capacity to buffer

This commit is contained in:
2024-12-12 00:17:02 +01:00
parent b509ebcdc5
commit 7c9e871eb6
4 changed files with 126 additions and 10 deletions

View File

@ -7,6 +7,8 @@ build:linux --repo_env=CC=clang
build:windows --cxxopt=-Xclang=-std=c++20
build:linux --cxxopt=-std=c++20
common --incompatible_autoload_externally=+@rules_python
build --cxxopt=-Wall
build --cxxopt=-Wno-c++98-compat
build --cxxopt=-Wno-c++98-compat-pedantic

View File

@ -4,6 +4,7 @@
#include "asl/allocator.hpp"
#include "asl/annotations.hpp"
#include "asl/memory.hpp"
#include "asl/assert.hpp"
namespace asl
{
@ -35,11 +36,21 @@ class buffer
return s;
}
constexpr void store_size_encoded(size_t encoded)
{
asl::memcpy(&m_size_encoded_, &encoded, sizeof(size_t));
}
static constexpr bool is_on_heap(size_t size_encoded)
{
return (size_encoded & kOnHeapMask) != 0;
}
static constexpr size_t encode_size_heap(isize_t size)
{
return static_cast<size_t>(size) | kOnHeapMask;
}
static constexpr isize_t decode_size(size_t size_encoded)
{
if constexpr (kInlineCapacity == 0)
@ -56,6 +67,11 @@ class buffer
}
}
constexpr bool is_on_heap() const
{
return is_on_heap(load_size_encoded());
}
public:
static constexpr isize_t kInlineCapacity = []() {
@ -85,12 +101,72 @@ public:
}
else
{
return is_on_heap(load_size_encoded())
? m_capacity
: kInlineCapacity;
return is_on_heap() ? m_capacity : kInlineCapacity;
}
}
void reserve_capacity(isize_t new_capacity)
{
ASL_ASSERT(new_capacity >= 0);
ASL_ASSERT_RELEASE(new_capacity <= 0x4000'0000'0000'0000);
if (new_capacity <= capacity()) { return; }
ASL_ASSERT(new_capacity > kInlineCapacity);
new_capacity = static_cast<isize_t>(round_up_pow2(static_cast<uint64_t>(new_capacity)));
T* old_data = data();
const isize_t old_capacity = capacity();
const isize_t current_size = size();
const bool currently_on_heap = is_on_heap();
auto old_layout = layout::array<T>(old_capacity);
auto new_layout = layout::array<T>(new_capacity);
if (currently_on_heap && trivially_copyable<T>)
{
m_data = reinterpret_cast<T*>(m_allocator.realloc(m_data, old_layout, new_layout));
m_capacity = new_capacity;
return;
}
T* new_data = reinterpret_cast<T*>(m_allocator.alloc(new_layout));
// @Todo Move this logic somewhere else. Make move/destruct/etc. abstractions.
if constexpr (trivially_copyable<T>)
{
auto init_layout = layout::array<T>(current_size);
memcpy(new_data, old_data, init_layout.size);
}
else
{
static_assert(move_constructible<T>);
for (isize_t i = 0; i < current_size; ++i)
{
// NOLINTNEXTLINE(*-pointer-arithmetic)
new(new_data + i) T(ASL_MOVE(old_data[i]));
}
}
if constexpr (!trivially_destructible<T>)
{
for (isize_t i = 0; i < current_size; ++i)
{
(old_data + i)->~T();
}
}
if (currently_on_heap)
{
m_allocator.dealloc(old_data, old_layout);
}
m_data = new_data;
m_capacity = new_capacity;
store_size_encoded(encode_size_heap(current_size));
}
// @Todo(C++23) Use deducing this
const T* data() const
{
@ -100,9 +176,7 @@ public:
}
else
{
return is_on_heap(load_size_encoded())
? m_data
: reinterpret_cast<const T*>(this);
return is_on_heap() ? m_data : reinterpret_cast<const T*>(this);
}
}
@ -114,9 +188,7 @@ public:
}
else
{
return is_on_heap(load_size_encoded())
? m_data
: reinterpret_cast<T*>(this);
return is_on_heap() ? m_data : reinterpret_cast<T*>(this);
}
}
};

View File

@ -24,3 +24,28 @@ ASL_TEST(default_size)
ASL_TEST_EXPECT(b2.capacity() == 0);
ASL_TEST_EXPECT(b2.data() == nullptr);
}
// @Todo Make test allocator that counts allocations
ASL_TEST(reserve_capacity)
{
asl::buffer<int32_t> b;
ASL_TEST_EXPECT(b.size() == 0);
ASL_TEST_EXPECT(b.capacity() == 5);
b.reserve_capacity(4);
ASL_TEST_EXPECT(b.size() == 0);
ASL_TEST_EXPECT(b.capacity() == 5);
b.reserve_capacity(12);
ASL_TEST_EXPECT(b.size() == 0);
ASL_TEST_EXPECT(b.capacity() >= 12);
b.reserve_capacity(13);
ASL_TEST_EXPECT(b.size() == 0);
ASL_TEST_EXPECT(b.capacity() >= 13);
b.reserve_capacity(130);
ASL_TEST_EXPECT(b.size() == 0);
ASL_TEST_EXPECT(b.capacity() >= 130);
}

View File

@ -2,6 +2,7 @@
#include "asl/meta.hpp"
#include "asl/layout.hpp"
#include "asl/assert.hpp"
#define ASL_MOVE(expr_) (static_cast<::asl::un_ref_t<decltype(expr_)>&&>(expr_))
@ -30,6 +31,22 @@ T min(T a, T b)
return (a <= b) ? a : b;
}
constexpr uint64_t round_up_pow2(uint64_t v)
{
ASL_ASSERT(v <= 0x8000'0000'0000'0000);
v -= 1;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
return v + 1;
}
#define ASL_DELETE_COPY(T) \
T(const T&) = delete; \
T& operator=(const T&) = delete;