diff --git a/CMakeLists.txt b/CMakeLists.txt
index c630fde..400113a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
-project(blt-gp VERSION 0.0.8)
+project(blt-gp VERSION 0.0.9)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
diff --git a/include/blt/gp/program.h b/include/blt/gp/program.h
index 99da360..225b8d6 100644
--- a/include/blt/gp/program.h
+++ b/include/blt/gp/program.h
@@ -16,10 +16,10 @@
* along with this program. If not, see .
*/
-#include
#ifndef BLT_GP_PROGRAM_H
#define BLT_GP_PROGRAM_H
+#include
#include
#include
#include
@@ -89,6 +89,99 @@ namespace blt::gp
{
constexpr static blt::size_t PAGE_SIZE = 0x1000;
public:
+ /**
+ * Pushes an instance of an object on to the stack
+ * @tparam T type to push
+ * @param value universal reference to the object to push
+ */
+ template
+ void push(T&& value)
+ {
+ auto ptr = allocate_bytes();
+ head->metadata.offset = ptr + sizeof(T);
+ new(ptr) T(std::forward(value));
+ }
+
+ template
+ T pop()
+ {
+ if (head == nullptr)
+ throw std::runtime_error("Silly boi the stack is empty!");
+ if (head->remaining_bytes_in_block() - head->storage_size() < sizeof(T))
+ throw std::runtime_error("Mismatched Types!");
+ T t = *reinterpret_cast(head->metadata.offset - sizeof(T));
+ head->metadata.offset -= sizeof(T);
+ if (head->used_bytes_in_block() == static_cast(head->storage_size()))
+ {
+ auto ptr = head;
+ head = head->metadata.prev;
+ delete ptr;
+ }
+ return t;
+ }
+
+ template
+ T& from(blt::size_t bytes)
+ {
+ auto remaining_bytes = static_cast(bytes);
+ blt::i64 bytes_into_block = 0;
+ block* blk = head;
+ while (remaining_bytes > 0)
+ {
+ if (blk == nullptr)
+ throw std::runtime_error("Requested size is beyond the scope of this stack!");
+ auto bytes_available = blk->used_bytes_in_block() - remaining_bytes;
+ bytes_into_block = remaining_bytes;
+ if (bytes_available < 0)
+ {
+ remaining_bytes = -bytes_available;
+ blk = head->metadata.prev;
+ } else
+ break;
+ }
+ if (blk == nullptr)
+ throw std::runtime_error("Some nonsense is going on. This function already smells");
+ return *reinterpret_cast((blk->metadata.offset - bytes_into_block) - sizeof(T));
+ }
+
+ [[nodiscard]] bool empty() const
+ {
+ if (head == nullptr)
+ return true;
+ if (head->metadata.prev != nullptr)
+ return false;
+ return head->used_bytes_in_block() == static_cast(head->storage_size());
+ }
+
+ stack_allocator() = default;
+
+ stack_allocator(const stack_allocator& copy) = delete;
+
+ stack_allocator& operator=(const stack_allocator& copy) = delete;
+
+ stack_allocator(stack_allocator&& move) noexcept
+ {
+ head = move.head;
+ move.head = nullptr;
+ }
+
+ stack_allocator& operator=(stack_allocator&& move) noexcept
+ {
+ head = move.head;
+ move.head = nullptr;
+ return *this;
+ }
+
+ ~stack_allocator()
+ {
+ block* current = head;
+ while (current != nullptr)
+ {
+ block* ptr = current;
+ current = current->metadata.prev;
+ delete ptr;
+ }
+ }
private:
struct block
@@ -108,17 +201,62 @@ namespace blt::gp
metadata.offset = buffer;
}
- [[nodiscard]] blt::size_t remainder_after_meta() const
+ [[nodiscard]] blt::ptrdiff_t storage_size() const
{
- return metadata.size - sizeof(typename block::block_metadata_t);
+ return static_cast(metadata.size - sizeof(typename block::block_metadata_t));
}
- [[nodiscard]] blt::ptrdiff_t remaining_bytes() const
+ [[nodiscard]] blt::ptrdiff_t remaining_bytes_in_block() const
+ {
+ return storage_size() - static_cast(metadata.offset - buffer);
+ }
+
+ [[nodiscard]] blt::ptrdiff_t used_bytes_in_block() const
{
return static_cast(metadata.offset - buffer);
}
};
+ template
+ void* allocate_bytes()
+ {
+ auto ptr = get_aligned_pointer(sizeof(T), alignof(T));
+ if (ptr == nullptr)
+ push_block_for();
+ ptr = get_aligned_pointer(sizeof(T), alignof(T));
+ if (ptr == nullptr)
+ throw std::bad_alloc();
+ return ptr;
+ }
+
+ void* get_aligned_pointer(blt::size_t bytes, blt::size_t alignment)
+ {
+ if (head == nullptr)
+ return nullptr;
+ blt::size_t remaining_bytes = head->remaining_bytes_in_block();
+ auto* pointer = static_cast(head->metadata.offset);
+ return std::align(alignment, bytes, pointer, remaining_bytes);
+ }
+
+ template
+ void push_block_for()
+ {
+ push_block(std::max(PAGE_SIZE, to_nearest_page_size(sizeof(T))));
+ }
+
+ void push_block(blt::size_t size)
+ {
+ auto blk = allocate_block(size);
+ if (head == nullptr)
+ {
+ head = blk;
+ return;
+ }
+ head->metadata.next = blk;
+ blk->metadata.prev = head;
+ head = blk;
+ }
+
static size_t to_nearest_page_size(blt::size_t bytes)
{
constexpr static blt::size_t MASK = ~(PAGE_SIZE - 1);