diff --git a/buffer.hpp b/buffer.hpp index 1696510..8e48592 100644 --- a/buffer.hpp +++ b/buffer.hpp @@ -1,145 +1,65 @@ #pragma once + #include "record.hpp" -#include -#include +#include #include -// Main buffer pool - owns all memory -class BufferPool { +class Buffer; + +class SubBuffer { private: - std::vector storage; - int buffer_capacity; - int num_buffers; + Record* data_; + size_t size_; + + friend class Buffer; + + SubBuffer(Record* data, size_t size) + : data_(data) + , size_(size) + { + } public: - BufferPool(int num_buffers, int buffer_capacity) - : storage(num_buffers * buffer_capacity) - , buffer_capacity(buffer_capacity) - , num_buffers(num_buffers) + // for std::sort support + using iterator = Record*; + iterator begin() { return data_; } + iterator end() { return data_ + size_; } + + Record& operator[](size_t index) { + return data_[index]; } - Record* get_buffer_ptr(int index) - { - return storage.data() + (index * buffer_capacity); - } - - int get_buffer_capacity() const { return buffer_capacity; } - int get_num_buffers() const { return num_buffers; } - int total_capacity() const { return storage.size(); } - - // Sort entire pool (for stage 1 - creating runs) - void sort_all(int count) - { - std::sort(storage.begin(), storage.begin() + count); - } + size_t size() const { return size_; } }; -// View into a section of the buffer pool -class BufferView { +class Buffer { private: - Record* data; - int capacity; - int length; + std::vector storage_; public: - BufferView(Record* ptr, int cap) - : data(ptr) - , capacity(cap) - , length(0) + explicit Buffer(size_t total_size) + : storage_(total_size) { } - // Read up to capacity records from stream - int read_from(std::istream& in) + std::vector divide(size_t n) { - length = 0; - for (int i = 0; i < capacity; i++) { - if (!(in >> data[i])) { - break; - } - length++; + if (n == 0) { + throw std::invalid_argument("Cannot divide buffer into 0 pieces"); } - return length; - } - // Write all current records to stream - bool write_to(std::ostream& out) const - { - for (int i = 0; i < length; i++) { - out << data[i] << '\n'; - if (!out) - return false; + size_t total_size = storage_.size(); + if (total_size % n != 0) { + throw std::invalid_argument("Size not divisible by n"); } - return true; - } - // For stage 2: peek at front record without consuming - const Record& front() const { return data[0]; } - - // For stage 2: consume the front record - void pop_front() - { - if (length > 0) { - for (int i = 0; i < length - 1; i++) { - data[i] = data[i + 1]; - } - length--; + std::vector result(n); + size_t piece_size = total_size / n; + for (size_t i = 0; i < n; ++i) { + result[i] = SubBuffer(storage_.data() + i * piece_size, piece_size); } + + return result; } - - // Refill from stream when buffer becomes empty during merge - bool refill_from(std::istream& in) - { - return read_from(in) > 0; - } - - int size() const { return length; } - int get_capacity() const { return capacity; } - bool empty() const { return length == 0; } - bool full() const { return length == capacity; } - - Record& operator[](int i) { return data[i]; } - const Record& operator[](int i) const { return data[i]; } -}; - -// For output buffer during merge -class OutputBuffer { -private: - Record* data; - int capacity; - int length; - -public: - OutputBuffer(Record* ptr, int cap) - : data(ptr) - , capacity(cap) - , length(0) - { - } - - // Add record to output buffer - bool add(const Record& rec) - { - if (length >= capacity) { - return false; // Buffer full - } - data[length++] = rec; - return true; - } - - // Flush buffer to stream and reset - bool flush_to(std::ostream& out) - { - for (int i = 0; i < length; i++) { - out << data[i] << '\n'; - if (!out) - return false; - } - length = 0; - return true; - } - - bool full() const { return length >= capacity; } - int size() const { return length; } };