Cogs.Core
ResourcePolicies.h
1#pragma once
2
3#include "Foundation/Collections/Pool.h"
4
5#include <mutex>
6
7#ifdef _WIN32
8#pragma warning(push)
9#pragma warning(disable:4512)
10#endif
11
12namespace Cogs
13{
17 template<typename ResourceType>
19 {
22 ResourceWrapper * next = nullptr;
23
25 ResourceWrapper * prev = nullptr;
26
28 ResourceType resource;
29
30#ifdef _DEBUG
32 uint16_t debugFlags = 0;
33#endif
34
36 bool pinned = false;
37 };
38
42 template<typename ResourceType>
44 {
46
47 typedef std::forward_iterator_tag iterator_category;
48
50 typedef ResourceType value_type;
51
53 typedef size_t difference_type;
54
56 typedef ResourceType * pointer;
57
59 typedef ResourceType & reference;
60
61 PoolIterator(WrapperType * current) : current(current) {}
62
63 PoolIterator(const PoolIterator & other) : current(other.current) {}
64
65 PoolIterator operator++() { PoolIterator t(current); current = current->next; return t; }
66 PoolIterator & operator++(int) { current = current->next; return *this; }
67
68 [[nodiscard]] constexpr bool operator==(const PoolIterator & other) const { return current == other.current; }
69
70 reference operator*() { return current->resource; }
71
72 reference operator*() const { return current->resource; }
73
74 const pointer operator->() const { return &current->resource; }
75
76 pointer operator->() { return &current->resource; }
77
78 private:
79 WrapperType * current;
80 };
81
85 template<typename HandleType, typename ResourceType>
87 {
90
91 constexpr static bool SafeDereference() { return true; }
92
93 PoolStoragePolicy(MemBlockType memType = MemBlockType::Rendering) : pool(memType) {}
94
95 PoolStoragePolicy(size_t capacity, size_t pageSize, Memory::Allocator * allocator, MemBlockType memType = MemBlockType::Rendering) :
96 pool((Collections::ElementOffset)capacity, (Collections::ElementOffset)pageSize, allocator, memType)
97 {}
98
99 HandleType allocate(ResourceType && resource, bool persistent)
100 {
101 auto r = pool.create();
102
103 ++count;
104
105 r->resource = std::move(resource);
106
107 // Insert at head of allocated list.
108 r->next = allocatedHead;
109 allocatedHead = r;
110 if (r->next) r->next->prev = r;
111
112#ifdef _DEBUG
113 // Reset debug flag, we might be reusing a deallocated resource.
114 r->debugFlags = 0;
115#endif
116
117 auto handle = getHandle(r->resource);
118
119 if (persistent) pin(handle);
120
121 return handle;
122 }
123
124 HandleType allocate(const ResourceType & resource, bool persistent)
125 {
126 auto r = pool.create();
127
128 ++count;
129
130 r->resource = resource;
131
132 // Insert at head of allocated list.
133 r->next = allocatedHead;
134 allocatedHead = r;
135 if (r->next) r->next->prev = r;
136
137#ifdef _DEBUG
138 // Reset debug flag, we might be reusing a deallocated resource.
139 r->debugFlags = 0;
140#endif
141
142 auto handle = getHandle(r->resource);
143
144 if (persistent) pin(handle);
145
146 return handle;
147 }
148
149 void deallocate(const HandleType & handle)
150 {
151 auto r = reinterpret_cast<WrapperType *>(handle.handle);
152
153#ifdef _DEBUG
154 assert(r->debugFlags == 0 && "Resource already deallocated.");
155 // Signal deallocation.
156 r->debugFlags = 1;
157#endif
158
159 // Remove from allocated list.
160 if (r->next) r->next->prev = r->prev;
161 if (r->prev) r->prev->next = r->next;
162 if (r == allocatedHead) allocatedHead = r->next;
163
164 pool.destroy(r);
165
166 --count;
167 }
168
169 bool hasResource(const HandleType & handle) const
170 {
171 return HandleIsValid(handle);
172 }
173
174 ResourceType & operator[](const HandleType & handle)
175 {
176 auto wrapper = reinterpret_cast<WrapperType *>(handle.handle);
177
178 return wrapper->resource;
179 }
180
181 void clear(bool force = false)
182 {
183 auto next = allocatedHead;
184 while (next) {
185 auto current = next;
186 next = next->next;
187
188 if (!current->pinned || force) {
189 deallocate(getHandle(current->resource));
190 }
191 }
192 }
193
194 void pin(const HandleType & handle)
195 {
196 auto wrapper = reinterpret_cast<ResourceWrapper<ResourceType>*>(handle.handle);
197
198 wrapper->pinned = true;
199 }
200
201 bool pinned(const HandleType & handle) const { return reinterpret_cast<WrapperType *>(handle.handle)->pinned; }
202
203 iterator begin() { return iterator(allocatedHead); }
204 iterator end() { return iterator(nullptr); }
205
206 size_t size() const { return count; }
207
208 HandleType getHandle(const ResourceType & r) { return HandleType(reinterpret_cast<int64_t>(getWrapperPointer(r))); }
209
210 static WrapperType * getWrapperPointer(const ResourceType & r) { return reinterpret_cast<WrapperType *>(reinterpret_cast<intptr_t>(&r) - sizeof(ResourceType *) * 2); }
211
212 private:
214 WrapperType * allocatedHead = nullptr;
215
216 size_t count = 0;
217 };
218
220 {
221 void lock() {}
222 void unlock() {}
223 };
224
226 {
227 void lock() { m.lock(); }
228 void unlock() { m.unlock(); }
229
230 private:
231 std::mutex m;
232 };
233
235 {
236#ifdef _DEBUG
237 template<typename HandleType, typename StorageType>
238 static void verify(const HandleType & handle, const StorageType & storage) { assert(storage.hasResource(handle) && "Resource handle does not exist."); }
239#else
240 template<typename HandleType, typename StorageType>
241 static void verify(const HandleType &, const StorageType &) {}
242#endif
243 };
244}
245
246#ifdef _WIN32
247#pragma warning(pop)
248#endif
Base allocator implementation.
Definition: Allocator.h:30
uint16_t ElementOffset
Offset type used to index elements in resource pools.
Definition: PoolBase.h:13
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
Pool used to store elements of ElementType.
Definition: Pool.h:17
Iterator type for iterating over resource pools accessing the actual wrapped resource instances.
ResourceType * pointer
Pointer type to the templated ResourceType.
ResourceType & reference
Reference type to the templated ResourceType.
size_t difference_type
Difference type to calculate iterator distance.
ResourceType value_type
Value type for dereferencing the iterator is the templated ResourceType.
Storage policy storing all resources in a pool, reusing resource memory when possible.
Provides a wrapper around resources for pool storage with intrusive linked list pointers added.
ResourceWrapper * next
ResourceWrapper * prev
Stores a pointer to the next active element when allocated.
bool pinned
If the wrapped resource is pinned and should be persistently allocated.
ResourceType resource
Wrapped resource.