#pragma once #include "gp_config.hpp" #include "gp/algorithm/move.hpp" #include "gp/array.hpp" #include "gp/iterator.hpp" #include namespace gp{ template class indexed_array{ size_t data_top = 0; size_t available_indexes_top = 0; size_t remove_top = 0; gp::array 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 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()[data_top])) T(gp::forward(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()[v_idx] = gp::move(data_table[data_top]); ::operator delete(&data_table.as_buffer().template cast()[data_top], &(data_table.as_buffer().template cast()[data_top])); data_table.as_buffer().template cast()[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; } pointer_iterator begin() { return data_table.as_buffer().template cast().begin(); } pointer_iterator end() { return data_table.as_buffer().template cast().begin()+data_top; } const_pointer_iterator cbegin() { return data_table.as_buffer().template cast().cbegin(); } const_pointer_iterator cend() { return data_table.as_buffer().template cast().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()[translation_table[idx]]; } }; }