32
32
#define RID_OWNER_H
33
33
34
34
#include " core/os/memory.h"
35
- #include " core/os/spin_lock .h"
35
+ #include " core/os/mutex .h"
36
36
#include " core/string/print_string.h"
37
37
#include " core/templates/hash_set.h"
38
38
#include " core/templates/list.h"
@@ -69,42 +69,54 @@ class RID_AllocBase {
69
69
70
70
template <typename T, bool THREAD_SAFE = false >
71
71
class RID_Alloc : public RID_AllocBase {
72
- T **chunks = nullptr ;
72
+ struct Chunk {
73
+ T data;
74
+ uint32_t validator;
75
+ };
76
+ Chunk **chunks = nullptr ;
73
77
uint32_t **free_list_chunks = nullptr ;
74
- uint32_t **validator_chunks = nullptr ;
75
78
76
79
uint32_t elements_in_chunk;
77
80
uint32_t max_alloc = 0 ;
78
81
uint32_t alloc_count = 0 ;
82
+ uint32_t chunk_limit = 0 ;
79
83
80
84
const char *description = nullptr ;
81
85
82
- mutable SpinLock spin_lock ;
86
+ mutable Mutex mutex ;
83
87
84
88
_FORCE_INLINE_ RID _allocate_rid () {
85
89
if constexpr (THREAD_SAFE) {
86
- spin_lock .lock ();
90
+ mutex .lock ();
87
91
}
88
92
89
93
if (alloc_count == max_alloc) {
90
94
// allocate a new chunk
91
95
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
+ }
92
104
93
105
// 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
100
110
// 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
+ }
102
114
free_list_chunks[chunk_count] = (uint32_t *)memalloc (sizeof (uint32_t ) * elements_in_chunk);
103
115
104
116
// initialize
105
117
for (uint32_t i = 0 ; i < elements_in_chunk; i++) {
106
118
// Don't initialize chunk.
107
- validator_chunks [chunk_count][i] = 0xFFFFFFFF ;
119
+ chunks [chunk_count][i]. validator = 0xFFFFFFFF ;
108
120
free_list_chunks[chunk_count][i] = alloc_count + i;
109
121
}
110
122
@@ -122,14 +134,13 @@ class RID_Alloc : public RID_AllocBase {
122
134
id <<= 32 ;
123
135
id |= free_index;
124
136
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
128
139
129
140
alloc_count++;
130
141
131
142
if constexpr (THREAD_SAFE) {
132
- spin_lock .unlock ();
143
+ mutex .unlock ();
133
144
}
134
145
135
146
return _make_from_id (id);
@@ -156,16 +167,10 @@ class RID_Alloc : public RID_AllocBase {
156
167
if (p_rid == RID ()) {
157
168
return nullptr ;
158
169
}
159
- if constexpr (THREAD_SAFE) {
160
- spin_lock.lock ();
161
- }
162
170
163
171
uint64_t id = p_rid.get_id ();
164
172
uint32_t idx = uint32_t (id & 0xFFFFFFFF );
165
173
if (unlikely (idx >= max_alloc)) {
166
- if constexpr (THREAD_SAFE) {
167
- spin_lock.unlock ();
168
- }
169
174
return nullptr ;
170
175
}
171
176
@@ -174,38 +179,26 @@ class RID_Alloc : public RID_AllocBase {
174
179
175
180
uint32_t validator = uint32_t (id >> 32 );
176
181
182
+ Chunk &c = chunks[idx_chunk][idx_element];
177
183
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 ))) {
182
185
ERR_FAIL_V_MSG (nullptr , " Initializing already initialized RID" );
183
186
}
184
187
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)) {
189
189
ERR_FAIL_V_MSG (nullptr , " Attempting to initialize the wrong RID" );
190
190
}
191
191
192
- validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF ; // initialized
192
+ c. validator &= 0x7FFFFFFF ; // initialized
193
193
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 ) {
199
196
ERR_FAIL_V_MSG (nullptr , " Attempting to use an uninitialized RID" );
200
197
}
201
198
return nullptr ;
202
199
}
203
200
204
- T *ptr = &chunks[idx_chunk][idx_element];
205
-
206
- if constexpr (THREAD_SAFE) {
207
- spin_lock.unlock ();
208
- }
201
+ T *ptr = &c.data ;
209
202
210
203
return ptr;
211
204
}
@@ -222,14 +215,14 @@ class RID_Alloc : public RID_AllocBase {
222
215
223
216
_FORCE_INLINE_ bool owns (const RID &p_rid) const {
224
217
if constexpr (THREAD_SAFE) {
225
- spin_lock .lock ();
218
+ mutex .lock ();
226
219
}
227
220
228
221
uint64_t id = p_rid.get_id ();
229
222
uint32_t idx = uint32_t (id & 0xFFFFFFFF );
230
223
if (unlikely (idx >= max_alloc)) {
231
224
if constexpr (THREAD_SAFE) {
232
- spin_lock .unlock ();
225
+ mutex .unlock ();
233
226
}
234
227
return false ;
235
228
}
@@ -239,25 +232,25 @@ class RID_Alloc : public RID_AllocBase {
239
232
240
233
uint32_t validator = uint32_t (id >> 32 );
241
234
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;
243
236
244
237
if constexpr (THREAD_SAFE) {
245
- spin_lock .unlock ();
238
+ mutex .unlock ();
246
239
}
247
240
248
241
return owned;
249
242
}
250
243
251
244
_FORCE_INLINE_ void free (const RID &p_rid) {
252
245
if constexpr (THREAD_SAFE) {
253
- spin_lock .lock ();
246
+ mutex .lock ();
254
247
}
255
248
256
249
uint64_t id = p_rid.get_id ();
257
250
uint32_t idx = uint32_t (id & 0xFFFFFFFF );
258
251
if (unlikely (idx >= max_alloc)) {
259
252
if constexpr (THREAD_SAFE) {
260
- spin_lock .unlock ();
253
+ mutex .unlock ();
261
254
}
262
255
ERR_FAIL ();
263
256
}
@@ -266,26 +259,26 @@ class RID_Alloc : public RID_AllocBase {
266
259
uint32_t idx_element = idx % elements_in_chunk;
267
260
268
261
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 )) {
270
263
if constexpr (THREAD_SAFE) {
271
- spin_lock .unlock ();
264
+ mutex .unlock ();
272
265
}
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)) {
275
268
if constexpr (THREAD_SAFE) {
276
- spin_lock .unlock ();
269
+ mutex .unlock ();
277
270
}
278
271
ERR_FAIL ();
279
272
}
280
273
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
283
276
284
277
alloc_count--;
285
278
free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk] = idx;
286
279
287
280
if constexpr (THREAD_SAFE) {
288
- spin_lock .unlock ();
281
+ mutex .unlock ();
289
282
}
290
283
}
291
284
@@ -294,43 +287,49 @@ class RID_Alloc : public RID_AllocBase {
294
287
}
295
288
void get_owned_list (List<RID> *p_owned) const {
296
289
if constexpr (THREAD_SAFE) {
297
- spin_lock .lock ();
290
+ mutex .lock ();
298
291
}
299
292
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 ;
301
294
if (validator != 0xFFFFFFFF ) {
302
295
p_owned->push_back (_make_from_id ((validator << 32 ) | i));
303
296
}
304
297
}
305
298
if constexpr (THREAD_SAFE) {
306
- spin_lock .unlock ();
299
+ mutex .unlock ();
307
300
}
308
301
}
309
302
310
303
// used for fast iteration in the elements or RIDs
311
304
void fill_owned_buffer (RID *p_rid_buffer) const {
312
305
if constexpr (THREAD_SAFE) {
313
- spin_lock .lock ();
306
+ mutex .lock ();
314
307
}
315
308
uint32_t idx = 0 ;
316
309
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 ;
318
311
if (validator != 0xFFFFFFFF ) {
319
312
p_rid_buffer[idx] = _make_from_id ((validator << 32 ) | i);
320
313
idx++;
321
314
}
322
315
}
316
+
323
317
if constexpr (THREAD_SAFE) {
324
- spin_lock .unlock ();
318
+ mutex .unlock ();
325
319
}
326
320
}
327
321
328
322
void set_description (const char *p_descrption) {
329
323
description = p_descrption;
330
324
}
331
325
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 ) {
333
327
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
+ }
334
333
}
335
334
336
335
~RID_Alloc () {
@@ -339,27 +338,25 @@ class RID_Alloc : public RID_AllocBase {
339
338
alloc_count, description ? description : typeid (T).name ()));
340
339
341
340
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 ;
343
342
if (validator & 0x80000000 ) {
344
343
continue ; // uninitialized
345
344
}
346
345
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 ();
348
347
}
349
348
}
350
349
}
351
350
352
351
uint32_t chunk_count = max_alloc / elements_in_chunk;
353
352
for (uint32_t i = 0 ; i < chunk_count; i++) {
354
353
memfree (chunks[i]);
355
- memfree (validator_chunks[i]);
356
354
memfree (free_list_chunks[i]);
357
355
}
358
356
359
357
if (chunks) {
360
358
memfree (chunks);
361
359
memfree (free_list_chunks);
362
- memfree (validator_chunks);
363
360
}
364
361
}
365
362
};
@@ -419,8 +416,8 @@ class RID_PtrOwner {
419
416
alloc.set_description (p_descrption);
420
417
}
421
418
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 ) {}
424
421
};
425
422
426
423
template <typename T, bool THREAD_SAFE = false >
@@ -473,8 +470,8 @@ class RID_Owner {
473
470
void set_description (const char *p_descrption) {
474
471
alloc.set_description (p_descrption);
475
472
}
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 ) {}
478
475
};
479
476
480
477
#endif // RID_OWNER_H
0 commit comments