things
This commit is contained in:
parent
4aefe8b42d
commit
94837ed410
14 changed files with 1196 additions and 0 deletions
137
stuff/generic_hash.h
Normal file
137
stuff/generic_hash.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
#ifndef _HASH_GENERIC
|
||||
#define _HASH_GENERIC
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// FIXME: change the api to just one HASH_DECL to HASH_PROTO and HASH_DEFINE
|
||||
|
||||
|
||||
#define HASH_MAXSIZE 4096
|
||||
// for fibonacci hashing, 2^{32,64}/<golden ratio>
|
||||
#define HASH_RATIO32 ((uint64_t)2654435769u)
|
||||
#define HASH_RATIO64 ((uint64_t)11400714819322457583u)
|
||||
// salt for string hashing
|
||||
#define HASH_SALT ((uint64_t)0xbabb0cac)
|
||||
|
||||
|
||||
/* Ready-made compares */
|
||||
static inline int hash_cmp_u32(uint32_t a, uint32_t b) { return a == b; }
|
||||
static inline int hash_cmp_u64(uint64_t a, uint64_t b) { return a == b; }
|
||||
static inline int hash_cmp_str(const char *a, const char *b) { return strcmp(a, b) == 0; }
|
||||
|
||||
|
||||
/* Ready-made hashes */
|
||||
static inline uint32_t hash_u64(uint64_t c)
|
||||
{
|
||||
return (uint64_t)((((uint64_t)c+HASH_SALT)*HASH_RATIO64)>>32);
|
||||
}
|
||||
static inline uint32_t hash_u32(uint32_t c)
|
||||
{
|
||||
return (uint32_t)((((uint64_t)c<<31)*HASH_RATIO64)>>32);
|
||||
}
|
||||
static inline uint32_t hash_str(const char *s)
|
||||
{
|
||||
uint32_t h = HASH_SALT;
|
||||
const uint8_t *v = (const uint8_t *)(s);
|
||||
for (int x = *s; x; x--) {
|
||||
h += v[x-1];
|
||||
h += h << 10;
|
||||
h ^= h >> 6;
|
||||
}
|
||||
h += h << 3;
|
||||
h ^= h >> 11;
|
||||
h += h << 15;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
#define HASH_DECL(htname, codetype, datatype, hashfn, cmpfn) \
|
||||
struct htname##_entry { \
|
||||
codetype code; \
|
||||
datatype data; \
|
||||
}; \
|
||||
\
|
||||
struct htname##_ref { \
|
||||
uint32_t items, size, exp; \
|
||||
struct htname##_entry bucket[]; \
|
||||
}; \
|
||||
\
|
||||
\
|
||||
struct htname##_ref * htname##_create(uint32_t size) \
|
||||
{ \
|
||||
if (!size || size > HASH_MAXSIZE) \
|
||||
return NULL; \
|
||||
/* round to the greater power of two */ \
|
||||
/* FIXME: check for intger overflow here */ \
|
||||
uint32_t exp = 32-__builtin_clz(size-1); \
|
||||
size = 1<<(exp); \
|
||||
/* FIXME: check for intger overflow here */ \
|
||||
struct htname##_ref *ht = malloc(sizeof(struct htname##_ref)+sizeof(struct htname##_entry)*size); \
|
||||
if (ht) { \
|
||||
ht->items = 0; \
|
||||
ht->size = size; \
|
||||
ht->exp = exp; \
|
||||
memset(ht->bucket, 0, sizeof(struct htname##_entry)*size); \
|
||||
} \
|
||||
return ht; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
void htname##_destroy(struct htname##_ref *ht) \
|
||||
{ \
|
||||
if (ht) free(ht); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static uint32_t htname##_lookup(struct htname##_ref *ht, uint32_t hash, uint32_t idx) \
|
||||
{ \
|
||||
if (!ht) return 0; \
|
||||
uint32_t mask = ht->size-1; \
|
||||
uint32_t step = (hash >> (32 - ht->exp)) | 1; \
|
||||
return (idx + step) & mask; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
/* Find and return the element by code */ \
|
||||
struct htname##_entry * htname##_search(struct htname##_ref *ht, codetype code)\
|
||||
{ \
|
||||
if (!ht) return NULL; \
|
||||
uint32_t h = hashfn(code); \
|
||||
for (uint32_t i=h, x=0; ; x++) { \
|
||||
i = htname##_lookup(ht, h, i); \
|
||||
if (x > (ht->size<<1) || \
|
||||
!ht->bucket[i].code || \
|
||||
cmpfn(ht->bucket[i].code, code) \
|
||||
) { \
|
||||
return &(ht->bucket[i]); \
|
||||
} \
|
||||
} \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
/* FIXME: this simply overrides the found item */ \
|
||||
struct htname##_entry * htname##_insert(struct htname##_ref *ht, struct htname##_entry *entry) \
|
||||
{ \
|
||||
struct htname##_entry *r = htname##_search(ht, entry->code); \
|
||||
if (r) { \
|
||||
if (!r->code) \
|
||||
ht->items++; \
|
||||
*r = *entry; \
|
||||
} \
|
||||
return r; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
struct htname##_entry * htname##_remove(struct htname##_ref *ht, codetype code)\
|
||||
{ \
|
||||
if (!ht) return NULL; \
|
||||
struct htname##_entry *r = htname##_search(ht, code); \
|
||||
if (r) r->code = 0; \
|
||||
return r; \
|
||||
} \
|
||||
|
||||
#endif
|
||||
118
stuff/generic_stack.h
Normal file
118
stuff/generic_stack.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#ifndef _STACK_GENERIC_H
|
||||
#define _STACK_GENERIC_H
|
||||
|
||||
|
||||
#define STACK_STEP 8
|
||||
#define STACK_SALT 0xbabb0cac
|
||||
|
||||
// FIXME: find a way to not re-hash the whole stack when removing one item
|
||||
|
||||
// incremental hash for every grow
|
||||
#if STACK_DISABLE_HASH
|
||||
#define STACK_HASH(p, s, h) {}
|
||||
#else
|
||||
#define STACK_HASH(p, s, h) \
|
||||
{ \
|
||||
unsigned char *v = (unsigned char *)(p); \
|
||||
for (int x = (s); x; x--) { \
|
||||
(h) += v[x-1]; \
|
||||
(h) += (h) << 10; \
|
||||
(h) ^= (h) >> 6; \
|
||||
} \
|
||||
(h) += (h) << 3; \
|
||||
(h) ^= (h) >> 11; \
|
||||
(h) += (h) << 15; \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// TODO: add a rolling hash
|
||||
#define STACK_DECL(stackname, type) \
|
||||
struct stackname { \
|
||||
type *items; \
|
||||
int size, idx, old_idx; \
|
||||
unsigned int hash, old_hash; \
|
||||
}; \
|
||||
\
|
||||
\
|
||||
struct stackname stackname##_init(void) \
|
||||
{ \
|
||||
return (struct stackname){0, .hash = STACK_SALT}; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
int stackname##_grow(struct stackname *stack, int step) \
|
||||
{ \
|
||||
if (!stack) \
|
||||
return -1; \
|
||||
stack->items = realloc(stack->items, (stack->size+step)*sizeof(type)); \
|
||||
if(!stack->items) \
|
||||
return -1; \
|
||||
memset(&(stack->items[stack->size]), 0, step*sizeof(*(stack->items))); \
|
||||
stack->size += step; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
int stackname##_push(struct stackname *stack, type *e) \
|
||||
{ \
|
||||
if (!stack || !e) \
|
||||
return -1; \
|
||||
if (stack->idx >= stack->size) \
|
||||
if (stackname##_grow(stack, STACK_STEP)) \
|
||||
return -1; \
|
||||
stack->items[stack->idx++] = *e; \
|
||||
STACK_HASH(e, sizeof(type), stack->hash); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
type stackname##_pop(struct stackname *stack) \
|
||||
{ \
|
||||
if (!stack || stack->idx == 0 || stack->size == 0) \
|
||||
return (type){0}; \
|
||||
stack->hash = STACK_SALT; \
|
||||
STACK_HASH(stack->items, sizeof(type)*(stack->idx-1), stack->hash); \
|
||||
return stack->items[stack->idx--]; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
int stackname##_clear(struct stackname *stack) \
|
||||
{ \
|
||||
if (!stack) \
|
||||
return -1; \
|
||||
stack->old_idx = stack->idx; \
|
||||
stack->old_hash = stack->hash; \
|
||||
stack->hash = STACK_SALT; \
|
||||
stack->idx = 0; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
int stackname##_changed(struct stackname *stack) \
|
||||
{ \
|
||||
if (!stack) \
|
||||
return -1; \
|
||||
return stack->hash != stack->old_hash; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
int stackname##_size_changed(struct stackname *stack) \
|
||||
{ \
|
||||
if (!stack) \
|
||||
return -1; \
|
||||
return stack->size != stack->old_idx; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
int stackname##_free(struct stackname *stack) \
|
||||
{ \
|
||||
if (stack) { \
|
||||
stackname##_clear(stack); \
|
||||
if (stack->items) \
|
||||
free(stack->items); \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
|
||||
#endif
|
||||
214
stuff/main.c
Executable file
214
stuff/main.c
Executable file
|
|
@ -0,0 +1,214 @@
|
|||
//#!/usr/bin/tcc -run
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define HASH_SALT (0xbabb0cac)
|
||||
#define HASH_RATIO64 ((unsigned long int)11400714819322457583u)
|
||||
|
||||
|
||||
struct ntree_node
|
||||
{
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
int children_no, children_size;
|
||||
struct ntree_node *children, *parent;
|
||||
};
|
||||
|
||||
|
||||
static char tmp_name_buffer[16] = {"node:"};
|
||||
|
||||
|
||||
unsigned int hash_str_to_uint(const char *s)
|
||||
{
|
||||
unsigned int h = HASH_SALT;
|
||||
const unsigned char *v = (const unsigned char *)(s);
|
||||
for (int x = *s; x; x--) {
|
||||
h += v[x-1];
|
||||
h += h << 10;
|
||||
h ^= h >> 6;
|
||||
}
|
||||
h += h << 3;
|
||||
h ^= h >> 11;
|
||||
h += h << 15;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
unsigned int hash_u32(unsigned int c)
|
||||
{
|
||||
return (unsigned int)((((unsigned long int)c<<31)*HASH_RATIO64)>>32);
|
||||
}
|
||||
|
||||
|
||||
const char * generate_new_name(void)
|
||||
{
|
||||
static int count = 0;
|
||||
unsigned int h = hash_u32(count++);
|
||||
snprintf(tmp_name_buffer+sizeof("node:"), 16-sizeof("node:"), "%x", h);
|
||||
return tmp_name_buffer;
|
||||
}
|
||||
|
||||
|
||||
int tree_prune(struct ntree_node *node)
|
||||
{
|
||||
if (node == NULL)
|
||||
return 0;
|
||||
|
||||
if ((node->children_no == 0 && node->children != NULL) ||
|
||||
(node->children_no != 0 && node->children == NULL)) {
|
||||
printf("ERR: (%x %s) Inconsistent node children", node->id, node->name);
|
||||
} else for (int i = 0; i < node->children_no; i++) {
|
||||
tree_prune(&(node->children[i]));
|
||||
}
|
||||
|
||||
if (node->children != NULL) {
|
||||
free(node->children);
|
||||
}
|
||||
free((void *)node->name);
|
||||
if (node->parent != NULL)
|
||||
node->parent->children_no--;
|
||||
*node = (struct ntree_node){0};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct ntree_node * tree_append(struct ntree_node *parent, const char *name)
|
||||
{
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
if (strlen(name) == 0)
|
||||
name = generate_new_name();
|
||||
|
||||
// generate the children information
|
||||
unsigned int id = hash_str_to_uint(name);
|
||||
char *str = malloc(strlen(name)+1);
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
strcpy(str, name);
|
||||
|
||||
// grow the parent buffer if necessary
|
||||
if (parent->children_no >= parent->children_size) {
|
||||
struct ntree_node *temp = NULL;
|
||||
temp = realloc(parent->children, (parent->children_size+1)*sizeof(struct ntree_node));
|
||||
if (temp == NULL) {
|
||||
free(str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parent->children = temp;
|
||||
parent->children[parent->children_size] = (struct ntree_node){0};
|
||||
parent->children_size++;
|
||||
}
|
||||
|
||||
// find an open spot for the child
|
||||
struct ntree_node *child = NULL;
|
||||
for (int i = 0; i < parent->children_size; i++) {
|
||||
if (parent->children[i].id == 0)
|
||||
child = &(parent->children[i]);
|
||||
}
|
||||
if (child == NULL)
|
||||
return NULL;
|
||||
|
||||
child->name = str;
|
||||
child->id = id;
|
||||
child->children = NULL;
|
||||
child->children_no = 0;
|
||||
child->parent = parent;
|
||||
parent->children_no++;
|
||||
//printf("append to %s, children: %d\n", parent->name, parent->children_no);
|
||||
return child;
|
||||
}
|
||||
|
||||
|
||||
struct ntree_node * tree_find_id(struct ntree_node *root, unsigned int id)
|
||||
{
|
||||
if (id == 0 || root == NULL)
|
||||
return NULL;
|
||||
|
||||
if (root->id == id)
|
||||
return root;
|
||||
|
||||
else for (int i = 0; i < root->children_size; i++) {
|
||||
if (root->children[i].id != 0 && tree_find_id(&(root->children[i]), id) != NULL)
|
||||
return &(root->children[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// TODO: add a foreach_child function
|
||||
struct ntree_node * tree_find(struct ntree_node *root, const char *name)
|
||||
{
|
||||
if (name == NULL || strlen(name) == 0 || root == NULL)
|
||||
return NULL;
|
||||
unsigned int id = hash_str_to_uint(name);
|
||||
return tree_find_id(root, id);
|
||||
}
|
||||
|
||||
|
||||
int tree_size(struct ntree_node *root)
|
||||
{
|
||||
if (root == NULL)
|
||||
return 0;
|
||||
|
||||
int count = root->children_no;
|
||||
if (count > 0) {
|
||||
for (int i = 0; i < root->children_size; i++) {
|
||||
if (root->children[i].id != 0)
|
||||
count += tree_size(&(root->children[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static int tree_print_ind(struct ntree_node *node, int dd)
|
||||
{
|
||||
for (int i = 0; i < dd; i++) printf(" ");
|
||||
printf("[%s]\n", node->name);
|
||||
for (int i = 0; i < node->children_size; i++) {
|
||||
if (node->children[i].id == 0) continue;
|
||||
tree_print_ind(&(node->children[i]), dd+1);
|
||||
}
|
||||
return node->children_no;
|
||||
}
|
||||
|
||||
|
||||
int tree_print(struct ntree_node *root)
|
||||
{
|
||||
if (root == NULL)
|
||||
return 1;
|
||||
|
||||
tree_print_ind(root, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char *root_name = malloc(sizeof("root"));
|
||||
strcpy(root_name, "root");
|
||||
struct ntree_node root = {.name = root_name};
|
||||
struct ntree_node *n;
|
||||
|
||||
n = tree_append(&root, "node 0:0");
|
||||
tree_append(n, "node 0:0:0");
|
||||
tree_append(&root, "node 0:1");
|
||||
tree_append(&root, "node 0:2");
|
||||
printf("Number of nodes %d\n", tree_size(&root));
|
||||
tree_print(&root);
|
||||
|
||||
tree_prune(tree_find(&root, "node 0:0"));
|
||||
printf("Number of nodes %d\n", tree_size(&root));
|
||||
|
||||
tree_prune(&root);
|
||||
printf("Number of nodes %d\n", tree_size(&root));
|
||||
|
||||
return 0;
|
||||
}
|
||||
348
stuff/vectree.h
Normal file
348
stuff/vectree.h
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
#ifndef _VECTREE_H
|
||||
#define _VECTREE_H
|
||||
|
||||
#ifdef VTREE_DTYPE
|
||||
|
||||
typedef struct {
|
||||
int size, elements;
|
||||
VTREE_DTYPE *vector;
|
||||
int *refs;
|
||||
} Vtree;
|
||||
|
||||
int vtree_init(Vtree *tree, unsigned int size);
|
||||
int vtree_pack(Vtree *tree);
|
||||
int vtree_resize(Vtree *tree, unsigned int newsize);
|
||||
int vtree_add(Vtree *tree, VTREE_DTYPE elem, int parent);
|
||||
int vtree_prune(Vtree *tree, int ref);
|
||||
int vtree_subtree_size(Vtree *tree, int ref);
|
||||
int vtree_children_it(Vtree *tree, int parent, int *cursor);
|
||||
int vtree_level_order_it(Vtree *tree, int ref, int **queue_p, int *cursor);
|
||||
int vtree_destroy(Vtree *tree);
|
||||
|
||||
#ifdef VTREE_IMPL
|
||||
|
||||
#define IS_VALID_REF(t, r) ((r) >= 0 && (r) < (t)->size)
|
||||
#define REF_IS_PRESENT(t, r) ((t)->refs[r] >= 0)
|
||||
|
||||
int vtree_init(Vtree *tree, unsigned int size)
|
||||
{
|
||||
if (tree == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tree->vector = malloc(sizeof(VTREE_DTYPE) * size);
|
||||
if (tree->vector == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tree->refs = malloc(sizeof(int) * size);
|
||||
if (tree->refs == NULL) {
|
||||
free(tree->vector);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// set all refs to -1, meaning invalid (free) element
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
tree->refs[i] = -1;
|
||||
}
|
||||
|
||||
// fill vector with zeroes
|
||||
memset(tree->vector, 0, size * sizeof(VTREE_DTYPE));
|
||||
|
||||
tree->size = size;
|
||||
tree->elements = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vtree_destroy(Vtree *tree)
|
||||
{
|
||||
if (tree == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(tree->vector);
|
||||
free(tree->refs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vtree_pack(Vtree *tree)
|
||||
{
|
||||
if (tree == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: add a PACKED flag to skip this
|
||||
|
||||
int free_spot = -1;
|
||||
for (int i = 0; i < tree->size; i++) {
|
||||
if (tree->refs[i] == -1) {
|
||||
free_spot = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// find a item that can be packed
|
||||
if (free_spot >= 0 && tree->refs[i] >= 0) {
|
||||
int old_ref = i;
|
||||
|
||||
// move the item
|
||||
tree->vector[free_spot] = tree->vector[i];
|
||||
tree->refs[free_spot] = tree->refs[i];
|
||||
|
||||
tree->vector[i] = (VTREE_DTYPE){0};
|
||||
tree->refs[i] = -1;
|
||||
|
||||
// and move all references
|
||||
for (int x = 0; x < tree->size; x++) {
|
||||
if (tree->refs[x] == old_ref) {
|
||||
tree->refs[x] = free_spot;
|
||||
}
|
||||
}
|
||||
|
||||
// mark the free spot as used
|
||||
free_spot = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vtree_resize(Vtree *tree, unsigned int newsize)
|
||||
{
|
||||
if (tree == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// return error when shrinking with too many elements
|
||||
if ((int)newsize < tree->elements) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// pack the vector when shrinking to avoid data loss
|
||||
if ((int)newsize < tree->size) {
|
||||
//if (vtree_pack(tree) < 0) {
|
||||
// return -1;
|
||||
//}
|
||||
// TODO: allow shrinking, since packing destroys all references
|
||||
return -1;
|
||||
}
|
||||
|
||||
VTREE_DTYPE *newvec = realloc(tree->vector, newsize * sizeof(VTREE_DTYPE));
|
||||
if (newvec == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int *newrefs = realloc(tree->refs, newsize * sizeof(int));
|
||||
if (newrefs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tree->vector = newvec;
|
||||
tree->refs = newrefs;
|
||||
if ((int)newsize > tree->size) {
|
||||
for (int i = tree->size; i < (int)newsize; i++) {
|
||||
tree->vector[i] = (VTREE_DTYPE){0};
|
||||
tree->refs[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
tree->size = newsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// add an element to the tree, return it's ref
|
||||
int vtree_add(Vtree *tree, VTREE_DTYPE elem, int parent)
|
||||
{
|
||||
if (tree == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// invalid parent
|
||||
if (!IS_VALID_REF(tree, parent)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// no space left
|
||||
if (tree->elements >= tree->size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check if the parent exists
|
||||
// if there are no elements in the tree the first add will set the root
|
||||
if (!REF_IS_PRESENT(tree, parent) && tree->elements != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get the first free spot
|
||||
int free_spot = -1;
|
||||
for (int i = 0; i < tree->size; i++) {
|
||||
if (tree->refs[i] == -1) {
|
||||
free_spot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (free_spot < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// finally add the element
|
||||
tree->vector[free_spot] = elem;
|
||||
tree->refs[free_spot] = parent;
|
||||
tree->elements++;
|
||||
|
||||
return free_spot;
|
||||
}
|
||||
|
||||
// prune the tree starting from the ref
|
||||
// returns the number of pruned elements
|
||||
int vtree_prune(Vtree *tree, int ref)
|
||||
{
|
||||
if (tree == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!IS_VALID_REF(tree, ref)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!REF_IS_PRESENT(tree, ref)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tree->vector[ref] = (VTREE_DTYPE){0};
|
||||
tree->refs[ref] = -1;
|
||||
|
||||
int count = 1;
|
||||
for (int i = 0; i < tree->size; i++) {
|
||||
if (tree->refs[i] == ref) {
|
||||
count += vtree_prune(tree, i);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// find the size of the subtree starting from ref
|
||||
int vtree_subtree_size(Vtree *tree, int ref)
|
||||
{
|
||||
if (tree == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!IS_VALID_REF(tree, ref)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!REF_IS_PRESENT(tree, ref)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = 1;
|
||||
for (int i = 0; i < tree->size; i++) {
|
||||
// only root has the reference to itself
|
||||
if (tree->refs[i] == ref && ref != i) {
|
||||
count += vtree_subtree_size(tree, i);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// iterate through the first level children, use a cursor like strtok_r
|
||||
int vtree_children_it(Vtree *tree, int parent, int *cursor)
|
||||
{
|
||||
if (tree == NULL || cursor == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if the cursor is out of bounds then we are done for sure
|
||||
if (!IS_VALID_REF(tree, *cursor)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// same for the parent, if it's invalid it can't have children
|
||||
if (!IS_VALID_REF(tree, parent) || !REF_IS_PRESENT(tree, parent)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// find the first child, update the cursor and return the ref
|
||||
for (int i = *cursor; i < tree->size; i++) {
|
||||
if (tree->refs[i] == parent) {
|
||||
*cursor = i + 1;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// if no children are found return -1
|
||||
*cursor = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* iterates trough every leaf of the subtree in the following manner
|
||||
* node [x], x: visit order
|
||||
* [0]
|
||||
* / | \
|
||||
* / [2] [3]
|
||||
* [1] |
|
||||
* / \ [6]
|
||||
* [4] [5]
|
||||
*/
|
||||
int vtree_level_order_it(Vtree *tree, int ref, int **queue_p, int *cursor)
|
||||
{
|
||||
if (tree == NULL || queue_p == NULL || cursor == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int *queue = *queue_p;
|
||||
|
||||
// TODO: this could also be done when adding or removing elements
|
||||
// first call, create a ref array ordered like we desire
|
||||
if (queue == NULL) {
|
||||
*cursor = 0;
|
||||
// create a queue of invalid refs, size is the worst case
|
||||
queue = malloc(sizeof(int) * tree->size);
|
||||
if (queue == NULL) {
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < tree->size; i++) {
|
||||
queue[i] = -1;
|
||||
}
|
||||
*queue_p = queue;
|
||||
|
||||
// iterate through the queue appending found children
|
||||
int pos = 0, off = 0;
|
||||
do {
|
||||
//printf ("ref=%d\n", ref);
|
||||
|
||||
for (int i = 0; i < tree->size; i++) {
|
||||
if (tree->refs[i] == ref) {
|
||||
queue[pos++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (;ref == queue[off] && off < tree->size; off++);
|
||||
ref = queue[off];
|
||||
|
||||
} while (IS_VALID_REF(tree, ref));
|
||||
}
|
||||
|
||||
//PRINT_ARR(queue, tree->size);
|
||||
//return -1;
|
||||
|
||||
// on successive calls just iterate through the queue until we find an
|
||||
// invalid ref
|
||||
int ret = queue[(*cursor)++];
|
||||
if (!IS_VALID_REF(tree, ret)) {
|
||||
free(queue);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif // VTREE_IMPL
|
||||
|
||||
#endif // VTREE_DTYPE
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue