apfl/src/resizable.c

124 lines
2.7 KiB
C
Raw Normal View History

2021-12-10 20:22:16 +00:00
#include <assert.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include "resizable.h"
void
apfl_resizable_init(void **mem, size_t *len, size_t *cap)
{
*mem = NULL;
*len = 0;
*cap = 0;
}
bool
apfl_resizable_resize(size_t elem_size, void **mem, size_t *len, size_t *cap, size_t newlen)
{
// TODO: We're wasteful here by never actually shrinking the memory.
if (newlen <= *len || newlen < *cap) {
*len = newlen;
return true;
}
assert(newlen >= *cap);
if (!apfl_resizable_ensure_cap(elem_size, mem, cap, newlen)) {
2021-12-10 20:22:16 +00:00
return false;
}
*len = newlen;
return true;
}
bool
apfl_resizable_ensure_cap(size_t elem_size, void **mem, size_t *cap, size_t want_cap)
2021-12-10 20:22:16 +00:00
{
if (want_cap <= *cap) {
2021-12-10 20:22:16 +00:00
return true;
}
// TODO: We currently simply grow the memory to have space for exactly
// 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);
2021-12-10 20:22:16 +00:00
if (newmem == NULL) {
return false;
}
*mem = newmem;
*cap = want_cap;
2021-12-10 20:22:16 +00:00
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?
}
2022-01-20 20:33:04 +00:00
bool apfl_resizable_splice(
size_t elem_size,
void **mem,
size_t *len,
size_t *cap,
size_t cut_start,
size_t cut_len,
const void *other_mem,
size_t other_len
) {
if (cut_start > *len || cut_start + cut_len > *len) {
return false;
2021-12-10 20:22:16 +00:00
}
2022-01-20 20:33:04 +00:00
if (other_len > cut_len) {
if (!apfl_resizable_ensure_cap_for_more_elements(
elem_size,
mem,
*len,
cap,
other_len - cut_len
)) {
return false;
}
}
size_t src_off = cut_start + cut_len;
size_t dst_off = cut_start + other_len;
memmove(
((char *)(*mem)) + (dst_off * elem_size),
((char *)(*mem)) + (src_off * elem_size),
(*len - cut_start - cut_len) * elem_size
);
if (other_len > 0 && other_mem != NULL) {
memcpy(
((char *)(*mem)) + cut_start * elem_size,
other_mem,
other_len * elem_size
);
}
*len += other_len - cut_len;
2021-12-10 20:22:16 +00:00
return true;
}
2022-01-20 20:33:04 +00:00
bool
apfl_resizable_append(size_t elem_size, void **mem, size_t *len, size_t *cap, const void *other_mem, size_t other_len)
{
return apfl_resizable_splice(
elem_size,
mem,
len,
cap,
*len,
0,
other_mem,
other_len
);
}