From 869ce0c7bf13ada2786de71b1e89a9de4f554237 Mon Sep 17 00:00:00 2001 From: Kittycannon Date: Sun, 14 Jun 2026 18:15:44 -0600 Subject: [PATCH] overengineered piece of shit, but compiles fine --- src/spider/runtime/reel/InstrReel.hpp | 14 +- src/spider/runtime/reel/InstrReelDyn.cpp | 435 +++++++++++++-------- src/spider/runtime/reel/InstrReelDyn.hpp | 48 +-- src/spider/runtime/reel/InstrReelFixed.cpp | 16 +- src/spider/runtime/reel/InstrReelFixed.hpp | 14 +- 5 files changed, 309 insertions(+), 218 deletions(-) diff --git a/src/spider/runtime/reel/InstrReel.hpp b/src/spider/runtime/reel/InstrReel.hpp index 31ed38f..c289593 100644 --- a/src/spider/runtime/reel/InstrReel.hpp +++ b/src/spider/runtime/reel/InstrReel.hpp @@ -26,7 +26,7 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u8 readU8(u64 ip) = 0; + virtual u8 readU8(u64 ip) const = 0; /** * Obtains a byte of data at @@ -34,7 +34,7 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u16 readU16(u64 ip) = 0; + virtual u16 readU16(u64 ip) const = 0; /** * Obtains a byte of data at @@ -42,7 +42,7 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u32 readU32(u64 ip) = 0; + virtual u32 readU32(u64 ip) const = 0; /** * Obtains a byte of data at @@ -50,20 +50,20 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u64 readU64(u64 ip) = 0; + virtual u64 readU64(u64 ip) const = 0; /** * Reads a range of data, and * outputs it. */ - virtual void readRange(u64 ip, u8* out, u64 length) = 0; + virtual void readRange(u64 ip, u8* out, u64 length) const = 0; - virtual void loadRegister(u64 ip, u8 size_code, register_t* r) = 0; + virtual void loadRegister(u64 ip, u8 size_code, register_t* r) const = 0; /** * Current size of the instructions. */ - virtual u64 size() = 0; + virtual u64 size() const = 0; public: // Static Utils // diff --git a/src/spider/runtime/reel/InstrReelDyn.cpp b/src/spider/runtime/reel/InstrReelDyn.cpp index 003df88..75c7397 100644 --- a/src/spider/runtime/reel/InstrReelDyn.cpp +++ b/src/spider/runtime/reel/InstrReelDyn.cpp @@ -5,181 +5,69 @@ namespace spider { InstrReelDyn::InstrReelDyn(u64 length) : _size(length) { - // Safe int ceil division - growTo((length >> 8) + ((length & 255) != 0)); + if (_size == 0) return; + + // 1. Allocate and fill the buffer with zeroed blocks + grow(_size); + _buffer.assign(_size, 0); + + // 2. Pad the physical vector to match block alignment + if (_buffer.size() % _blocksize != 0) { + u64 padding = _blocksize - (_buffer.size() % _blocksize); + _buffer.insert(_buffer.end(), padding, 0); + } + + // 3. Manifest the initial blank part in our orchestration + _pieces.push_back({ 0, _size }); } - //InstrReelDyn::InstrReelDyn(const u8* data, u64 length) {} + InstrReelDyn::InstrReelDyn(const u8* data, u64 length) : _size(0) { + if (length == 0) return; + grow(length); + write(0, data, length); + } InstrReelDyn::InstrReelDyn(const InstrReelDyn& copy) - : _blocks(copy._blocks), _size(copy._size) { - } - + : _buffer(copy._buffer), + _pieces(copy._pieces), + _size(copy._size) {} + + // No-throw Move Constructor InstrReelDyn::InstrReelDyn(InstrReelDyn&& move) noexcept - : _blocks(std::move(move._blocks)), _size(std::move(move._size)) { + : _buffer(std::move(move._buffer)), + _pieces(std::move(move._pieces)), + _size(move._size) { + move._size = 0; } + // Explicit Destructor execution InstrReelDyn::~InstrReelDyn() { - // .. // + _pieces.clear(); + _buffer.clear(); } + // Deep Copy Assignment Operator InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) { - _blocks = copy._blocks; - _size = copy._size; + if (this != ©) { + _buffer = copy._buffer; + _pieces = copy._pieces; + _size = copy._size; + } return *this; } + // No-throw Move Assignment Operator InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept { - _blocks = std::move(move._blocks); - _size = std::move(move._size); + if (this != &move) { + _buffer = std::move(move._buffer); + _pieces = std::move(move._pieces); + _size = move._size; + move._size = 0; + } return *this; } - void InstrReelDyn::growTo(u64 ip) { - u64 b_index = (ip >> 8) + 1; - while (_blocks.size() < b_index) { - _blocks.emplace_back(); - } - if (ip >= _size) _size = ip + 1; - } - - std::pair InstrReelDyn::indexOf(u64 ip) { - return { ip >> 8, ip & 0xFF }; // { ip / 256, ip % 256 }; - } - - bool InstrReelDyn::continous(u64 ip0, u64 ip1, u64* b_index, u16* s_index) { - auto i = indexOf(ip0); - *b_index = i.first; - *s_index = i.second; - return i.first == (ip1 >> 8); - } - - // Particular Cases - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - u8 InstrReelDyn::readU8(u64 ip) { - if (ip + 1 > _size) return 0; - auto i = indexOf(ip); - return _blocks[i.first].data[i.second]; - } - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - u16 InstrReelDyn::readU16(u64 ip) { - if (ip + 2 > _size) return 0; - - u16 dat; - u64 b_index; - u16 s_index; - - if (continous(ip, ip + 1, &b_index, &s_index)) { - spider::loadLE(&dat, &_blocks[b_index].data[s_index]); - return dat; - } - - dat = 0; - for (isize i = 0; i < sizeof(dat); i++) { - auto& b = _blocks[(b_index + s_index) >> 8]; - dat |= u16(b.data[s_index++ & 0xFF] << (i * 8)); - } - return dat; - } - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - u32 InstrReelDyn::readU32(u64 ip) { - if (ip + 4 > _size) return 0; - - u32 dat; - u64 b_index; - u16 s_index; - - if (continous(ip, ip + 3, &b_index, &s_index)) { - spider::loadLE(&dat, &_blocks[b_index].data[s_index]); - return dat; - } - - dat = 0; - for (isize i = 0; i < sizeof(dat); i++) { - auto& b = _blocks[(b_index + s_index) >> 8]; - dat |= u32(b.data[s_index++ & 0xFF]) << (i * 8); - } - return dat; - } - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - u64 InstrReelDyn::readU64(u64 ip) { - if (ip + 8 > _size) return 0; - - u64 dat; - u64 b_index; - u16 s_index; - - if (continous(ip, ip + 7, &b_index, &s_index)) { - spider::loadLE(&dat, &_blocks[b_index].data[s_index]); - return dat; - } - - dat = 0; - for (isize i = 0; i < sizeof(dat); i++) { - auto& b = _blocks[(b_index + s_index) >> 8]; - dat |= u64(b.data[s_index++ & 0xFF]) << (i * 8); - } - return dat; - } - - /** - * Reads a range of data, and - * outputs it. - */ - void InstrReelDyn::readRange(u64 ip, u8* out, u64 length) { - if (ip + length > _size) { - std::memset(out, 0, length); - return; - } - - u64 b_index; - u16 s_index; - - if (continous(ip, ip + length, &b_index, &s_index)) { - std::memcpy(out, &_blocks[b_index].data[s_index], length); - return; - } - - u64 bytes_read = 0; - while (bytes_read < length) { - u64 remaining_in_block = 256 - s_index; - u64 chunk_size = std::min(remaining_in_block, length - bytes_read); - - // Perform bulk copy for the current segment - std::memcpy(out + bytes_read, &_blocks[b_index].data[s_index], chunk_size); - - // Advance pointers - bytes_read += chunk_size; - b_index++; - s_index = 0; // reset - } - } - - void InstrReelDyn::loadRegister(u64 ip, u8 size_code, register_t* r) { + void InstrReelDyn::loadRegister(u64 ip, u8 size_code, register_t* r) const { u8 bytes[8]; readRange(ip, bytes, 1 << size_code); spider::loadRegister[size_code](r, bytes, 8); @@ -188,22 +76,235 @@ namespace spider { /** * Current size of the instructions. */ - u64 InstrReelDyn::size() { + u64 InstrReelDyn::size() const { return _size; } + // Reading, Prepared // + + u8 InstrReelDyn::readU8(u64 ip) const { + u8 dat; + u8 arr[sizeof(dat)]; + readRange(ip, arr, sizeof(arr)); + spider::loadPartialLE(&dat, arr, sizeof(arr)); + return dat; + } + + u16 InstrReelDyn::readU16(u64 ip) const { + u16 dat; + u8 arr[sizeof(dat)]; + readRange(ip, arr, sizeof(arr)); + spider::loadPartialLE(&dat, arr, sizeof(arr)); + return dat; + } + + u32 InstrReelDyn::readU32(u64 ip) const { + u32 dat; + u8 arr[sizeof(dat)]; + readRange(ip, arr, sizeof(arr)); + spider::loadPartialLE(&dat, arr, sizeof(arr)); + return dat; + } + + u64 InstrReelDyn::readU64(u64 ip) const { + u64 dat; + u8 arr[sizeof(dat)]; + readRange(ip, arr, sizeof(arr)); + spider::loadPartialLE(&dat, arr, sizeof(arr)); + return dat; + } + // Mutation // - // TODO! + void InstrReelDyn::readRange(u64 ip, u8* dat, const u64 len) const { + // 1. Boundary Guard + if (len == 0 || ip + len > _size || dat == nullptr) return; - //void InstrReelDyn::writeU8(u64 ip, u8 dat) {} - //void InstrReelDyn::writeU16(u64 ip, u16 dat) {} - //void InstrReelDyn::writeU32(u64 ip, u32 dat) {} - //void InstrReelDyn::writeU64(u64 ip, u64 dat) {} + u64 bytes_copied = 0; + u64 current_ip = 0; - /** - * Appends instruction at the end. - */ - //void InstrReelDyn::append(u16 bc) {} + for (const auto& p : _pieces) { + u64 piece_start = current_ip; + u64 piece_end = current_ip + p.length; + + // 2. Determine if the requested read window overlaps with this piece + if (ip + bytes_copied < piece_end && (ip + len) > piece_start) { + + // Calculate where inside this specific piece our read window begins + u64 read_start_logical = std::max(ip + bytes_copied, piece_start); + u64 local_offset_within_piece = read_start_logical - piece_start; + + // Calculate how many remaining bytes can be extracted from this piece + u64 available_in_piece = p.length - local_offset_within_piece; + u64 bytes_to_copy = std::min(len - bytes_copied, available_in_piece); + + // 3. Perform safe unaligned copy from our master buffer to the user's destination + const u8* src_ptr = _buffer.data() + p.offset + local_offset_within_piece; + std::memcpy(dat + bytes_copied, src_ptr, bytes_to_copy); + + bytes_copied += bytes_to_copy; + + // 4. Optimization: Break early if we've completely satisfied the read request + if (bytes_copied == len) { + break; + } + } + current_ip += p.length; + } + } + + void InstrReelDyn::write(u64 ip, const u8* dat, const u64 len) { + if (len == 0) return; + + // If writing inside existing data, we OVERWRITE by removing the old section first. + // If ip >= _size, it naturally appends, so remove does nothing. + if (ip < _size) { + u64 bytes_to_overwrite = std::min(len, _size - ip); + remove(ip, bytes_to_overwrite); + } + + // 1. Capture the exact physical offset BEFORE inserting data or padding + grow(len); + u64 write_offset = _buffer.size(); + _buffer.insert(_buffer.end(), dat, dat + len); + + // Apply padding immediately so _buffer.size() is always clean for the next run + if (_buffer.size() % _blocksize != 0) { + u64 padding = _blocksize - (_buffer.size() % _blocksize); + _buffer.insert(_buffer.end(), padding, 0); + } + + // 2. Orchestrate Pieces (This is strictly an Insertion now because Old Data was removed) + if (_pieces.empty() || ip >= _size) { + _pieces.push_back({ write_offset, len }); + _size += len; + return; + } + + u64 current_ip = 0; + for (auto it = _pieces.begin(); it != _pieces.end(); ++it) { + if (current_ip + it->length >= ip) { + u64 local_offset = ip - current_ip; + + if (local_offset == 0) { + _pieces.insert(it, { write_offset, len }); + } else { + // Split the piece cleanly + piece left = { it->offset, local_offset }; + piece right = { it->offset + local_offset, it->length - local_offset }; + + *it = left; // Update existing piece to be the 'left' side + + auto next_it = std::next(it); + next_it = _pieces.insert(next_it, { write_offset, len }); + _pieces.insert(std::next(next_it), right); + } + break; // Essential: stop processing once the piece is handled! + } + current_ip += it->length; + } + _size += len; + } + + void InstrReelDyn::remove(u64 ip, const u64 len) { + if (len == 0 || ip + len > _size) return; + + u64 current_ip = 0; + u64 bytes_to_remove = len; + + for (auto it = _pieces.begin(); it != _pieces.end() && bytes_to_remove > 0;) { + u64 piece_start = current_ip; + u64 piece_end = current_ip + it->length; + + if (ip < piece_end && (ip + bytes_to_remove) > piece_start) { + u64 overlap_start = std::max(ip, piece_start); + u64 overlap_end = std::min(ip + bytes_to_remove, piece_end); + u64 overlap_len = overlap_end - overlap_start; + + u64 local_offset = overlap_start - piece_start; + + if (local_offset == 0 && overlap_len == it->length) { + it = _pieces.erase(it); // Returns next valid iterator safely + } else if (local_offset == 0) { + it->offset += overlap_len; + it->length -= overlap_len; + ++it; + } else if (local_offset + overlap_len == it->length) { + it->length -= overlap_len; + ++it; + } else { + // Slice a hole out of the middle + piece right = { it->offset + local_offset + overlap_len, it->length - (local_offset + overlap_len) }; + it->length = local_offset; + _pieces.insert(std::next(it), right); + break; + } + bytes_to_remove -= overlap_len; + } else { + current_ip += it->length; + ++it; + } + } + _size -= len; + } + + void InstrReelDyn::defragment() { + // 1. Edge Case: If the buffer is completely empty, reset states cleanly + if (_size == 0) { + _pieces.clear(); + _buffer.clear(); + _size = 0; + return; + } + + // 2. Optimization: If there is only 1 piece and it's already aligned at physical offset 0, + // then the buffer is already perfectly defragmented. Skip the work entirely. + if (_pieces.size() == 1 && _pieces.front().offset == 0) { + return; + } + + // 3. Allocate a fresh, temporary vector aligned perfectly to your 256-byte blocks + std::vector clean_buffer; + + // We use the same rounding formula to ensure clean_buffer matches block boundaries + u64 blocks_needed = (_size + _blocksize - 1) / _blocksize; + clean_buffer.reserve(blocks_needed * _blocksize); + + // 4. Linearly stream only the ACTIVE byte chunks into our clean buffer + for (const auto& p : _pieces) { + const u8* src_ptr = _buffer.data() + p.offset; + clean_buffer.insert(clean_buffer.end(), src_ptr, src_ptr + p.length); + } + + // 5. Enforce trailing block alignment padding + if (clean_buffer.size() % _blocksize != 0) { + u64 padding = _blocksize - (clean_buffer.size() % _blocksize); + clean_buffer.insert(clean_buffer.end(), padding, 0); + } + + // 6. Fast O(1) swap to point your class to the new optimized buffer + _buffer = std::move(clean_buffer); + + // 7. Reset piece orchestration to a single monolithic piece mapping 1:1 + _pieces.clear(); + _pieces.push_back({ 0, _size }); + } + + void InstrReelDyn::grow(u64 len) { + u64 current_capacity = _buffer.capacity(); + + // Account for requested bytes PLUS up to a block's worth of trailing alignment padding + u64 minimum_needed = _buffer.size() + len + (_blocksize - 1); + + if (minimum_needed > current_capacity) { + // Grow exponentially (1.5x). If empty, seed it with 1 full block minimum. + u64 raw_growth = (current_capacity == 0) ? _blocksize : current_capacity + (current_capacity / 2); + u64 target_capacity = std::max(minimum_needed, raw_growth); + + // Round the final target UP to the nearest 256-byte block + u64 blocks = (target_capacity + _blocksize - 1) / _blocksize; + _buffer.reserve(blocks * _blocksize); + } + } } diff --git a/src/spider/runtime/reel/InstrReelDyn.hpp b/src/spider/runtime/reel/InstrReelDyn.hpp index ea932f1..86a9fcf 100644 --- a/src/spider/runtime/reel/InstrReelDyn.hpp +++ b/src/spider/runtime/reel/InstrReelDyn.hpp @@ -2,6 +2,8 @@ #include +#include + namespace spider { /** @@ -10,13 +12,14 @@ namespace spider { class InstrReelDyn : public InstrReel { private: - struct ReelBlock { - u8 data[256] = {}; + struct piece { + u64 offset; + u64 length; }; - private: - - deque _blocks; + static constexpr u64 _blocksize = 256; + std::vector _buffer; + std::list _pieces; u64 _size; public: @@ -37,14 +40,6 @@ namespace spider { InstrReelDyn& operator=(InstrReelDyn&& move) noexcept; - private: - - std::pair indexOf(u64 ip); - - bool continous(u64 ip0, u64 ip1, u64* b_index, u16* s_index); - - void growTo(u64 ip); - public: /** @@ -53,7 +48,7 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u8 readU8(u64 ip) override; + virtual u8 readU8(u64 ip) const override; /** * Obtains a byte of data at @@ -61,7 +56,7 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u16 readU16(u64 ip) override; + virtual u16 readU16(u64 ip) const override; /** * Obtains a byte of data at @@ -69,7 +64,7 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u32 readU32(u64 ip) override; + virtual u32 readU32(u64 ip) const override; /** * Obtains a byte of data at @@ -77,35 +72,32 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u64 readU64(u64 ip) override; + virtual u64 readU64(u64 ip) const override; /** * Reads a range of data, and * outputs it. */ - virtual void readRange(u64 ip, u8* out, u64 length) override; + virtual void readRange(u64 ip, u8* out, u64 length) const override; - virtual void loadRegister(u64 ip, u8 size_code, register_t* r) override; + virtual void loadRegister(u64 ip, u8 size_code, register_t* r) const override; /** * Current size of the instructions. */ - virtual u64 size() override; + virtual u64 size() const override; public: - void writeU8(u64 ip, u8 dat); + void write(u64 ip, const u8* dat, const u64 len); - void writeU16(u64 ip, u16 dat); + void remove(u64 ip, const u64 len); - void writeU32(u64 ip, u32 dat); + void defragment(); - void writeU64(u64 ip, u64 dat); + private: - /** - * Appends instruction at the end. - */ - void append(u16 bc); + void grow(u64 len); }; diff --git a/src/spider/runtime/reel/InstrReelFixed.cpp b/src/spider/runtime/reel/InstrReelFixed.cpp index 48882b4..fa87653 100644 --- a/src/spider/runtime/reel/InstrReelFixed.cpp +++ b/src/spider/runtime/reel/InstrReelFixed.cpp @@ -42,44 +42,42 @@ namespace spider { delete[] _mem; } - // General Case(s) // - // Instruction abstraction // - u8 InstrReelFixed::readU8(u64 ip) { + u8 InstrReelFixed::readU8(u64 ip) const { u8 dat; spider::loadPartialLE(&dat, _mem + ip, _size); return dat; } - u16 InstrReelFixed::readU16(u64 ip) { + u16 InstrReelFixed::readU16(u64 ip) const { u16 dat; spider::loadPartialLE(&dat, _mem + ip, _size); return dat; } - u32 InstrReelFixed::readU32(u64 ip) { + u32 InstrReelFixed::readU32(u64 ip) const { u32 dat; spider::loadPartialLE(&dat, _mem + ip, _size); return dat; } - u64 InstrReelFixed::readU64(u64 ip) { + u64 InstrReelFixed::readU64(u64 ip) const { u64 dat; spider::loadPartialLE(&dat, _mem + ip, _size); return dat; } - void InstrReelFixed::readRange(u64 ip, u8* out, u64 length) { + void InstrReelFixed::readRange(u64 ip, u8* out, u64 length) const { spider::loadPartialBytes(_mem, isize(ip), _size, out, length); } - void InstrReelFixed::loadRegister(u64 ip, u8 size_code, register_t* r) { + void InstrReelFixed::loadRegister(u64 ip, u8 size_code, register_t* r) const { ip = std::min(ip, _size); spider::loadRegister[size_code](r, _mem + ip, _size - ip); } - u64 InstrReelFixed::size() { + u64 InstrReelFixed::size() const { return _size; } diff --git a/src/spider/runtime/reel/InstrReelFixed.hpp b/src/spider/runtime/reel/InstrReelFixed.hpp index 39c272c..2d7a9b7 100644 --- a/src/spider/runtime/reel/InstrReelFixed.hpp +++ b/src/spider/runtime/reel/InstrReelFixed.hpp @@ -38,7 +38,7 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u8 readU8(u64 ip) override; + virtual u8 readU8(u64 ip) const override; /** * Obtains a byte of data at @@ -46,7 +46,7 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u16 readU16(u64 ip) override; + virtual u16 readU16(u64 ip) const override; /** * Obtains a byte of data at @@ -54,7 +54,7 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u32 readU32(u64 ip) override; + virtual u32 readU32(u64 ip) const override; /** * Obtains a byte of data at @@ -62,20 +62,20 @@ namespace spider { * Reindexing may occur, continous access * may incurr in less penalties. */ - virtual u64 readU64(u64 ip) override; + virtual u64 readU64(u64 ip) const override; /** * Reads a range of data, and * outputs it. */ - virtual void readRange(u64 ip, u8* out, u64 length) override; + virtual void readRange(u64 ip, u8* out, u64 length) const override; - virtual void loadRegister(u64 ip, u8 size_code, register_t* r) override; + virtual void loadRegister(u64 ip, u8 size_code, register_t* r) const override; /** * Current size of the instructions. */ - virtual u64 size() override; + virtual u64 size() const override; public: