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 /****f* silcutil/SilcTreeCompare
78 * typedef int (*SilcTreeCompare)(void *entry1, void *entry2,
83 * Callback function of this type is called to compare values in the
84 * tree. If the `entry1' is smaller, equal to or greater than `entry2'
85 * this function must return less than, equal to, or greater than zero,
89 typedef int (*SilcTreeCompare)(void *entry1, void *entry2, void *context);
91 /****d* silcutil/SilcTreeType
95 * typedef enum { ... } SilcTreeType;
99 * The supported tree types.
104 /* AVL Tree. Automatically balancing binary search tree that provides
105 excellent performance. */
110 #include "silctree_i.h"
112 /* Tree implementations */
113 extern DLLAPI const struct SilcTreeOpsStruct silc_tree_avl_ops;
115 /****f* silcutil/silc_tree_init
119 * SilcBool silc_tree_init(SilcTree tree, SilcTreeType type,
120 * SilcTreeCompare compare, void *context,
121 * SilcUInt16 offset, SilcBool duplicates);
125 * Initializes the `tree' as a tree type indicated by `type'. The
126 * `compare' function will be called to compare entries in the tree,
127 * for example, when finding entries from the tree. The `context' is
128 * delivered to the callback function.
130 * The `offset' is the byte offset of the SilcTreeHeader structure field
131 * in the entry structure that is going to be added to the tree. Each
132 * structure that is added to the tree must contain SilcTreeHeader
133 * structure. Use silc_offsetof to get the byte offset.
135 * If the `duplicates' is TRUE the tree will allow the addition of
136 * duplicate values. However, the entry context to be added must not
137 * already be in the tree, but its value may be same as some other
140 * The `tree' need not be uninitialized. The caller is responsible of
141 * freeing the entries it has added to the tree.
143 * Return FALSE if the `type' is of unknown tree type. Returns TRUE
144 * otherwise. This function does not allocate any memory.
148 * // Structure that is going to be added to tree
150 * SilcTreeHeader header;
156 * silc_tree_init(tree, SILC_TREE_AVL, compare, context,
157 * silc_offsetof(FooEntry, header));
160 #define silc_tree_init(tree, type, compare, context, offset, d) \
161 __silc_tree_init(&(tree), type, compare, context, offset, d)
163 SilcBool __silc_tree_init(SilcTree *tree,
164 SilcTreeType type, SilcTreeCompare compare,
165 void *context, SilcUInt32 offset,
170 tree->ops = &silc_tree_avl_ops;
179 tree->compare = compare;
180 tree->context = context;
182 tree->offset = offset;
183 tree->duplicates = duplicates;
188 /****f* silcutil/silc_tree_add
192 * SilcBool silc_tree_add(SilcTree *tree, void *entry);
196 * Add `entry' to the `tree'. Returns TRUE after the entry has been
197 * added to the tree. If the `tree' does not allocate duplicate entries
198 * this will return FALSE if same value as `entry' is already in the
203 * FooEntry *client_entry;
205 * client_entry->id = id;
206 * client_entry->name = name;
207 * silc_tree_add(tree, client_entry);
210 #define silc_tree_add(tree, e) (tree).ops->add(&(tree), (e))
212 /****f* silcutil/silc_tree_del
216 * SilcBool silc_tree_del(SilcTree *tree, void *entry);
220 * Delete entry from the `tree'. If the `entry' is not the actual entry
221 * context that was added to the tree but is merely a temporary context
222 * it must be memset'ed to zero (0) initially. The deletion routine will
223 * assume that the given `entry' is the actual added entry context if its
224 * SilcTreeHeader structure is not zeroed when deleting the entry. If it
225 * is zeroed the deletion will first try to find the entry from the tree
226 * and then delete the found entry. See example for both cases.
228 * Return FALSE if the entry does not exist in the tree. Returns TRUE
229 * after successful deletion.
233 * // Delete the entry, we have access to the originally added context
234 * silc_tree_del(tree, client_entry);
236 * // Delete client entry with ID 100
238 * memset(&tmp, 0, sizeof(tmp));
240 * silc_tree_del(tree, &tmp);
242 * // Delete all entries from the tree
243 * while ((entry = silc_tree_enumerate(tree, NULL)))
244 * silc_tree_del(tree, entry);
247 #define silc_tree_del(tree, e) (tree).ops->del(&(tree), (e))
249 /****f* silcutil/silc_tree_find
253 * void *silc_tree_find(SilcTree *tree, void *entry);
257 * Find entry from the tree. Returns the found entry or NULL if the
258 * entry does not exist in the tree and sets silc_errno.
260 * If there are duplicate values in the tree this will find the first
261 * one. Rest of the duplicate values can be found by calling
262 * silc_tree_enumerate_duplicates. It will stop the enumeration when
263 * the last duplicate entry is returned.
267 * FooEntry probe, *client_entry;
269 * // Find entry by ID 100
271 * client_entry = silc_tree_find(tree, &probe);
274 #define silc_tree_find(tree, e) (tree).ops->find(&(tree), (e), NULL, NULL)
276 /****f* silcutil/silc_tree_find_ext
280 * void *silc_tree_find_ext(SilcTree *tree, void *entry,
281 * SilcTreeCompare compare, void *context);
285 * Same as silc_tree_find but takes a separate comparison function as
289 #define silc_tree_find_ext(tree, e, compare, context) \
290 (tree).ops->find(&(tree), (e), (compare), (context))
292 /****f* silcutil/silc_tree_count
296 * SilcUInt32 silc_tree_count(SilcTree *tree);
300 * Returns the number of entries in the tree.
303 #define silc_tree_count(tree) (tree).count
305 /****f* silcutil/silc_tree_minmax
309 * void *silc_tree_minmax(SilcTree *tree, SilcBool min);
313 * Returns either smallest or largest value from the `tree'. If the `min'
314 * is TRUE returns the smallest, otherwise returns the largest. Returns
315 * NULL if the tree is empty.
318 #define silc_tree_minmax(tree, min) __silc_tree_minmax(&(tree), (min))
320 void *__silc_tree_minmax(SilcTree *tree, SilcBool min)
335 return SILC_TREE_GET_ENTRY(tree, h);
338 /****f* silcutil/silc_tree_enumerate
342 * void *silc_tree_enumerate(SilcTree *tree, void *at);
346 * Enumerates the `tree' starting/continuing at the `at'. When `at' is
347 * NULL this will start enumeration from the root of the tree. The found
348 * entry must be given as `at' for next call to continue the enumeration
349 * in order. The enumeration is done in ascending order starting from the
350 * smallest value. If there are duplicates in the tree, their order is
351 * undefined. Returns NULL at the end of the enumeration.
355 * // Start enumerating from beginning in order
356 * for (entry = silc_tree_enumerate(tree, NULL); entry != NULL;
357 * entry = silc_tree_enumerate(tree, entry))
358 * printf("Client entry %s\n", entry->name);
360 * // Delete all entries from the tree
361 * while ((entry = silc_tree_enumerate(tree, NULL)))
362 * silc_tree_del(tree, entry);
365 #define silc_tree_enumerate(tree, e) __silc_tree_enumerate(&(tree), (e))
367 void *__silc_tree_enumerate(SilcTree *tree, void *at)
369 SilcTreeHeader *h, *p;
372 return __silc_tree_minmax(tree, TRUE);
374 h = SILC_TREE_GET_HEADER(tree, at);
377 return SILC_TREE_GET_ENTRY(tree, h->dup);
378 else if (h->duplicate)
379 for (h = h->parent; h->duplicate; h = h->parent) ;
382 for (h = h->right; h->left; h = h->left) ;
383 return SILC_TREE_GET_ENTRY(tree, h);
387 while (p && p->right == h) {
392 return p ? SILC_TREE_GET_ENTRY(tree, p) : NULL;
395 /****f* silcutil/silc_tree_enumerate_duplicates
399 * void *silc_tree_enumerate_duplicates(SilcTree *tree, void *at);
403 * Enumerates all duplicate values starting at the `at'. If `at' is the
404 * only one of that value in the tree this will return NULL. Returns same
405 * values as `at' until there are no more and will then return NULL. The
406 * `at' must not be NULL.
410 * // Find all entries of ID 100
412 * entry = silc_tree_find(tree, &probe);
413 * printf("Entry %p ID %d\n", entry, entry->id);
414 * while ((entry = silc_tree_enumerate_duplicates(tree, entry)))
415 * printf("Entry %p ID %d\n", entry, entry->id);
418 #define silc_tree_enumerate_duplicates(tree, e) \
419 __silc_tree_enumerate_dup(&(tree), (e))
421 void *__silc_tree_enumerate_dup(SilcTree *tree, void *at)
423 SilcTreeHeader *h = SILC_TREE_GET_HEADER(tree, at);
424 return h->dup ? SILC_TREE_GET_ENTRY(tree, h->dup) : NULL;
427 #endif /* SILCTREE_H */