@@ -52,7 +52,7 @@ class VMap;
52
52
template <class T >
53
53
class CharStringT ;
54
54
55
- SAFE_NUMERIC_TYPE_PUN_GUARANTEES ( uint64_t )
55
+ static_assert (std::is_trivially_destructible_v<std::atomic< uint64_t >>);
56
56
57
57
// Silence a false positive warning (see GH-52119).
58
58
#if defined(__GNUC__) && !defined(__clang__)
@@ -96,26 +96,47 @@ class CowData {
96
96
return ++x;
97
97
}
98
98
99
- static constexpr USize ALLOC_PAD = sizeof (USize) * 2 ; // For size and atomic refcount.
99
+ // Alignment: ↓ max_align_t ↓ USize ↓ max_align_t
100
+ // ┌────────────────────┬──┬─────────────┬──┬───────────...
101
+ // │ SafeNumeric<USize> │░░│ USize │░░│ T[]
102
+ // │ ref. count │░░│ data size │░░│ data
103
+ // └────────────────────┴──┴─────────────┴──┴───────────...
104
+ // Offset: ↑ REF_COUNT_OFFSET ↑ SIZE_OFFSET ↑ DATA_OFFSET
105
+
106
+ static constexpr size_t REF_COUNT_OFFSET = 0 ;
107
+ static constexpr size_t SIZE_OFFSET = ((REF_COUNT_OFFSET + sizeof (SafeNumeric<USize>)) % alignof(USize) == 0 ) ? (REF_COUNT_OFFSET + sizeof (SafeNumeric<USize>)) : ((REF_COUNT_OFFSET + sizeof (SafeNumeric<USize>)) + alignof(USize) - ((REF_COUNT_OFFSET + sizeof (SafeNumeric<USize>)) % alignof(USize)));
108
+ static constexpr size_t DATA_OFFSET = ((SIZE_OFFSET + sizeof (USize)) % alignof(max_align_t ) == 0 ) ? (SIZE_OFFSET + sizeof (USize)) : ((SIZE_OFFSET + sizeof (USize)) + alignof(max_align_t ) - ((SIZE_OFFSET + sizeof (USize)) % alignof(max_align_t )));
100
109
101
110
mutable T *_ptr = nullptr ;
102
111
103
112
// internal helpers
104
113
114
+ static _FORCE_INLINE_ SafeNumeric<USize> *_get_refcount_ptr (uint8_t *p_ptr) {
115
+ return (SafeNumeric<USize> *)(p_ptr + REF_COUNT_OFFSET);
116
+ }
117
+
118
+ static _FORCE_INLINE_ USize *_get_size_ptr (uint8_t *p_ptr) {
119
+ return (USize *)(p_ptr + SIZE_OFFSET);
120
+ }
121
+
122
+ static _FORCE_INLINE_ T *_get_data_ptr (uint8_t *p_ptr) {
123
+ return (T *)(p_ptr + DATA_OFFSET);
124
+ }
125
+
105
126
_FORCE_INLINE_ SafeNumeric<USize> *_get_refcount () const {
106
127
if (!_ptr) {
107
128
return nullptr ;
108
129
}
109
130
110
- return reinterpret_cast < SafeNumeric<USize> *>(_ptr) - 2 ;
131
+ return ( SafeNumeric<USize> *)(( uint8_t *)_ptr - DATA_OFFSET + REF_COUNT_OFFSET) ;
111
132
}
112
133
113
134
_FORCE_INLINE_ USize *_get_size () const {
114
135
if (!_ptr) {
115
136
return nullptr ;
116
137
}
117
138
118
- return reinterpret_cast < USize *>(_ptr) - 1 ;
139
+ return ( USize *)(( uint8_t *)_ptr - DATA_OFFSET + SIZE_OFFSET) ;
119
140
}
120
141
121
142
_FORCE_INLINE_ USize _get_alloc_size (USize p_elements) const {
@@ -240,7 +261,7 @@ void CowData<T>::_unref(void *p_data) {
240
261
}
241
262
// clean up
242
263
243
- if (!std::is_trivially_destructible <T>::value ) {
264
+ if constexpr (!std::is_trivially_destructible_v <T>) {
244
265
USize *count = _get_size ();
245
266
T *data = (T *)(count + 1 );
246
267
@@ -251,7 +272,7 @@ void CowData<T>::_unref(void *p_data) {
251
272
}
252
273
253
274
// free mem
254
- Memory::free_static (((uint8_t *)p_data) - ALLOC_PAD , false );
275
+ Memory::free_static (((uint8_t *)p_data) - DATA_OFFSET , false );
255
276
}
256
277
257
278
template <class T >
@@ -267,26 +288,27 @@ typename CowData<T>::USize CowData<T>::_copy_on_write() {
267
288
/* in use by more than me */
268
289
USize current_size = *_get_size ();
269
290
270
- USize *mem_new = (USize *)Memory::alloc_static (_get_alloc_size (current_size) + ALLOC_PAD , false );
271
- mem_new += 2 ;
291
+ uint8_t *mem_new = (uint8_t *)Memory::alloc_static (_get_alloc_size (current_size) + DATA_OFFSET , false );
292
+ ERR_FAIL_NULL_V ( mem_new, 0 ) ;
272
293
273
- new (mem_new - 2 ) SafeNumeric<USize>(1 ); // refcount
274
- *(mem_new - 1 ) = current_size; // size
294
+ SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr (mem_new);
295
+ USize *_size_ptr = _get_size_ptr (mem_new);
296
+ T *_data_ptr = _get_data_ptr (mem_new);
275
297
276
- T *_data = (T *)(mem_new);
298
+ new (_refc_ptr) SafeNumeric<USize>(1 ); // refcount
299
+ *(_size_ptr) = current_size; // size
277
300
278
301
// initialize new elements
279
- if (std::is_trivially_copyable<T>::value) {
280
- memcpy (mem_new, _ptr, current_size * sizeof (T));
281
-
302
+ if constexpr (std::is_trivially_copyable_v<T>) {
303
+ memcpy ((uint8_t *)_data_ptr, _ptr, current_size * sizeof (T));
282
304
} else {
283
305
for (USize i = 0 ; i < current_size; i++) {
284
- memnew_placement (&_data [i], T (_ptr[i]));
306
+ memnew_placement (&_data_ptr [i], T (_ptr[i]));
285
307
}
286
308
}
287
309
288
310
_unref (_ptr);
289
- _ptr = _data ;
311
+ _ptr = _data_ptr ;
290
312
291
313
rc = 1 ;
292
314
}
@@ -322,27 +344,33 @@ Error CowData<T>::resize(Size p_size) {
322
344
if (alloc_size != current_alloc_size) {
323
345
if (current_size == 0 ) {
324
346
// alloc from scratch
325
- USize *ptr = (USize *)Memory::alloc_static (alloc_size + ALLOC_PAD, false );
326
- ptr += 2 ;
327
- ERR_FAIL_NULL_V (ptr, ERR_OUT_OF_MEMORY);
328
- *(ptr - 1 ) = 0 ; // size, currently none
329
- new (ptr - 2 ) SafeNumeric<USize>(1 ); // refcount
347
+ uint8_t *mem_new = (uint8_t *)Memory::alloc_static (alloc_size + DATA_OFFSET, false );
348
+ ERR_FAIL_NULL_V (mem_new, ERR_OUT_OF_MEMORY);
349
+
350
+ SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr (mem_new);
351
+ USize *_size_ptr = _get_size_ptr (mem_new);
352
+ T *_data_ptr = _get_data_ptr (mem_new);
330
353
331
- _ptr = (T *)ptr;
354
+ new (_refc_ptr) SafeNumeric<USize>(1 ); // refcount
355
+ *(_size_ptr) = 0 ; // size, currently none
332
356
357
+ _ptr = _data_ptr;
333
358
} else {
334
- USize *_ptrnew = (USize *)Memory::realloc_static (((uint8_t *)_ptr) - ALLOC_PAD, alloc_size + ALLOC_PAD, false );
335
- ERR_FAIL_NULL_V (_ptrnew, ERR_OUT_OF_MEMORY);
336
- _ptrnew += 2 ;
337
- new (_ptrnew - 2 ) SafeNumeric<USize>(rc); // refcount
359
+ uint8_t *mem_new = (uint8_t *)Memory::realloc_static (((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false );
360
+ ERR_FAIL_NULL_V (mem_new, ERR_OUT_OF_MEMORY);
361
+
362
+ SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr (mem_new);
363
+ T *_data_ptr = _get_data_ptr (mem_new);
338
364
339
- _ptr = (T *)(_ptrnew);
365
+ new (_refc_ptr) SafeNumeric<USize>(rc); // refcount
366
+
367
+ _ptr = _data_ptr;
340
368
}
341
369
}
342
370
343
371
// construct the newly created elements
344
372
345
- if (!std::is_trivially_constructible <T>::value ) {
373
+ if constexpr (!std::is_trivially_constructible_v <T>) {
346
374
for (Size i = *_get_size (); i < p_size; i++) {
347
375
memnew_placement (&_ptr[i], T);
348
376
}
@@ -353,7 +381,7 @@ Error CowData<T>::resize(Size p_size) {
353
381
*_get_size () = p_size;
354
382
355
383
} else if (p_size < current_size) {
356
- if (!std::is_trivially_destructible <T>::value ) {
384
+ if constexpr (!std::is_trivially_destructible_v <T>) {
357
385
// deinitialize no longer needed elements
358
386
for (USize i = p_size; i < *_get_size (); i++) {
359
387
T *t = &_ptr[i];
@@ -362,12 +390,15 @@ Error CowData<T>::resize(Size p_size) {
362
390
}
363
391
364
392
if (alloc_size != current_alloc_size) {
365
- USize *_ptrnew = (USize *)Memory::realloc_static (((uint8_t *)_ptr) - ALLOC_PAD, alloc_size + ALLOC_PAD, false );
366
- ERR_FAIL_NULL_V (_ptrnew, ERR_OUT_OF_MEMORY);
367
- _ptrnew += 2 ;
368
- new (_ptrnew - 2 ) SafeNumeric<USize>(rc); // refcount
393
+ uint8_t *mem_new = (uint8_t *)Memory::realloc_static (((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false );
394
+ ERR_FAIL_NULL_V (mem_new, ERR_OUT_OF_MEMORY);
395
+
396
+ SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr (mem_new);
397
+ T *_data_ptr = _get_data_ptr (mem_new);
398
+
399
+ new (_refc_ptr) SafeNumeric<USize>(rc); // refcount
369
400
370
- _ptr = (T *)(_ptrnew) ;
401
+ _ptr = _data_ptr ;
371
402
}
372
403
373
404
*_get_size () = p_size;
0 commit comments