vec -> prick_darr.h

This commit is contained in:
2025-11-17 00:30:46 +00:00
parent 44d97efd54
commit f4364f38d1
2 changed files with 130 additions and 111 deletions

130
prick_darr.h Normal file
View File

@@ -0,0 +1,130 @@
/* prick_darr.h: A dynamically sized array, all on the heap.
* Created: 2024-10-01
* Author: Aryadev Chavali
* License: see end of file
* Commentary:
To utilise this library, please put:
#define PRICK_DARR_IMPL
#include "prick_darr.h"
in one of your code units.
This library defines a dynamic array purely on the heap. We split the one
dynamic array allocation into two parts: the metadata, and the actual data.
Consumers of the library will only ever need to deal with the latter component
i.e. they'll only ever have access to the data they require.
Unfortuntely this does mean that the underlying data pointer is _not_ stable
during capacity reallocation, as we're allocating a whole new pointer with the
correct size. Therefore, if you're expecting the array to grow during the
runtime of your program, you should ensure any pointers to components of it are
updated as they will otherwise be dangling.
*/
#ifndef PRICK_DARR_H
#define PRICK_DARR_H
#include <stdint.h>
typedef struct
{
uint32_t size, capacity;
uint8_t bytes[];
} darr_t;
#define DARR_GET(P) (((darr_t *)(P)) - 1)
#define DARR_SIZE(P) (DARR_GET(P)->size)
#define DARR_CAP(P) (DARR_GET(P)->capacity)
void darr_make(void **ptr, uint32_t size);
void darr_free(void **ptr);
void darr_append_byte(void **ptr, uint8_t byte);
void darr_append(void **ptr, void *data, uint32_t size);
void darr_clone(void **dest, void **src);
void darr_ensure_remaining(void **ptr, uint32_t space);
#ifdef PRICK_DARR_IMPL
#include <malloc.h>
#include <string.h>
#ifndef DARR_MULT
#define DARR_MULT 2
#endif
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
void darr_make(void **ptr, uint32_t size)
{
if (!ptr)
return;
darr_t *darrtor = calloc(1, sizeof(*darrtor) + size);
darrtor->size = 0;
darrtor->capacity = size;
*ptr = (darrtor + 1);
}
void darr_free(void **data)
{
if (!data || !*data)
return;
free(DARR_GET(*data));
*data = NULL;
}
void darr_ensure_remaining(void **ptr, uint32_t space)
{
if (!ptr || !*ptr)
return;
darr_t *darr = DARR_GET(*ptr);
if (darr->capacity - darr->size < space)
{
void *new_darr = NULL;
darr_make(&new_darr, MAX(darr->capacity * DARR_MULT, darr->size + space));
DARR_SIZE(new_darr) = darr->size;
memcpy(new_darr, *ptr, darr->size);
darr_free(ptr);
*ptr = new_darr;
}
}
void darr_append_byte(void **ptr, uint8_t byte)
{
darr_ensure_remaining(ptr, 1);
darr_t *darr = DARR_GET(*ptr);
darr->bytes[darr->size++] = byte;
}
void darr_append(void **ptr, void *data, uint32_t size)
{
darr_ensure_remaining(ptr, size);
darr_t *darr = DARR_GET(*ptr);
memcpy(*ptr + darr->size, data, size);
darr->size += size;
}
void darr_clone(void **dest, void **src)
{
if (!dest || !src || !*src)
return;
darr_make(dest, DARR_SIZE(*src));
memcpy(*dest, *src, DARR_SIZE(*src));
DARR_SIZE(*dest) = DARR_SIZE(*src);
}
#endif
#endif
/* Copyright (C) 2024 Aryadev Chavali
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Unlicense
* for details.
* You may distribute and modify this code under the terms of the
* Unlicense, which you should have received a copy of along with this
* program. If not, please go to <https://unlicense.org/>.
*/

111
vec.h
View File

@@ -1,111 +0,0 @@
/* Copyright (C) 2024 Aryadev Chavali
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Unlicense
* for details.
* You may distribute and modify this code under the terms of the
* Unlicense, which you should have received a copy of along with this
* program. If not, please go to <https://unlicense.org/>.
* Created: 2024-10-01
* Author: Aryadev Chavali
* Description: A dynamically sized container.
*/
#ifndef VEC_H
#define VEC_H
#include <stdint.h>
typedef struct
{
uint32_t size, capacity;
uint8_t bytes[];
} vec_t;
#define VEC_GET(P) (((vec_t *)(P)) - 1)
#define VEC_SIZE(P) (VEC_GET(P)->size)
#define VEC_CAP(P) (VEC_GET(P)->capacity)
void vec_make(void **ptr, uint32_t size);
void vec_free(void **ptr);
void vec_append_byte(void **ptr, uint8_t byte);
void vec_append(void **ptr, void *data, uint32_t size);
void vec_clone(void **dest, void **src);
void vec_ensure_remaining(void **ptr, uint32_t space);
#ifdef VEC_IMPL
#include <malloc.h>
#include <string.h>
#ifndef VEC_MULT
#define VEC_MULT 2
#endif
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
void vec_make(void **ptr, uint32_t size)
{
if (!ptr)
return;
vec_t *vector = calloc(1, sizeof(*vector) + size);
vector->size = 0;
vector->capacity = size;
*ptr = (vector + 1);
}
void vec_free(void **data)
{
if (!data || !*data)
return;
free(VEC_GET(*data));
*data = NULL;
}
void vec_ensure_remaining(void **ptr, uint32_t space)
{
if (!ptr || !*ptr)
return;
vec_t *vec = VEC_GET(*ptr);
if (vec->capacity - vec->size < space)
{
void *new_vec = NULL;
vec_make(&new_vec, MAX(vec->capacity * VEC_MULT, vec->size + space));
VEC_SIZE(new_vec) = vec->size;
memcpy(new_vec, *ptr, vec->size);
vec_free(ptr);
*ptr = new_vec;
}
}
void vec_append_byte(void **ptr, uint8_t byte)
{
vec_ensure_remaining(ptr, 1);
vec_t *vec = VEC_GET(*ptr);
vec->bytes[vec->size++] = byte;
}
void vec_append(void **ptr, void *data, uint32_t size)
{
vec_ensure_remaining(ptr, size);
vec_t *vec = VEC_GET(*ptr);
memcpy(*ptr + vec->size, data, size);
vec->size += size;
}
void vec_clone(void **dest, void **src)
{
if (!dest || !src || !*src)
return;
vec_make(dest, VEC_SIZE(*src));
memcpy(*dest, *src, VEC_SIZE(*src));
VEC_SIZE(*dest) = VEC_SIZE(*src);
}
#endif
#endif