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);