Initial commit

This commit is contained in:
2024-02-29 09:48:29 +08:00
commit a6642911d7
15 changed files with 1365 additions and 0 deletions

43
util/minmax.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
static inline int intmin(int x, int y) {
return x < y ? x : y;
}
static inline int intmax(int x, int y) {
return x > y ? x : y;
}
static inline int intmin3(int x, int y, int z) {
if (x < y)
if (x < z)
return x;
else
return z;
else if (y < z)
return y;
else
return z;
}
static inline int intmax3(int x, int y, int z) {
if (x > y)
if (x > z)
return x;
else
return z;
else if (y > z)
return y;
else
return z;
}
static inline int intminmax(int x, int min, int max) {
if (x < min)
return min;
else if (x > max)
return max;
else
return x;
}

72
util/queue.c Normal file
View File

@ -0,0 +1,72 @@
#include "queue.h"
#include <stdio.h>
void queue_InitBuffered(queue *q, void *buffer, uintptr_t size) {
q->data = q->begin = q->end = buffer;
q->size = size;
q->count = 0;
}
void queue_PushByte(queue *q, const uint8_t b) {
if (q->count == q->size) { // no more space
fprintf(stderr, "queue_PushByte: full[%llu bytes], discarding byte 0x%x\n", q->size, b);
return;
}
q->count++;
*((uint8_t *)(q->end++)) = b;
if (q->end == q->data + q->size)
q->end = q->data; // out of the buffer: wrap around
}
uint8_t queue_PopByte(queue *q) {
if (q->count == 0) {
fprintf(stderr, "queue_PopByte: poping an empty queue\n");
return 0;
}
q->count--;
uint8_t data = *((uint8_t *)(q->begin++));
if (q->begin == q->data + q->size)
q->begin = q->data; // wrap around
return data;
}
void queue_Push(queue *q, const void *buffer, uintptr_t size) {
// TODO Optimize queue_Push and queue_Pop
if (queue_Space(q) < size)
return;
for (const uint8_t *i = buffer; i < (const uint8_t *)buffer + size; i++)
queue_PushByte(q, *i);
}
uintptr_t queue_Pop(queue *q, void *buffer, uintptr_t size) {
if (queue_Size(q) < size)
return 0;
for (uint8_t *i = buffer; i < (uint8_t *)buffer + size; i++)
*i = queue_PopByte(q);
return size;
}
uint8_t queue_FrontByte(queue *q) {
if (q->count == 0) {
fprintf(stderr, "queue_TopByte: accessing an empty queue\n");
return 0;
}
return *((uint8_t *)q->begin);
}
bool queue_Empty(queue *q) {
return q->count == 0;
}
uintptr_t queue_Size(queue *q) {
return q->count;
}
uintptr_t queue_Space(queue *q) {
return q->size - q->count;
}

49
util/queue.h Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint8_t *data; // the data buffer
uintptr_t size; // size of data buffer
uint8_t *begin, *end; // begin and past-the-end for in-queue data
uintptr_t count; // number of in-queue bytes
} queue;
// initialize a queue with a existing buffer
void queue_InitBuffered(queue *q, void *buffer, uintptr_t size);
// writes one byte to the queue, discarding if full
void queue_PushByte(queue *q, const uint8_t b);
// pops one byte from the front of the queue, returning it
uint8_t queue_PopByte(queue *q);
// write Size bytes to the queue, none written if there is not space for all the bytes
void queue_Push(queue *q, const void *buffer, uintptr_t size);
// pops Size bytes from the queue, none popped if there are no enough data
// returns the number of bytes popped (either Size or 0)
uintptr_t queue_Pop(queue *q, void *buffer, uintptr_t size);
// return the byte at the front of the queue
uint8_t queue_FrontByte(queue *q);
// tells if the queue is empty
bool queue_Empty(queue *q);
// returns the number of bytes in the queue
uintptr_t queue_Size(queue *q);
// returns the empty space left at the end of the queue
uintptr_t queue_Space(queue *q);
#ifdef __cplusplus
}
#endif

176
util/tree.c Normal file
View File

@ -0,0 +1,176 @@
#include "tree.h"
#include "tree_internal.h"
#include <stdlib.h>
#include <string.h>
// Create allocates and creates a new default Tree object.
tree_Tree *tree_Create(uintptr_t objectSize) {
tree_Tree *t = malloc(sizeof(tree_Tree));
t->objectSize = objectSize;
t->size = 0;
t->root = 0;
return t;
}
static inline tree_Node *__tree_NewNode(tree_Tree *t, uintptr_t key, tree_Node *father, uintptr_t internal) {
t->size++;
tree_Node *node = malloc(sizeof(tree_Node) - 1 + t->objectSize);
node->left = node->right = 0;
node->father = father;
node->key = key;
node->internal = internal;
return node;
}
static void __tree_DestroyNodes(tree_Node *node) {
if (node->left)
__tree_DestroyNodes(node->left);
if (node->right)
__tree_DestroyNodes(node->right);
free(node);
}
void tree_Destroy(tree_Tree *tree) {
if (tree->root)
__tree_DestroyNodes(tree->root);
free(tree);
}
// Will not return NULL
tree_Node *__tree_InsertNodes(tree_Tree *t, tree_Node *node, tree_Node *father, uintptr_t key, tree_Node **result, bool *added) {
if (!node) {
if (added)
*added = true;
#ifdef HELOS_UTIL_TREE_TYPE_TREAP
return *result = __tree_NewNode(t, key, father, random_Rand() ^ key);
#else
return *result = __tree_NewNode(t, key, father, 0);
#endif
} else if (key < node->key) {
node->left = __tree_InsertNodes(t, node->left, node, key, result, added);
return node;
} else if (key > node->key) {
node->right = __tree_InsertNodes(t, node->right, node, key, result, added);
return node;
} else {
if (added)
*added = false;
*result = node;
return node;
}
}
tree_Node *tree_InsertNode(tree_Tree *t, uintptr_t key, bool *added) {
tree_Node *result;
t->root = __tree_InsertNodes(t, t->root, 0, key, &result, added);
#ifdef HELOS_UTIL_TREE_TYPE_TREAP
if (*added)
__tree_treap_Adjust(result, &t->root);
#endif
return result;
}
void *tree_Insert(tree_Tree *t, uintptr_t key, bool *added) {
return tree_InsertNode(t, key, added)->data;
}
static tree_Node *__tree_FindNode(tree_Node *node, uintptr_t key) {
if (!node)
return NULL;
else if (key < node->key)
return __tree_FindNode(node->left, key);
else if (key > node->key)
return __tree_FindNode(node->right, key);
else
return node;
}
tree_Node *tree_FindNode(tree_Tree *t, uintptr_t key) {
return __tree_FindNode(t->root, key);
}
void *tree_Find(tree_Tree *t, uintptr_t key) {
tree_Node *node = tree_FindNode(t, key);
if (!node)
return NULL;
else
return node->data;
}
void tree_Delete(tree_Tree *t, tree_Node *node) {
#ifdef HELOS_UTIL_TREE_TYPE_TREAP
while (node->left && node->right)
if (node->left->internal < node->right->internal)
__tree_Rotate(node->left, &t->root);
else
__tree_Rotate(node->right, &t->root);
#else
while (node->left)
__tree_Rotate(node->left, &t->root);
#endif
if (node == t->root)
t->root = (node->left ? node->left : node->right);
__tree_Connect(node->father, (node->left ? node->left : node->right), __tree_Tell(node));
free(node);
}
tree_Node *tree_FirstNode(tree_Tree *tree) {
tree_Node *result = tree->root;
if (!result)
return 0;
while (result->right)
result = result->left;
return result;
}
tree_Node *tree_LastNode(tree_Tree *tree) {
tree_Node *result = tree->root;
if (!result)
return 0;
while (result->right)
result = result->right;
return result;
}
tree_Node *tree_Node_Next(tree_Node *node) {
if (node->right) {
tree_Node *result = node->right;
while (result->left)
result = result->left;
return result;
} else {
tree_Node *result = node;
while (result->father && __tree_Tell(result) == __tree_Right)
result = result->father;
return result->father;
}
}
// Node_Previous returns the previous node. Returns NULL if first.
tree_Node *tree_Node_Previous(tree_Node *node) {
if (node->left) {
tree_Node *result = node->left;
while (result->right)
result = result->right;
return result;
} else {
tree_Node *result = node;
while (result->father && __tree_Tell(result) == __tree_Left)
result = result->father;
return result->father;
}
}

75
util/tree.h Normal file
View File

@ -0,0 +1,75 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct __tree_Node {
uintptr_t key; // node key
struct __tree_Node *left, *right; // left and right sons
struct __tree_Node *father; // father node
uintptr_t internal; // internal data for balanced trees
char data[1]; // placeholder for object data
} tree_Node;
// Tree is a basic tree-based associative container.
//
// Right now it's a Treap.
typedef struct {
uintptr_t objectSize; // size in bytes of the object
tree_Node *root; // root of the tree, NULL if empty
uintptr_t size; // number of objects in the tree
} tree_Tree;
// Create allocates and creates a new default Tree object.
tree_Tree *tree_Create(uintptr_t objectSize);
// Destroy properly frees all data related to the structure, and itself.
void tree_Destroy(tree_Tree *tree);
// Insert inserts a new object (or locates an existing one).
//
// If *added is not NULL, it is set to true if the key does
// not exist and is actually added.
//
// Newly allocated data is not zeroed, nor initialized in any way.
//
// Returns the pointer to the newly allocated (or existing) data.
void *tree_Insert(tree_Tree *tree, uintptr_t key, bool *added);
// InsertNode does the same as Insert, but returns Node* instead of data.
tree_Node *tree_InsertNode(tree_Tree *tree, uintptr_t key, bool *added);
// Find locates an existing object by its key.
//
// Returns NULL if the object does not exist.
void *tree_Find(tree_Tree *tree, uintptr_t key);
// FindNode returns an existing tree node by its key.
//
// Used for iterating the tree objects.
tree_Node *tree_FindNode(tree_Tree *tree, uintptr_t key);
// FirstNode returns the first node in increasing order.
tree_Node *tree_FirstNode(tree_Tree *tree);
// LastNode returns the last node in increasing order.
tree_Node *tree_LastNode(tree_Tree *tree);
// Delete deletes an existing node from the tree.
void tree_Delete(tree_Tree *tree, tree_Node *node);
// Node_Next returns the next node. Returns NULL if the node is the last.
tree_Node *tree_Node_Next(tree_Node *node);
// Node_Previous returns the previous node. Returns NULL if first.
tree_Node *tree_Node_Previous(tree_Node *node);
#ifdef __cplusplus
}
#endif

60
util/tree_internal.h Normal file
View File

@ -0,0 +1,60 @@
#pragma once
#include "tree.h"
typedef enum {
__tree_Left,
__tree_Right,
} __tree_ConnectType;
static inline __tree_ConnectType __tree_ConnectType_Invert(__tree_ConnectType type) {
return (__tree_ConnectType)(!type);
}
static inline __tree_ConnectType __tree_Tell(tree_Node *son) {
if (!son->father)
return __tree_Left;
if (son->father->left == son)
return __tree_Left;
else
return __tree_Right;
}
static inline tree_Node *__tree_Get(tree_Node *father, __tree_ConnectType type) {
return (type == __tree_Left) ? father->left : father->right;
}
static inline void __tree_Connect(tree_Node *father, tree_Node *son, __tree_ConnectType type) {
if (son)
son->father = father;
if (father) {
if (type == __tree_Left)
father->left = son;
else
father->right = son;
}
}
// Rotates the node up.
static inline void __tree_Rotate(tree_Node *node, tree_Node **root) {
if (!node->father)
return;
__tree_ConnectType type = __tree_Tell(node);
tree_Node *f = node->father,
*b = __tree_Get(node, __tree_ConnectType_Invert(type));
__tree_Connect(f->father, node, __tree_Tell(f));
__tree_Connect(node, f, __tree_ConnectType_Invert(type));
__tree_Connect(f, b, type);
if (!node->father)
*root = node;
}
// Adjust the tree as a Treap
static inline void __tree_treap_Adjust(tree_Node *node, tree_Node **root) {
while (node->father && node->father->internal > node->internal)
__tree_Rotate(node, root);
}

91
util/vector.c Normal file
View File

@ -0,0 +1,91 @@
#include "vector.h"
#include "string.h"
#include "stdlib.h"
vector_Vector *vector_Create(uintptr_t objectSize) {
vector_Vector *vec = malloc(sizeof(vector_Vector));
vec->objectSize = objectSize;
vec->size = 0;
vec->data = 0;
vec->data = malloc(objectSize);
vec->cap = objectSize;
return vec;
}
// Resizes the underlying buffer to a new capacity
static inline void __vector_Rebuffer(vector_Vector *vec, uintptr_t newcap) {
void *newbuf = malloc(newcap);
memcpy(newbuf, vec->data, vec->size);
free(vec->data);
vec->data = newbuf;
vec->cap = newcap;
}
void vector_Destroy(vector_Vector *vec) {
free(vec->data);
free(vec);
}
void *vector_Push(vector_Vector *vec, const void *data) {
vector_Append(vec, data, 1);
return vec->data + vec->size - vec->objectSize;
}
void vector_Append(vector_Vector *vec, const void *data, uintptr_t n) {
uintptr_t oldsize = vec->size, addsize = vec->objectSize * n;
vector_Resize(vec, oldsize + addsize);
if (data)
memcpy(vec->data + oldsize, data, addsize);
else
memset(vec->data + oldsize, 0, addsize);
}
void vector_Resize(vector_Vector *vec, uintptr_t size) {
uintptr_t newsize = vec->size + size * vec->objectSize;
if (newsize > vec->cap) {
// grow the buffer exponentially
uint64_t newcap = vec->cap;
while (newcap < newsize)
newcap *= 2;
__vector_Rebuffer(vec, newcap);
}
vec->size = newsize;
}
uintptr_t vector_Size(vector_Vector *vec) {
return vec->size / vec->objectSize;
}
void vector_Clear(vector_Vector *vec) {
vec->size = 0;
}
void vector_ShrinkBuffer(vector_Vector *vec) {
if (vec->size != vec->cap)
__vector_Rebuffer(vec, vec->size);
}
uintptr_t vector_Capacity(vector_Vector *vec) {
return vec->cap / vec->objectSize;
}
void vector_Reserve(vector_Vector *vec, uintptr_t cap) {
uintptr_t newcap = vec->objectSize * cap;
if (newcap > vec->cap)
__vector_Rebuffer(vec, newcap);
}
void *vector_At(vector_Vector *vec, uintptr_t i) {
return vec->data + vec->objectSize * i;
}
// Data returns the data buffer.
void *vector_Data(vector_Vector *vec) {
return vec->data;
}

65
util/vector.h Normal file
View File

@ -0,0 +1,65 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// Vector is an automatic-resizing array.
typedef struct {
uint8_t *data; // actual data buffer
uintptr_t size, cap; // size of the data and buffer, in bytes
uintptr_t objectSize; // size of the object
} vector_Vector;
// Create allocates a new vector.
vector_Vector *vector_Create(uintptr_t objectSize);
// Destroy properly frees all data related to the structure, and itself.
void vector_Destroy(vector_Vector *vec);
// Push pushes an object at the back of the vector.
//
// If data is NULL, the data is zeroed.
//
// Returns a pointer to data.
void *vector_Push(vector_Vector *vec, const void *data);
// Append pushes multiple objects at the back of the buffer.
//
// If data is NULL, the data is zeroed.
void vector_Append(vector_Vector *vec, const void *data, uintptr_t n);
// Resize resizes the vector to a new number of elements.
void vector_Resize(vector_Vector *vec, uintptr_t size);
// Size returns the number of objects in a vector.
uintptr_t vector_Size(vector_Vector *vec);
// Clear clears a vector, without resizing the buffer.
void vector_Clear(vector_Vector *vec);
// ShrinkBuffer shrinks the internal buffer to exactly the size of the elements.
void vector_ShrinkBuffer(vector_Vector *vec);
// Capacity returns the size of the internal buffer.
uintptr_t vector_Capacity(vector_Vector *vec);
// Reserve reallocates the size of the buffer to CAP objects,
// if the current buffer is smaller.
void vector_Reserve(vector_Vector *vec, uintptr_t cap);
// At returns the i-th object of the vector.
//
// No boundary test is performed.
void *vector_At(vector_Vector *vec, uintptr_t i);
// Data returns the data buffer.
void *vector_Data(vector_Vector *vec);
#ifdef __cplusplus
}
#endif