added some prick libraries for useful data structures

This commit is contained in:
2026-03-09 07:19:47 +00:00
parent c26e462429
commit 9781384d30
3 changed files with 323 additions and 0 deletions

44
lib/prick_aliases.h Normal file
View File

@@ -0,0 +1,44 @@
/* prick_aliases.h:
* Created: 2025-04-09
* Author: Aryadev Chavali
* License: See end of file
* Commentary:
This library defines some useful aliases for common types. These are mostly
handpicked, and aren't necessary.
*/
#ifndef PRICK_ALIASES_H
#define PRICK_ALIASES_H
#include <assert.h>
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
static_assert(sizeof(float) == 4, "f32 requires 4 byte floats");
static_assert(sizeof(double) == 8, "f64 requires 8 byte doubles");
typedef float f32;
typedef double f64;
#endif
/* Copyright (C) 2025 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/>.
*/

115
lib/prick_sv.h Normal file
View File

@@ -0,0 +1,115 @@
/* prick_sv.h: String Views.
* Created: 2026-03-01
* Author: Aryadev Chavali
* License: See end of file
* Commentary:
To utilise this library, please put:
#define PRICK_SV_IMPL
#include "prick_sv.h"
in one of your code units.
This is a simple read-only string view library. It defines some extremely
common functions you'd expect for a string view library, excluding any that
require allocation.
*/
#ifndef PRICK_SV_H
#define PRICK_SV_H
#include <stdint.h>
typedef struct
{
uint64_t size;
const char *data;
} prick_sv_t;
#define PRICK_SV(DATA, SIZE) ((prick_sv_t){.data = (DATA), .size = (SIZE)})
#define PRICK_SV_AUTO(DATA) \
((prick_sv_t){.data = (void *)(DATA), .size = sizeof(DATA) - 1})
// Pretty printers
#define PRICK_SV_FMT(SV) (int)(SV).size, (SV).data
#define PR_PRICK_SV "%.*s"
prick_sv_t prick_sv_chop_left(prick_sv_t, uint64_t size);
prick_sv_t prick_sv_chop_right(prick_sv_t, uint64_t size);
prick_sv_t prick_sv_truncate(prick_sv_t, uint64_t newsize);
prick_sv_t prick_sv_substr(prick_sv_t, uint64_t position, uint64_t size);
prick_sv_t prick_sv_till(prick_sv_t, const char *reject);
prick_sv_t prick_sv_while(prick_sv_t, const char *accept);
#ifdef PRICK_SV_IMPL
#include <stddef.h>
#include <string.h>
prick_sv_t prick_sv_chop_left(prick_sv_t sv, uint64_t size)
{
if (sv.size <= size)
return PRICK_SV(NULL, 0);
return PRICK_SV(sv.data + size, sv.size - size);
}
prick_sv_t prick_sv_chop_right(prick_sv_t sv, uint64_t size)
{
if (sv.size <= size)
return PRICK_SV(NULL, 0);
return PRICK_SV(sv.data, sv.size - size);
}
prick_sv_t prick_sv_truncate(prick_sv_t sv, uint64_t newsize)
{
if (newsize > sv.size)
return PRICK_SV(NULL, 0);
return PRICK_SV(sv.data, newsize);
}
prick_sv_t prick_sv_substr(prick_sv_t sv, uint64_t position, uint64_t size)
{
prick_sv_t result = prick_sv_truncate(prick_sv_chop_left(sv, position), size);
return result;
}
prick_sv_t prick_sv_till(prick_sv_t sv, const char *reject)
{
if (sv.size == 0 || !sv.data)
return PRICK_SV(NULL, 0);
uint64_t offset;
for (offset = 0; offset < sv.size && strchr(reject, sv.data[offset]) == NULL;
++offset)
continue;
return prick_sv_truncate(sv, offset);
}
prick_sv_t prick_sv_while(prick_sv_t sv, const char *accept)
{
if (sv.size == 0 || !sv.data)
return PRICK_SV(NULL, 0);
uint64_t offset;
for (offset = 0; offset < sv.size && strchr(accept, sv.data[offset]) != NULL;
++offset)
continue;
return prick_sv_truncate(sv, offset);
}
#endif
#endif
/* Copyright (C) 2026 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/>.
*/

164
lib/prick_vec.h Normal file
View File

@@ -0,0 +1,164 @@
/* prick_vec.h: A dynamically sized array with SBO.
* Created: 2026-01-22
* Author: Aryadev Chavali
* License: See end of file
* Commentary:
To utilise this library, please put:
#define PRICK_VEC_IMPL
#include "prick_vec.h"
in one of your code units.
This library defines another form of dynamically sized array as opposed to
prick_darr.h. This one is closer to the one classically implemented by most; a
structure with some metadata and a pointer to the raw buffer. This way,
pointers to the dynamic array are stable (as the structure itself is never
reallocated) and the array can still grow as required.
We use a trick, called Small Buffer Optimisation (SBO), to inline elements
directly into the structure when there are a small number of them (see
PRICK_VEC_INLINE_CAPACITY). This makes lookup _even faster_ (no derefence and
possibility of the entire vector existing in the CPU cache) and allows us to
avoid allocation for smaller use cases. If the number of elements exceeds
PRICK_VEC_INLINE_CAPACITY, we utilise the allocator.
*/
#ifndef PRICK_VEC_H
#define PRICK_VEC_H
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#define PRICK_VEC_INLINE_CAPACITY 32
#define PRICK_VEC_MULT 2
typedef struct
{
uint64_t size, capacity;
uint8_t not_inlined;
union
{
void *ptr;
alignas(max_align_t) uint8_t inlined[PRICK_VEC_INLINE_CAPACITY];
};
} prick_vec_t;
static_assert(sizeof(prick_vec_t) == 64,
"Expected sizeof(prick_vec_t) to be 64");
void prick_vec_append(prick_vec_t *vec, const void *const ptr, uint64_t size);
void prick_vec_append_byte(prick_vec_t *vec, uint8_t byte);
void *prick_vec_data(prick_vec_t *vec);
void prick_vec_ensure_capacity(prick_vec_t *vec, uint64_t capacity);
void prick_vec_ensure_free(prick_vec_t *vec, uint64_t size);
void prick_vec_free(prick_vec_t *vec);
void prick_vec_clone(prick_vec_t *v2, prick_vec_t *v1);
#define PRICK_VEC_GET(VEC, INDEX, TYPE) (((TYPE *)prick_vec_data(VEC))[INDEX])
#ifdef PRICK_VEC_IMPL
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#include <stdlib.h>
#include <string.h>
void prick_vec_append(prick_vec_t *vec, const void *const ptr, uint64_t size)
{
if (!vec || !ptr || !size)
return;
prick_vec_ensure_free(vec, size);
memcpy(&PRICK_VEC_GET(vec, vec->size, uint8_t), ptr, size);
vec->size += size;
}
void prick_vec_append_byte(prick_vec_t *vec, uint8_t byte)
{
if (!vec)
return;
prick_vec_ensure_free(vec, 1);
PRICK_VEC_GET(vec, vec->size, uint8_t) = byte;
++vec->size;
}
void *prick_vec_data(prick_vec_t *vec)
{
if (!vec)
return NULL;
if (vec->not_inlined)
{
return vec->ptr;
}
else
{
return vec->inlined;
}
}
void prick_vec_ensure_capacity(prick_vec_t *vec, uint64_t capacity)
{
if (!vec)
return;
if (vec->capacity == 0)
vec->capacity = PRICK_VEC_INLINE_CAPACITY;
if (vec->capacity < capacity)
{
vec->capacity = MAX(vec->capacity * PRICK_VEC_MULT, capacity);
if (!vec->not_inlined)
{
// We were a small buffer, and now we cannot be i.e. we need to allocate
// on the heap.
vec->not_inlined = 1;
void *buffer = calloc(1, vec->capacity);
memcpy(buffer, vec->inlined, vec->size);
memset(vec->inlined, 0, sizeof(vec->inlined));
vec->ptr = buffer;
}
else
{
// We're already on the heap, just reallocate.
vec->ptr = realloc(vec->ptr, vec->capacity);
}
}
}
void prick_vec_ensure_free(prick_vec_t *vec, uint64_t size)
{
if (!vec)
return;
prick_vec_ensure_capacity(vec, vec->size + size);
}
void prick_vec_free(prick_vec_t *vec)
{
if (!vec)
return;
if (vec->not_inlined)
free(vec->ptr);
memset(vec, 1, sizeof(*vec));
}
void prick_vec_clone(prick_vec_t *v2, prick_vec_t *v1)
{
if (!v1 || !v2)
return;
prick_vec_append(v2, prick_vec_data(v1), v1->size);
}
#undef MAX
#endif
#endif
/* Copyright (C) 2026 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/>.
*/