#pragma once #include "utils.hpp" #include "handle.hpp" static constexpr u32 default_element_count = 1024U; template class freelist { public: freelist() { grow(initial_size); } handle add(const T& item) { // auto id = elements[0U].next_free; auto id = next_free_id; if (id == freelist::invalid_id) { grow(elements.size()); // id = elements[0U].next_free; id = next_free_id; } auto& element = elements[id]; next_free_id = element.next_free; // elements[0U].next_free = element.next_free; element.item = std::move(item); assert(element.generation + 1 != UINT32_MAX); return { id, ++element.generation }; } void remove(handle handle) { assert(handle.generation == elements[handle.id].generation); // elements[handle.id].next_free = elements[0U].next_free; // elements[0U].next_free = handle.id; elements[handle.id].next_free = next_free_id; next_free_id = handle.id; } T& operator[](handle handle) { assert(handle.generation == elements[handle.id].generation); return elements[handle.id].item; } const T& operator[](handle handle) const { assert(handle.generation == elements[handle.id].generation); return elements[handle.id].item; } static constexpr uint32_t invalid_id = UINT32_MAX; struct element { union { T item; uint32_t next_free = freelist::invalid_id; }; uint32_t generation = 0U; }; const std::vector& get_list() const { return elements; } private: void grow(size_t grow_size) { size_t size = elements.size(); uint32_t next_free = static_cast(size); next_free_id = next_free; elements.reserve(size + grow_size); for (auto id { 0U }; id < initial_size; id++) { elements.push_back( { .next_free = static_cast(++next_free % initial_size), } ); } // this makes it impossible to know elements.back().next_free = freelist::invalid_id; elements.back().next_free = freelist::invalid_id; } std::vector elements; uint32_t next_free_id; }; template class idlist { public: idlist() { grow(initial_size); } handle add() { // auto id = elements[0U].next_free; auto id = next_free_id; if (id == idlist::invalid_id) { grow(elements.size()); // id = elements[0U].next_free; id = next_free_id; } auto& element = elements[id]; next_free_id = element.next_free; elements[0U].next_free = element.next_free; element.next_free = idlist::invalid_id; return { id, ++element.generation }; } void remove(handle handle) { assert(handle.generation == elements[handle.id].generation); // elements[handle.id].next_free = elements[0U].next_free; // elements[0U].next_free = handle.id; elements[handle.id].next_free = next_free_id; next_free_id = handle.id; } static constexpr uint32_t invalid_id = UINT32_MAX; private: void grow(size_t grow_size) { auto size = elements.size(); uint32_t next_free = static_cast(size); next_free_id = next_free; elements.reserve(size + grow_size); for (auto id { 0U }; id < initial_size; id++) { elements.push_back( { .next_free = static_cast(++next_free% initial_size), } ); } elements.back().next_free = idlist::invalid_id; } struct element { uint32_t next_free = idlist::invalid_id; uint32_t generation = 0U; }; std::vector elements; uint32_t next_free_id; };