Initial commit
This commit is contained in:
43
util/minmax.h
Normal file
43
util/minmax.h
Normal 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
72
util/queue.c
Normal 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
49
util/queue.h
Normal 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
176
util/tree.c
Normal 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
75
util/tree.h
Normal 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
60
util/tree_internal.h
Normal 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
91
util/vector.c
Normal 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
65
util/vector.h
Normal 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
|
Reference in New Issue
Block a user