dtrie.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dtrie.c 5237 2008-11-21 10:17:10Z henningw $
00003  *
00004  * Copyright (C) 2008 1&1 Internet AG
00005  *
00006  * This file is part of sip-router, a free SIP server.
00007  *
00008  * sip-router is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * sip-router is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00040 #include "dtrie.h"
00041 
00042 #include "../../dprint.h"
00043 #include "../../mem/shm_mem.h"
00044 #include "../../mem/mem.h"
00045 
00046 
00047 struct dtrie_node_t *dtrie_init(const unsigned int branches)
00048 {
00049         struct dtrie_node_t *root;
00050 
00051         root = shm_malloc(sizeof(struct dtrie_node_t));
00052         if (root == NULL) {
00053                 SHM_MEM_ERROR;
00054                 return NULL;
00055         }
00056         LM_DBG("allocate %lu bytes for root at %p\n",
00057                         (long unsigned)sizeof(struct dtrie_node_t), root);
00058         memset(root, 0, sizeof(struct dtrie_node_t));
00059 
00060         root->child = shm_malloc(sizeof(struct dtrie_node_t *) * branches);
00061         if (root->child == NULL) {
00062                 shm_free(root);
00063                 SHM_MEM_ERROR;
00064                 return NULL;
00065         }
00066         LM_DBG("allocate %lu bytes for %d root children pointer at %p\n",
00067                         (long unsigned)sizeof(struct dtrie_node_t *) * branches,
00068                         branches, root->child);
00069         memset(root->child, 0, sizeof(struct dtrie_node_t *) * branches);
00070 
00071         return root;
00072 }
00073 
00074 
00075 void dtrie_delete(struct dtrie_node_t *root, struct dtrie_node_t *node,
00076                 dt_delete_func_t delete_payload, const unsigned int branches)
00077 {
00078         unsigned int i;
00079         if (node==NULL) return;
00080 
00081         for (i=0; i<branches; i++) {
00082                 dtrie_delete(root, node->child[i], delete_payload, branches);
00083                 node->child[i] = NULL;
00084         }
00085 
00086         if (delete_payload) {
00087                 delete_payload(node->data);
00088         }
00089 
00090         node->data = NULL;
00091 
00092         if (node != root) {
00093                 LM_DBG("free node at %p\n", node);
00094                 shm_free(node->child);
00095                 node->child = NULL;
00096                 shm_free(node);
00097         }
00098 }
00099 
00100 
00101 void dtrie_destroy(struct dtrie_node_t **root, dt_delete_func_t delete_payload, const unsigned int branches)
00102 {
00103         if ((root!=NULL) && (*root!=NULL)) {
00104                 dtrie_delete(*root, *root, delete_payload, branches);
00105                 LM_DBG("free root at %p\n", root);
00106                 shm_free((*root)->child);
00107                 shm_free(*root);
00108                 *root = NULL;
00109         }
00110 }
00111 
00112 
00113 void dtrie_clear(struct dtrie_node_t *root, dt_delete_func_t delete_payload,
00114                 const unsigned int branches)
00115 {
00116         dtrie_delete(root, root, delete_payload, branches);
00117 }
00118 
00119 
00120 int dtrie_insert(struct dtrie_node_t *root, const char *number, const unsigned int numberlen,
00121                 void *data, const unsigned int branches)
00122 {
00123         struct dtrie_node_t *node = root;
00124         unsigned char digit, i=0;
00125 
00126         while (i<numberlen) {
00127                 if (branches==10) {
00128                         digit = number[i] - '0';
00129                         if (digit>9) {
00130                                 LM_ERR("cannot insert non-numerical character\n");
00131                                 return -1;
00132                         }
00133                 } else {
00134                         digit = number[i];
00135                         if (digit>127) {
00136                                 LM_ERR("cannot insert extended ascii character\n");
00137                                 return -1;
00138                         }
00139                 }
00140 
00141                 if (node->child[digit] == NULL) {
00142                         node->child[digit] = shm_malloc(sizeof(struct dtrie_node_t));
00143                         if(node->child[digit] == NULL ){
00144                                 SHM_MEM_ERROR;
00145                                 return -1;
00146                         }
00147 
00148                         LM_DBG("allocate %lu bytes for node at %p\n", (long unsigned)sizeof(struct dtrie_node_t), node->child[digit]);
00149                         memset(node->child[digit], 0, sizeof(struct dtrie_node_t));
00150 
00151                         node->child[digit]->child = shm_malloc(sizeof(struct dtrie_node_t *) * branches);
00152                         if(node->child[digit]->child == NULL){
00153                                 SHM_MEM_ERROR;
00154                                 shm_free(node->child[digit]);
00155                                 return -1;
00156                         }
00157                         LM_DBG("allocate %lu bytes for %d root children pointer at %p\n",
00158                                         (long unsigned)sizeof(struct dtrie_node_t *) * branches,
00159                                         branches, node->child[digit]->child);
00160                         memset(node->child[digit]->child, 0, sizeof(struct dtrie_node_t *) * branches);
00161                 }
00162                 node = node->child[digit];
00163                 i++;
00164         }
00165         node->data = data;
00166         return 0;
00167 }
00168 
00169 
00170 unsigned int dtrie_size(const struct dtrie_node_t *root, const unsigned int branches)
00171 {
00172         unsigned int i, sum = 0;
00173 
00174         if (root == NULL) return 0;
00175 
00176         for (i=0; i<branches; i++) {
00177                 sum += dtrie_size(root->child[i], branches);
00178         }
00179 
00180         return sum+1;
00181 }
00182 
00183 
00184 unsigned int dtrie_loaded_nodes(const struct dtrie_node_t *root, const unsigned int branches)
00185 {
00186         unsigned int i, sum = 0;
00187 
00188         if (root == NULL) return 0;
00189 
00190         for (i=0; i<branches; i++) {
00191                 sum += dtrie_loaded_nodes(root->child[i], branches);
00192         }
00193 
00194         if (root->data != NULL) sum++;
00195 
00196         return sum;
00197 }
00198 
00199 
00200 unsigned int dtrie_leaves(const struct dtrie_node_t *root, const unsigned int branches)
00201 {
00202         unsigned int i, sum = 0, leaf = 1;
00203 
00204         for (i=0; i<branches; i++) {
00205                 if (root->child[i]) {
00206                         sum += dtrie_leaves(root->child[i], branches);
00207                         leaf = 0;
00208                 }
00209         }
00210 
00211         return sum+leaf;
00212 }
00213 
00214 
00215 void **dtrie_longest_match(struct dtrie_node_t *root, const char *number,
00216                 const unsigned int numberlen, int *nmatchptr, const unsigned int branches)
00217 {
00218         struct dtrie_node_t *node = root;
00219         unsigned char digit, i = 0;
00220         void **ret = NULL;
00221 
00222         if (nmatchptr) *nmatchptr=-1;
00223         if (node->data != NULL) {
00224                 if (nmatchptr) *nmatchptr=0;
00225                 ret = &node->data;
00226         }
00227         while (i<numberlen) {
00228                 if (branches==10) {
00229                         digit = number[i] - '0';
00230                         if (digit>9) return ret;
00231                 } else {
00232                         digit = number[i];
00233                         if (digit>127) return ret;
00234                 }
00235                 
00236                 if (node->child[digit] == NULL) return ret;
00237                 node = node->child[digit];
00238                 i++;
00239                 if (node->data != NULL) {
00240                         if (nmatchptr) *nmatchptr=i;
00241                         ret = &node->data;
00242                 }
00243         }
00244 
00245         return ret;
00246 }
00247 
00248 
00249 void **dtrie_contains(struct dtrie_node_t *root, const char *number,
00250                 const unsigned int numberlen, const unsigned int branches)
00251 {
00252         int nmatch;
00253         void **ret;
00254         ret = dtrie_longest_match(root, number, numberlen, &nmatch, branches);
00255 
00256         if (nmatch == numberlen) return ret;
00257         return NULL;
00258 }