@@ -52,7 +52,7 @@ class VMap;
5252template <class T >
5353class CharStringT ;
5454
55- SAFE_NUMERIC_TYPE_PUN_GUARANTEES ( uint64_t )
55+ static_assert (std::is_trivially_destructible_v<std::atomic< uint64_t >>);
5656
5757// Silence a false positive warning (see GH-52119).
5858#if defined(__GNUC__) && !defined(__clang__)
@@ -96,26 +96,47 @@ class CowData {
9696 return ++x;
9797 }
9898
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 )));
100109
101110 mutable T *_ptr = nullptr ;
102111
103112 // internal helpers
104113
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+
105126 _FORCE_INLINE_ SafeNumeric<USize> *_get_refcount () const {
106127 if (!_ptr) {
107128 return nullptr ;
108129 }
109130
110- return reinterpret_cast < SafeNumeric<USize> *>(_ptr) - 2 ;
131+ return ( SafeNumeric<USize> *)(( uint8_t *)_ptr - DATA_OFFSET + REF_COUNT_OFFSET) ;
111132 }
112133
113134 _FORCE_INLINE_ USize *_get_size () const {
114135 if (!_ptr) {
115136 return nullptr ;
116137 }
117138
118- return reinterpret_cast < USize *>(_ptr) - 1 ;
139+ return ( USize *)(( uint8_t *)_ptr - DATA_OFFSET + SIZE_OFFSET) ;
119140 }
120141
121142 _FORCE_INLINE_ USize _get_alloc_size (USize p_elements) const {
@@ -240,7 +261,7 @@ void CowData<T>::_unref(void *p_data) {
240261 }
241262 // clean up
242263
243- if (!std::is_trivially_destructible <T>::value ) {
264+ if constexpr (!std::is_trivially_destructible_v <T>) {
244265 USize *count = _get_size ();
245266 T *data = (T *)(count + 1 );
246267
@@ -251,7 +272,7 @@ void CowData<T>::_unref(void *p_data) {
251272 }
252273
253274 // free mem
254- Memory::free_static (((uint8_t *)p_data) - ALLOC_PAD , false );
275+ Memory::free_static (((uint8_t *)p_data) - DATA_OFFSET , false );
255276}
256277
257278template <class T >
@@ -267,26 +288,27 @@ typename CowData<T>::USize CowData<T>::_copy_on_write() {
267288 /* in use by more than me */
268289 USize current_size = *_get_size ();
269290
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 ) ;
272293
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);
275297
276- T *_data = (T *)(mem_new);
298+ new (_refc_ptr) SafeNumeric<USize>(1 ); // refcount
299+ *(_size_ptr) = current_size; // size
277300
278301 // 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));
282304 } else {
283305 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]));
285307 }
286308 }
287309
288310 _unref (_ptr);
289- _ptr = _data ;
311+ _ptr = _data_ptr ;
290312
291313 rc = 1 ;
292314 }
@@ -322,27 +344,33 @@ Error CowData<T>::resize(Size p_size) {
322344 if (alloc_size != current_alloc_size) {
323345 if (current_size == 0 ) {
324346 // 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);
330353
331- _ptr = (T *)ptr;
354+ new (_refc_ptr) SafeNumeric<USize>(1 ); // refcount
355+ *(_size_ptr) = 0 ; // size, currently none
332356
357+ _ptr = _data_ptr;
333358 } 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);
338364
339- _ptr = (T *)(_ptrnew);
365+ new (_refc_ptr) SafeNumeric<USize>(rc); // refcount
366+
367+ _ptr = _data_ptr;
340368 }
341369 }
342370
343371 // construct the newly created elements
344372
345- if (!std::is_trivially_constructible <T>::value ) {
373+ if constexpr (!std::is_trivially_constructible_v <T>) {
346374 for (Size i = *_get_size (); i < p_size; i++) {
347375 memnew_placement (&_ptr[i], T);
348376 }
@@ -353,7 +381,7 @@ Error CowData<T>::resize(Size p_size) {
353381 *_get_size () = p_size;
354382
355383 } else if (p_size < current_size) {
356- if (!std::is_trivially_destructible <T>::value ) {
384+ if constexpr (!std::is_trivially_destructible_v <T>) {
357385 // deinitialize no longer needed elements
358386 for (USize i = p_size; i < *_get_size (); i++) {
359387 T *t = &_ptr[i];
@@ -362,12 +390,15 @@ Error CowData<T>::resize(Size p_size) {
362390 }
363391
364392 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
369400
370- _ptr = (T *)(_ptrnew) ;
401+ _ptr = _data_ptr ;
371402 }
372403
373404 *_get_size () = p_size;
0 commit comments