Skip to content

Instantly share code, notes, and snippets.

@JAChapmanII
Created September 11, 2012 00:06
Show Gist options
  • Save JAChapmanII/3694953 to your computer and use it in GitHub Desktop.
Save JAChapmanII/3694953 to your computer and use it in GitHub Desktop.
vmap from current c_map
#ifndef MAP_ITERATOR_H
#define MAP_ITERATOR_H
// Various locations an iterator can be at currently
typedef enum { IT_BEGIN, IT_END, IT_NODE, IT_INVALID } IteratorType;
#endif /* MAP_ITERATOR_H */
#include "map_util.h"
size_t util_writeSizeT(FILE *outFile, size_t toWrite) { // {{{
if(!outFile)
return 0;
uint8_t buf[sizeof(size_t)] = { 0 };
for(size_t i = 0; i < sizeof(size_t); ++i)
buf[i] = (toWrite >> (8*i)) & 0xff;
return fwrite(buf, 1, sizeof(size_t), outFile);
} // }}}
size_t util_readSizeT(FILE *inFile) { // {{{
uint8_t buf[sizeof(size_t)] = { 0 };
size_t read = fread(buf, 1, sizeof(size_t), inFile);
if(read != sizeof(size_t))
return 0;
size_t result = 0;
for(size_t i = sizeof(size_t); i > 0; --i)
result = (result << 8) + buf[i - 1];
return result;
} // }}}
#ifndef UTIL_H
#define UTIL_H
#include <stdio.h>
#include <stdint.h>
// Write a size_t to a file in a endian independant way
size_t util_writeSizeT(FILE *outFile, size_t toWrite);
// Read a size_t from a file in a endian independant way
size_t util_readSizeT(FILE *inFile);
#endif // UTIL_H
#include "vmap.h"
#include <stdlib.h>
#include <string.h>
#include "map_util.h"
#define SUCCESS 0
#define FAILURE 1
#define INVALID_SOURCE 8
#define ALLOC_FAIL 9
//----------------------------------------
void vmap_stringInit(char **str);
void vmap_stringFree(char *str);
int vmap_stringCopy(char **dst, char **src);
int vmap_stringCompare(char *s1, char *s2);
char *vmap_stringFormat(char *str);
size_t vmap_stringSize(char *str);
int vmap_stringWrite(char *str, FILE *file);
int vmap_stringRead(char **str, FILE *file);
// vim: ft=c:
void vmapn_fixHeight(VMap_Node *vmapn);
VMap_Node *vmapn_set(VMap_Node *vmapn,
char * key, char * val);
VMap_Node *vmapn_find(VMap_Node *vmapn, char * key);
VMap_Node *vmapn_min(VMap_Node *vmapn);
VMap_Node *vmapn_max(VMap_Node *vmapn);
int vmapn_kequals(VMap_Node *left, VMap_Node *right);
VMap_Node *vmapn_erase(VMap_Node *vmapn, char * key);
VMap_Node *vmapn_balance(VMap_Node *vmapn);
VMap_Node *vmapn_rightRotation(VMap_Node *n);
VMap_Node *vmapn_leftRotation(VMap_Node *n);
size_t vmapn_size(VMap_Node *vmapn);
VMap *vmap_create(void) { // {{{
VMap *vmap = malloc(sizeof(VMap));
if(!vmap)
return NULL;
vmap->root = NULL;
return vmap;
} // }}}
void vmap_free(VMap *vmap) { // {{{
if(!vmap)
return;
if(vmap->root)
vmapn_free(vmap->root);
free(vmap);
} // }}}
VMap_Node *vmapn_create(char * key, char * val) { // {{{
if(!(key != NULL) || !(val != NULL))
return NULL;
VMap_Node *vmapn = malloc(sizeof(VMap_Node));
if(!vmapn)
return NULL;
vmapn->left = vmapn->right = NULL;
vmapn->height = 1;
vmap_stringInit(&vmapn->key);
vmap_stringInit(&vmapn->val);
vmap_stringCopy(&vmapn->key, &key);
vmap_stringCopy(&vmapn->val, &val);
if(!(key != NULL) || !(val != NULL)) {
vmapn_free(vmapn);
return NULL;
}
return vmapn;
} // }}}
void vmapn_free(VMap_Node *vmapn) { // {{{
if(!vmapn)
return;
if(vmapn->left)
vmapn_free(vmapn->left);
if(vmapn->right)
vmapn_free(vmapn->right);
char * key = vmapn->key;
if((key != NULL))
vmap_stringFree(vmapn->key);
char * val = vmapn->val;
if((val != NULL))
vmap_stringFree(vmapn->val);
free(vmapn);
} // }}}
VMap_Iterator *vmapi_create(void) { // {{{
VMap_Iterator *vmapi = malloc(sizeof(VMap_Iterator));
if(!vmapi)
return NULL;
vmapi->type = IT_INVALID;
vmapi->map = NULL;
vmapi->current = NULL;
return vmapi;
}// }}}
void vmapi_free(VMap_Iterator *vmapi) { // {{{
if(!vmapi)
return;
free(vmapi);
} // }}}
/* TODO: error handling */
int vmap_set(VMap *vmap, char * key, char * val) {
if(!(key != NULL) || !(val != NULL))
return 1;
if(!vmap->root) {
vmap->root = vmapn_create(key, val);
if(!vmap->root)
return 1;
return 0;
}
vmap->root = vmapn_set(vmap->root, key, val);
return 0;
}
VMap_Node *vmapn_set(VMap_Node *vmapn, // {{{
char * key, char * val) {
// TODO: this was just return; ....
if(!vmapn || !(key != NULL) || !(val != NULL)) return vmapn;
int cmp = vmap_stringCompare(vmapn->key, key);
// TODO: error on this condition? This makes _set obsolete
if(!cmp) {
if(vmap_stringCopy(&vmapn->val, &val) != SUCCESS) {
// TODO: handle errors
}
return vmapn;
}
VMap_Node **child;
if(cmp > 0)
child = &vmapn->left;
else
child = &vmapn->right;
if(!*child)
*child = vmapn_create(key, val);
else
*child = vmapn_set(*child, key, val);
vmapn_fixHeight(vmapn);
return vmapn_balance(vmapn);
} // }}}
uint8_t vmapn_height(VMap_Node *vmapn) { // {{{
if(!vmapn)
return 0;
return vmapn->height;
} // }}}
// TODO: implement -- is this still needed thanks to add semantics?
int vmap_set(VMap *vmap, char * key, char * val);
VMap_Node *vmap_min(VMap *vmap) { // {{{
if(!vmap || !vmap->root)
return NULL;
return vmapn_min(vmap->root);
} // }}}
VMap_Node *vmapn_min(VMap_Node *vmapn) { // {{{
if(!vmapn)
return NULL;
if(vmapn->left)
return vmapn_min(vmapn->left);
return vmapn;
} // }}}
VMap_Node *vmap_max(VMap *vmap) { // {{{
if(!vmap || !vmap->root)
return NULL;
return vmapn_max(vmap->root);
} // }}}
VMap_Node *vmapn_max(VMap_Node *vmapn) { // {{{
if(!vmapn)
return NULL;
if(vmapn->right)
return vmapn_max(vmapn->right);
return vmapn;
} // }}}
int vmapn_kequals(VMap_Node *left, VMap_Node *right) { // {{{
if((left == NULL) || (right == NULL))
return 0;
return (vmap_stringCompare(left->key, right->key) == 0);
} // }}}
// TODO: the find method can probably use this, then simply look at the left
// TODO: or right child for the final result.
VMap_Node *vmap_parent(VMap *vmap, VMap_Node *vmapn) { // {{{
if(!vmap || !vmap->root || !vmapn)
return NULL;
VMap_Node *cur = vmap->root;
// TODO: currently if the the target is the root, we skip over it and
// TODO: return a NULL. We may want to keep these semantics, but bail early?
do {
if(vmapn_kequals(cur->left, vmapn) ||
vmapn_kequals(cur->right, vmapn))
return cur;
int cmp = vmap_stringCompare(cur->key, vmapn->key);
if(cmp > 0)
cur = cur->left;
else
cur = cur->right;
} while(cur != NULL);
return NULL;
} // }}}
// TODO: these probably have special cases when there are no/few nodes
VMap_Node *vmap_next(VMap *vmap, VMap_Node *vmapn) { // {{{
if(vmapn->right != NULL)
return vmapn_min(vmapn->right);
VMap_Node *cur = vmapn;
while(1) {
VMap_Node *parent = vmap_parent(vmap, cur);
// hit end, or we don't have a parent (not in map)
if(parent == NULL)
return NULL;
if(parent->left == cur)
return parent;
cur = parent;
}
} // }}}
VMap_Node *vmap_prev(VMap *vmap, VMap_Node *vmapn) { // {{{
if(vmapn->left != NULL)
return vmapn_max(vmapn->left);
VMap_Node *cur = vmapn;
while(1) {
VMap_Node *parent = vmap_parent(vmap, cur);
// hit end, or we don't have a parent (not in map)
if(parent == NULL)
return NULL;
if(parent->right == cur)
return parent;
cur = parent;
}
} // }}}
int vmap_erase(VMap *vmap, char * key) { // {{{
if(!vmap || !(key != NULL))
return 1;
vmap->root = vmapn_erase(vmap->root, key);
return 0;
} // }}}
VMap_Node *vmapn_erase(VMap_Node *vmapn, char * key) { // {{{
if(!vmapn || !(key != NULL))
return NULL;
int cmp = vmap_stringCompare(vmapn->key, key);
if(!cmp) {
if(!vmapn->left && !vmapn->right) {
vmapn_free(vmapn);
return NULL;
}
if(vmapn->left && !vmapn->right) {
VMap_Node *l = vmapn->left;
vmapn->left = NULL;
vmapn_free(vmapn);
return l;
}
if(!vmapn->left && vmapn->right) {
VMap_Node *r = vmapn->right;
vmapn->right = NULL;
vmapn_free(vmapn);
return r;
}
// replace with min from right tree
VMap_Node *min = vmapn_min(vmapn->right);
if(!min) {
; // TODO: panic
}
VMap_Node *m = vmapn_create(min->key, min->val);
if(!m) {
; // TODO: panic
}
// this should be one of the simple cases above
vmapn->right = vmapn_erase(vmapn->right, min->key);
m->left = vmapn->left;
m->right = vmapn->right;
m->height = vmapn->height;
vmapn->left = vmapn->right = NULL;
vmapn_free(vmapn);
vmapn_fixHeight(m);
return vmapn_balance(m);
}
if(cmp > 0) {
if(!vmapn->left)
return vmapn;
vmapn->left = vmapn_erase(vmapn->left, key);
} else {
if(!vmapn->right)
return vmapn;
vmapn->right = vmapn_erase(vmapn->right, key);
}
vmapn_fixHeight(vmapn);
return vmapn_balance(vmapn);
} // }}}
void vmapn_fixHeight(VMap_Node *vmapn) { // {{{
if(!vmapn)
return;
int lh = vmapn_height(vmapn->left),
rh = vmapn_height(vmapn->right);
vmapn->height = ((lh > rh) ? lh : rh) + 1;
} // }}}
VMap_Node *vmapn_balance(VMap_Node *vmapn) { // {{{
int lh = vmapn_height(vmapn->left), rh = vmapn_height(vmapn->right);
if(rh - lh > 1) {
lh = vmapn_height(vmapn->right->left);
rh = vmapn_height(vmapn->right->right);
if(lh > rh)
vmapn->right = vmapn_rightRotation(vmapn->right);
vmapn = vmapn_leftRotation(vmapn);
} else if(lh - rh > 1) {
lh = vmapn_height(vmapn->left->left);
rh = vmapn_height(vmapn->left->right);
if(rh > lh)
vmapn->left = vmapn_leftRotation(vmapn->left);
vmapn = vmapn_rightRotation(vmapn);
}
return vmapn;
} // }}}
VMap_Node *vmapn_rightRotation(VMap_Node *n) { // {{{
VMap_Node *nr = n->left, *c = n->left->right;
nr->right = n;
n->left = c;
vmapn_fixHeight(n);
vmapn_fixHeight(nr);
return nr;
} // }}}
VMap_Node *vmapn_leftRotation(VMap_Node *n) { // {{{
VMap_Node *nr = n->right, *b = n->right->left;
nr->left = n;
n->right = b;
vmapn_fixHeight(n);
vmapn_fixHeight(nr);
return nr;
} // }}}
VMap_Node *vmap_find(VMap *vmap, char * key) { // {{{
if(!vmap->root || !(key != NULL))
return NULL;
return vmapn_find(vmap->root, key);
} // }}}
VMap_Node *vmapn_find(VMap_Node *vmapn, char * key) { // {{{
if(!vmapn || !(key != NULL))
return NULL;
int cmp = vmap_stringCompare(vmapn->key, key);
if(!cmp)
return vmapn;
if(cmp > 0)
return vmapn_find(vmapn->left, key);
return vmapn_find(vmapn->right, key);
} // }}}
int vmap_contains(VMap *vmap, char * key) {
return vmap_find(vmap, key) != NULL;
}
char * vmap_get(VMap *vmap, char * key) {
VMap_Node *node = vmap_find(vmap, key);
if(node)
return node->val;
return NULL;
}
void vmapi_front(VMap_Iterator *vmapi, VMap *vmap) { // {{{
if(!vmapi || !vmap)
return;
vmapi->map = vmap;
vmapi->type = IT_NODE;
vmapi->current = vmap_min(vmap);
} // }}}
void vmapi_back(VMap_Iterator *vmapi, VMap *vmap) { // {{{
if(!vmapi || !vmap)
return;
vmapi->map = vmap;
vmapi->type = IT_NODE;
vmapi->current = vmap_max(vmap);
} // }}}
void vmapi_next(VMap_Iterator *vmapi) { // {{{
if(!vmapi || !vmapi->map)
return;
switch(vmapi->type) {
case IT_BEGIN:
vmapi->current = vmap_min(vmapi->map);
vmapi->type = IT_NODE;
return;
case IT_END:
return;
case IT_NODE:
vmapi->current = vmap_next(vmapi->map, vmapi->current);
if(vmapi->current == NULL)
vmapi->type = IT_END;
case IT_INVALID:
return;
}
} // }}}
void vmapi_prev(VMap_Iterator *vmapi) { // {{{
if(!vmapi || !vmapi->map)
return;
switch(vmapi->type) {
case IT_BEGIN:
return;
case IT_END:
vmapi->current = vmap_max(vmapi->map);
vmapi->type = IT_NODE;
return;
case IT_NODE:
vmapi->current = vmap_prev(vmapi->map, vmapi->current);
if(vmapi->current == NULL)
vmapi->type = IT_BEGIN;
case IT_INVALID:
return;
}
} // }}}
size_t vmap_size(VMap *vmap) { // {{{
if(!vmap->root)
return 0;
return vmapn_size(vmap->root);
} // }}}
size_t vmapn_size(VMap_Node *vmapn) { // {{{
if(!vmapn)
return 0;
/* NULL children are handled above */
return vmapn_size(vmapn->left) + vmapn_size(vmapn->right) + 1;
} // }}}
int vmap_load(VMap *vmap, FILE *inFile) { // {{{
if(!vmap || !inFile)
return -1;
size_t size = util_readSizeT(inFile);
if(size == 0)
return -2;
size_t rnodes = 0;
for(; rnodes < size; ++rnodes) {
char * key;
char * val;
if(vmap_stringRead(&key, inFile) != SUCCESS) {
// TODO: handle errors?
fprintf(stderr, "vmap_load: error on READ_KEY\n");
}
if(vmap_stringRead(&val, inFile) != SUCCESS) {
// TODO: handle errors?
fprintf(stderr, "vmap_load: error on READ_VAL\n");
}
// add the node to the VMap
vmap_set(vmap, key, val);
}
if(rnodes != size) {
fprintf(stderr, "rn: %lu, s: %lu\n", rnodes, size);
return -3;
}
return rnodes;
} // }}}
int vmap_read(VMap *vmap, char *fileName) { // {{{
if(!vmap || !fileName)
return 0;
FILE *dumpFile = fopen(fileName, "r");
if(!dumpFile)
return 0;
int res = vmap_load(vmap, dumpFile);
fclose(dumpFile);
return res;
} // }}}
int vmapn_dump(VMap_Node *vmapn, FILE *dumpFile) { // {{{
if(!vmapn || !dumpFile)
return 0;
int count = 1;
if(vmap_stringWrite(vmapn->key, dumpFile) != SUCCESS) {
// TODO: handle errors?
fprintf(stderr, "vmapn_dump: error during WRITE_KEY\n");
count = 0;
} else {
if(vmap_stringWrite(vmapn->val, dumpFile) != SUCCESS) {
// TODO: handle errors?
fprintf(stderr, "vmapn_dump: error during WRITE_VAL\n");
count = 0;
}
}
count += vmapn_dump(vmapn->left, dumpFile);
count += vmapn_dump(vmapn->right, dumpFile);
return count;
} // }}}
int vmap_write(VMap *vmap, FILE *outFile) { // {{{
if(!vmap || !outFile)
return -1;
size_t size = vmap_size(vmap);
if(size < 1)
return 0;
if(util_writeSizeT(outFile, size) != sizeof(size_t))
return -128;
int count = vmapn_dump(vmap->root, outFile);
return count;
} // }}}
int vmap_dump(VMap *vmap, char *fileName) { // {{{
if(!vmap || !fileName)
return 0;
FILE *dumpFile = fopen(fileName, "wb");
if(!dumpFile)
return 0;
int count = vmap_write(vmap, dumpFile);
fclose(dumpFile);
return count;
} // }}}
int vmapn_writeDot(VMap_Node *vmapn, FILE *of, int nullCount) { // {{{
if(!of || !vmapn)
return 0;
char *keyString = vmap_stringFormat(vmapn->key);
char *valString = vmap_stringFormat(vmapn->val);
fprintf(of, "\t\"%s = %s\";\n", keyString, valString);
if(vmapn->left) {
char *lKeyString = vmap_stringFormat(vmapn->left->key);
char *lValString = vmap_stringFormat(vmapn->left->val);
fprintf(of, "\t\"%s = %s\" -> \"%s = %s\";\n", keyString, valString,
lKeyString, lValString);
free(lKeyString);
free(lValString);
nullCount += vmapn_writeDot(vmapn->left, of, nullCount);
} else {
fprintf(of, "null%d [shape=point]\n", nullCount);
fprintf(of, "\t\"%s = %s\" -> null%d\n", keyString, valString, nullCount);
nullCount++;
}
if(vmapn->right) {
char *rKeyString = vmap_stringFormat(vmapn->right->key);
char *rValString = vmap_stringFormat(vmapn->right->val);
fprintf(of, "\t\"%s = %s\" -> \"%s = %s\";\n", keyString, valString,
rKeyString, rValString);
free(rKeyString);
free(rValString);
nullCount += vmapn_writeDot(vmapn->right, of, nullCount);
} else {
fprintf(of, "null%d [shape=point]\n", nullCount);
fprintf(of, "\t\"%s = %s\" -> null%d\n", keyString, valString, nullCount);
nullCount++;
}
free(keyString);
free(valString);
return nullCount;
} // }}}
int vmap_writeDot(VMap *vmap, char *outputName) { // {{{
if(!vmap || !outputName)
return 1;
FILE *of = fopen(outputName, "w");
if(!of)
return 2;
fprintf(of, "digraph BST {\n");
fprintf(of, "\tnode [fontname=\"Arial\"];\n");
vmapn_writeDot(vmap->root, of, 0);
fprintf(of, "}\n");
fclose(of);
return 0;
} // }}}
//----------------------------------------
void vmap_stringInit(char **str) { // {{{
*str = NULL;
} // }}}
void vmap_stringFree(char *str) { // {{{
free(str);
} // }}}
int vmap_stringCopy(char **dst, char **src) { // {{{
if(*src == NULL)
return INVALID_SOURCE;
if(*dst != NULL) {
free(*dst);
*dst = NULL;
}
*dst = strdup(*src);
if(*dst == NULL)
return ALLOC_FAIL;
return SUCCESS;
} // }}}
int vmap_stringCompare(char *s1, char *s2) { // {{{
return strcmp(s1, s2);
} // }}}
char *vmap_stringFormat(char *str) { // {{{
return strdup(str); // TODO: better error handling
} // }}}
size_t vmap_stringSize(char *str) { // {{{
if(str == NULL)
return 0;
return strlen(str);
} // }}}
int vmap_stringWrite(char *str, FILE *file) { // {{{
size_t len = strlen(str), byteSize = (2 << 8) - 1;
if(len > byteSize)
return FAILURE;
uint8_t l = len;
if(fwrite(&l, 1, 1, file) != 1)
return FAILURE;// TODO: error handling? Seek backward?
if(fwrite(str, 1, len, file) != len)
return FAILURE;// TODO: error handling? Seek backward?
return SUCCESS;
} // }}}
int vmap_stringRead(char **str, FILE *file) { // {{{
uint8_t len = 0;
if(fread(&len, 1, 1, file) != 1) {
return FAILURE;// TODO: error handling? Seek?
}
*str = calloc(len + 1, 1);
if(*str == NULL) {
return ALLOC_FAIL; // TODO: error handling? Seek?
}
if(fread(*str, 1, len, file) != len) {
return FAILURE;// TODO: error handling? Seek?
}
(*str)[len] = '\0';
return SUCCESS;
} // }}}
// vim: ft=c:
#ifndef VMAP_H
#define VMAP_H
#include <stdint.h>
#include <stdio.h>
#include "map_iterator.h"
/* VMap_Node, a node in an AVL tree */
typedef struct VMap_Node {
char * key;
char * val;
struct VMap_Node *left;
struct VMap_Node *right;
uint8_t height;
} VMap_Node;
/* A char * -> char * map backed by an AVL tree */
typedef struct {
VMap_Node *root;
} VMap;
// A VMap bidirectional iterator
typedef struct {
IteratorType type;
VMap_Node *current;
VMap *map;
} VMap_Iterator;
/* Create an empty VMap */
VMap *vmap_create(void);
/* Free all memory associated with a VMap */
void vmap_free(VMap *vmap);
/* Create a VMap_Node object */
VMap_Node *vmapn_create(char * key, char * val);
/* Free space associated with a VMap_Node */
void vmapn_free(VMap_Node *vmapn);
// Create a VMap_Iterator object
VMap_Iterator *vmapi_create(void);
// Free space assoicated with a VMap_Iterator
void vmapi_free(VMap_Iterator *vmapi);
/* Set a key/value pair in the tree (create if necessary)
* returns 1 on failure, 0 otherwise
*/
int vmap_set(VMap *vmap, char * key, char * val);
/* Remove a node from the tree */
int vmap_erase(VMap *vmap, char * key);
/* Search VMap for a specific node */
VMap_Node *vmap_find(VMap *vmap, char * key);
/* Determine if a VMap contains the given key, returns a boolean */
int vmap_contains(VMap *vmap, char * key);
/* Return a node from a VMap
* if the VMap doesn't contain the key, a default value is returned
*/
char * vmap_get(VMap *vmap, char * key);
// Search a VMap for the minimum element
VMap_Node *vmap_min(VMap *vmap);
// Search a VMap for the maximum element
VMap_Node *vmap_max(VMap *vmap);
// Search a VMap for the parent of the given element
VMap_Node *vmap_parent(VMap *vmap, VMap_Node *vmapn);
// Search a VMap for the element occurring after a given element
VMap_Node *vmap_next(VMap *vmap, VMap_Node *vmapn);
// Search a VMap for the element occurring before a given element
VMap_Node *vmap_prev(VMap *vmap, VMap_Node *vmapn);
// Start a VMap_Iterator at the front of a VMap
void vmapi_front(VMap_Iterator *vmapi, VMap *vmap);
// Start a VMap_Iterator at the back of a VMap
void vmapi_back(VMap_Iterator *vmapi, VMap *vmap);
// Move a VMap_Iterator to the next element
void vmapi_next(VMap_Iterator *vmapi);
// Move a VMap_Iterator to the previous element
void vmapi_prev(VMap_Iterator *vmapi);
/* Recursively compute the total nodes in a VMap */
size_t vmap_size(VMap *vmap);
/* Write a VMap to a file */
int vmap_write(VMap *vmap, FILE *outFile);
/* Try to open a file and write the VMap to it */
int vmap_dump(VMap *vmap, char *fileName);
/* Read a VMap from a file */
int vmap_load(VMap *vmap, FILE *inFile);
/* Try to open a file and load the VMap from it */
int vmap_read(VMap *vmap, char *fileName);
/* Write this VMap out as a graphviz .dot file */
int vmap_writeDot(VMap *vmap, char *outputName);
#endif /* VMAP_H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment