ona/source/coral/stack.cpp

127 lines
3.6 KiB
C++
Raw Normal View History

2023-02-23 20:13:56 +00:00
export module coral.stack;
import coral;
// Collections.
export namespace coral {
/**
2023-03-03 17:08:49 +00:00
* Result codes used when pushing elements to a stack.
2023-02-23 20:13:56 +00:00
*
2023-03-03 17:08:49 +00:00
* [push_result::ok] indicates that the push operation was successful.
2023-02-23 20:13:56 +00:00
*
2023-02-26 01:16:53 +00:00
* [push_result::out_of_memory] alerts that the memory required to perform the push operation failed.
2023-02-23 20:13:56 +00:00
*/
enum class [[nodiscard]] push_result {
ok,
out_of_memory,
};
/**
2023-03-03 17:08:49 +00:00
* Last-in-first-out contiguous sequence of `element` values.
2023-02-23 20:13:56 +00:00
*
2023-03-03 17:08:49 +00:00
* *Note*: the [allocator] used by the stack must remain valid for the duration of the stack lifetime.
2023-02-23 20:13:56 +00:00
*/
template<typename element> struct stack {
2023-03-03 17:08:49 +00:00
stack(allocator & element_allocator) : element_allocator{element_allocator} {
this->filled_elements = {};
2023-02-23 20:13:56 +00:00
}
2023-03-03 17:08:49 +00:00
~stack() {
for (element & e : this->filled_elements) e.~element();
2023-03-03 17:08:49 +00:00
this->element_allocator.deallocate(this->filled_elements.pointer);
2023-02-23 20:13:56 +00:00
}
/**
* Returns `true` if there are no elements in the stack, otherwise `false`.
*/
2023-03-03 17:08:49 +00:00
bool is_empty() const {
return this->filled_elements.length == 0;
}
2023-02-23 20:13:56 +00:00
/**
2023-03-03 17:08:49 +00:00
* Attempts to append `value` to the top of the stack.
2023-02-23 20:13:56 +00:00
*
* The returned [push_result] indicates whether the operation was successful or not.
*
2023-02-26 01:16:53 +00:00
* If the returned [push_result] is anything but [push_result::ok], the stack will be be left in an empty but
* valid state.
2023-02-23 20:13:56 +00:00
*
2023-03-03 17:08:49 +00:00
* *Note* [push_all] is recommended when appending many values at once.
2023-02-23 20:13:56 +00:00
*/
2023-03-03 17:08:49 +00:00
push_result push(element const & value) {
if (this->filled_elements.length == this->element_capacity) {
constexpr usize min_size {2};
push_result const result {this->reserve(this->element_capacity + (static_cast<usize>(this->element_capacity == 0) * min_size))};
2023-02-23 20:13:56 +00:00
if (result != push_result::ok) return result;
}
2023-03-03 17:08:49 +00:00
this->filled_elements[this->filled_elements.length] = value;
this->filled_elements.length += 1;
2023-02-23 20:13:56 +00:00
return push_result::ok;
}
/**
2023-03-03 17:08:49 +00:00
* Attempts to append `elements` to the top of the stack.
2023-02-23 20:13:56 +00:00
*
* The returned [push_result] indicates whether the operation was successful or not.
*
2023-02-26 01:16:53 +00:00
* If the returned [push_result] is anything but [push_result::ok], the stack will be left in an empty but valid
* state.
2023-02-23 20:13:56 +00:00
*
2023-03-03 17:08:49 +00:00
* *Note* [push] is recommended when appending singular values.
2023-02-23 20:13:56 +00:00
*/
2023-03-03 17:08:49 +00:00
push_result push_all(slice<element const> const & values) {
usize const updated_fill {this->filled + values.length};
2023-02-23 20:13:56 +00:00
if (updated_fill >= this->elements.length) {
2023-03-03 17:08:49 +00:00
push_result const result {this->reserve(values.length)};
2023-02-23 20:13:56 +00:00
2023-03-03 17:08:49 +00:00
if (result != push_result::ok) return result;
2023-02-23 20:13:56 +00:00
}
2023-03-03 17:08:49 +00:00
for (usize i {0}; i < values.length; i += 1) this->elements[this->filled + i] = values[i];
2023-02-23 20:13:56 +00:00
this->filled = updated_fill;
return push_result::ok;
}
/**
2023-03-03 17:08:49 +00:00
* Attempts to reserve `requested_capacity` number of elements additional space on the stack.
2023-02-23 20:13:56 +00:00
*
* The returned [push_result] indicates whether the operation was successful or not.
*
2023-02-26 01:16:53 +00:00
* If the returned [push_result] is anything but [push_result::ok], the stack will be left in an empty but valid
* state.
2023-02-23 20:13:56 +00:00
*/
2023-03-03 17:08:49 +00:00
push_result reserve(usize requested_capacity) {
usize const total_capacity {this->elements_filled + requested_capacity};
2023-02-23 20:13:56 +00:00
2023-03-03 17:08:49 +00:00
u8 * const buffer {this->element_allocator.reallocate(reinterpret_cast<u8 *>(
this->elements_filled.pointer), sizeof(element) * total_capacity)};
2023-02-23 20:13:56 +00:00
2023-03-03 17:08:49 +00:00
if (buffer == nullptr) {
this->element_capacity = 0;
this->filled_elements = {};
2023-02-23 20:13:56 +00:00
2023-03-03 17:08:49 +00:00
return push_result::out_of_memory;
2023-02-23 20:13:56 +00:00
}
2023-03-03 17:08:49 +00:00
this->filled_elements.pointer = reinterpret_cast<element *>(buffer);
this->element_capacity = total_capacity;
2023-02-23 20:13:56 +00:00
2023-03-03 17:08:49 +00:00
return push_result::ok;
2023-02-23 20:13:56 +00:00
}
private:
2023-03-03 17:08:49 +00:00
allocator & element_allocator;
2023-02-23 20:13:56 +00:00
2023-03-03 17:08:49 +00:00
usize element_capacity{0};
2023-02-23 20:13:56 +00:00
2023-03-03 17:08:49 +00:00
slice<element> filled_elements;
2023-02-23 20:13:56 +00:00
};
}