#ifndef _PDS_H
#define _PDS_H
/* pointer data structures */
/* Simple stack with psuh/pop */
/* Simple hashmap with char * as key */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef PDSDEF
#ifdef PDS_STATIC
#define PDSDEF static
#else
#define PDSDEF extern
#endif
#endif
#define PSTACK_RESIZE_FACTOR 2
#define PSTACK_INIT_CAPACITY 16
typedef struct pstack
{
uint64_t cap;
uint64_t size;
uint64_t stride;
} pstack;
/* Exported API */
/* Stack */
PDSDEF void* _pstack_create(uint64_t length, uint64_t stride);
#ifndef pstack_create
#define pstack_create(type) _pstack_create(PSTACK_INIT_CAPACITY, sizeof(type));
#endif
#ifndef pstack_create_ex
#define pstack_create_ex(type, cap) _pstack_create(cap, sizeof(type));
#endif
PDSDEF void* _pstack_push(void* list, const void* value_ptr);
#ifndef pstack_push
#define pstack_push(list, val) \
do { \
typeof(val) tmp = val; \
list = _pstack_push(list, &tmp); \
} while (0);
#endif
PDSDEF int pstack_pop(const void* list, void* dest);
PDSDEF uint64_t pstack_capacity(const void* list);
PDSDEF uint64_t pstack_size(const void* list);
PDSDEF uint64_t pstack_stride(const void* list);
PDSDEF void pstack_size_set(const void* list, uint64_t value);
PDSDEF void pstack_destroy(void* list);
PDSDEF void* pstack_resize(void* list);
/* Hashmap */
typedef struct phash
{
uint64_t element_size;
uint32_t element_count;
int8_t is_pointer_type;
void* memory;
} phash;
/* Exported API */
PDSDEF void phash_create(uint64_t element_size,
uint32_t element_count,
void* memory,
int8_t is_pointer_type,
phash* out_phash);
PDSDEF void phash_destroy(phash* table);
PDSDEF int8_t phash_set(phash* table, const char* name, void* value);
PDSDEF int8_t phash_set_ptr(phash* table, const char* name, void** value);
PDSDEF int8_t phash_get(phash* table, const char* name, void* out_value);
PDSDEF int8_t phash_get_ptr(phash* table, const char* name, void** out_value);
#ifdef __cplusplus
}
#endif
/* End header file */
#endif /* _PDS_H */
#ifdef PDS_IMPLEMENTATION
PDSDEF void*
_pstack_create(uint64_t length, uint64_t stride)
{
uint64_t header_size = sizeof(pstack);
uint64_t list_size = length * stride;
pstack* list = (pstack*)malloc(header_size + list_size);
list->cap = length;
list->size = 0;
list->stride = stride;
return (void*)((uint8_t*)list + header_size);
}
PDSDEF uint64_t
pstack_capacity(const void* list)
{
uint64_t header_size = sizeof(pstack);
pstack* header = (pstack*)((uint8_t*)list - header_size);
return header->cap;
}
PDSDEF uint64_t
pstack_size(const void* list)
{
uint64_t header_size = sizeof(pstack);
pstack* header = (pstack*)((uint8_t*)list - header_size);
return header->size;
}
PDSDEF uint64_t
pstack_stride(const void* list)
{
uint64_t header_size = sizeof(pstack);
pstack* header = (pstack*)((uint8_t*)list - header_size);
return header->stride;
}
PDSDEF void
pstack_size_set(const void* list, uint64_t value)
{
uint64_t header_size = sizeof(pstack);
pstack* header = (pstack*)((uint8_t*)list - header_size);
header->size = value;
}
PDSDEF void
pstack_destroy(void* list)
{
if (list) {
uint64_t header_size = sizeof(pstack);
pstack* header = (pstack*)((uint8_t*)list - header_size);
free(header);
}
}
PDSDEF void*
pstack_resize(void* list)
{
uint64_t header_size = sizeof(pstack);
pstack* header = (pstack*)((uint8_t*)list - header_size);
if (header->cap == 0) {
fprintf(stderr,
"pstack_resize called on an list with 0 capacity. This should not "
"be possible.\n");
return 0;
}
void* temp =
_pstack_create((PSTACK_RESIZE_FACTOR * header->cap), header->stride);
pstack* new_header = (pstack*)((uint8_t*)temp - header_size);
new_header->size = header->size;
memcpy(temp, list, header->size * header->stride);
pstack_destroy(list);
return temp;
}
PDSDEF void*
_pstack_push(void* list, const void* value_ptr)
{
uint64_t header_size = sizeof(pstack);
pstack* header = (pstack*)((uint8_t*)list - header_size);
if (header->size >= header->cap) {
list = pstack_resize(list);
}
header = (pstack*)((uint8_t*)list - header_size);
uint64_t addr = (uint64_t)list;
addr += (header->size * header->stride);
memcpy((void*)addr, value_ptr, header->stride);
pstack_size_set(list, header->size + 1);
return list;
}
PDSDEF int
pstack_pop(const void* list, void* dest)
{
uint64_t size = pstack_size(list);
uint64_t stride = pstack_stride(list);
if (size < 1) {
// fprintf(stderr, "pstack_pop called on an empty pstack. Nothing to be
// done.\n");
return 1;
}
uint64_t addr = (uint64_t)list;
addr += ((size - 1) * stride);
memcpy(dest, (void*)addr, stride);
pstack_size_set(list, size - 1);
return 0;
}
/* int */
/* main() */
/* { */
/* int* lst = pstack_create(int); */
/* pstack_push(lst, 1); */
/* pstack_push(lst, 2); */
/* int i; */
/* while (!pstack_pop(lst, &i)) { */
/* printf("%d\n", i); */
/* } */
/* char** lst2 = pstack_create(char*); */
/* pstack_push(lst2, &"Hello"); */
/* pstack_push(lst2, &"you!"); */
/* char *s; */
/* while (!pstack_pop(lst2, &s)) { */
/* printf("%s\n", s); */
/* } */
/* pstack_destroy(lst); */
/* pstack_destroy(lst2); */
/* return 0; */
/* } */
static uint64_t
hash_name(const char* name, uint32_t element_count)
{
// A multipler to use when generating a hash. Prime to hopefully avoid
// collisions.
static const uint64_t multiplier = 97;
unsigned const char* us;
uint64_t hash = 0;
for (us = (unsigned const char*)name; *us; us++) {
hash = hash * multiplier + *us;
}
// Mod it against the size of the table.
hash %= element_count;
return hash;
}
PDSDEF void
phash_create(uint64_t element_size,
uint32_t element_count,
void* memory,
int8_t is_pointer_type,
phash* out_phash)
{
if (!memory || !out_phash) {
fprintf(
stderr,
"phash_create failed! Pointer to memory and out_phash are required.\n");
return;
}
if (!element_count || !element_size) {
fprintf(
stderr,
"element_size and element_count must be a positive non-zero value.\n");
return;
}
out_phash->memory = memory;
out_phash->element_count = element_count;
out_phash->element_size = element_size;
out_phash->is_pointer_type = is_pointer_type;
memset(out_phash->memory, 0, element_size * element_count);
}
PDSDEF void
phash_destroy(phash* table)
{
if (table) {
memset(table->memory, 0, table->element_size * table->element_count);
}
}
PDSDEF int8_t
phash_set(phash* table, const char* name, void* value)
{
if (!table || !name || !value) {
fprintf(stderr, "phash_set requires table, name and value to exist.");
return 0;
}
if (table->is_pointer_type) {
fprintf(stderr,
"phash_set should not be used with tables that have pointer types. "
"Use phash_set_ptr instead.\n");
return 0;
}
uint64_t hash = hash_name(name, table->element_count);
memcpy(
table->memory + (table->element_size * hash), value, table->element_size);
return 1;
}
PDSDEF int8_t
phash_set_ptr(phash* table, const char* name, void** value)
{
if (!table || !name) {
fprintf(stderr, "phash_set_ptr requires table and name to exist.\n");
return 0;
}
if (!table->is_pointer_type) {
fprintf(stderr,
"phash_set_ptr should not be used with tables that do not have "
"pointer types. Use phash_set instead.\n");
return 0;
}
uint64_t hash = hash_name(name, table->element_count);
((void**)table->memory)[hash] = value ? *value : 0;
return 1;
}
PDSDEF int8_t
phash_get(phash* table, const char* name, void* out_value)
{
if (!table || !name || !out_value) {
fprintf(stderr, "phash_get requires table, name and out_value to exist.\n");
return 0;
}
if (table->is_pointer_type) {
fprintf(stderr,
"phash_get should not be used with tables that have pointer types. "
"Use phash_set_ptr instead.\n");
return 0;
}
uint64_t hash = hash_name(name, table->element_count);
memcpy(out_value,
table->memory + (table->element_size * hash),
table->element_size);
return 1;
}
PDSDEF int8_t
phash_get_ptr(phash* table, const char* name, void** out_value)
{
if (!table || !name || !out_value) {
fprintf(stderr,
"phash_get_ptr requires table, name and out_value to exist.\n");
return 0;
}
if (!table->is_pointer_type) {
fprintf(stderr,
"phash_get_ptr should not be used with tables that do not have "
"pointer types. Use phash_get instead.\n");
return 0;
}
uint64_t hash = hash_name(name, table->element_count);
*out_value = ((void**)table->memory)[hash];
return *out_value != 0;
}
/* struct test */
/* { */
/* int a; */
/* char b[15]; */
/* }; */
/* int */
/* main() */
/* { */
/* phash tbl; */
/* int mem[2]; */
/* phash_create(sizeof(int), 2, &mem, 0, &tbl); */
/* int x = 2; */
/* phash_set(&tbl, "Val", &x); */
/* x = 3; */
/* phash_set(&tbl, "Val1", &x); */
/* x = 4; */
/* phash_set(&tbl, "Val2", &x); */
/* int y; */
/* phash_get(&tbl, "Val", &y); */
/* printf("%d\n", y); */
/* phash_get(&tbl, "Val1", &y); */
/* printf("%d\n", y); */
/* phash_get(&tbl, "Val2", &y); */
/* printf("%d\n", y); */
/* phash_destroy(&tbl); */
/* phash tbl2; */
/* struct test mem2[15]; */
/* phash_create(sizeof(struct test), 15, &mem2, 1, &tbl2); */
/* struct test a = { .a = 5, .b = "Yooo" }; */
/* struct test* aa = &a; */
/* phash_set_ptr(&tbl2, "aha", (void**)&aa); */
/* struct test* get; */
/* phash_get_ptr(&tbl2, "aha", (void**)&get); */
/* printf("{ a: %d, b: %s }\n", get->a, get->b); */
/* return 0; */
/* } */
#endif /* PDS_IMPLEMENTATION */