/**
* ez-list is a low-level double-linked list implementation that works
- * without memory allocation.
+ * without memory allocation.
*
* o Adding to or removing from either end is an O(1) operation.
* o Removing any given node is an O(1) operation.
/**
* Initialise a list at runtime.
- *
+ *
*/
-static __inline__ void ez_list_init(struct ez_list *l) {
+static __inline__ void ez_list_init(struct ez_list * __restrict l) {
l->head = (struct ez_node *)&l->tail;
l->tail = (struct ez_node *)0L;
l->tail_pred = (struct ez_node *)&l->head;
/**
* Add a node to the head of the list.
*/
-static __inline__ void ez_list_addhead(struct ez_list *l, void *np) {
+static __inline__ void ez_list_addhead(struct ez_list * __restrict l, void *np) {
struct ez_node *n = np, *head = l->head;
- n->u.list.succ = head;
- n->u.list.pred = (struct ez_node *)&l->head;
- head->u.list.pred = n;
+ n->succ = head;
+ n->pred = (struct ez_node *)&l->head;
+ head->pred = n;
l->head = n;
}
static __inline__ void ez_list_addtail(struct ez_list *l, void *np) {
struct ez_node *n = np, *tail_pred = l->tail_pred;
- n->u.list.pred = tail_pred;
- n->u.list.succ = (struct ez_node *)&l->tail;
- tail_pred->u.list.succ = n;
+ n->pred = tail_pred;
+ n->succ = (struct ez_node *)&l->tail;
+ tail_pred->succ = n;
l->tail_pred = n;
}
* This performs a software memory barrier after
* write do workaround aliasing issues with gcc.
*/
-static __inline__ void ez_node_remove(void *np) {
- struct ez_node *n = np, *pred = n->u.list.pred, *succ = n->u.list.succ;
-
- pred->u.list.succ = succ;
- succ->u.list.pred = pred;
+static __inline__ void ez_node_remove(void * __restrict np) {
+ struct ez_node *n = np, *pred = n->pred, *succ = n->succ;
+
+ pred->succ = succ;
+ succ->pred = pred;
}
/**
*
* @return the head node, or NULL if the list is empty.
*/
-static __inline__ void *ez_list_remhead(struct ez_list *l) {
+static __inline__ void *ez_list_remhead(struct ez_list * __restrict l) {
struct ez_node *n = l->head;
- struct ez_node *s = n->u.list.succ;
+ struct ez_node *s = n->succ;
if (s) {
- s->u.list.pred = (struct ez_node *)&l->head;
+ s->pred = (struct ez_node *)&l->head;
l->head = s;
return n;
} else
*
* @return the tail node, or NULL if the list is empty.
*/
-static __inline__ void *ez_list_remtail(struct ez_list *l) {
+static __inline__ void *ez_list_remtail(struct ez_list * __restrict l) {
struct ez_node *n = l->tail_pred;
- struct ez_node *p = n->u.list.pred;
+ struct ez_node *p = n->pred;
if (p) {
- p->u.list.succ = (struct ez_node *)&l->tail;
+ p->succ = (struct ez_node *)&l->tail;
l->tail_pred = p;
return n;
} else
* @param n node to insert.
* @param p node that is already present in list, or NULL (insert after head).
*/
-static __inline__ void ez_list_insert_after(struct ez_list *l, void *n, void *p) {
+static __inline__ void ez_list_insert_after(struct ez_list * __restrict l, void *n, void *p) {
struct ez_node *nn = n;
struct ez_node *pp = p ? p : (struct ez_node *)&l->head;
- struct ez_node *succ = pp->u.list.succ;
+ struct ez_node *succ = pp->succ;
- nn->u.list.succ = succ;
- nn->u.list.pred = pp;
- succ->u.list.pred = nn;
- pp->u.list.succ = nn;
+ nn->succ = succ;
+ nn->pred = pp;
+ succ->pred = nn;
+ pp->succ = nn;
}
/**
* @param n node to insert.
* @param p node that is already present in list, or NULL (insert before tail).
*/
-static __inline__ void ez_list_insert(struct ez_list *l, void *n, void *p) {
+static __inline__ void ez_list_insert(struct ez_list * __restrict l, void *n, void *p) {
struct ez_node *nn = n;
struct ez_node *pp = p ? p : (struct ez_node *)&l->tail;
- struct ez_node *pred = pp->u.list.pred;
-
- nn->u.list.succ = pp;
- nn->u.list.pred = pred;
- pred->u.list.succ = nn;
- pp->u.list.pred = nn;
+ struct ez_node *pred = pp->pred;
+
+ nn->succ = pp;
+ nn->pred = pred;
+ pred->succ = nn;
+ pp->pred = nn;
}
/**
* This is an O(n) operation, use ez_list_empty() to check for empty
* lists.
*/
-static __inline__ int ez_list_size(struct ez_list *l) {
+static __inline__ int ez_list_size(struct ez_list * __restrict l) {
struct ez_node *w, *n;
int size = 0;
- for (w = l->head, n = w->u.list.succ; n; w = n, n = n->u.list.succ)
+ for (w = l->head, n = w->succ; n; w = n, n = n->succ)
size += 1;
return size;
*
* @param returns true (1) if the list is empty.
*/
-static __inline__ int ez_list_empty(struct ez_list *l) {
+static __inline__ int ez_list_empty(struct ez_list * __restrict l) {
return l->tail_pred == (struct ez_node *)l;
}
/**
* Retrieve the successor to the head node (the first user node).
*/
-static __inline__ void *ez_list_head(struct ez_list *l) {
+static __inline__ void *ez_list_head(struct ez_list * __restrict l) {
return (void *)l->head;
}
/**
* Retrieve the predecessor of the tail node (the last user node).
*/
-static __inline__ void *ez_list_tail(struct ez_list *l) {
+static __inline__ void *ez_list_tail(struct ez_list * __restrict l) {
return (void *)l->tail_pred;
}
static int ez_list_empty(struct ez_list *l) __attribute__ ((always_inline));
static void *ez_list_head(struct ez_list *l) __attribute__ ((always_inline));
static void *ez_list_tail(struct ez_list *l) __attribute__ ((always_inline));
-
+
#endif
struct {
struct ez_node * volatile succ;
struct ez_node * volatile pred;
- } list;
+ };
struct {
intptr_t link[2];
- } tree;
+ };
struct {
struct ez_node *next;
unsigned int hash;
- } set;
- } u;
+ };
+ };
};
/**
* == NULL.
*/
static __inline__ void *ez_node_succ(void *n) {
- return (void *)((struct ez_node *)n)->u.list.succ;
+ return (void *)((struct ez_node *)n)->succ;
}
/**
* == NULL.
*/
static __inline__ void *ez_node_pred(void *n) {
- return (void *)((struct ez_node *)n)->u.list.pred;
+ return (void *)((struct ez_node *)n)->pred;
}
/**
* Retrieve the left child tree node.
*/
static __inline__ void *ez_node_left(void *node) {
- return (void *)(((struct ez_node *)node)->u.tree.link[0] & ~3);
+ return (void *)(((struct ez_node *)node)->link[0] & ~3);
}
/**
* Retrieve the right child tree node.
*/
static __inline__ void *ez_node_right(void *node) {
- return (void *)(((struct ez_node *)node)->u.tree.link[1] & ~3);
+ return (void *)(((struct ez_node *)node)->link[1] & ~3);
}
/**
* Retrieve either the left or right child node.
*/
static __inline__ void *ez_node_link(void *node, enum ez_node_link_t i) {
- return (void *)(((struct ez_node *)node)->u.tree.link[i] & ~3);
+ return (void *)(((struct ez_node *)node)->link[i] & ~3);
}
/**
* Retrieve the next set hash chain bucket.
*/
static __inline__ void *ez_node_next(void *node) {
- return ((struct ez_node *)node)->u.set.next;
+ return ((struct ez_node *)node)->next;
}
/**
* Retrieve the set hash bucket hash.
*/
static __inline__ unsigned int ez_node_hash(void *node) {
- return ((struct ez_node *)node)->u.set.hash;
+ return ((struct ez_node *)node)->hash;
}
static void *ez_node_succ(void *n) __attribute__ ((always_inline));
ez_node *scan = h->table[idx];
ez_node *p = (ez_node *)&h->table[idx];
- while (scan && !(hash == scan->u.set.hash && h->equals(key, scan))) {
+ while (scan && !(hash == scan->hash && h->equals(key, scan))) {
p = scan;
- scan = scan->u.set.next;
+ scan = scan->next;
}
*pp = p;
ez_node *e = h->table[i];
while (e) {
- ez_node *n = e->u.set.next;
- unsigned int nidx = e->u.set.hash & mask;
+ ez_node *n = e->next;
+ unsigned int nidx = e->hash & mask;
- e->u.set.next = table[nidx];
+ e->next = table[nidx];
table[nidx] = e;
e = n;
}
// Entries are only ever hashed once, here.
- e->u.set.hash = h->hash(e);
- scan = set_lookup(h, e, e->u.set.hash, &p);
+ e->hash = h->hash(e);
+ scan = set_lookup(h, e, e->hash, &p);
// insert new node, possibly unlinking old one
- p->u.set.next = e;
+ p->next = e;
if (scan) {
// link old node tail
- e->u.set.next = scan->u.set.next;
+ e->next = scan->next;
} else {
// new node added
- e->u.set.next = NULL;
+ e->next = NULL;
h->count += 1;
if (h->count > h->mask)
set_rehash(h, (h->mask+1) * 2);
scan = set_lookup(h, e, hash, &p);
if (scan) {
// unlink old node
- p->u.set.next = scan->u.set.next;
+ p->next = scan->next;
h->count -= 1;
if (h->mask > 15 && h->count*2 < h->mask)
set_rehash(h, (h->mask+1)>>1);
if (scan->e) {
// advance e and p
scan->p = scan->e;
- scan->e = scan->e->u.set.next;
+ scan->e = scan->e->next;
if (!scan->e)
return scan_next_chain(scan->set, scan, scan->idx);
void *ez_set_scan_remove(ez_set_scan *scan) {
if (scan->e) {
// unlink e and advance but don't change p
- scan->p->u.set.next = scan->e = scan->e->u.set.next;
+ scan->p->next = scan->e = scan->e->next;
scan->set->count -= 1;
if (!scan->e)
}
static __inline__ int node_balance(struct ez_node *n) {
- int i = n->u.tree.link[0];
+ int i = n->link[0];
return i << 30 >> 30;
}
static __inline__ void node_set_balance(struct ez_node *node, int balance) {
- node->u.tree.link[0] = (node->u.tree.link[0] & ~3) | (balance & 3);
+ node->link[0] = (node->link[0] & ~3) | (balance & 3);
}
static __inline__ void *node_link(struct ez_node *n, int i) {
- return (void *)(n->u.tree.link[i] & ~3);
+ return (void *)(n->link[i] & ~3);
}
static __inline__ void node_set_link(struct ez_node *n, int i, struct ez_node *link) {
- n->u.tree.link[i] = (n->u.tree.link[i] & 3) | (intptr_t)link;
+ n->link[i] = (n->link[i] & 3) | (intptr_t)link;
}
/**
si -= 1;
}
- stack[0].node->u.tree.link[0] -= 1;
+ stack[0].node->link[0] -= 1;
}
/**
/* ********************************************************************** */
void ez_tree_init(struct ez_tree *tree, ez_cmp_fn node_cmp) {
- tree->root.u.tree.link[0] = 0;
- tree->root.u.tree.link[1] = 0;
+ tree->root.link[0] = 0;
+ tree->root.link[1] = 0;
tree->node_cmp = node_cmp;
}
void ez_tree_clear(ez_tree *tree, ez_free_fn node_free) {
tree_free(tree, ez_tree_root(tree), node_free);
- tree->root.u.tree.link[0] = 0;
- tree->root.u.tree.link[1] = 0;
+ tree->root.link[0] = 0;
+ tree->root.link[1] = 0;
}
void *ez_tree_get(ez_tree *tree, const void *node) {
struct ez_tree_scan_info *sp = stack, *se = sp + EZ_TREE_MAX_DEPTH - 1;
ez_cmp_fn node_cmp = tree->node_cmp;
- k->u.tree.link[0] = BALANCE0; // balance=0
+ k->link[0] = BALANCE0; // balance=0
node_set_link(k, 1, 0);
- if (!tree->root.u.tree.link[1]) {
- tree->root.u.tree.link[1] = (intptr_t)k;
- tree->root.u.tree.link[0] += 1;
+ if (!tree->root.link[1]) {
+ tree->root.link[1] = (intptr_t)k;
+ tree->root.link[0] += 1;
return NULL;
}
// Insert new node
node_set_link(p, cmp > 0, k);
- tree->root.u.tree.link[0] += 1;
+ tree->root.link[0] += 1;
*sp = (struct ez_tree_scan_info){ k, 0 };
// Fix balance factors between s and q
*
* struct ez_tree tree = EZ_INIT_TREE(tree, cmp);
*/
-#define EZ_INIT_TREE(t, cmp) { .root.u.tree.link[0] = 0, .root.u.tree.link[1] = 0, .node_cmp = cmp }
+#define EZ_INIT_TREE(t, cmp) { .root.link[0] = 0, .root.link[1] = 0, .node_cmp = cmp }
typedef struct ez_tree_scan ez_tree_scan;
*/
static __inline__ int ez_tree_size(ez_tree *tree) {
// well if it's good enough for Knuth.
- return tree->root.u.tree.link[0];
+ return tree->root.link[0];
}
/**
* Retrieve the root node of the tree.
*/
static __inline__ void *ez_tree_root(ez_tree *tree) {
- return (void *)tree->root.u.tree.link[1];
+ return (void *)tree->root.link[1];
}
/**
* Determine if the tree is empty.
*/
static __inline__ int ez_tree_empty(ez_tree *tree) {
- return !tree->root.u.tree.link[1];
+ return !tree->root.link[1];
}
/**
static __inline__ int node_balance(struct ez_node *n) __attribute__((always_inline));
static __inline__ int node_balance(struct ez_node *n) {
- int i = n->u.tree.link[0];
+ int i = n->link[0];
return i << 30 >> 30;
}