export module core.sequence; import core; export namespace core { enum class reserve_error { out_of_memory, }; template struct sequence { sequence() = default; sequence(sequence const &) = delete; virtual ~sequence() {}; virtual slice as_slice() const = 0; virtual optional append(slice const & appended_elements) = 0; }; template struct stack : public sequence { stack(allocator * buffer_allocator) : filled{0}, buffer{0}, buffer_allocator{buffer_allocator} { this->elements = this->buffer; } ~stack() override { if (this->elements.pointer != this->buffer) this->buffer_allocator->deallocate(this->elements.pointer); } slice as_slice() const override { return this->elements; } optional push(element const & pushed_element) { if (this->filled == this->elements.length) { optional const maybe_error = this->reserve(this->elements.length); if (maybe_error.has_value()) return maybe_error; } this->elements[this->filled] = pushed_element; this->filled += 1; return {}; } optional append(slice const & pushed_elements) override { usize const updated_fill = this->filled + pushed_elements.length; if (updated_fill >= this->elements.length) { optional const maybe_error = this->reserve(max(this->elements.length, updated_fill)); if (maybe_error.has_value()) return maybe_error; } for (usize i = 0; i < pushed_elements.length; i += 1) this->elements[this->filled + i] = pushed_elements[i]; this->filled = updated_fill; return {}; } optional reserve(usize capacity) { usize const requested_capacity = this->elements.length + capacity; if (this->elements.pointer == this->buffer) { u8 * const maybe_allocation = this->buffer_allocator-> reallocate(nullptr, sizeof(element) * requested_capacity); if (maybe_allocation == nullptr) { this->elements = {}; return reserve_error::out_of_memory; } this->elements = {reinterpret_cast(maybe_allocation), requested_capacity}; } else { u8 * const maybe_allocation = this->buffer_allocator->reallocate( reinterpret_cast(this->elements.pointer), sizeof(element) * requested_capacity); if (maybe_allocation == nullptr) { this->elements = {}; return reserve_error::out_of_memory; } this->elements = {reinterpret_cast(maybe_allocation), requested_capacity}; } return {}; } private: allocator * buffer_allocator; usize filled; slice elements; element buffer[initial_capacity]; }; struct sequence_writer : public writable { sequence_writer(sequence * target_sequence) : writable{[target_sequence](slice const & buffer) -> optional { optional const maybe_error = target_sequence->append(buffer); if (maybe_error.has_value()) return {}; return buffer.length; }} {} }; }