#pragma once #include #include #include #include using namespace std; template class ListAlloc { static_assert(is_integral_v && is_unsigned_v); public: const size_t capacity; ListAlloc(size_t capacity); ~ListAlloc(); template Index allocate(Args... args); void deallocate(Index index); T* at(Index index); private: char *buffer; stack freeStack; size_t cursor = 0; }; template class ListAllocRef { static_assert(is_integral_v && is_unsigned_v); public: ListAllocRef() : index(-1) {} ListAllocRef(Index index) : index(index) {} ~ListAllocRef() { if (index != (Index)-1) { assert(false && "Non-empty ListAllocRef upon destruction"); } } // No copying ListAllocRef(const ListAllocRef &other) = delete; ListAllocRef& operator=(const ListAllocRef &other) = delete; operator bool() const { return index != (Index)-1; } ListAllocRef& operator=(Index newIndex) { if (index != (Index)-1) { throw logic_error("operator= on non-empty ListAllocRef"); } index = newIndex; return *this; } T* get(ListAlloc &allocator) { return allocator.at(index); } const T* get(ListAlloc &allocator) const { return allocator.at(index); } void deallocate(ListAlloc &allocator) { if (index != (Index)-1) { allocator.deallocate(index); index = -1; } } private: Index index; }; template ListAlloc::ListAlloc(size_t capacity) : capacity(capacity) , buffer(new char[capacity * sizeof(T)]) { size_t largestIndex = capacity - 1; if (capacity != 0 && (size_t)(Index)largestIndex != largestIndex) { throw logic_error("Capacity too large for index type in ListAlloc"); } fprintf(stderr, "ListAlloc with capacity=%zu, size=%zu\n", capacity, capacity * sizeof(T)); } template ListAlloc::~ListAlloc() { if (freeStack.size() != cursor) { assert(false && "Not all entries deallocated in ~ListAlloc"); } delete[] buffer; } template template Index ListAlloc::allocate(Args... args) { Index index; if (!freeStack.empty()) { index = freeStack.top(); freeStack.pop(); } else if (cursor < capacity) { index = cursor++; } else { throw runtime_error("Out of memory in ListAlloc"); } new(at(index)) T(args...); return index; } template void ListAlloc::deallocate(Index index) { at(index)->~T(); freeStack.push(index); } template T* ListAlloc::at(Index index) { return (T*)&buffer[index * sizeof(T)]; }