--- /dev/null
+# Dragontype
+Dragontype is a small C library providing the types that [dragonblocks_alpha](https://github.com/dragonblocks/dragonblocks_alpha) uses.
+It serves a similar purpose as the C++ standard library would, but C++ is just bloated af.
+This library is only capable of what dragonblocks needs, and it does not intend to be general purpose.
+
+Included are Array, Bintree, List and Queue as well as numeric types and (de-)serialisation for them.
+To use this in your project, just compile the implementation.c file into your project's binary.
--- /dev/null
+#include <string.h>
+#include <stdlib.h>
+#include "array.h"
+
+Array array_create(size_t membsiz)
+{
+ return (Array) {
+ .membsiz = membsiz,
+ .siz = 0,
+ .cap = 0,
+ .ptr = NULL,
+ };
+}
+
+
+static void array_realloc(Array *array)
+{
+ if (array->siz > array->cap) {
+ array->cap = array->siz + DRAGONTYPE_ARRAY_REALLOC_EXTRA;
+ array->ptr = realloc(array->ptr, array->cap * array->membsiz);
+ }
+}
+
+static void array_alloc(Array *array, size_t siz)
+{
+ array->siz += siz;
+ array_realloc(array);
+}
+
+void array_insert(Array *array, void *elem, size_t idx)
+{
+ size_t oldsiz = array->siz;
+ array_alloc(array, 1);
+
+ char *iptr = (char *) array->ptr + idx * array->membsiz;
+ memmove(iptr + array->membsiz, iptr, (oldsiz - idx) * array->membsiz);
+ memcpy(iptr, elem, array->membsiz);
+}
+
+void array_append(Array *array, void *elem)
+{
+ size_t oldsiz = array->siz;
+ array_alloc(array, 1);
+
+ memcpy((char *) array->ptr + oldsiz * array->membsiz, elem, array->membsiz);
+}
+
+void array_copy(Array *array, void **ptr, size_t *count)
+{
+ *count = array->siz;
+ size_t size = array->siz * array->membsiz;
+ *ptr = malloc(size);
+ memcpy(*ptr, array->ptr, size);
+}
--- /dev/null
+#ifndef _DRAGONTYPE_ARRAY_H_
+#define _DRAGONTYPE_ARRAY_H_
+
+#define DRAGONTYPE_ARRAY_REALLOC_EXTRA 25
+
+#include <stddef.h>
+#include <stdbool.h>
+
+typedef struct
+{
+ size_t membsiz;
+ size_t siz, cap;
+ void *ptr;
+} Array;
+
+Array array_create(size_t membsiz);
+void array_insert(Array *array, void *elem, size_t idx);
+void array_append(Array *array, void *elem);
+void array_copy(Array *array, void **ptr, size_t *count);
+
+#endif
--- /dev/null
+#include <string.h>
+#include <stdlib.h>
+#include "bintree.h"
+
+Bintree bintree_create(size_t key_size)
+{
+ return (Bintree) {
+ .root = NULL,
+ .key_size = key_size,
+ };
+}
+
+static BintreeNode **search_recursive(Bintree *tree, BintreeNode **nodeptr, void *key)
+{
+ if (*nodeptr) {
+ int cond;
+
+ if ((cond = memcmp((*nodeptr)->key, key, tree->key_size)) == 0)
+ return nodeptr;
+ else if (cond > 0)
+ return search_recursive(tree, &(*nodeptr)->left, key);
+ else
+ return search_recursive(tree, &(*nodeptr)->right, key);
+ } else {
+ return nodeptr;
+ }
+}
+
+BintreeNode **bintree_search(Bintree *tree, void *key)
+{
+ return search_recursive(tree, &tree->root, key);
+}
+
+void bintree_add_node(Bintree *tree, BintreeNode **nodeptr, void *key, void *value)
+{
+ *nodeptr = malloc(sizeof(BintreeNode));
+ (*nodeptr)->key = malloc(tree->key_size);
+ memcpy((*nodeptr)->key, key, tree->key_size);
+ (*nodeptr)->value = value;
+ (*nodeptr)->left = (*nodeptr)->right = NULL;
+}
+
+static void free_recursive(BintreeNode *node, BintreeFreeFunction func, void *arg)
+{
+ if (node) {
+ free_recursive(node->left, func, arg);
+ free_recursive(node->right, func, arg);
+ free(node->key);
+ if (func)
+ func(node->value, arg);
+ free(node);
+ }
+}
+
+void bintree_clear(Bintree *tree, BintreeFreeFunction func, void *arg)
+{
+ if (tree) {
+ free_recursive(tree->root, func, arg);
+ tree->root = NULL;
+ }
+}
--- /dev/null
+#ifndef _DRAGONTYPE_BINTREE_H_
+#define _DRAGONTYPE_BINTREE_H_
+
+#include <stddef.h>
+
+typedef struct BintreeNode
+{
+ void *key;
+ void *value;
+ struct BintreeNode *left;
+ struct BintreeNode *right;
+} BintreeNode;
+
+typedef struct
+{
+ BintreeNode *root;
+ size_t key_size;
+} Bintree;
+
+typedef void (*BintreeFreeFunction)(void *value, void *arg);
+
+Bintree bintree_create(size_t key_size);
+BintreeNode **bintree_search(Bintree *tree, void *key);
+void bintree_add_node(Bintree *tree, BintreeNode **nodeptr, void *key, void *value);
+void bintree_clear(Bintree *tree, BintreeFreeFunction func, void *arg);
+
+#endif
--- /dev/null
+// include *.c files
+
+#include "array.c"
+#include "bintree.c"
+#include "list.c"
+#include "number.c"
+#include "queue.c"
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include "list.h"
+
+bool list_compare_default(void *v1, void *v2)
+{
+ return v1 == v2;
+}
+
+bool list_compare_string(void *v1, void *v2)
+{
+ return strcmp(v1, v2) == 0;
+}
+
+List list_create(ListComparator cmp)
+{
+ return (List) {
+ .cmp = cmp ? cmp : list_compare_default,
+ .first = NULL,
+ };
+}
+
+void list_clear(List *list)
+{
+ list_clear_func(list, NULL, NULL);
+}
+
+void list_clear_func(List *list, void (*func)(void *key, void *value, void *arg), void *arg)
+{
+ for (ListPair *pair = list->first; pair != NULL;) {
+ ListPair *next = pair->next;
+ if (func)
+ func(pair->key, pair->value, arg);
+ free(pair);
+ pair = next;
+ }
+ list->first = NULL;
+}
+
+static ListPair *make_pair(void *key, void *value)
+{
+ ListPair *pair = malloc(sizeof(ListPair));
+ pair->key = key;
+ pair->value = value;
+ pair->next = NULL;
+ return pair;
+}
+
+bool list_put(List *list, void *key, void *value)
+{
+ ListPair **pairptr;
+ for (pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
+ if (list->cmp((*pairptr)->key, key))
+ return false;
+ }
+ *pairptr = make_pair(key, value);
+ return true;
+}
+
+void *list_get_cached(List *list, void *key, void *(*provider)(void *key))
+{
+ ListPair **pairptr;
+ for (pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
+ if (list->cmp((*pairptr)->key, key))
+ return (*pairptr)->value;
+ }
+ return (*pairptr = make_pair(key, provider(key)))->value;
+}
+
+void list_set(List *list, void *key, void *value)
+{
+ ListPair **pairptr;
+ for (pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
+ if (list->cmp((*pairptr)->key, key))
+ break;
+ }
+ *pairptr = make_pair(key, value);
+}
+
+void *list_delete(List *list, void *key)
+{
+ for (ListPair **pairptr = &list->first; *pairptr != NULL; pairptr = &(*pairptr)->next) {
+ if (list->cmp((*pairptr)->key, key)) {
+ ListPair *pair = *pairptr;
+ void *value = (*pairptr)->value;
+ *pairptr = pair->next;
+ free(pair);
+ return value;
+ }
+ }
+ return NULL;
+}
+
+void *list_get(List *list, void *key)
+{
+ for (ListPair *pair = list->first; pair != NULL; pair = pair->next)
+ if (list->cmp(pair->key, key))
+ return pair->value;
+ return NULL;
+}
--- /dev/null
+#ifndef _DRAGONTYPE_LIST_H_
+#define _DRAGONTYPE_LIST_H_
+
+#include <stdbool.h>
+
+#define ITERATE_LIST(list, pair) for (ListPair *pair = (list)->first; pair != NULL; pair = pair->next)
+
+typedef struct ListPair
+{
+ struct ListPair *next;
+ void *key;
+ void *value;
+} ListPair;
+
+typedef bool (*ListComparator)(void *v1, void *v2);
+
+typedef struct
+{
+ ListComparator cmp;
+ ListPair *first;
+} List;
+
+bool list_compare_default(void *v1, void *v2);
+bool list_compare_string(void *v1, void *v2);
+
+List list_create(ListComparator cmp);
+void list_clear(List *list);
+void list_clear_func(List *list, void (*func)(void *key, void *value, void *arg), void *arg);
+
+bool list_put(List *list, void *key, void *value);
+void *list_get_cached(List *list, void *key, void *(*provider)(void *key));
+void list_set(List *list, void *key, void *value);
+void *list_get(List *list, void *key);
+void *list_delete(List *list, void *key);
+
+bool list_serialize(int fd, List *list); // ToDo
+bool list_deserialize(int fd, List *list); // ToDo
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <unistd.h>
+#include <endian.h>
+#include <poll.h>
+#include "number.h"
+
+bool read_full(int fd, char *buffer, size_t size)
+{
+ size_t n_read_total = 0;
+ int n_read;
+ while (n_read_total < size) {
+ if ((n_read = read(fd, buffer + n_read_total, size - n_read_total)) == -1) {
+ perror("read");
+ return false;
+ }
+ n_read_total += n_read;
+ }
+ return true;
+}
+
+#define htobe8(x) x
+#define be8toh(x) x
+
+#define READVEC(type, n) \
+ type buf[n]; \
+ for (int i = 0; i < n; i++) { \
+ if (! read_ ## type(fd, &buf[i])) \
+ return false; \
+ }
+
+#define WRITEVEC(type, n) \
+ for (int i = 0; i < n; i++) { \
+ if (! write_ ## type(fd, vec[i])) \
+ return false; \
+ } \
+ return true;
+
+#define DEFVEC(type) \
+ bool read_v2 ## type(int fd, v2 ## type *ptr) \
+ { \
+ READVEC(type, 2) \
+ ptr->x = buf[0]; \
+ ptr->y = buf[1]; \
+ return true; \
+ } \
+ bool write_v2 ## type(int fd, v2 ## type val) \
+ { \
+ type vec[2] = {val.x, val.y}; \
+ WRITEVEC(type, 2) \
+ } \
+ bool v2 ## type ## _equals(v2 ## type a, v2 ## type b) \
+ { \
+ return a.x == b.x && a.y == b.y; \
+ } \
+ v2 ## type v2 ## type ## _add(v2 ## type a, v2 ## type b) \
+ { \
+ return (v2 ## type) {a.x + b.x, a.y + b.y}; \
+ } \
+ bool read_v3 ## type(int fd, v3 ## type *ptr) \
+ { \
+ READVEC(type, 3) \
+ ptr->x = buf[0]; \
+ ptr->y = buf[1]; \
+ ptr->z = buf[2]; \
+ return true; \
+ } \
+ bool write_v3 ## type(int fd, v3 ## type val) \
+ { \
+ type vec[3] = {val.x, val.y, val.z}; \
+ WRITEVEC(type, 3) \
+ } \
+ bool v3 ## type ## _equals(v3 ## type a, v3 ## type b) \
+ { \
+ return a.x == b.x && a.y == b.y && a.z == b.z; \
+ } \
+ v3 ## type v3 ## type ## _add(v3 ## type a, v3 ## type b) \
+ { \
+ return (v3 ## type) {a.x + b.x, a.y + b.y, a.z + b.z}; \
+ }
+
+#define DEFTYP(type, bits) \
+ bool read_ ## type(int fd, type *buf) \
+ { \
+ u ## bits encoded; \
+ if (! read_full(fd, (char *) &encoded, sizeof(type))) \
+ return false; \
+ *buf = be ## bits ## toh(encoded); \
+ return true; \
+ } \
+ bool write_ ## type(int fd, type val) \
+ { \
+ u ## bits encoded = htobe ## bits(val); \
+ if (write(fd, &encoded, sizeof(encoded)) == -1) { \
+ perror("write"); \
+ return false; \
+ } \
+ return true; \
+ } \
+ DEFVEC(type)
+
+#define DEFTYPES(bits) \
+ DEFTYP(s ## bits, bits) \
+ DEFTYP(u ## bits, bits)
+
+DEFTYPES(8)
+DEFTYPES(16)
+DEFTYPES(32)
+DEFTYPES(64)
+
+#define DEFFLOAT(type) \
+ bool read_ ## type(int fd, type *buf) \
+ { \
+ if (! read_full(fd, (char *) buf, sizeof(type))) \
+ return false; \
+ return true; \
+ } \
+ bool write_ ## type(int fd, type val) \
+ { \
+ if (write(fd, &val, sizeof(val)) == -1) { \
+ perror("write"); \
+ return false; \
+ } \
+ return true; \
+ } \
+ DEFVEC(type)
+
+DEFFLOAT(f32)
+DEFFLOAT(f64)
--- /dev/null
+#ifndef _DRAGONTYPE_NUMBER_H_
+#define _DRAGONTYPE_NUMBER_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+bool read_full(int fd, char *buffer, size_t size);
+
+#define DEFRW(type) \
+ bool read_ ## type(int fd, type *ptr); \
+ bool write_ ## type(int fd, type val);
+
+#define DEFBOX(type) \
+ typedef struct {v ## type min; v ## type max;} aabb ## type;
+
+#define DEFVEC(type) \
+ typedef struct {type x, y;} v2 ## type; \
+ DEFRW(v2 ## type) \
+ DEFBOX(2 ## type) \
+ bool v2 ## type ## _equals(v2 ## type a, v2 ## type b); \
+ v2 ## type v2 ## type ## _add(v2 ## type a, v2 ## type b); \
+ typedef struct {type x, y, z;} v3 ## type; \
+ DEFRW(v3 ## type) \
+ DEFBOX(3 ## type) \
+ bool v3 ## type ## _equals(v3 ## type a, v3 ## type b); \
+ v3 ## type v3 ## type ## _add(v3 ## type a, v3 ## type b);
+
+#define DEFTYP(from, to) \
+ typedef from to; \
+ DEFRW(to) \
+ DEFVEC(to)
+
+#define DEFTYPES(bits) \
+ DEFTYP(int ## bits ## _t, s ## bits) \
+ DEFTYP(uint ## bits ## _t, u ## bits)
+
+DEFTYPES(8)
+DEFTYPES(16)
+DEFTYPES(32)
+DEFTYPES(64)
+
+typedef float f32;
+typedef double f64;
+
+DEFTYP(float, f32)
+DEFTYP(double, f64)
+
+#undef DEFRW
+#undef DEFBOX
+#undef DEFVEC
+#undef DEFTYP
+#undef DEFTYPES
+
+#endif
--- /dev/null
+#include <stdlib.h>
+#include "queue.h"
+
+Queue *queue_create()
+{
+ Queue *queue = malloc(sizeof(Queue));
+ queue->list = list_create(NULL);
+ pthread_mutex_init(&queue->mtx, NULL);
+ return queue;
+}
+
+void queue_delete(Queue *queue)
+{
+ pthread_mutex_destroy(&queue->mtx);
+ list_clear(&queue->list);
+ free(queue);
+}
+
+void queue_enqueue(Queue *queue, void *elem)
+{
+ pthread_mutex_lock(&queue->mtx);
+ list_put(&queue->list, elem, NULL);
+ pthread_mutex_unlock(&queue->mtx);
+}
+
+void *dequeue(Queue *queue)
+{
+ return queue_dequeue_callback(queue, NULL);
+}
+
+void *queue_dequeue_callback(Queue *queue, void (*callback)(void *elem))
+{
+ pthread_mutex_lock(&queue->mtx);
+ void *elem = NULL;
+ ListPair **lptr = &queue->list.first;
+ if (*lptr) {
+ elem = (*lptr)->key;
+ ListPair *next = (*lptr)->next;
+ free(*lptr);
+ *lptr = next;
+
+ if (callback)
+ callback(elem);
+ }
+ pthread_mutex_unlock(&queue->mtx);
+ return elem;
+}
--- /dev/null
+#ifndef _DRAGONTYPE_QUEUE_H_
+#define _DRAGONTYPE_QUEUE_H_
+
+#include <pthread.h>
+#include "list.h"
+
+typedef struct
+{
+ List list;
+ pthread_mutex_t mtx;
+} Queue;
+
+Queue *queue_create();
+void queue_delete(Queue *queue);
+void queue_enqueue(Queue *queue, void *elem);
+void *queue_dequeue(Queue *queue);
+void *queue_dequeue_callback(Queue *queue, void (*callback)(void *elem));
+
+#endif