first commit

This commit is contained in:
Zander Thannhauser 2025-07-26 19:35:56 -05:00
commit 9be542c93c
8 changed files with 2795 additions and 0 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.direnv/
bin/
outputs/

651
avl.c Normal file
View file

@ -0,0 +1,651 @@
/*****************************************************************************
avl.c - Source code for the AVL-tree library.
Copyright (C) 1998 Michael H. Buselli <cosine@cosine.org>
Copyright (C) 2000-2002 Wessel Dankers <wsl@nl.linux.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Augmented AVL-tree. Original by Michael H. Buselli <cosine@cosine.org>.
Modified by Wessel Dankers <wsl@nl.linux.org> to add a bunch of bloat to
the sourcecode, change the interface and squash a few bugs.
Mail him if you find new bugs.
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "avl.h"
static void avl_rebalance(avl_tree_t *, avl_node_t *);
#ifdef AVL_COUNT
#define NODE_COUNT(n) ((n) ? (n)->count : 0)
#define L_COUNT(n) (NODE_COUNT((n)->left))
#define R_COUNT(n) (NODE_COUNT((n)->right))
#define CALC_COUNT(n) (L_COUNT(n) + R_COUNT(n) + 1)
#endif
#ifdef AVL_DEPTH
#define NODE_DEPTH(n) ((n) ? (n)->depth : 0)
#define L_DEPTH(n) (NODE_DEPTH((n)->left))
#define R_DEPTH(n) (NODE_DEPTH((n)->right))
#define CALC_DEPTH(n) ((L_DEPTH(n) > R_DEPTH(n) ? L_DEPTH(n) : R_DEPTH(n)) + 1)
#endif
#ifndef AVL_DEPTH
/* Also known as ffs() (from BSD) */
static int lg(unsigned int u) {
int r = 1;
if(!u) return 0;
if(u & 0xffff0000) { u >>= 16; r += 16; }
if(u & 0x0000ff00) { u >>= 8; r += 8; }
if(u & 0x000000f0) { u >>= 4; r += 4; }
if(u & 0x0000000c) { u >>= 2; r += 2; }
if(u & 0x00000002) r++;
return r;
}
#endif
static int avl_check_balance(avl_node_t *avlnode) {
#ifdef AVL_DEPTH
int d;
d = R_DEPTH(avlnode) - L_DEPTH(avlnode);
return d<-1?-1:d>1?1:0;
#else
/* int d;
* d = lg(R_COUNT(avlnode)) - lg(L_COUNT(avlnode));
* d = d<-1?-1:d>1?1:0;
*/
#ifdef AVL_COUNT
int pl, r;
pl = lg(L_COUNT(avlnode));
r = R_COUNT(avlnode);
if(r>>pl+1)
return 1;
if(pl<2 || r>>pl-2)
return 0;
return -1;
#else
#error No balancing possible.
#endif
#endif
}
#ifdef AVL_COUNT
unsigned int avl_count(const avl_tree_t *avltree) {
return NODE_COUNT(avltree->top);
}
avl_node_t *avl_at(const avl_tree_t *avltree, unsigned int index) {
avl_node_t *avlnode;
unsigned int c;
avlnode = avltree->top;
while(avlnode) {
c = L_COUNT(avlnode);
if(index < c) {
avlnode = avlnode->left;
} else if(index > c) {
avlnode = avlnode->right;
index -= c+1;
} else {
return avlnode;
}
}
return NULL;
}
unsigned int avl_index(const avl_node_t *avlnode) {
avl_node_t *next;
unsigned int c;
c = L_COUNT(avlnode);
while((next = avlnode->parent)) {
if(avlnode == next->right)
c += L_COUNT(next) + 1;
avlnode = next;
}
return c;
}
#endif
int avl_search_closest(const avl_tree_t *avltree, const void *item, avl_compare_t cmp, avl_node_t **avlnode) {
avl_node_t *node;
int c;
if (!avlnode)
avlnode = &node;
if (!cmp)
{
cmp = avltree->cmp;
}
node = avltree->top;
if (!node)
return *avlnode = NULL, 0;
for (;;) {
c = cmp(item, node->item);
if(c < 0) {
if(node->left)
node = node->left;
else
return *avlnode = node, -1;
} else if(c > 0) {
if(node->right)
node = node->right;
else
return *avlnode = node, 1;
} else {
return *avlnode = node, 0;
}
}
}
/*
* avl_search:
* Return a pointer to a node with the given item in the tree.
* If no such item is in the tree, then NULL is returned.
*/
avl_node_t *avl_search(const avl_tree_t *avltree, const void *item) {
avl_node_t *node;
return avl_search_closest(avltree, item, NULL, &node) ? NULL : node;
}
avl_node_t *avl_search2(const avl_tree_t *avltree, const void *item, avl_compare_t cmp) {
avl_node_t *node;
return avl_search_closest(avltree, item, cmp, &node) ? NULL : node;
}
avl_tree_t *avl_init_tree(avl_tree_t *rc, avl_compare_t cmp, avl_freeitem_t freeitem) {
if(rc) {
rc->head = NULL;
rc->tail = NULL;
rc->top = NULL;
rc->cmp = cmp;
rc->freeitem = freeitem;
}
return rc;
}
avl_tree_t *avl_alloc_tree(avl_compare_t cmp, avl_freeitem_t freeitem) {
return avl_init_tree(malloc(sizeof(avl_tree_t)), cmp, freeitem);
}
void avl_clear_tree(avl_tree_t *avltree) {
avltree->top = avltree->head = avltree->tail = NULL;
}
void avl_free_nodes(avl_tree_t *avltree) {
avl_node_t *node, *next;
avl_freeitem_t freeitem;
freeitem = avltree->freeitem;
for(node = avltree->head; node; node = next) {
next = node->next;
if(freeitem)
freeitem(node->item);
free(node);
}
avl_clear_tree(avltree);
}
/*
* avl_free_tree:
* Free all memory used by this tree. If freeitem is not NULL, then
* it is assumed to be a destructor for the items referenced in the avl_
* tree, and they are deleted as well.
*/
void avl_free_tree(avl_tree_t *avltree) {
if (avltree) {
avl_free_nodes(avltree);
free(avltree);
}
}
static void avl_clear_node(avl_node_t *newnode) {
newnode->left = newnode->right = NULL;
#ifdef AVL_COUNT
newnode->count = 1;
#endif
#ifdef AVL_DEPTH
newnode->depth = 1;
#endif
}
avl_node_t *avl_init_node(avl_node_t *newnode, void *item) {
if(newnode) {
/* avl_clear_node(newnode); */
newnode->item = item;
}
return newnode;
}
avl_node_t *avl_insert_top(avl_tree_t *avltree, avl_node_t *newnode) {
avl_clear_node(newnode);
newnode->prev = newnode->next = newnode->parent = NULL;
avltree->head = avltree->tail = avltree->top = newnode;
return newnode;
}
avl_node_t *avl_insert_before(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) {
if(!node)
return avltree->tail
? avl_insert_after(avltree, avltree->tail, newnode)
: avl_insert_top(avltree, newnode);
if(node->left)
return avl_insert_after(avltree, node->prev, newnode);
avl_clear_node(newnode);
newnode->next = node;
newnode->parent = node;
newnode->prev = node->prev;
if(node->prev)
node->prev->next = newnode;
else
avltree->head = newnode;
node->prev = newnode;
node->left = newnode;
avl_rebalance(avltree, node);
return newnode;
}
avl_node_t *avl_insert_after(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) {
if(!node)
return avltree->head
? avl_insert_before(avltree, avltree->head, newnode)
: avl_insert_top(avltree, newnode);
if(node->right)
return avl_insert_before(avltree, node->next, newnode);
avl_clear_node(newnode);
newnode->prev = node;
newnode->parent = node;
newnode->next = node->next;
if(node->next)
node->next->prev = newnode;
else
avltree->tail = newnode;
node->next = newnode;
node->right = newnode;
avl_rebalance(avltree, node);
return newnode;
}
avl_node_t *avl_insert_node(avl_tree_t *avltree, avl_node_t *newnode) {
avl_node_t *node;
if(!avltree->top)
return avl_insert_top(avltree, newnode);
switch (avl_search_closest(avltree, newnode->item, avltree->cmp, &node))
{
case -1:
return avl_insert_before(avltree, node, newnode);
case 1:
return avl_insert_after(avltree, node, newnode);
case 0:
break;
default:
abort();
break;
}
return NULL;
}
/*
* avl_insert:
* Create a new node and insert an item there.
* Returns the new node on success or NULL if no memory could be allocated.
*/
avl_node_t *avl_insert(avl_tree_t *avltree, void *item) {
avl_node_t *newnode;
newnode = avl_init_node(malloc(sizeof(avl_node_t)), item);
if(newnode) {
if(avl_insert_node(avltree, newnode))
return newnode;
free(newnode);
errno = EEXIST;
}
return NULL;
}
/*
* avl_unlink_node:
* Removes the given node. Does not delete the item at that node.
* The item of the node may be freed before calling avl_unlink_node.
* (In other words, it is not referenced by this function.)
*/
void avl_unlink_node(avl_tree_t *avltree, avl_node_t *avlnode) {
avl_node_t *parent;
avl_node_t **superparent;
avl_node_t *subst, *left, *right;
avl_node_t *balnode;
if(avlnode->prev)
avlnode->prev->next = avlnode->next;
else
avltree->head = avlnode->next;
if(avlnode->next)
avlnode->next->prev = avlnode->prev;
else
avltree->tail = avlnode->prev;
parent = avlnode->parent;
superparent = parent
? avlnode == parent->left ? &parent->left : &parent->right
: &avltree->top;
left = avlnode->left;
right = avlnode->right;
if(!left) {
*superparent = right;
if(right)
right->parent = parent;
balnode = parent;
} else if(!right) {
*superparent = left;
left->parent = parent;
balnode = parent;
} else {
subst = avlnode->prev;
if(subst == left) {
balnode = subst;
} else {
balnode = subst->parent;
balnode->right = subst->left;
if(balnode->right)
balnode->right->parent = balnode;
subst->left = left;
left->parent = subst;
}
subst->right = right;
subst->parent = parent;
right->parent = subst;
*superparent = subst;
}
avl_rebalance(avltree, balnode);
}
void *avl_delete_node(avl_tree_t *avltree, avl_node_t *avlnode) {
void *item = NULL;
if(avlnode) {
item = avlnode->item;
avl_unlink_node(avltree, avlnode);
if(avltree->freeitem)
avltree->freeitem(item);
free(avlnode);
}
return item;
}
void *avl_delete(avl_tree_t *avltree, const void *item) {
return avl_delete_node(avltree, avl_search(avltree, item));
}
avl_node_t *avl_fixup_node(avl_tree_t *avltree, avl_node_t *newnode) {
avl_node_t *oldnode = NULL, *node;
if(!avltree || !newnode)
return NULL;
node = newnode->prev;
if(node) {
oldnode = node->next;
node->next = newnode;
} else {
avltree->head = newnode;
}
node = newnode->next;
if(node) {
oldnode = node->prev;
node->prev = newnode;
} else {
avltree->tail = newnode;
}
node = newnode->parent;
if(node) {
if(node->left == oldnode)
node->left = newnode;
else
node->right = newnode;
} else {
oldnode = avltree->top;
avltree->top = newnode;
}
return oldnode;
}
/*
* avl_rebalance:
* Rebalances the tree if one side becomes too heavy. This function
* assumes that both subtrees are AVL-trees with consistant data. The
* function has the additional side effect of recalculating the count of
* the tree at this node. It should be noted that at the return of this
* function, if a rebalance takes place, the top of this subtree is no
* longer going to be the same node.
*/
void avl_rebalance(avl_tree_t *avltree, avl_node_t *avlnode) {
avl_node_t *child;
avl_node_t *gchild;
avl_node_t *parent;
avl_node_t **superparent;
parent = avlnode;
while(avlnode) {
parent = avlnode->parent;
superparent = parent
? avlnode == parent->left ? &parent->left : &parent->right
: &avltree->top;
switch(avl_check_balance(avlnode)) {
case -1:
child = avlnode->left;
#ifdef AVL_DEPTH
if(L_DEPTH(child) >= R_DEPTH(child)) {
#else
#ifdef AVL_COUNT
if(L_COUNT(child) >= R_COUNT(child)) {
#else
#error No balancing possible.
#endif
#endif
avlnode->left = child->right;
if(avlnode->left)
avlnode->left->parent = avlnode;
child->right = avlnode;
avlnode->parent = child;
*superparent = child;
child->parent = parent;
#ifdef AVL_COUNT
avlnode->count = CALC_COUNT(avlnode);
child->count = CALC_COUNT(child);
#endif
#ifdef AVL_DEPTH
avlnode->depth = CALC_DEPTH(avlnode);
child->depth = CALC_DEPTH(child);
#endif
} else {
gchild = child->right;
avlnode->left = gchild->right;
if(avlnode->left)
avlnode->left->parent = avlnode;
child->right = gchild->left;
if(child->right)
child->right->parent = child;
gchild->right = avlnode;
if(gchild->right)
gchild->right->parent = gchild;
gchild->left = child;
if(gchild->left)
gchild->left->parent = gchild;
*superparent = gchild;
gchild->parent = parent;
#ifdef AVL_COUNT
avlnode->count = CALC_COUNT(avlnode);
child->count = CALC_COUNT(child);
gchild->count = CALC_COUNT(gchild);
#endif
#ifdef AVL_DEPTH
avlnode->depth = CALC_DEPTH(avlnode);
child->depth = CALC_DEPTH(child);
gchild->depth = CALC_DEPTH(gchild);
#endif
}
break;
case 1:
child = avlnode->right;
#ifdef AVL_DEPTH
if(R_DEPTH(child) >= L_DEPTH(child)) {
#else
#ifdef AVL_COUNT
if(R_COUNT(child) >= L_COUNT(child)) {
#else
#error No balancing possible.
#endif
#endif
avlnode->right = child->left;
if(avlnode->right)
avlnode->right->parent = avlnode;
child->left = avlnode;
avlnode->parent = child;
*superparent = child;
child->parent = parent;
#ifdef AVL_COUNT
avlnode->count = CALC_COUNT(avlnode);
child->count = CALC_COUNT(child);
#endif
#ifdef AVL_DEPTH
avlnode->depth = CALC_DEPTH(avlnode);
child->depth = CALC_DEPTH(child);
#endif
} else {
gchild = child->left;
avlnode->right = gchild->left;
if(avlnode->right)
avlnode->right->parent = avlnode;
child->left = gchild->right;
if(child->left)
child->left->parent = child;
gchild->left = avlnode;
if(gchild->left)
gchild->left->parent = gchild;
gchild->right = child;
if(gchild->right)
gchild->right->parent = gchild;
*superparent = gchild;
gchild->parent = parent;
#ifdef AVL_COUNT
avlnode->count = CALC_COUNT(avlnode);
child->count = CALC_COUNT(child);
gchild->count = CALC_COUNT(gchild);
#endif
#ifdef AVL_DEPTH
avlnode->depth = CALC_DEPTH(avlnode);
child->depth = CALC_DEPTH(child);
gchild->depth = CALC_DEPTH(gchild);
#endif
}
break;
default:
#ifdef AVL_COUNT
avlnode->count = CALC_COUNT(avlnode);
#endif
#ifdef AVL_DEPTH
avlnode->depth = CALC_DEPTH(avlnode);
#endif
}
avlnode = parent;
}
}
void avl_foreach(avl_tree_t* tree, void (*callback)(void*))
{
for (avl_node_t* node = tree->head; node; node = node->next)
{
callback(node->item);
}
};

208
avl.h Normal file
View file

@ -0,0 +1,208 @@
/*****************************************************************************
avl.h - Source code for the AVL-tree library.
Copyright (C) 1998 Michael H. Buselli <cosine@cosine.org>
Copyright (C) 2000-2002 Wessel Dankers <wsl@nl.linux.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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 GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Augmented AVL-tree. Original by Michael H. Buselli <cosine@cosine.org>.
Modified by Wessel Dankers <wsl@nl.linux.org> to add a bunch of bloat to
the sourcecode, change the interface and squash a few bugs.
Mail him if you find new bugs.
*****************************************************************************/
#ifndef _AVL_H
#define _AVL_H
/* We need either depths, counts or both (the latter being the default) */
#if !defined(AVL_DEPTH) && !defined(AVL_COUNT)
#define AVL_DEPTH
#define AVL_COUNT
#endif
/* User supplied function to compare two items like strcmp() does.
* For example: cmp(a,b) will return:
* -1 if a < b
* 0 if a = b
* 1 if a > b
*/
typedef int (*avl_compare_t)(const void *, const void *);
/* User supplied function to delete an item when a node is free()d.
* If NULL, the item is not free()d.
*/
typedef void (*avl_freeitem_t)(void *);
typedef struct avl_node_t {
struct avl_node_t *next;
struct avl_node_t *prev;
struct avl_node_t *parent;
struct avl_node_t *left;
struct avl_node_t *right;
void *item;
#ifdef AVL_COUNT
unsigned int count;
#endif
#ifdef AVL_DEPTH
int depth;
#endif
} avl_node_t;
typedef struct avl_tree_t {
avl_node_t *head;
avl_node_t *tail;
avl_node_t *top;
avl_compare_t cmp;
avl_freeitem_t freeitem;
} avl_tree_t;
/* Initializes a new tree for elements that will be ordered using
* the supplied strcmp()-like function.
* Returns the value of avltree (even if it's NULL).
* O(1) */
extern avl_tree_t *avl_init_tree(avl_tree_t *avltree, avl_compare_t, avl_freeitem_t);
/* Allocates and initializes a new tree for elements that will be
* ordered using the supplied strcmp()-like function.
* Returns NULL if memory could not be allocated.
* O(1) */
extern avl_tree_t *avl_alloc_tree(avl_compare_t, avl_freeitem_t);
/* Frees the entire tree efficiently. Nodes will be free()d.
* If the tree's freeitem is not NULL it will be invoked on every item.
* O(n) */
extern void avl_free_tree(avl_tree_t *);
/* Reinitializes the tree structure for reuse. Nothing is free()d.
* Compare and freeitem functions are left alone.
* O(1) */
extern void avl_clear_tree(avl_tree_t *);
/* Free()s all nodes in the tree but leaves the tree itself.
* If the tree's freeitem is not NULL it will be invoked on every item.
* O(n) */
extern void avl_free_nodes(avl_tree_t *);
/* Initializes memory for use as a node. Returns NULL if avlnode is NULL.
* O(1) */
extern avl_node_t *avl_init_node(avl_node_t *avlnode, void *item);
/* Insert an item into the tree and return the new node.
* Returns NULL and sets errno if memory for the new node could not be
* allocated or if the node is already in the tree (EEXIST).
* O(lg n) */
extern avl_node_t *avl_insert(avl_tree_t *, void *item);
/* Insert a node into the tree and return it.
* Returns NULL if the node is already in the tree.
* O(lg n) */
extern avl_node_t *avl_insert_node(avl_tree_t *, avl_node_t *);
/* Insert a node in an empty tree. If avlnode is NULL, the tree will be
* cleared and ready for re-use.
* If the tree is not empty, the old nodes are left dangling.
* O(1) */
extern avl_node_t *avl_insert_top(avl_tree_t *, avl_node_t *avlnode);
/* Insert a node before another node. Returns the new node.
* If old is NULL, the item is appended to the tree.
* O(lg n) */
extern avl_node_t *avl_insert_before(avl_tree_t *, avl_node_t *old, avl_node_t *new);
/* Insert a node after another node. Returns the new node.
* If old is NULL, the item is prepended to the tree.
* O(lg n) */
extern avl_node_t *avl_insert_after(avl_tree_t *, avl_node_t *old, avl_node_t *new);
/* Deletes a node from the tree. Returns immediately if the node is NULL.
* The item will not be free()d regardless of the tree's freeitem handler.
* This function comes in handy if you need to update the search key.
* O(lg n) */
extern void avl_unlink_node(avl_tree_t *, avl_node_t *);
/* Deletes a node from the tree. Returns immediately if the node is NULL.
* If the tree's freeitem is not NULL, it is invoked on the item.
* If it is, returns the item.
* O(lg n) */
extern void *avl_delete_node(avl_tree_t *, avl_node_t *);
/* Searches for an item in the tree and deletes it if found.
* If the tree's freeitem is not NULL, it is invoked on the item.
* If it is, returns the item.
* O(lg n) */
extern void *avl_delete(avl_tree_t *, const void *item);
/* If exactly one node is moved in memory, this will fix the pointers
* in the tree that refer to it. It must be an exact shallow copy.
* Returns the pointer to the old position.
* O(1) */
extern avl_node_t *avl_fixup_node(avl_tree_t *, avl_node_t *new);
/* Searches for a node with the key closest (or equal) to the given item.
* If avlnode is not NULL, *avlnode will be set to the node found or NULL
* if the tree is empty. Return values:
* -1 if the returned node is smaller
* 0 if the returned node is equal or if the tree is empty
* 1 if the returned node is greater
* O(lg n) */
int avl_search_closest(const avl_tree_t *avltree, const void *item, avl_compare_t cmp, avl_node_t **avlnode);
/* Searches for the item in the tree and returns a matching node if found
* or NULL if not.
* O(lg n) */
extern avl_node_t *avl_search(const avl_tree_t *, const void *item);
avl_node_t *avl_search2(const avl_tree_t *avltree, const void *item, avl_compare_t cmp);
void avl_foreach(avl_tree_t* tree, void (*callback)(void*));
#ifdef AVL_COUNT
/* Returns the number of nodes in the tree.
* O(1) */
extern unsigned int avl_count(const avl_tree_t *);
/* Searches a node by its rank in the list. Counting starts at 0.
* Returns NULL if the index exceeds the number of nodes in the tree.
* O(lg n) */
extern avl_node_t *avl_at(const avl_tree_t *, unsigned int);
/* Returns the rank of a node in the list. Counting starts at 0.
* O(lg n) */
extern unsigned int avl_index(const avl_node_t *);
#endif
#endif

77
flake.lock Normal file
View file

@ -0,0 +1,77 @@
{
"nodes": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1747046372,
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1749664469,
"narHash": "sha256-Ar3r6cmQVKVoEy/TWAKq8WuGqZibRjMt5oZRvkn+2Bk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3fa008da69980bd61324ad9e3a825022f0b736f1",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

47
flake.nix Normal file
View file

@ -0,0 +1,47 @@
# vim: set sw=2 ts=2 et: #
{
description = "An example project using flutter";
inputs.nixpkgs = { url = "github:NixOS/nixpkgs"; };
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.flake-compat = {
url = "github:edolstra/flake-compat";
flake = false;
};
outputs = { self, nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
};
in {
devShells.default =
pkgs.mkShell {
buildInputs = with pkgs; [
gcc
gnumake
readline.dev
gmp.dev
python3
gedit
valgrind
man-pages
man-pages-posix
];
};
packages.default = pkgs.stdenv.mkDerivation rec {
pname = "qc";
version = "1.0";
src = ./.;
nativeBuildInputs = with pkgs; [ gcc gnumake ];
buildInputs = with pkgs; [ readline.dev ];
};
});
}

1767
main.c Normal file

File diff suppressed because it is too large Load diff

41
makefile Normal file
View file

@ -0,0 +1,41 @@
# vim: noexpandtab tabstop=4 :
PREFIX ?= ${out}
PREFIX ?= ${HOME}
args =
cc = gcc
cppflags += -D _GNU_SOURCE
#cppflags += -D ZDEBUG=1
cflags = -Werror -Wall -Wextra -Wstrict-prototypes -Wfatal-errors
# cflags += -O3
cflags += -g
cflags += -Wno-unused
ldflags += -lreadline -lgmp
bin/qc: main.c avl.c | bin/
$(cc) $(cppflags) $(cflags) $^ -o $@ $(ldflags)
bin/:
mkdir -pv bin
run: bin/qc
$< $(args)
valrun: bin/qc
valgrind -- $< $(args)
install: ${PREFIX}/bin/qc
${PREFIX}/bin/qc: bin/qc
mkdir -pv ${PREFIX}/bin/
cp -vau $< $@