/* Implementation of the string TRIE utility. Copyright (C) 2008 Cristi Balas This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ //#include #include #include #include "string_trie.h" /* * * * * * * * * * * * * * * NEW and DELETE * * * * * * * * * * * * * * */ static void trie_init_node(TRIE_NODE *node) { int i; for(i = 0; i < 256; i++) node->nxt[i] = 0; node->childs = 0; // # children = 0 node->is_final = 0; node->data = 0; } TRIE *trie_new() { TRIE *trie = malloc(sizeof(TRIE)); trie->root = malloc(sizeof(TRIE_NODE)); trie_init_node(trie->root); return trie; } static void trie_node_free(TRIE_NODE *node) { int i; for(i = 1; i < 256; i++) if(node->nxt[i]) trie_node_free(node->nxt[i]); free(node->data); // free(0) is valid free(node); } void trie_delete(TRIE *trie) { trie_node_free(trie->root); free(trie); } /* * * * * * * * * * * * * * * ADDING * * * * * * * * * * * * * * */ static void *crt_user_data; static int crt_user_data_len; static int trie_add_nodes(TRIE_NODE *node, char *str, int pos) { unsigned char ch = (unsigned char)str[pos]; // current char if( ch ) // ch != '\0', i.e., string not finished { if( 0 == node->nxt[ch] ) // construct next node { node->nxt[ch] = malloc(sizeof(TRIE_NODE)); if(0 == node->nxt[ch]) // out of memory return 0; trie_init_node(node->nxt[ch]); node->childs++; } return trie_add_nodes(node->nxt[ch], str, pos + 1); } else { /* --------------------------------------- End of string... insert real data --------------------------------------- */ if(node->is_final) free(node->data); // There was some data -> de-allocate it node->is_final = 1; // Mark node as data containing if(crt_user_data && crt_user_data_len) { node->data = malloc(crt_user_data_len); // Allocate space for data if(0 == node->data) return 0; // Out of memory memcpy(node->data, crt_user_data, crt_user_data_len); // Copy data } else node->data = 0; return 1; } } int trie_add(TRIE *trie, char *str, void *user_data, int user_data_len) { /* ============================================================ Use global variables so we don't need to pass these stuff into a RECURSIVE function (too many parameters !) ============================================================ */ crt_user_data = user_data; crt_user_data_len = user_data_len; return trie_add_nodes(trie->root, str, 0); // Call recursive function // to do the the job } /* * * * * * * * * * * * * * * DELETING * * * * * * * * * * * * * * */ static void trie_del_recursive(TRIE_NODE *node, char *str, int pos) { unsigned char ch = (unsigned char)str[pos]; // current char if(ch) // string not finished { if(node->nxt[ch]) // next character is in trie { trie_del_recursive(node->nxt[ch], str, pos + 1); if(node->nxt[ch]->is_final == 0 && node->nxt[ch]->childs == 0) { free(node->nxt[ch]); node->nxt[ch] = 0; node->childs--; } } } else { if(node->is_final) { node->is_final = 0; free(node->data); node->data = 0; } } } void trie_del(TRIE *trie, char *str) { trie_del_recursive(trie->root, str, 0); } /* * * * * * * * * * * * * * * SEARCHING * * * * * * * * * * * * * * */ static void *crt_search_data; int trie_search_nodes(TRIE_NODE *node, char *str, int pos) { unsigned char ch = (unsigned char)str[pos]; // current char if(ch) // string not finished { if(node->nxt[ch]) return trie_search_nodes(node->nxt[ch], str, pos + 1); else return 0; // not found } else { if(node->is_final) { crt_search_data = node->data; return 1; } else return 0; } } int trie_search(TRIE *trie, char *str, void **p_user_data) { crt_search_data = 0; if(trie_search_nodes(trie->root, str, 0)) { if(p_user_data) *p_user_data = crt_search_data; return 1; } else return 0; }