summaryrefslogtreecommitdiff
path: root/asl
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2024-12-17 23:56:03 +0100
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2024-12-20 15:35:58 +0100
commit19c358c32fe91685e7fc001a866b3208444068da (patch)
treed8cb9eff9054e6d59845337e273e1216c4d0283d /asl
parent6d69512c6ff58ee8a7c1266257db5bf94cc91886 (diff)
Add buffer::push
Diffstat (limited to 'asl')
-rw-r--r--asl/buffer.hpp53
-rw-r--r--asl/tests/buffer_tests.cpp34
2 files changed, 79 insertions, 8 deletions
diff --git a/asl/buffer.hpp b/asl/buffer.hpp
index 8ee2869..e001ee0 100644
--- a/asl/buffer.hpp
+++ b/asl/buffer.hpp
@@ -16,6 +16,16 @@ class buffer
T* m_data{};
isize_t m_capacity{};
+public:
+ static constexpr isize_t kInlineCapacity = []() {
+ // 1 byte is used for size inline in m_size_encoded.
+ // This is enough because we have at most 24 bytes available,
+ // so 23 chars of capacity.
+ const isize_t available_size = size_of<T*> + size_of<isize_t> + size_of<size_t> - 1;
+ return available_size / size_of<T>;
+ }();
+
+private:
static constexpr size_t kOnHeapMask = 0x8000'0000'0000'0000ULL;
// bit 63 : 1 = on heap, 0 = inline
@@ -72,15 +82,32 @@ class buffer
return is_on_heap(load_size_encoded());
}
-public:
+ constexpr T* push_uninit()
+ {
+ isize_t sz = size();
+ reserve_capacity(sz + 1);
+ set_size(sz + 1);
+ return data() + sz;
+ }
- static constexpr isize_t kInlineCapacity = []() {
- // 1 byte is used for size inline in m_size_encoded.
- // This is enough because we have at most 24 bytes available,
- // so 23 chars of capacity.
- const isize_t available_size = size_of<T*> + size_of<isize_t> + size_of<size_t> - 1;
- return available_size / size_of<T>;
- }();
+ constexpr void set_size(isize_t new_size)
+ {
+ ASL_ASSERT(new_size >= 0);
+ ASL_ASSERT_RELEASE(new_size <= capacity());
+ size_t size_encoded = load_size_encoded();
+ if (kInlineCapacity == 0 || is_on_heap(size_encoded))
+ {
+ store_size_encoded(encode_size_heap(new_size));
+ }
+ else
+ {
+ ASL_ASSERT(new_size <= kInlineCapacity);
+ size_encoded = (size_encoded & size_t{0x00ff'ffff'ffff'ffff}) | (bit_cast<size_t>(new_size) << 56);
+ store_size_encoded(size_encoded);
+ }
+ }
+
+public:
constexpr buffer() requires default_constructible<Allocator> = default;
@@ -144,6 +171,14 @@ public:
store_size_encoded(encode_size_heap(current_size));
}
+ constexpr T& push(auto&&... args)
+ requires constructible_from<T, decltype(args)&&...>
+ {
+ T* uninit = push_uninit();
+ T* init = construct_at<T>(uninit, ASL_FWD(args)...);
+ return *init;
+ }
+
// @Todo(C++23) Use deducing this
const T* data() const
{
@@ -168,6 +203,8 @@ public:
return is_on_heap() ? m_data : reinterpret_cast<T*>(this);
}
}
+
+ // @Todo operator[]
};
} // namespace asl
diff --git a/asl/tests/buffer_tests.cpp b/asl/tests/buffer_tests.cpp
index 32f6682..3dc8ffb 100644
--- a/asl/tests/buffer_tests.cpp
+++ b/asl/tests/buffer_tests.cpp
@@ -49,3 +49,37 @@ ASL_TEST(reserve_capacity)
ASL_TEST_EXPECT(b.size() == 0);
ASL_TEST_EXPECT(b.capacity() >= 130);
}
+
+// NOLINTBEGIN(*-pointer-arithmetic)
+ASL_TEST(push)
+{
+ asl::buffer<int32_t> b;
+ ASL_TEST_EXPECT(b.size() == 0);
+
+ b.push(1);
+ ASL_TEST_EXPECT(b.size() == 1);
+ ASL_TEST_EXPECT(b.data()[0] == 1);
+
+ b.push(2);
+ b.push(3);
+ ASL_TEST_EXPECT(b.size() == 3);
+ ASL_TEST_EXPECT(b.data()[0] == 1);
+ ASL_TEST_EXPECT(b.data()[1] == 2);
+ ASL_TEST_EXPECT(b.data()[2] == 3);
+
+ b.push(4);
+ b.push(5);
+ b.push(6);
+ b.push(7);
+ ASL_TEST_EXPECT(b.size() == 7);
+ ASL_TEST_EXPECT(b.data()[0] == 1);
+ ASL_TEST_EXPECT(b.data()[1] == 2);
+ ASL_TEST_EXPECT(b.data()[2] == 3);
+ ASL_TEST_EXPECT(b.data()[3] == 4);
+ ASL_TEST_EXPECT(b.data()[4] == 5);
+ ASL_TEST_EXPECT(b.data()[5] == 6);
+ ASL_TEST_EXPECT(b.data()[6] == 7);
+}
+// NOLINTEND(*-pointer-arithmetic)
+
+// @Todo Test push with non trivial move (non copy) types