#include "bin.h" #include "commands.h" #include "b-tree.h" #include #include #include #include #define INVALID_NODE_PTR 0xFFFF #define ORDER 6 #define MAX (ORDER - 1) #define MIN (MAX / 2) enum { ARG_INPATH, OPT_OUTPATH, OPT_OUTPATH_PATH, }; struct entry { uint32_t key; uint32_t value; }; struct node { uint16_t nr_entries; struct entry entries[MAX]; uint16_t children[ORDER]; }; struct data_tree { struct b_tree base; FILE *fp; }; static int node_init(struct node *n) { memset(n, 0x0, sizeof * n); for (int i = 0; i < ORDER; i++) { n->children[i] = INVALID_NODE_PTR; } return 0; } static int tree_get_node(struct b_tree *p, unsigned long id, b_tree_node *n) { struct data_tree *tree = (struct data_tree *)p; size_t offset = (id * sizeof(struct node)); fseek(tree->fp, offset, SEEK_SET); size_t r = fread(n, sizeof(struct node), 1, tree->fp); return r == 1 ? 0 : -1; } static int tree_put_node(struct b_tree *p, unsigned long id, const b_tree_node *n) { struct data_tree *tree = (struct data_tree *)p; size_t offset = (id * sizeof(struct node)); fseek(tree->fp, offset, SEEK_SET); size_t r = fwrite(n, sizeof(struct node), 1, tree->fp); return r == 1 ? 0 : -1; } static long tree_alloc_node(struct b_tree *p) { struct data_tree *tree = (struct data_tree *)p; size_t pos = ftell(tree->fp); fseek(tree->fp, 0, SEEK_END); size_t len = ftell(tree->fp); struct node n; node_init(&n); fwrite(&n, sizeof n, 1, tree->fp); fseek(tree->fp, pos, SEEK_SET); len /= sizeof(struct node); return (long)len; } static unsigned long node_get_nr_entries(b_tree_node *n) { struct node *node = (struct node *)n; return node->nr_entries; } static void node_set_nr_entries(b_tree_node *n, unsigned long val) { struct node *node = (struct node *)n; node->nr_entries = val; } static b_tree_node_entry *node_get_entries(b_tree_node *n) { struct node *node = (struct node *)n; return (b_tree_node_entry *)node->entries; } static uint16_t *node_get_children(b_tree_node *n) { struct node *node = (struct node *)n; return node->children; } static int entry_compare(const b_tree_node_entry *e0, const b_tree_node_entry *e1) { struct entry *a = (struct entry *)e0, *b = (struct entry *)e1; if (a->key < b->key) { return -1; } if (a->key > b->key) { return 1; } return 0; } static const struct b_tree_ops ops = { .node_size = sizeof(struct node), .entry_size = sizeof(struct entry), .tree_get_node = tree_get_node, .tree_put_node = tree_put_node, .tree_alloc_node = tree_alloc_node, .node_get_nr_entries = node_get_nr_entries, .node_set_nr_entries = node_set_nr_entries, .node_get_entries = node_get_entries, .node_get_children = node_get_children, .entry_compare = entry_compare, }; void indent(int depth) { for (int i = 0; i < depth; i++) { fputs(" ", stdout); } } int node_print(struct b_tree *tree, struct node *n, int depth) { int c_before = (n->nr_entries + 1) / 2; int c_after = n->nr_entries + 1 - c_before; int i_before = 0; int i_after = i_before + c_before; int err = 0; for (unsigned short i = 0; i < c_before; i++) { struct node child; int index = i_before + i; if (n->children[index] == INVALID_NODE_PTR) { // indent(depth + 1); continue; } err = tree_get_node(tree, n->children[index], (b_tree_node *)&child); if (err != 0) { printf("ERR: failed to read node %u\n", n->children[index]); continue; } node_print(tree, &child, depth + 1); } indent(depth); printf("["); for (unsigned short i = 0; i < n->nr_entries; i++) { if (i > 0) { printf(" "); } printf("%d", n->entries[i].key); } printf("]\n"); for (unsigned short i = 0; i < c_after; i++) { struct node child; int index = i_after + i; if (n->children[index] == INVALID_NODE_PTR) { // indent(depth + 1); continue; } err = tree_get_node(tree, n->children[index], (b_tree_node *)&child); if (err != 0) { printf("ERR: failed to read node %u\n", n->children[index]); continue; } node_print(tree, &child, depth + 1); } return 0; } int tree_print(struct b_tree *tree) { struct node root; tree_get_node(tree, 0, (b_tree_node *)&root); return node_print(tree, &root, 0); } static int create( const b_command *self, const b_arglist *opt, const b_array *args) { const char *in_path = NULL, *out_path = NULL; b_arglist_get_string( opt, B_COMMAND_INVALID_ID, ARG_INPATH, 0, &in_path); b_arglist_get_string(opt, OPT_OUTPATH, OPT_OUTPATH_PATH, 0, &out_path); printf("in path: %s\n", in_path); printf("out path: %s\n", out_path); FILE *fp = fopen(out_path, "w+b"); struct node root; node_init(&root); fwrite(&root, sizeof root, 1, fp); struct data_tree tree; b_tree_init(&tree.base, &ops, ORDER); tree.fp = fp; for (int i = 1; i <= 32; i++) { int key = rand() % 65535; //int key = i; // printf("%d: adding [%d]\n", i, key); struct entry e = { .key = key, .value = key * 2 }; b_tree_put(&tree.base, (b_tree_node_entry *)&e); } tree_print(&tree.base); fclose(fp); return 0; } B_COMMAND(CMD_CREATE, CMD_ROOT) { B_COMMAND_NAME("create"); B_COMMAND_SHORT_NAME('C'); B_COMMAND_DESC("create an ec3 file"); B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); B_COMMAND_FUNCTION(create); B_COMMAND_HELP_OPTION(); B_COMMAND_OPTION(OPT_OUTPATH) { B_OPTION_SHORT_NAME('o'); B_OPTION_LONG_NAME("out"); B_OPTION_DESC("the path to save the new file to"); B_OPTION_ARG(OPT_OUTPATH_PATH) { B_ARG_NAME("path"); B_ARG_NR_VALUES(1); } } B_COMMAND_ARG(ARG_INPATH) { B_ARG_NAME("input file"); B_ARG_NR_VALUES(1); } B_COMMAND_USAGE() { B_COMMAND_USAGE_ARG(ARG_INPATH); B_COMMAND_USAGE_OPT(OPT_OUTPATH); } }