/** * @file aptree.c * * * @brief パトリシア検索木を用いた名前検索:データ型がポインタの場合 * * * * @brief Patricia index tree for name lookup: data type = pointer * * * @author Akinobu LEE * @date Thu Feb 17 15:21:53 2005 * * $Revision: 1.5 $ * */ /* * Copyright (c) 1991-2012 Kawahara Lab., Kyoto University * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology * Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology * All rights reserved */ #include #include /** * Allocate a new node. * * * @return pointer to the new node. */ static APATNODE * new_node(BMALLOC_BASE **mroot) { APATNODE *tmp; tmp = (APATNODE *)mybmalloc2(sizeof(APATNODE), mroot); tmp->left0 = NULL; tmp->right1 = NULL; return(tmp); } /** * Recursive function to search the data in the tree * * @param node [in] current node. * * @return pointer to the found data */ static void * aptree_search_data_r(APATNODE *node, char *str, int maxbitplace) { #if 1 /* non-recursive */ APATNODE *n; APATNODE *branch = NULL; n = node; while(n->left0 != NULL || n->right1 != NULL) { branch = n; if (testbit_max(str, n->value.thres_bit, maxbitplace) != 0) { n = n->right1; } else { n = n->left0; } } return(n->value.data); #else if (node->left0 == NULL && node->right1 == NULL) { return(node->value.data); } else { if (testbit_max(str, node->value.thres_bit, maxbitplace) != 0) { return(aptree_search_data_r(node->right1, str, maxbitplace)); } else { return(aptree_search_data_r(node->left0, str, maxbitplace)); } } #endif } /** * Search for the data whose key string matches the given string. * * @param str [in] search key string * @param node [in] root node of index tree * * @return the exactly found data pointer, or the nearest one. */ void * aptree_search_data(char *str, APATNODE *node) { if (node == NULL) { //("Error: aptree_search_data: no node, search for \"%s\" failed\n", str); return NULL; } return(aptree_search_data_r(node, str, strlen(str) * 8 + 8)); } /*******************************************************************/ /* add 1 node to given ptree */ /** * Make a root node of a index tree. * * @param data [in] the first data * * @return the newly allocated root node. */ APATNODE * aptree_make_root_node(void *data, BMALLOC_BASE **mroot) { APATNODE *nnew; /* make new leaf node for newstr */ nnew = new_node(mroot); nnew->value.data = data; return(nnew); } /** * Insert a new node to the existing index tree. * * @param str [in] new key string * @param bitloc [in] bit branch to which this node will be added * @param data [in] new data pointer * @param parentlink [i/o] the parent node to which this node will be added */ static void aptree_add_entry_at(char *str, int slen, int bitloc, void *data, APATNODE **parentlink, BMALLOC_BASE **mroot) { #if 1 /* non-recursive */ APATNODE **p; APATNODE *newleaf, *newbranch, *node; p = parentlink; node = *p; while(node->value.thres_bit <= bitloc && (node->left0 != NULL || node->right1 != NULL)) { if (testbit(str, slen, node->value.thres_bit) != 0) { p = &(node->right1); } else { p = &(node->left0); } node = *p; } /* insert between [parent] and [node] */ newleaf = new_node(mroot); newleaf->value.data = data; newbranch = new_node(mroot); newbranch->value.thres_bit = bitloc; *p = newbranch; if (testbit(str, slen, bitloc) ==0) { newbranch->left0 = newleaf; newbranch->right1 = node; } else { newbranch->left0 = node; newbranch->right1 = newleaf; } #else APATNODE *node; APATNODE *newleaf, *newbranch; node = *parentlink; if (node->value.thres_bit > bitloc || (node->left0 == NULL && node->right1 == NULL)) { /* insert between [parent] and [node] */ newleaf = new_node(mroot); newleaf->value.data = data; newbranch = new_node(mroot); newbranch->value.thres_bit = bitloc; *parentlink = newbranch; if (testbit(str, slen, bitloc) ==0) { newbranch->left0 = newleaf; newbranch->right1 = node; } else { newbranch->left0 = node; newbranch->right1 = newleaf; } return; } else { if (testbit(str, slen, node->value.thres_bit) != 0) { aptree_add_entry_at(str, slen, bitloc, data, &(node->right1), mroot); } else { aptree_add_entry_at(str, slen, bitloc, data, &(node->left0), mroot); } } #endif } /** * Insert a new node to the index tree. * * @param str [in] new key string * @param data [in] new data pointer * @param matchstr [in] the most matching data already exist in the index tree, * as obtained by aptree_search_data() * @param rootnode [i/o] pointer to root index node */ void aptree_add_entry(char *str, void *data, char *matchstr, APATNODE **rootnode, BMALLOC_BASE **mroot) { int bitloc; bitloc = where_the_bit_differ(str, matchstr); if (*rootnode == NULL) { *rootnode = aptree_make_root_node(data, mroot); } else { aptree_add_entry_at(str, strlen(str), bitloc, data, rootnode, mroot); } } /*******************************************************************/ /** * Recursive sunction to find and remove an entry. * * @param now [in] current node * @param up [in] parent node * @param up2 [in] parent parent node */ static void aptree_remove_entry_r(APATNODE *now, APATNODE *up, APATNODE *up2, char *str, int maxbitplace, APATNODE **root) { APATNODE *b; if (now->left0 == NULL && now->right1 == NULL) { /* assume this is exactly the node of data that has specified key string */ /* make sure the data of your removal request already exists before call this */ /* execute removal */ if (up == NULL) { //free(now); *root = NULL; return; } b = (up->right1 == now) ? up->left0 : up->right1; if (up2 == NULL) { //free(now); //free(up); *root = b; return; } if (up2->left0 == up) { up2->left0 = b; } else { up2->right1 = b; } //free(now); //free(up); return; } else { /* traverse */ if (testbit_max(str, now->value.thres_bit, maxbitplace) != 0) { aptree_remove_entry_r(now->right1, now, up, str, maxbitplace, root); } else { aptree_remove_entry_r(now->left0, now, up, str, maxbitplace, root); } } } /** * Remove a node from the index tree. * * @param str [in] existing key string (must exist in the index tree) * @param rootnode [i/o] pointer to root index node * */ void aptree_remove_entry(char *str, APATNODE **rootnode) { if (*rootnode == NULL) { jlog("Warning: aptree: no node, deletion for \"%s\" failed\n", str); return; } aptree_remove_entry_r(*rootnode, NULL, NULL, str, strlen(str)*8+8, rootnode); } /*******************************************************************/ /** * Recursive function to traverse index tree and execute * the callback for all the existing data. * * @param node [in] current node * @param callback [in] callback function */ void aptree_traverse_and_do(APATNODE *node, void (*callback)(void *)) { if (node->left0 == NULL && node->right1 == NULL) { (*callback)(node->value.data); } else { if (node->left0 != NULL) { aptree_traverse_and_do(node->left0, callback); } if (node->right1 != NULL) { aptree_traverse_and_do(node->right1, callback); } } } /*************************************************************/ static void aptree_count(APATNODE *node, int *count_branch, int *count_data, int *maxbit) { if (node->left0 == NULL && node->right1 == NULL) { (*count_data)++; } else { if (node->value.thres_bit > *maxbit) { *maxbit = node->value.thres_bit; } (*count_branch)++; if (node->left0 != NULL) { aptree_count(node->left0, count_branch, count_data, maxbit); } if (node->right1 != NULL) { aptree_count(node->right1, count_branch, count_data, maxbit); } } } static int aptree_build_index(APATNODE *node, int *num, int *data_id, int *left, int *right, int *data) { int id; id = *num; (*num)++; if (node->left0 == NULL && node->right1 == NULL) { left[id] = -1; right[id] = -1; data[id] = *data_id; /* node->value.data を保存 */ (*data_id)++; } else { data[id] = node->value.thres_bit; if (node->left0 != NULL) { left[id] = aptree_build_index(node->left0, num, data_id, left, right, data); } else { left[id] = -1; } if (node->right1 != NULL) { right[id] = aptree_build_index(node->right1, num, data_id, left, right, data); } else { right[id] = -1; } } return id; } static void aptree_write_leaf(FILE *fp, APATNODE *node, boolean (*callback)(void *, FILE *fp), boolean *error_p) { if (node->left0 == NULL && node->right1 == NULL) { if ((*callback)(node->value.data, fp) == FALSE) { *error_p = TRUE; } } else { if (node->left0 != NULL) { aptree_write_leaf(fp, node->left0, callback, error_p); } if (node->right1 != NULL) { aptree_write_leaf(fp, node->right1, callback, error_p); } } } boolean aptree_write(FILE *fp, APATNODE *root, boolean (*save_data_func)(void *, FILE *fp)) { int count_node, count_branch, count_data, maxbit; int *left, *right, *value; int num, did; boolean err; if (root == NULL) return TRUE; /* count statistics */ count_branch = count_data = 0; maxbit = 0; aptree_count(root, &count_branch, &count_data, &maxbit); count_node = count_branch + count_data; jlog("Stat: aptree_write: %d nodes (%d branch + %d data), maxbit=%d\n", count_node, count_branch, count_data, maxbit); /* allocate */ left = (int *)mymalloc(sizeof(int) * count_node); right = (int *)mymalloc(sizeof(int) * count_node); value = (int *)mymalloc(sizeof(int) * count_node); /* make index */ did = num = 0; aptree_build_index(root, &num, &did, left, right, value); #if 0 { int i; for(i=0;ileft0 = NULL; } else { node->left0 = &(nodelist[left[i]]); } if (right[i] == -1) { node->right1 = NULL; } else { node->right1 = &(nodelist[right[i]]); } if (left[i] == -1 && right[i] == -1) { /* load leaf data node */ if ((*load_data_func)(&(node->value.data), data, fp) == FALSE) { jlog("Error: aptree_read: failed to load leaf data entity\n"); return FALSE; } } else { /* set thres bit */ node->value.thres_bit = value[i]; } } /* set root node */ *root = &(nodelist[0]); free(value); free(right); free(left); return TRUE; }