darray: fix buffer size calculation for element with strict alignment

This commit is contained in:
Alan Wu 2021-02-16 20:48:14 -05:00
parent fff6d642b3
commit 47e05fca10

View File

@ -43,7 +43,7 @@
// bool rb_darray_append(rb_darray(T) *ptr_to_ary, T element); // bool rb_darray_append(rb_darray(T) *ptr_to_ary, T element);
// //
#define rb_darray_append(ptr_to_ary, element) ( \ #define rb_darray_append(ptr_to_ary, element) ( \
rb_darray_ensure_space((ptr_to_ary)) ? ( \ rb_darray_ensure_space((ptr_to_ary), sizeof(**(ptr_to_ary)), sizeof((*(ptr_to_ary))->data[0])) ? ( \
rb_darray_set(*(ptr_to_ary), \ rb_darray_set(*(ptr_to_ary), \
(*(ptr_to_ary))->meta.size, \ (*(ptr_to_ary))->meta.size, \
(element)), \ (element)), \
@ -91,21 +91,25 @@ rb_darray_free(void *ary)
// //
#define rb_darray_pop_back(ary) ((ary)->meta.size--) #define rb_darray_pop_back(ary) ((ary)->meta.size--)
// Internal macro // Internal function. Calculate buffer size on malloc heap.
// Ensure there is space for one more element. Return 1 on success and 0 on failure. static inline size_t
// `ptr_to_ary` is evaluated multiple times. rb_darray_buffer_size(int32_t capacity, size_t header_size, size_t element_size)
#define rb_darray_ensure_space(ptr_to_ary) ( \ {
(rb_darray_capa(*(ptr_to_ary)) > rb_darray_size(*(ptr_to_ary))) ? \ if (capacity == 0) return 0;
1 : \ return header_size + (size_t)capacity * element_size;
rb_darray_double(ptr_to_ary, sizeof((*(ptr_to_ary))->data[0]))) }
// Internal function // Internal function
// Ensure there is space for one more element. Return 1 on success and 0 on failure.
// Note: header_size can be bigger than sizeof(rb_darray_meta_t) for example when T is __int128_t.
// for example.
static inline int static inline int
rb_darray_double(void *ptr_to_ary, size_t element_size) rb_darray_ensure_space(void *ptr_to_ary, size_t header_size, size_t element_size)
{ {
rb_darray_meta_t **ptr_to_ptr_to_meta = ptr_to_ary; rb_darray_meta_t **ptr_to_ptr_to_meta = ptr_to_ary;
const rb_darray_meta_t *meta = *ptr_to_ptr_to_meta; rb_darray_meta_t *meta = *ptr_to_ptr_to_meta;
int32_t current_capa = rb_darray_capa(meta); int32_t current_capa = rb_darray_capa(meta);
if (rb_darray_size(meta) < current_capa) return 1;
int32_t new_capa; int32_t new_capa;
// Calculate new capacity // Calculate new capacity
@ -119,11 +123,11 @@ rb_darray_double(void *ptr_to_ary, size_t element_size)
} }
// Calculate new buffer size // Calculate new buffer size
size_t current_buffer_size = element_size * (size_t)current_capa + (meta ? sizeof(*meta) : 0); size_t current_buffer_size = rb_darray_buffer_size(current_capa, header_size, element_size);
size_t new_buffer_size = element_size * (size_t)new_capa + sizeof(*meta); size_t new_buffer_size = rb_darray_buffer_size(new_capa, header_size, element_size);
if (new_buffer_size <= current_buffer_size) return 0; if (new_buffer_size <= current_buffer_size) return 0;
rb_darray_meta_t *doubled_ary = realloc(*ptr_to_ptr_to_meta, new_buffer_size); rb_darray_meta_t *doubled_ary = realloc(meta, new_buffer_size);
if (!doubled_ary) return 0; if (!doubled_ary) return 0;
if (meta == NULL) { if (meta == NULL) {