3232#define RID_OWNER_H
3333
3434#include " core/os/memory.h"
35- #include " core/os/spin_lock .h"
35+ #include " core/os/mutex .h"
3636#include " core/string/print_string.h"
3737#include " core/templates/hash_set.h"
3838#include " core/templates/list.h"
@@ -69,42 +69,54 @@ class RID_AllocBase {
6969
7070template <typename T, bool THREAD_SAFE = false >
7171class RID_Alloc : public RID_AllocBase {
72- T **chunks = nullptr ;
72+ struct Chunk {
73+ T data;
74+ uint32_t validator;
75+ };
76+ Chunk **chunks = nullptr ;
7377 uint32_t **free_list_chunks = nullptr ;
74- uint32_t **validator_chunks = nullptr ;
7578
7679 uint32_t elements_in_chunk;
7780 uint32_t max_alloc = 0 ;
7881 uint32_t alloc_count = 0 ;
82+ uint32_t chunk_limit = 0 ;
7983
8084 const char *description = nullptr ;
8185
82- mutable SpinLock spin_lock ;
86+ mutable Mutex mutex ;
8387
8488 _FORCE_INLINE_ RID _allocate_rid () {
8589 if constexpr (THREAD_SAFE) {
86- spin_lock .lock ();
90+ mutex .lock ();
8791 }
8892
8993 if (alloc_count == max_alloc) {
9094 // allocate a new chunk
9195 uint32_t chunk_count = alloc_count == 0 ? 0 : (max_alloc / elements_in_chunk);
96+ if (THREAD_SAFE && chunk_count == chunk_limit) {
97+ mutex.unlock ();
98+ if (description != nullptr ) {
99+ ERR_FAIL_V_MSG (RID (), vformat (" Element limit for RID of type '%s' reached." , String (description)));
100+ } else {
101+ ERR_FAIL_V_MSG (RID (), " Element limit reached." );
102+ }
103+ }
92104
93105 // grow chunks
94- chunks = (T **)memrealloc (chunks, sizeof (T *) * (chunk_count + 1 ));
95- chunks[chunk_count] = (T *)memalloc (sizeof (T) * elements_in_chunk); // but don't initialize
96-
97- // grow validators
98- validator_chunks = (uint32_t **)memrealloc (validator_chunks, sizeof (uint32_t *) * (chunk_count + 1 ));
99- validator_chunks[chunk_count] = (uint32_t *)memalloc (sizeof (uint32_t ) * elements_in_chunk);
106+ if constexpr (!THREAD_SAFE) {
107+ chunks = (Chunk **)memrealloc (chunks, sizeof (Chunk *) * (chunk_count + 1 ));
108+ }
109+ chunks[chunk_count] = (Chunk *)memalloc (sizeof (Chunk) * elements_in_chunk); // but don't initialize
100110 // grow free lists
101- free_list_chunks = (uint32_t **)memrealloc (free_list_chunks, sizeof (uint32_t *) * (chunk_count + 1 ));
111+ if constexpr (!THREAD_SAFE) {
112+ free_list_chunks = (uint32_t **)memrealloc (free_list_chunks, sizeof (uint32_t *) * (chunk_count + 1 ));
113+ }
102114 free_list_chunks[chunk_count] = (uint32_t *)memalloc (sizeof (uint32_t ) * elements_in_chunk);
103115
104116 // initialize
105117 for (uint32_t i = 0 ; i < elements_in_chunk; i++) {
106118 // Don't initialize chunk.
107- validator_chunks [chunk_count][i] = 0xFFFFFFFF ;
119+ chunks [chunk_count][i]. validator = 0xFFFFFFFF ;
108120 free_list_chunks[chunk_count][i] = alloc_count + i;
109121 }
110122
@@ -122,14 +134,13 @@ class RID_Alloc : public RID_AllocBase {
122134 id <<= 32 ;
123135 id |= free_index;
124136
125- validator_chunks[free_chunk][free_element] = validator;
126-
127- validator_chunks[free_chunk][free_element] |= 0x80000000 ; // mark uninitialized bit
137+ chunks[free_chunk][free_element].validator = validator;
138+ chunks[free_chunk][free_element].validator |= 0x80000000 ; // mark uninitialized bit
128139
129140 alloc_count++;
130141
131142 if constexpr (THREAD_SAFE) {
132- spin_lock .unlock ();
143+ mutex .unlock ();
133144 }
134145
135146 return _make_from_id (id);
@@ -156,16 +167,10 @@ class RID_Alloc : public RID_AllocBase {
156167 if (p_rid == RID ()) {
157168 return nullptr ;
158169 }
159- if constexpr (THREAD_SAFE) {
160- spin_lock.lock ();
161- }
162170
163171 uint64_t id = p_rid.get_id ();
164172 uint32_t idx = uint32_t (id & 0xFFFFFFFF );
165173 if (unlikely (idx >= max_alloc)) {
166- if constexpr (THREAD_SAFE) {
167- spin_lock.unlock ();
168- }
169174 return nullptr ;
170175 }
171176
@@ -174,38 +179,26 @@ class RID_Alloc : public RID_AllocBase {
174179
175180 uint32_t validator = uint32_t (id >> 32 );
176181
182+ Chunk &c = chunks[idx_chunk][idx_element];
177183 if (unlikely (p_initialize)) {
178- if (unlikely (!(validator_chunks[idx_chunk][idx_element] & 0x80000000 ))) {
179- if constexpr (THREAD_SAFE) {
180- spin_lock.unlock ();
181- }
184+ if (unlikely (!(c.validator & 0x80000000 ))) {
182185 ERR_FAIL_V_MSG (nullptr , " Initializing already initialized RID" );
183186 }
184187
185- if (unlikely ((validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF ) != validator)) {
186- if constexpr (THREAD_SAFE) {
187- spin_lock.unlock ();
188- }
188+ if (unlikely ((c.validator & 0x7FFFFFFF ) != validator)) {
189189 ERR_FAIL_V_MSG (nullptr , " Attempting to initialize the wrong RID" );
190190 }
191191
192- validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF ; // initialized
192+ c. validator &= 0x7FFFFFFF ; // initialized
193193
194- } else if (unlikely (validator_chunks[idx_chunk][idx_element] != validator)) {
195- if constexpr (THREAD_SAFE) {
196- spin_lock.unlock ();
197- }
198- if ((validator_chunks[idx_chunk][idx_element] & 0x80000000 ) && validator_chunks[idx_chunk][idx_element] != 0xFFFFFFFF ) {
194+ } else if (unlikely (c.validator != validator)) {
195+ if ((c.validator & 0x80000000 ) && c.validator != 0xFFFFFFFF ) {
199196 ERR_FAIL_V_MSG (nullptr , " Attempting to use an uninitialized RID" );
200197 }
201198 return nullptr ;
202199 }
203200
204- T *ptr = &chunks[idx_chunk][idx_element];
205-
206- if constexpr (THREAD_SAFE) {
207- spin_lock.unlock ();
208- }
201+ T *ptr = &c.data ;
209202
210203 return ptr;
211204 }
@@ -222,14 +215,14 @@ class RID_Alloc : public RID_AllocBase {
222215
223216 _FORCE_INLINE_ bool owns (const RID &p_rid) const {
224217 if constexpr (THREAD_SAFE) {
225- spin_lock .lock ();
218+ mutex .lock ();
226219 }
227220
228221 uint64_t id = p_rid.get_id ();
229222 uint32_t idx = uint32_t (id & 0xFFFFFFFF );
230223 if (unlikely (idx >= max_alloc)) {
231224 if constexpr (THREAD_SAFE) {
232- spin_lock .unlock ();
225+ mutex .unlock ();
233226 }
234227 return false ;
235228 }
@@ -239,25 +232,25 @@ class RID_Alloc : public RID_AllocBase {
239232
240233 uint32_t validator = uint32_t (id >> 32 );
241234
242- bool owned = (validator != 0x7FFFFFFF ) && (validator_chunks [idx_chunk][idx_element] & 0x7FFFFFFF ) == validator;
235+ bool owned = (validator != 0x7FFFFFFF ) && (chunks [idx_chunk][idx_element]. validator & 0x7FFFFFFF ) == validator;
243236
244237 if constexpr (THREAD_SAFE) {
245- spin_lock .unlock ();
238+ mutex .unlock ();
246239 }
247240
248241 return owned;
249242 }
250243
251244 _FORCE_INLINE_ void free (const RID &p_rid) {
252245 if constexpr (THREAD_SAFE) {
253- spin_lock .lock ();
246+ mutex .lock ();
254247 }
255248
256249 uint64_t id = p_rid.get_id ();
257250 uint32_t idx = uint32_t (id & 0xFFFFFFFF );
258251 if (unlikely (idx >= max_alloc)) {
259252 if constexpr (THREAD_SAFE) {
260- spin_lock .unlock ();
253+ mutex .unlock ();
261254 }
262255 ERR_FAIL ();
263256 }
@@ -266,26 +259,26 @@ class RID_Alloc : public RID_AllocBase {
266259 uint32_t idx_element = idx % elements_in_chunk;
267260
268261 uint32_t validator = uint32_t (id >> 32 );
269- if (unlikely (validator_chunks [idx_chunk][idx_element] & 0x80000000 )) {
262+ if (unlikely (chunks [idx_chunk][idx_element]. validator & 0x80000000 )) {
270263 if constexpr (THREAD_SAFE) {
271- spin_lock .unlock ();
264+ mutex .unlock ();
272265 }
273- ERR_FAIL_MSG (" Attempted to free an uninitialized or invalid RID. " );
274- } else if (unlikely (validator_chunks [idx_chunk][idx_element] != validator)) {
266+ ERR_FAIL_MSG (" Attempted to free an uninitialized or invalid RID" );
267+ } else if (unlikely (chunks [idx_chunk][idx_element]. validator != validator)) {
275268 if constexpr (THREAD_SAFE) {
276- spin_lock .unlock ();
269+ mutex .unlock ();
277270 }
278271 ERR_FAIL ();
279272 }
280273
281- chunks[idx_chunk][idx_element].~T ();
282- validator_chunks [idx_chunk][idx_element] = 0xFFFFFFFF ; // go invalid
274+ chunks[idx_chunk][idx_element].data . ~T ();
275+ chunks [idx_chunk][idx_element]. validator = 0xFFFFFFFF ; // go invalid
283276
284277 alloc_count--;
285278 free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk] = idx;
286279
287280 if constexpr (THREAD_SAFE) {
288- spin_lock .unlock ();
281+ mutex .unlock ();
289282 }
290283 }
291284
@@ -294,43 +287,49 @@ class RID_Alloc : public RID_AllocBase {
294287 }
295288 void get_owned_list (List<RID> *p_owned) const {
296289 if constexpr (THREAD_SAFE) {
297- spin_lock .lock ();
290+ mutex .lock ();
298291 }
299292 for (size_t i = 0 ; i < max_alloc; i++) {
300- uint64_t validator = validator_chunks [i / elements_in_chunk][i % elements_in_chunk];
293+ uint64_t validator = chunks [i / elements_in_chunk][i % elements_in_chunk]. validator ;
301294 if (validator != 0xFFFFFFFF ) {
302295 p_owned->push_back (_make_from_id ((validator << 32 ) | i));
303296 }
304297 }
305298 if constexpr (THREAD_SAFE) {
306- spin_lock .unlock ();
299+ mutex .unlock ();
307300 }
308301 }
309302
310303 // used for fast iteration in the elements or RIDs
311304 void fill_owned_buffer (RID *p_rid_buffer) const {
312305 if constexpr (THREAD_SAFE) {
313- spin_lock .lock ();
306+ mutex .lock ();
314307 }
315308 uint32_t idx = 0 ;
316309 for (size_t i = 0 ; i < max_alloc; i++) {
317- uint64_t validator = validator_chunks [i / elements_in_chunk][i % elements_in_chunk];
310+ uint64_t validator = chunks [i / elements_in_chunk][i % elements_in_chunk]. validator ;
318311 if (validator != 0xFFFFFFFF ) {
319312 p_rid_buffer[idx] = _make_from_id ((validator << 32 ) | i);
320313 idx++;
321314 }
322315 }
316+
323317 if constexpr (THREAD_SAFE) {
324- spin_lock .unlock ();
318+ mutex .unlock ();
325319 }
326320 }
327321
328322 void set_description (const char *p_descrption) {
329323 description = p_descrption;
330324 }
331325
332- RID_Alloc (uint32_t p_target_chunk_byte_size = 65536 ) {
326+ RID_Alloc (uint32_t p_target_chunk_byte_size = 65536 , uint32_t p_maximum_number_of_elements = 262144 ) {
333327 elements_in_chunk = sizeof (T) > p_target_chunk_byte_size ? 1 : (p_target_chunk_byte_size / sizeof (T));
328+ if constexpr (THREAD_SAFE) {
329+ chunk_limit = (p_maximum_number_of_elements / elements_in_chunk) + 1 ;
330+ chunks = (Chunk **)memalloc (sizeof (Chunk *) * chunk_limit);
331+ free_list_chunks = (uint32_t **)memalloc (sizeof (uint32_t *) * chunk_limit);
332+ }
334333 }
335334
336335 ~RID_Alloc () {
@@ -339,27 +338,25 @@ class RID_Alloc : public RID_AllocBase {
339338 alloc_count, description ? description : typeid (T).name ()));
340339
341340 for (size_t i = 0 ; i < max_alloc; i++) {
342- uint64_t validator = validator_chunks [i / elements_in_chunk][i % elements_in_chunk];
341+ uint64_t validator = chunks [i / elements_in_chunk][i % elements_in_chunk]. validator ;
343342 if (validator & 0x80000000 ) {
344343 continue ; // uninitialized
345344 }
346345 if (validator != 0xFFFFFFFF ) {
347- chunks[i / elements_in_chunk][i % elements_in_chunk].~T ();
346+ chunks[i / elements_in_chunk][i % elements_in_chunk].data . ~T ();
348347 }
349348 }
350349 }
351350
352351 uint32_t chunk_count = max_alloc / elements_in_chunk;
353352 for (uint32_t i = 0 ; i < chunk_count; i++) {
354353 memfree (chunks[i]);
355- memfree (validator_chunks[i]);
356354 memfree (free_list_chunks[i]);
357355 }
358356
359357 if (chunks) {
360358 memfree (chunks);
361359 memfree (free_list_chunks);
362- memfree (validator_chunks);
363360 }
364361 }
365362};
@@ -419,8 +416,8 @@ class RID_PtrOwner {
419416 alloc.set_description (p_descrption);
420417 }
421418
422- RID_PtrOwner (uint32_t p_target_chunk_byte_size = 65536 ) :
423- alloc (p_target_chunk_byte_size) {}
419+ RID_PtrOwner (uint32_t p_target_chunk_byte_size = 65536 , uint32_t p_maximum_number_of_elements = 262144 ) :
420+ alloc (p_target_chunk_byte_size, p_maximum_number_of_elements ) {}
424421};
425422
426423template <typename T, bool THREAD_SAFE = false >
@@ -473,8 +470,8 @@ class RID_Owner {
473470 void set_description (const char *p_descrption) {
474471 alloc.set_description (p_descrption);
475472 }
476- RID_Owner (uint32_t p_target_chunk_byte_size = 65536 ) :
477- alloc (p_target_chunk_byte_size) {}
473+ RID_Owner (uint32_t p_target_chunk_byte_size = 65536 , uint32_t p_maximum_number_of_elements = 262144 ) :
474+ alloc (p_target_chunk_byte_size, p_maximum_number_of_elements ) {}
478475};
479476
480477#endif // RID_OWNER_H
0 commit comments