@@ -46,7 +46,7 @@ class CharString;
46
46
template <class T , class V >
47
47
class VMap ;
48
48
49
- SAFE_NUMERIC_TYPE_PUN_GUARANTEES ( uint64_t )
49
+ static_assert (std::is_trivially_destructible_v<std::atomic< uint64_t >>);
50
50
51
51
// Silence a false positive warning (see GH-52119).
52
52
#if defined(__GNUC__) && !defined(__clang__)
@@ -89,26 +89,47 @@ class CowData {
89
89
return ++x;
90
90
}
91
91
92
- static constexpr USize ALLOC_PAD = sizeof (USize) * 2 ; // For size and atomic refcount.
92
+ // Alignment: ↓ max_align_t ↓ USize ↓ max_align_t
93
+ // ┌────────────────────┬──┬─────────────┬──┬───────────...
94
+ // │ SafeNumeric<USize> │░░│ USize │░░│ T[]
95
+ // │ ref. count │░░│ data size │░░│ data
96
+ // └────────────────────┴──┴─────────────┴──┴───────────...
97
+ // Offset: ↑ REF_COUNT_OFFSET ↑ SIZE_OFFSET ↑ DATA_OFFSET
98
+
99
+ static constexpr size_t REF_COUNT_OFFSET = 0 ;
100
+ 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)));
101
+ 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 )));
93
102
94
103
mutable T *_ptr = nullptr ;
95
104
96
105
// internal helpers
97
106
107
+ static _FORCE_INLINE_ SafeNumeric<USize> *_get_refcount_ptr (uint8_t *p_ptr) {
108
+ return (SafeNumeric<USize> *)(p_ptr + REF_COUNT_OFFSET);
109
+ }
110
+
111
+ static _FORCE_INLINE_ USize *_get_size_ptr (uint8_t *p_ptr) {
112
+ return (USize *)(p_ptr + SIZE_OFFSET);
113
+ }
114
+
115
+ static _FORCE_INLINE_ T *_get_data_ptr (uint8_t *p_ptr) {
116
+ return (T *)(p_ptr + DATA_OFFSET);
117
+ }
118
+
98
119
_FORCE_INLINE_ SafeNumeric<USize> *_get_refcount () const {
99
120
if (!_ptr) {
100
121
return nullptr ;
101
122
}
102
123
103
- return reinterpret_cast < SafeNumeric<USize> *>(_ptr) - 2 ;
124
+ return ( SafeNumeric<USize> *)(( uint8_t *)_ptr - DATA_OFFSET + REF_COUNT_OFFSET) ;
104
125
}
105
126
106
127
_FORCE_INLINE_ USize *_get_size () const {
107
128
if (!_ptr) {
108
129
return nullptr ;
109
130
}
110
131
111
- return reinterpret_cast < USize *>(_ptr) - 1 ;
132
+ return ( USize *)(( uint8_t *)_ptr - DATA_OFFSET + SIZE_OFFSET) ;
112
133
}
113
134
114
135
_FORCE_INLINE_ USize _get_alloc_size (USize p_elements) const {
@@ -244,7 +265,7 @@ void CowData<T>::_unref(void *p_data) {
244
265
}
245
266
246
267
// free mem
247
- Memory::free_static (((uint8_t *)p_data) - ALLOC_PAD , false );
268
+ Memory::free_static (((uint8_t *)p_data) - DATA_OFFSET , false );
248
269
}
249
270
250
271
template <class T >
@@ -260,26 +281,27 @@ typename CowData<T>::USize CowData<T>::_copy_on_write() {
260
281
/* in use by more than me */
261
282
USize current_size = *_get_size ();
262
283
263
- USize *mem_new = (USize *)Memory::alloc_static (_get_alloc_size (current_size) + ALLOC_PAD , false );
264
- mem_new += 2 ;
284
+ uint8_t *mem_new = (uint8_t *)Memory::alloc_static (_get_alloc_size (current_size) + DATA_OFFSET , false );
285
+ ERR_FAIL_NULL_V ( mem_new, 0 ) ;
265
286
266
- new (mem_new - 2 ) SafeNumeric<USize>(1 ); // refcount
267
- *(mem_new - 1 ) = current_size; // size
287
+ SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr (mem_new);
288
+ USize *_size_ptr = _get_size_ptr (mem_new);
289
+ T *_data_ptr = _get_data_ptr (mem_new);
268
290
269
- T *_data = (T *)(mem_new);
291
+ new (_refc_ptr) SafeNumeric<USize>(1 ); // refcount
292
+ *(_size_ptr) = current_size; // size
270
293
271
294
// initialize new elements
272
295
if constexpr (std::is_trivially_copyable_v<T>) {
273
- memcpy (mem_new, _ptr, current_size * sizeof (T));
274
-
296
+ memcpy ((uint8_t *)_data_ptr, _ptr, current_size * sizeof (T));
275
297
} else {
276
298
for (USize i = 0 ; i < current_size; i++) {
277
- memnew_placement (&_data [i], T (_ptr[i]));
299
+ memnew_placement (&_data_ptr [i], T (_ptr[i]));
278
300
}
279
301
}
280
302
281
303
_unref (_ptr);
282
- _ptr = _data ;
304
+ _ptr = _data_ptr ;
283
305
284
306
rc = 1 ;
285
307
}
@@ -315,21 +337,28 @@ Error CowData<T>::resize(Size p_size) {
315
337
if (alloc_size != current_alloc_size) {
316
338
if (current_size == 0 ) {
317
339
// alloc from scratch
318
- USize *ptr = (USize *)Memory::alloc_static (alloc_size + ALLOC_PAD, false );
319
- ptr += 2 ;
320
- ERR_FAIL_NULL_V (ptr, ERR_OUT_OF_MEMORY);
321
- *(ptr - 1 ) = 0 ; // size, currently none
322
- new (ptr - 2 ) SafeNumeric<USize>(1 ); // refcount
340
+ uint8_t *mem_new = (uint8_t *)Memory::alloc_static (alloc_size + DATA_OFFSET, false );
341
+ ERR_FAIL_NULL_V (mem_new, ERR_OUT_OF_MEMORY);
342
+
343
+ SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr (mem_new);
344
+ USize *_size_ptr = _get_size_ptr (mem_new);
345
+ T *_data_ptr = _get_data_ptr (mem_new);
323
346
324
- _ptr = (T *)ptr;
347
+ new (_refc_ptr) SafeNumeric<USize>(1 ); // refcount
348
+ *(_size_ptr) = 0 ; // size, currently none
349
+
350
+ _ptr = _data_ptr;
325
351
326
352
} else {
327
- USize *_ptrnew = (USize *)Memory::realloc_static (((uint8_t *)_ptr) - ALLOC_PAD, alloc_size + ALLOC_PAD, false );
328
- ERR_FAIL_NULL_V (_ptrnew, ERR_OUT_OF_MEMORY);
329
- _ptrnew += 2 ;
330
- new (_ptrnew - 2 ) SafeNumeric<USize>(rc); // refcount
353
+ uint8_t *mem_new = (uint8_t *)Memory::realloc_static (((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false );
354
+ ERR_FAIL_NULL_V (mem_new, ERR_OUT_OF_MEMORY);
355
+
356
+ SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr (mem_new);
357
+ T *_data_ptr = _get_data_ptr (mem_new);
331
358
332
- _ptr = (T *)(_ptrnew);
359
+ new (_refc_ptr) SafeNumeric<USize>(rc); // refcount
360
+
361
+ _ptr = _data_ptr;
333
362
}
334
363
}
335
364
@@ -355,12 +384,15 @@ Error CowData<T>::resize(Size p_size) {
355
384
}
356
385
357
386
if (alloc_size != current_alloc_size) {
358
- USize *_ptrnew = (USize *)Memory::realloc_static (((uint8_t *)_ptr) - ALLOC_PAD, alloc_size + ALLOC_PAD, false );
359
- ERR_FAIL_NULL_V (_ptrnew, ERR_OUT_OF_MEMORY);
360
- _ptrnew += 2 ;
361
- new (_ptrnew - 2 ) SafeNumeric<USize>(rc); // refcount
387
+ uint8_t *mem_new = (uint8_t *)Memory::realloc_static (((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false );
388
+ ERR_FAIL_NULL_V (mem_new, ERR_OUT_OF_MEMORY);
389
+
390
+ SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr (mem_new);
391
+ T *_data_ptr = _get_data_ptr (mem_new);
392
+
393
+ new (_refc_ptr) SafeNumeric<USize>(rc); // refcount
362
394
363
- _ptr = (T *)(_ptrnew) ;
395
+ _ptr = _data_ptr ;
364
396
}
365
397
366
398
*_get_size () = p_size;
0 commit comments