resizable: Replace grow_cap function

This replaces the grow_cap function with the ensure_cap family of
functions, as they actually do what you want: You'll likely not want to
blindly increase the capacity of a growable, but you want to make sure that
the capacity is large enough to hold the elements you're about to insert.
This commit is contained in:
Laria 2022-01-02 17:16:32 +01:00
parent eea7e8f840
commit 80ad5c979d
3 changed files with 26 additions and 21 deletions

View file

@ -79,9 +79,11 @@ static enum parse_fragment_result parse_fragment(apfl_parser_ptr, struct fragmen
static bool
grow_fragment_cap(struct fragment_list *list, size_t inc)
{
return apfl_resizable_grow_cap(
return apfl_resizable_ensure_cap_for_more_elements(
sizeof(struct fragment),
APFL_RESIZABLE_ARGS(*list, children),
(void **)&list->children,
list->len,
&list->cap,
inc
);
}
@ -1536,9 +1538,11 @@ break_inner:
goto error;
}
if (!apfl_resizable_grow_cap(
if (!apfl_resizable_ensure_cap_for_more_elements(
sizeof(struct partial_assignment),
APFL_RESIZABLE_ARGS(partial_assignments, items),
(void **)&partial_assignments.items,
partial_assignments.len,
&partial_assignments.cap,
1
)) {
p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED);

View file

@ -25,7 +25,7 @@ apfl_resizable_resize(size_t elem_size, void **mem, size_t *len, size_t *cap, si
assert(newlen >= *cap);
if (!apfl_resizable_grow_cap(elem_size, mem, len, cap, newlen - *cap)) {
if (!apfl_resizable_ensure_cap(elem_size, mem, cap, newlen)) {
return false;
}
@ -34,37 +34,36 @@ apfl_resizable_resize(size_t elem_size, void **mem, size_t *len, size_t *cap, si
}
bool
apfl_resizable_grow_cap(size_t elem_size, void **mem, size_t *len, size_t *cap, size_t inc_cap)
apfl_resizable_ensure_cap(size_t elem_size, void **mem, size_t *cap, size_t want_cap)
{
(void)len;// \mystuff\TODO:better not even have the arg
if (inc_cap == 0) {
if (want_cap <= *cap) {
return true;
}
size_t newcap = *cap + inc_cap;
// TODO: We currently simply grow the memory to have space for exactly
// inc_cap more elements. It would probably be smarter to grow the
// memory a bit larger to reduce calls to realloc.
void *newmem = realloc(*mem, newcap * elem_size);
// want_cap elements. It would probably be smarter to grow the memory
// a bit larger to reduce calls to realloc.
void *newmem = realloc(*mem, want_cap * elem_size);
if (newmem == NULL) {
return false;
}
*mem = newmem;
*cap = newcap;
*cap = want_cap;
return true;
}
bool
apfl_resizable_ensure_cap_for_more_elements(size_t elem_size, void **mem, size_t len, size_t *cap, size_t more_elements)
{
return apfl_resizable_ensure_cap(elem_size, mem, cap, len + more_elements); // TODO: What if len + more_elements overflows?
}
bool
apfl_resizable_append(size_t elem_size, void **mem, size_t *len, size_t *cap, const void *other_mem, size_t other_len)
{
size_t newlen = *len + other_len;
if (newlen > *cap) {
if (!apfl_resizable_grow_cap(elem_size, mem, len, cap, newlen - *cap)) {
return false;
}
if (!apfl_resizable_ensure_cap_for_more_elements(elem_size, mem, *len, cap, other_len)) {
return false;
}
memcpy(*((char**)mem) + (elem_size * *len), other_mem, other_len * elem_size);

View file

@ -15,7 +15,9 @@ void apfl_resizable_init(void **mem, size_t *len, size_t *cap);
bool apfl_resizable_resize(size_t elem_size, void **mem, size_t *len, size_t *cap, size_t newlen);
bool apfl_resizable_grow_cap(size_t elem_size, void **mem, size_t *len, size_t *cap, size_t inc_cap);
bool apfl_resizable_ensure_cap(size_t elem_size, void **mem, size_t *cap, size_t want_cap);
bool apfl_resizable_ensure_cap_for_more_elements(size_t elem_size, void **mem, size_t len, size_t *cap, size_t more_elements);
bool apfl_resizable_append(size_t elem_size, void **mem, size_t *len, size_t *cap, const void *other_mem, size_t other_len);