5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2008 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program 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.
20 /****h* silcutil/Binary Search Tree Interface
24 * Binary Search Tree Interface provides simple interface for adding,
25 * deleting, retrieving and enumerating items in a tree. The inteface
26 * allows also duplicate values in the tree, and it does not allocate any
27 * memory. The interface can support many types of binary search trees.
29 * The interface is not thread-safe. If the same SilcTree context must be
30 * used in multithreaded environment concurrency control must be employed.
37 /****s* silcutil/SilcTree
41 * typedef struct SilcTreeStruct SilcTree;
45 * This is the SilcTree context, and is initialized by calling the
46 * function silc_tree_init. It need not be uninitialized.
49 typedef struct SilcTreeStruct SilcTree;
51 /****s* silcutil/SilcTreeHeader
55 * typedef struct SilcTreeHeaderStruct SilcTreeHeader;
59 * This structure must be present in each context that is added to the
60 * tree. The structure can be at any place in the context.
64 * // Structure that is going to be added to tree
66 * SilcTreeHeader header;
72 typedef struct SilcTreeHeaderStruct SilcTreeHeader;
74 /****d* silcutil/SilcTreeType
78 * typedef enum { ... } SilcTreeType;
82 * The supported tree types.
87 /* AVL Tree. Automatically balancing binary search tree that provides
88 excellent performance. */
93 #include "silctree_i.h"
95 /* Tree implementations */
96 extern DLLAPI const struct SilcTreeOpsStruct silc_tree_avl_ops;
98 /****f* silcutil/silc_tree_init
102 * SilcBool silc_tree_init(SilcTree tree, SilcTreeType type,
103 * SilcCompare compare, void *context,
104 * SilcUInt16 offset, SilcBool duplicates);
108 * Initializes the `tree' as a tree type indicated by `type'. The
109 * `compare' function will be called to compare entries in the tree,
110 * for example, when finding entries from the tree. The `context' is
111 * delivered to the callback function.
113 * The `offset' is the byte offset of the SilcTreeHeader structure field
114 * in the entry structure that is going to be added to the tree. Each
115 * structure that is added to the tree must contain SilcTreeHeader
116 * structure. Use silc_offsetof to get the byte offset.
118 * If the `duplicates' is TRUE the tree will allow the addition of
119 * duplicate values. However, the entry context to be added must not
120 * already be in the tree, but its value may be same as some other
123 * The `tree' need not be uninitialized. The caller is responsible of
124 * freeing the entries it has added to the tree.
126 * Return FALSE if the `type' is of unknown tree type. Returns TRUE
127 * otherwise. This function does not allocate any memory.
131 * // Structure that is going to be added to tree
133 * SilcTreeHeader header;
139 * silc_tree_init(tree, SILC_TREE_AVL, compare, context,
140 * silc_offsetof(FooEntry, header));
143 #define silc_tree_init(tree, type, compare, context, offset, d) \
144 __silc_tree_init(&(tree), type, compare, context, offset, d)
146 SilcBool __silc_tree_init(SilcTree *tree,
147 SilcTreeType type, SilcCompare compare,
148 void *context, SilcUInt32 offset,
153 tree->ops = &silc_tree_avl_ops;
162 tree->compare = compare;
163 tree->context = context;
165 tree->offset = offset;
166 tree->duplicates = duplicates;
171 /****f* silcutil/silc_tree_add
175 * SilcBool silc_tree_add(SilcTree *tree, void *entry);
179 * Add `entry' to the `tree'. Returns TRUE after the entry has been
180 * added to the tree. If the `tree' does not allow duplicate entries
181 * this will return FALSE if same value as `entry' is already in the
186 * FooEntry *client_entry;
188 * client_entry->id = id;
189 * client_entry->name = name;
190 * silc_tree_add(tree, client_entry);
193 #define silc_tree_add(tree, e) (tree).ops->add(&(tree), (e))
195 /****f* silcutil/silc_tree_del
199 * SilcBool silc_tree_del(SilcTree *tree, void *entry);
203 * Delete entry from the `tree'. If the `entry' is not the actual entry
204 * context that was added to the tree but is merely a temporary context
205 * it must be memset'ed to zero (0) initially. The deletion routine will
206 * assume that the given `entry' is the actual added entry context if its
207 * SilcTreeHeader structure is not zeroed when deleting the entry. If it
208 * is zeroed the deletion will first try to find the entry from the tree
209 * and then delete the found entry. See example for both cases.
211 * Return FALSE if the entry does not exist in the tree. Returns TRUE
212 * after successful deletion.
216 * // Delete the entry, we have access to the originally added context
217 * silc_tree_del(tree, client_entry);
219 * // Delete client entry with ID 100
221 * memset(&tmp, 0, sizeof(tmp));
223 * silc_tree_del(tree, &tmp);
225 * // Delete all entries from the tree
226 * while ((entry = silc_tree_enumerate(tree, NULL)))
227 * silc_tree_del(tree, entry);
230 #define silc_tree_del(tree, e) (tree).ops->del(&(tree), (e))
232 /****f* silcutil/silc_tree_find
236 * void *silc_tree_find(SilcTree *tree, void *entry);
240 * Find entry from the tree. Returns the found entry or NULL if the
241 * entry does not exist in the tree and sets silc_errno.
243 * If there are duplicate values in the tree this will find the first
244 * one. Rest of the duplicate values can be found by calling
245 * silc_tree_enumerate_duplicates. It will stop the enumeration when
246 * the last duplicate entry is returned.
250 * FooEntry probe, *client_entry;
252 * // Find entry by ID 100
254 * client_entry = silc_tree_find(tree, &probe);
257 #define silc_tree_find(tree, e) (tree).ops->find(&(tree), (e), NULL, NULL)
259 /****f* silcutil/silc_tree_find_ext
263 * void *silc_tree_find_ext(SilcTree *tree, void *entry,
264 * SilcCompare compare, void *context);
268 * Same as silc_tree_find but takes a separate comparison function as
272 #define silc_tree_find_ext(tree, e, compare, context) \
273 (tree).ops->find(&(tree), (e), (compare), (context))
275 /****f* silcutil/silc_tree_count
279 * SilcUInt32 silc_tree_count(SilcTree *tree);
283 * Returns the number of entries in the tree.
286 #define silc_tree_count(tree) (tree).count
288 /****f* silcutil/silc_tree_minmax
292 * void *silc_tree_minmax(SilcTree *tree, SilcBool min);
296 * Returns either smallest or largest value from the `tree'. If the `min'
297 * is TRUE returns the smallest, otherwise returns the largest. Returns
298 * NULL if the tree is empty.
301 #define silc_tree_minmax(tree, min) __silc_tree_minmax(&(tree), (min))
303 void *__silc_tree_minmax(SilcTree *tree, SilcBool min)
318 return SILC_TREE_GET_ENTRY(tree, h);
321 /****f* silcutil/silc_tree_enumerate
325 * void *silc_tree_enumerate(SilcTree *tree, void *at);
329 * Enumerates the `tree' starting/continuing at the `at'. When `at' is
330 * NULL this will start enumeration from the root of the tree. The found
331 * entry must be given as `at' for next call to continue the enumeration
332 * in order. The enumeration is done in ascending order starting from the
333 * smallest value. If there are duplicates in the tree, their order is
334 * undefined. Returns NULL at the end of the enumeration.
338 * // Start enumerating from beginning in order
339 * for (entry = silc_tree_enumerate(tree, NULL); entry != NULL;
340 * entry = silc_tree_enumerate(tree, entry))
341 * printf("Client entry %s\n", entry->name);
343 * // Delete all entries from the tree
344 * while ((entry = silc_tree_enumerate(tree, NULL)))
345 * silc_tree_del(tree, entry);
348 #define silc_tree_enumerate(tree, e) __silc_tree_enumerate(&(tree), (e))
350 void *__silc_tree_enumerate(SilcTree *tree, void *at)
352 SilcTreeHeader *h, *p;
355 return __silc_tree_minmax(tree, TRUE);
357 h = SILC_TREE_GET_HEADER(tree, at);
360 return SILC_TREE_GET_ENTRY(tree, h->dup);
361 else if (h->duplicate)
362 for (h = h->parent; h->duplicate; h = h->parent) ;
365 for (h = h->right; h->left; h = h->left) ;
366 return SILC_TREE_GET_ENTRY(tree, h);
370 while (p && p->right == h) {
375 return p ? SILC_TREE_GET_ENTRY(tree, p) : NULL;
378 /****f* silcutil/silc_tree_enumerate_duplicates
382 * void *silc_tree_enumerate_duplicates(SilcTree *tree, void *at);
386 * Enumerates all duplicate values starting at the `at'. If `at' is the
387 * only one of that value in the tree this will return NULL. Returns same
388 * values as `at' until there are no more and will then return NULL. The
389 * `at' must not be NULL.
393 * // Find all entries of ID 100
395 * entry = silc_tree_find(tree, &probe);
396 * printf("Entry %p ID %d\n", entry, entry->id);
397 * while ((entry = silc_tree_enumerate_duplicates(tree, entry)))
398 * printf("Entry %p ID %d\n", entry, entry->id);
401 #define silc_tree_enumerate_duplicates(tree, e) \
402 __silc_tree_enumerate_dup(&(tree), (e))
404 void *__silc_tree_enumerate_dup(SilcTree *tree, void *at)
406 SilcTreeHeader *h = SILC_TREE_GET_HEADER(tree, at);
407 return h->dup ? SILC_TREE_GET_ENTRY(tree, h->dup) : NULL;
410 #endif /* SILCTREE_H */