Browse code

add trie to library directory

- add generic digit trie implementation to lib directory,
needed from userblacklist and carrieroute
- add a note to the README

Henning Westerholt authored on 21/11/2008 12:29:07
Showing 4 changed files
... ...
@@ -26,6 +26,9 @@ xcap - Common XCAP operations and structures (XCAP authorization documents
26 26
 
27 27
 Used by modules: pa, rls, dialog, rpa
28 28
 
29
+trie - Common digit trie implementation for prefix matching, used by
30
+       carrierroute and userblacklist
31
+
29 32
 Usage:
30 33
 -----
31 34
 
32 35
new file mode 100644
... ...
@@ -0,0 +1,9 @@
1
+include ../../Makefile.defs
2
+auto_gen=
3
+NAME:=trie
4
+MAJOR_VER=1
5
+MINOR_VER=0
6
+BUGFIX_VER=0
7
+LIBS=
8
+
9
+include ../../Makefile.libs
0 10
new file mode 100644
... ...
@@ -0,0 +1,248 @@
1
+/*
2
+ * $Id: dtrie.c 5237 2008-11-21 10:17:10Z henningw $
3
+ *
4
+ * Copyright (C) 2008 1&1 Internet AG
5
+ *
6
+ * This file is part of sip-router, a free SIP server.
7
+ *
8
+ * sip-router is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * sip-router is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License 
19
+ * along with this program; if not, write to the Free Software 
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ */
22
+
23
+/**
24
+ * \file
25
+ * \brief Trie datastructure with utility functions
26
+ *
27
+ * Provides a generic trie datastructure and utility functions to
28
+ * initialize and manage individual nodes. Its optimized towards
29
+ * the usecase of a matching tree that contains only digits, e.g.
30
+ * for LCR or blacklist modules. Nevertheless it also supports the
31
+ * matching of characters when configured correctly. For normal
32
+ * digit only matching you need to use a branches parameter of
33
+ * 10, when you use 128, the complete standard ascii charset is
34
+ * available for matching. The trie is setup in shared memory.
35
+ * - Module: \ref carrierroute
36
+ * - Module: \ref userblacklist
37
+ */
38
+
39
+
40
+#include "dtrie.h"
41
+
42
+#include <assert.h>
43
+
44
+#include "../../dprint.h"
45
+#include "../../mem/shm_mem.h"
46
+#include "../../mem/mem.h"
47
+
48
+
49
+struct dtrie_node_t *dtrie_init(const unsigned int branches)
50
+{
51
+	struct dtrie_node_t *root;
52
+
53
+	root = shm_malloc(sizeof(struct dtrie_node_t));
54
+	if (root == NULL) {
55
+		SHM_MEM_ERROR;
56
+		return NULL;
57
+	}
58
+	LM_DBG("allocate %lu bytes for root at %p",
59
+			(long unsigned)sizeof(struct dtrie_node_t), root);
60
+	memset(root, 0, sizeof(struct dtrie_node_t));
61
+
62
+	root->child = shm_malloc(sizeof(struct dtrie_node_t *) * branches);
63
+	if (root->child == NULL) {
64
+		shm_free(root);
65
+		SHM_MEM_ERROR;
66
+		return NULL;
67
+	}
68
+	LM_DBG("allocate %lu bytes for %d root children pointer at %p",
69
+			(long unsigned)sizeof(struct dtrie_node_t *) * branches,
70
+			branches, root->child);
71
+	memset(root->child, 0, sizeof(struct dtrie_node_t *) * branches);
72
+
73
+	return root;
74
+}
75
+
76
+
77
+void dtrie_delete(struct dtrie_node_t *root, struct dtrie_node_t *node,
78
+		dt_delete_func_t delete_payload, const unsigned int branches)
79
+{
80
+	unsigned int i;
81
+	if (node==NULL) return;
82
+
83
+	for (i=0; i<branches; i++) {
84
+		dtrie_delete(root, node->child[i], delete_payload, branches);
85
+		node->child[i] = NULL;
86
+	}
87
+
88
+	if (delete_payload) {
89
+		delete_payload(node->data);
90
+		node->data = NULL;
91
+	}
92
+
93
+	if (node != root) {
94
+		LM_DBG("free node at %p", node);
95
+		shm_free(node);
96
+	}
97
+}
98
+
99
+
100
+void dtrie_destroy(struct dtrie_node_t **root, dt_delete_func_t delete_payload, const unsigned int branches)
101
+{
102
+	if ((root!=NULL) && (*root!=NULL)) {
103
+		dtrie_delete(*root, *root, delete_payload, branches);
104
+		LM_DBG("free root at %p", root);
105
+		shm_free(*root);
106
+		*root = NULL;
107
+	}
108
+}
109
+
110
+
111
+void dtrie_clear(struct dtrie_node_t *root, dt_delete_func_t delete_payload,
112
+		const unsigned int branches)
113
+{
114
+	dtrie_delete(root, root, delete_payload, branches);
115
+}
116
+
117
+
118
+int dtrie_insert(struct dtrie_node_t *root, const char *number, const unsigned int numberlen,
119
+		void *data, const unsigned int branches)
120
+{
121
+	struct dtrie_node_t *node = root;
122
+	unsigned char digit, i=0;
123
+
124
+	while (i<numberlen) {
125
+		if (branches==10) {
126
+			digit = number[i] - '0';
127
+			if (digit>9) {
128
+				LM_ERR("cannot insert non-numerical character\n");
129
+				return -1;
130
+			}
131
+		} else {
132
+			digit = number[i];
133
+			if (digit>127) {
134
+				LM_ERR("cannot insert extended ascii character\n");
135
+				return -1;
136
+			}
137
+		}
138
+
139
+		if (node->child[digit] == NULL) {
140
+			node->child[digit] = shm_malloc(sizeof(struct dtrie_node_t));
141
+			assert(node->child[digit] != NULL);
142
+			LM_DBG("allocate %lu bytes for node at %p", (long unsigned)sizeof(struct dtrie_node_t), node->child[digit]);
143
+			memset(node->child[digit], 0, sizeof(struct dtrie_node_t));
144
+
145
+			node->child[digit]->child = shm_malloc(sizeof(struct dtrie_node_t *) * branches);
146
+			assert(node->child[digit]->child != NULL);
147
+			LM_DBG("allocate %lu bytes for %d root children pointer at %p",
148
+					(long unsigned)sizeof(struct dtrie_node_t *) * branches,
149
+					branches, node->child[digit]->child);
150
+			memset(node->child[digit]->child, 0, sizeof(struct dtrie_node_t *) * branches);
151
+		}
152
+		node = node->child[digit];
153
+		i++;
154
+	}
155
+	node->data = data;
156
+	return 0;
157
+}
158
+
159
+
160
+unsigned int dtrie_size(const struct dtrie_node_t *root, const unsigned int branches)
161
+{
162
+	unsigned int i, sum = 0;
163
+
164
+	if (root == NULL) return 0;
165
+
166
+	for (i=0; i<branches; i++) {
167
+		sum += dtrie_size(root->child[i], branches);
168
+	}
169
+
170
+	return sum+1;
171
+}
172
+
173
+
174
+unsigned int dtrie_loaded_nodes(const struct dtrie_node_t *root, const unsigned int branches)
175
+{
176
+	unsigned int i, sum = 0;
177
+
178
+	if (root == NULL) return 0;
179
+
180
+	for (i=0; i<branches; i++) {
181
+		sum += dtrie_loaded_nodes(root->child[i], branches);
182
+	}
183
+
184
+	if (root->data != NULL) sum++;
185
+
186
+	return sum;
187
+}
188
+
189
+
190
+unsigned int dtrie_leaves(const struct dtrie_node_t *root, const unsigned int branches)
191
+{
192
+	unsigned int i, sum = 0, leaf = 1;
193
+
194
+	for (i=0; i<branches; i++) {
195
+		if (root->child[i]) {
196
+			sum += dtrie_leaves(root->child[i], branches);
197
+			leaf = 0;
198
+		}
199
+	}
200
+
201
+	return sum+leaf;
202
+}
203
+
204
+
205
+void **dtrie_longest_match(struct dtrie_node_t *root, const char *number,
206
+		const unsigned int numberlen, int *nmatchptr, const unsigned int branches)
207
+{
208
+	struct dtrie_node_t *node = root;
209
+	unsigned char digit, i = 0;
210
+	void **ret = NULL;
211
+
212
+	if (nmatchptr) *nmatchptr=-1;
213
+	if (node->data != NULL) {
214
+		if (nmatchptr) *nmatchptr=0;
215
+		ret = &node->data;
216
+	}
217
+	while (i<numberlen) {
218
+		if (branches==10) {
219
+			digit = number[i] - '0';
220
+			if (digit>9) return ret;
221
+		} else {
222
+			digit = number[i];
223
+			if (digit>127) return ret;
224
+		}
225
+		
226
+		if (node->child[digit] == NULL) return ret;
227
+		node = node->child[digit];
228
+		i++;
229
+		if (node->data != NULL) {
230
+			if (nmatchptr) *nmatchptr=i;
231
+			ret = &node->data;
232
+		}
233
+	}
234
+
235
+	return ret;
236
+}
237
+
238
+
239
+void **dtrie_contains(struct dtrie_node_t *root, const char *number,
240
+		const unsigned int numberlen, const unsigned int branches)
241
+{
242
+	int nmatch;
243
+	void **ret;
244
+	ret = dtrie_longest_match(root, number, numberlen, &nmatch, branches);
245
+
246
+	if (nmatch == numberlen) return ret;
247
+	return NULL;
248
+}
0 249
new file mode 100644
... ...
@@ -0,0 +1,174 @@
1
+/*
2
+ * $Id: dtrie.h 5237 2008-11-21 10:17:10Z henningw $
3
+ *
4
+ * Copyright (C) 2008 1&1 Internet AG
5
+ *
6
+ * This file is part of Kamailio, a free SIP server.
7
+ *
8
+ * Kamailio is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * Kamailio is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License 
19
+ * along with this program; if not, write to the Free Software 
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ */
22
+
23
+/**
24
+ * \file
25
+ * \brief Trie datastructure with utility functions
26
+ *
27
+ * Provides a generic trie datastructure and utility functions to
28
+ * initialize and manage individual nodes. Its optimized towards
29
+ * the usecase of a matching tree that contains only digits, e.g.
30
+ * for LCR or blacklist modules. Nevertheless it also supports the
31
+ * matching of characters when configured correctly. For normal
32
+ * digit only matching you need to use a branches parameter of
33
+ * 10, when you use 128, the complete standard ascii charset is
34
+ * available for matching. The trie is setup in shared memory.
35
+ * - Module: \ref carrierroute
36
+ * - Module: \ref userblacklist
37
+ */
38
+
39
+#ifndef _DTRIE_H_
40
+#define _DTRIE_H_
41
+
42
+
43
+/*! Trie node */
44
+struct dtrie_node_t {
45
+	struct dtrie_node_t **child; /*!< children */
46
+	void *data; /*!< custom data */
47
+};
48
+
49
+
50
+/*! Function signature for destroying the payload. First parameter is the payload. */
51
+typedef void(*dt_delete_func_t)(void *);
52
+
53
+
54
+/*!
55
+ * \brief Allocates memory for the root node and initializes it
56
+ * \param branches number of branches in the trie
57
+ * \return pointer to an initialized root node on success, NULL otherwise.
58
+ */
59
+struct dtrie_node_t *dtrie_init(const unsigned int branches);
60
+
61
+
62
+/*!
63
+ * \brief Deletes a subtree and frees memory including node
64
+ * \param root root node of the whole tree
65
+ * \param node root of the subtree
66
+ * \param delete_payload pointer to a function for deleting payload. If NULL, it will not be used.
67
+ * \param branches number of branches in the trie
68
+ * \note Memory for the root node is not freed.
69
+ */
70
+void dtrie_delete(struct dtrie_node_t *root, struct dtrie_node_t *node,
71
+		dt_delete_func_t delete_payload, const unsigned int branches);
72
+
73
+
74
+/*!
75
+ * \brief Deletes the whole tree and frees the memory including the root node
76
+ * \param root root node
77
+ * \param delete_payload pointer to a function for deleting payload. If NULL, it will not be used.
78
+ * \param branches number of branches in the trie
79
+ */
80
+void dtrie_destroy(struct dtrie_node_t **root, dt_delete_func_t delete_payload,
81
+		const unsigned int branches);
82
+
83
+
84
+/*!
85
+ * \brief Deletes everything but the root node
86
+ *
87
+ * Deletes everything but the root node, the root node is new initialized.
88
+ * This could be used to create an empty tree like after dtrie_init. It
89
+ * also deletes eventual payload on all nodes including the root node.
90
+ * \param root root node
91
+ * \param delete_payload pointer to a function for deleting payload. If NULL, it will not be used.
92
+ * \param branches number of branches in the trie
93
+ */
94
+void dtrie_clear(struct dtrie_node_t *root, dt_delete_func_t delete_payload,
95
+		const unsigned int branches);
96
+
97
+
98
+/*!
99
+ * \brief Insert a number with a corresponding id
100
+ *
101
+ * Insert a number with a corresponding id. Nodes are created if necessary
102
+ * and the node after the last digit is marked with the given id.
103
+ * \param root root node
104
+ * \param number inserted number string
105
+ * \param numberlen number of individual numbers in number
106
+ * \param data pointer to some custom data
107
+ * \param branches number of branches in the trie
108
+ * \return 0 on success, -1 otherwise.
109
+ */
110
+int dtrie_insert(struct dtrie_node_t *root, const char *number, const unsigned int numberlen,
111
+		void *data, const unsigned int dtrie_size);
112
+
113
+
114
+/*!
115
+ * \brief Returns the number of nodes in the given tree
116
+ * \param root root node
117
+ * \param branches number of branches in the trie
118
+ * \return number of nodes in tree, at least 1
119
+ */
120
+unsigned int dtrie_size(const struct dtrie_node_t *root, const unsigned int branches);
121
+
122
+
123
+/*!
124
+ * \brief Returns the number of nodes in the given tree that holds custom data.
125
+ *
126
+ * Returns the number of nodes in the given tree that are loaded with data (data != NULL).
127
+ * \param root root node
128
+ * \param branches number of branches in the trie
129
+ * \return number of nodes in the tree with custom data
130
+ */
131
+unsigned int dtrie_loaded_nodes(const struct dtrie_node_t *root, const unsigned int branches);
132
+
133
+
134
+/*!
135
+ * \brief Returns the number of leaf nodes in the given tree
136
+ *
137
+ * Returns the number of leaf nodes in the given tree.
138
+ * On leaf nodes the leaf flag is set, on other nodes it is cleared.
139
+ * \param root root node
140
+ * \param branches number of branches in the trie
141
+ * \return number of leaf nodes
142
+ */
143
+unsigned int dtrie_leaves(const struct dtrie_node_t *root, const unsigned int branches);
144
+
145
+
146
+/*!
147
+ *\brief Find the longest prefix match of number in root.
148
+ *
149
+ * Find the longest prefix match of number in root.
150
+ * Set *data according to value in the tree.
151
+ * \param root root node
152
+ * \param number matched prefix
153
+ * \param numberlen length of number
154
+ * \param nmatchptr if not NULL store the number of matched digits or -1 if not found.
155
+ * \param branches number of branches in the trie
156
+ * \return the address of the pointer in the tree node if number is found in root, NULL if the number is not found.
157
+ */
158
+void **dtrie_longest_match(struct dtrie_node_t *root, const char *number,
159
+		const unsigned int numberlen, int *nmatchptr, const unsigned int branches);
160
+
161
+
162
+/*!
163
+ * \brief Check if the trie contains a number
164
+ * \param root root node
165
+ * \param number matched prefix
166
+ * \param numberlen length of number
167
+ * \param branches number of branches in the trie
168
+ * \return the address of the pointer in the tree node if number is found in root, NULL if the number is not found.
169
+ */
170
+void **dtrie_contains(struct dtrie_node_t *root, const char *number,
171
+		const unsigned int numberlen, const unsigned int branches);
172
+
173
+
174
+#endif