|
|
- #pragma once
-
- #include "gp_config.hpp"
-
- #include "gp/algorithms/move.hpp"
- #include "gp/containers/array.hpp"
- #include "gp/utils/iterator.hpp"
-
- #include <stddef.h>
-
- namespace gp{
- /**
- * @brief An array that has static indexes that are not affected by deletions or new additions
- *
- * @tparam T The stored type
- * @tparam _capacity The total capacity of the array
- */
- template<typename T, size_t _capacity>
- class indexed_array{
- size_t data_top = 0;
- size_t available_indexes_top = 0;
- size_t remove_top = 0;
-
- gp::array<char, sizeof(T)*_capacity> data_table;
- size_t available_indexes[_capacity];
- size_t translation_table[_capacity];
- size_t reverse_translation_table[_capacity];
- size_t remove_table[_capacity];
- public:
- indexed_array() {}
-
- template<typename U>
- size_t push(U&& value) {
- size_t index;
-
- gp_config::assertion(data_top+1 != _capacity, "Indexed array capacity exceeded");
-
- if(available_indexes_top) {
- available_indexes_top--;
- index = available_indexes[available_indexes_top];
- } else {
- index = data_top;
- }
-
- new(&(data_table.as_buffer().template cast<T>()[data_top])) T(gp::forward<U>(value));
- translation_table[index] = data_top;
- reverse_translation_table[data_top] = index;
-
- ++data_top;
-
- return index;
- }
-
- void pop(size_t idx) {
- size_t v_idx = translation_table[idx];
-
- available_indexes[available_indexes_top] = idx;
- ++available_indexes_top;
-
- translation_table[idx] = -1;
- --data_top;
- if(v_idx < data_top) {
- size_t u_idx = reverse_translation_table[data_top];
- data_table.as_buffer().template cast<T>()[v_idx] = gp::move(reinterpret_cast<T&>(data_table[data_top]));
- ::operator delete(&data_table.as_buffer().template cast<T>()[data_top], &(data_table.as_buffer().template cast<T>()[data_top]));
- data_table.as_buffer().template cast<T>()[data_top].~T();
- translation_table[u_idx] = v_idx;
- reverse_translation_table[v_idx] = u_idx;
- }
- }
-
- void reset() {
- auto it = data_table;
- auto end = data_table+data_top;
- while(it != end) {
- ::operator delete(it, it);
- ++it;
- }
- data_top = 0;
- available_indexes_top = 0;
- remove_top = 0;
- }
-
- void mark_internal_for_removal(size_t i_idx) {
- remove_table[remove_top] = reverse_translation_table[i_idx];
- ++remove_top;
- }
-
- void mark_for_removal(size_t idx) {
- remove_table[remove_top] = idx;
- ++remove_top;
- }
-
- void sweep_removed() {
- auto it = remove_table;
- auto end = remove_table+remove_top;
- while(it != end) {
- pop(*it);
- ++it;
- }
- }
-
- bool has(size_t idx) {
- if(idx > data_top) return false;
- if(translation_table[idx] == -1) return false;
- return true;
- }
-
- template<typename fn_t>
- void foreach(fn_t function) {
- for(size_t i = 0; i < data_top; ++i) {
- function(reverse_translation_table[i], operator[](reverse_translation_table[i]));
- }
- }
-
- pointer_iterator<T> begin()
- {
- return data_table.as_buffer().template cast<T>().begin();
- }
-
- pointer_iterator<T> end()
- {
- return data_table.as_buffer().template cast<T>().begin()+data_top;
- }
-
- const_pointer_iterator<T> cbegin()
- {
- return data_table.as_buffer().template cast<T>().cbegin();
- }
-
- const_pointer_iterator<T> cend()
- {
- return data_table.as_buffer().template cast<T>().cbegin()+data_top;
- }
-
- size_t size() {
- return data_top;
- }
-
- size_t capacity() {
- return _capacity;
- }
-
- T& operator[](size_t idx) {
- gp_config::assertion(idx < data_top, "Bad indexed array access");
- return data_table.as_buffer().template cast<T>()[translation_table[idx]];
- }
- };
- }
|