aboutsummaryrefslogtreecommitdiff
path: root/lib/array/array_resz.c
blob: d28a7a099715ce797de7f8390c14bc6d2962a781 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdckdint.h>
#include <stddef.h>
#include <stdint.h>

#include "array.h"
#include "alloc.h"

void *
(array_resz)(void *ptr, ptrdiff_t ncap, ptrdiff_t elemsz, ptrdiff_t align)
{
	ptrdiff_t newsz, pad = -sizeof(_mlib_arr_hdr_t) & (align - 1);
	_mlib_arr_hdr_t *hdr = _mlib_array_hdr(ptr, align);
	/* Overflow; just call the allocator with the maximum size to force
	   proper error handling */
	if (ckd_mul(&newsz, ncap, elemsz)
	 || ckd_add(&newsz, newsz, pad)
	 || ckd_add(&newsz, newsz, sizeof(_mlib_arr_hdr_t)))
	{
		hdr->mem.alloc(hdr->mem, ALLOC_NEW, nullptr, 0,
			PTRDIFF_MAX, PTRDIFF_MAX, PTRDIFF_MAX);
		unreachable();
	}

	ptrdiff_t oldsz = sizeof(_mlib_arr_hdr_t) + pad + hdr->cap*elemsz;
	hdr = (_mlib_arr_hdr_t *)resz(hdr->mem, (uint8_t *)hdr, oldsz, newsz);
	hdr->cap = ncap;
	return (uint8_t *)hdr + sizeof(*hdr) + pad;
}