2023-02-18 04:34:40 +01:00
|
|
|
export module core.sequence;
|
|
|
|
|
|
|
|
import core;
|
|
|
|
|
|
|
|
export namespace core {
|
|
|
|
enum class reserve_error {
|
|
|
|
out_of_memory,
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename element> struct sequence {
|
|
|
|
sequence() = default;
|
|
|
|
|
|
|
|
sequence(sequence const &) = delete;
|
|
|
|
|
|
|
|
virtual ~sequence() {};
|
|
|
|
|
|
|
|
virtual slice<element const> as_slice() const = 0;
|
|
|
|
|
|
|
|
virtual optional<reserve_error> append(slice<element const> const & appended_elements) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename element, usize initial_capacity = 1> struct stack : public sequence<element> {
|
|
|
|
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<element const> as_slice() const override {
|
|
|
|
return this->elements;
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<reserve_error> 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<reserve_error> append(slice<element const> 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_error> 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<element *>(maybe_allocation), requested_capacity};
|
|
|
|
} else {
|
|
|
|
u8 * const maybe_allocation = this->buffer_allocator->reallocate(
|
|
|
|
reinterpret_cast<u8 *>(this->elements.pointer),
|
|
|
|
sizeof(element) * requested_capacity);
|
|
|
|
|
|
|
|
if (maybe_allocation == nullptr) {
|
|
|
|
this->elements = {};
|
|
|
|
|
|
|
|
return reserve_error::out_of_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->elements = {reinterpret_cast<element *>(maybe_allocation), requested_capacity};
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
allocator * buffer_allocator;
|
|
|
|
|
|
|
|
usize filled;
|
|
|
|
|
|
|
|
slice<element> elements;
|
|
|
|
|
|
|
|
element buffer[initial_capacity];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sequence_writer : public writable {
|
2023-02-18 14:19:01 +01:00
|
|
|
sequence_writer(sequence<u8> * target_sequence) : writable{[target_sequence](slice<u8 const> const & buffer) -> expected<usize, io_error> {
|
2023-02-18 04:34:40 +01:00
|
|
|
optional const maybe_error = target_sequence->append(buffer);
|
|
|
|
|
2023-02-18 14:19:01 +01:00
|
|
|
if (maybe_error.has_value()) return io_error::unavailable;
|
2023-02-18 04:34:40 +01:00
|
|
|
|
|
|
|
return buffer.length;
|
|
|
|
}} {}
|
|
|
|
};
|
|
|
|
}
|