From: Quentin Young Date: Thu, 24 May 2018 18:43:57 +0000 (+0000) Subject: lib: add proper doc comments for hash & linklist X-Git-Tag: frr-6.1-dev~404^2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=refs%2Fpull%2F2289%2Fhead;p=mirror%2Ffrr.git lib: add proper doc comments for hash & linklist * Remove references to ospf source files from linklist.[ch] * Remove documentation comments from hash.c and linklist.c * Add comprehensive documentation comments to linklist.h and hash.h Signed-off-by: Quentin Young --- diff --git a/lib/hash.c b/lib/hash.c index 01f160f94a..ee5401b236 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -36,7 +36,6 @@ DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index") pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER; static struct list *_hashes; -/* Allocate a new hash. */ struct hash *hash_create_size(unsigned int size, unsigned int (*hash_key)(void *), int (*hash_cmp)(const void *, const void *), @@ -67,7 +66,6 @@ struct hash *hash_create_size(unsigned int size, return hash; } -/* Allocate a new hash with default hash size. */ struct hash *hash_create(unsigned int (*hash_key)(void *), int (*hash_cmp)(const void *, const void *), const char *name) @@ -75,9 +73,6 @@ struct hash *hash_create(unsigned int (*hash_key)(void *), return hash_create_size(HASH_INITIAL_SIZE, hash_key, hash_cmp, name); } -/* Utility function for hash_get(). When this function is specified - as alloc_func, return arugment as it is. This function is used for - intern already allocated value. */ void *hash_alloc_intern(void *arg) { return arg; @@ -133,9 +128,6 @@ static void hash_expand(struct hash *hash) hash->index = new_index; } -/* Lookup and return hash backet in hash. If there is no - corresponding hash backet and alloc_func is specified, create new - hash backet. */ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *)) { unsigned int key; @@ -189,13 +181,11 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *)) return NULL; } -/* Hash lookup. */ void *hash_lookup(struct hash *hash, void *data) { return hash_get(hash, data, NULL); } -/* Simple Bernstein hash which is simple and fast for common case */ unsigned int string_hash_make(const char *str) { unsigned int hash = 0; @@ -206,9 +196,6 @@ unsigned int string_hash_make(const char *str) return hash; } -/* This function release registered value from specified hash. When - release is successfully finished, return the data pointer in the - hash backet. */ void *hash_release(struct hash *hash, void *data) { void *ret; @@ -248,7 +235,6 @@ void *hash_release(struct hash *hash, void *data) return NULL; } -/* Iterator function for hash. */ void hash_iterate(struct hash *hash, void (*func)(struct hash_backet *, void *), void *arg) { @@ -266,7 +252,6 @@ void hash_iterate(struct hash *hash, void (*func)(struct hash_backet *, void *), } } -/* Iterator function for hash. */ void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *), void *arg) { @@ -288,7 +273,6 @@ void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *), } } -/* Clean up hash. */ void hash_clean(struct hash *hash, void (*free_func)(void *)) { unsigned int i; @@ -327,8 +311,6 @@ struct list *hash_to_list(struct hash *hash) return list; } -/* Free hash memory. You may call hash_clean before call this - function. */ void hash_free(struct hash *hash) { pthread_mutex_lock(&_hashes_mtx); diff --git a/lib/hash.h b/lib/hash.h index 2510422e21..c7e670b723 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -36,9 +36,10 @@ DECLARE_MTYPE(HASH_BACKET) #define HASHWALK_ABORT -1 struct hash_backet { - /* if this backet is the head of the linked listed, len denotes the - * number of - * elements in the list */ + /* + * if this backet is the head of the linked listed, len denotes the + * number of elements in the list + */ int len; /* Linked list. */ @@ -85,38 +86,232 @@ struct hash { #define hashcount(X) ((X)->count) -extern struct hash *hash_create(unsigned int (*)(void *), - int (*)(const void *, const void *), - const char *); -extern struct hash *hash_create_size(unsigned int, unsigned int (*)(void *), - int (*)(const void *, const void *), - const char *); +/* + * Create a hash table. + * + * The created hash table uses chaining and a user-provided comparator function + * to resolve collisions. For best performance use a perfect hash function. + * Worst case lookup time is O(N) when using a constant hash function. Best + * case lookup time is O(1) when using a perfect hash function. + * + * The initial size of the created hash table is HASH_INITIAL_SIZE. + * + * hash_key + * hash function to use; should return a unique unsigned integer when called + * with a data item. Collisions are acceptable. + * + * hash_cmp + * comparison function used for resolving collisions; when called with two + * data items, should return nonzero if the two items are equal and 0 + * otherwise + * + * name + * optional name for the hashtable; this is used when displaying global + * hashtable statistics. If this parameter is NULL the hash's name will be + * set to NULL and the default name will be displayed when showing + * statistics. + * + * Returns: + * a new hash table + */ +extern struct hash *hash_create(unsigned int (*hash_key)(void *), + int (*hash_cmp)(const void *, const void *), + const char *name); + +/* + * Create a hash table. + * + * The created hash table uses chaining and a user-provided comparator function + * to resolve collisions. For best performance use a perfect hash function. + * Worst case lookup time is O(N) when using a constant hash function. Best + * case lookup time is O(1) when using a perfect hash function. + * + * size + * initial number of hash buckets to allocate; must be a power of 2 or the + * program will assert + * + * hash_key + * hash function to use; should return a unique unsigned integer when called + * with a data item. Collisions are acceptable. + * + * hash_cmp + * comparison function used for resolving collisions; when called with two + * data items, should return nonzero if the two items are equal and 0 + * otherwise + * + * name + * optional name for the hashtable; this is used when displaying global + * hashtable statistics. If this parameter is NULL the hash's name will be + * set to NULL and the default name will be displayed when showing + * statistics. + * + * Returns: + * a new hash table + */ +extern struct hash * +hash_create_size(unsigned int size, unsigned int (*hash_key)(void *), + int (*hash_cmp)(const void *, const void *), const char *name); + +/* + * Retrieve or insert data from / into a hash table. + * + * This function is somewhat counterintuitive in its usage. In order to look up + * an element from its key, you must provide the data item itself, with the + * portions used in the hash function set to the same values as the data item + * to retrieve. To insert a data element, either provide the key as just + * described and provide alloc_func as descrbied below to allocate the full + * data element, or provide the full data element and pass 'hash_alloc_intern' + * to alloc_func. + * + * hash + * hash table to operate on + * + * data + * data to insert or retrieve + * + * alloc_func + * function to call if the item is not found in the hash table. This + * function is called with the value of 'data' and should create the data + * item to insert and return a pointer to it. If the data has already been + * completely created and provided in the 'data' parameter, passing + * 'hash_alloc_intern' to this parameter will cause 'data' to be inserted. + * If this parameter is NULL, then this call to hash_get is equivalent to + * hash_lookup. + * + * Returns: + * the data item found or inserted, or NULL if alloc_func is NULL and the + * data is not found + */ +extern void *hash_get(struct hash *hash, void *data, + void *(*alloc_func)(void *)); + +/* + * Dummy element allocation function. + * + * See hash_get for details. + * + * data + * data to insert into the hash table + * + * Returns: + * data + */ +extern void *hash_alloc_intern(void *data); + +/* + * Retrieve an item from a hash table. + * + * This function is equivalent to calling hash_get with alloc_func set to NULL. + * + * hash + * hash table to operate on + * + * data + * data element with values used for key computation set + * + * Returns: + * the data element if found, or NULL if not found + */ +extern void *hash_lookup(struct hash *hash, void *data); -extern void *hash_get(struct hash *, void *, void *(*)(void *)); -extern void *hash_alloc_intern(void *); -extern void *hash_lookup(struct hash *, void *); -extern void *hash_release(struct hash *, void *); +/* + * Remove an element from a hash table. + * + * hash + * hash table to operate on + * + * data + * data element to remove with values used for key computation set + * + * Returns: + * the removed element if found, or NULL if not found + */ +extern void *hash_release(struct hash *hash, void *data); -extern void hash_iterate(struct hash *, void (*)(struct hash_backet *, void *), - void *); +/* + * Iterate over the elements in a hash table. + * + * It is safe to delete items passed to the iteration function from the hash + * table during iteration. + * + * hash + * hash table to operate on + * + * func + * function to call with each data item + * + * arg + * arbitrary argument passed as the second parameter in each call to 'func' + */ +extern void hash_iterate(struct hash *hash, + void (*func)(struct hash_backet *, void *), void *arg); -extern void hash_walk(struct hash *, int (*)(struct hash_backet *, void *), - void *); +/* + * Iterate over the elements in a hash table, stopping on condition. + * + * It is safe to delete items passed to the iteration function from the hash + * table during iteration. + * + * hash + * hash table to operate on + * + * func + * function to call with each data item. If this function returns + * HASHWALK_ABORT then the iteration stops. + * + * arg + * arbitrary argument passed as the second parameter in each call to 'func' + */ +extern void hash_walk(struct hash *hash, + int (*func)(struct hash_backet *, void *), void *arg); -extern void hash_clean(struct hash *, void (*)(void *)); -extern void hash_free(struct hash *); +/* + * Remove all elements from a hash table. + * + * hash + * hash table to operate on + * + * free_func + * function to call with each removed item; intended to free the data + */ +extern void hash_clean(struct hash *hash, void (*free_func)(void *)); + +/* + * Delete a hash table. + * + * This function assumes the table is empty. Call hash_clean to delete the + * hashtable contents if necessary. + * + * hash + * hash table to delete + */ +extern void hash_free(struct hash *hash); /* * Converts a hash table to an unsorted linked list. * Does not modify the hash table in any way. * * hash - * the hash to convert + * hash table to convert */ extern struct list *hash_to_list(struct hash *hash); +/* + * Hash a string using the modified Bernstein hash. + * + * This is not a perfect hash function. + * + * str + * string to hash + * + * Returns: + * modified Bernstein hash of the string + */ extern unsigned int string_hash_make(const char *); +/* + * Install CLI commands for viewing global hash table statistics. + */ extern void hash_cmd_init(void); #endif /* _ZEBRA_HASH_H */ diff --git a/lib/linklist.c b/lib/linklist.c index 3a35b250ca..2cfa3e7482 100644 --- a/lib/linklist.c +++ b/lib/linklist.c @@ -27,7 +27,6 @@ DEFINE_MTYPE_STATIC(LIB, LINK_LIST, "Link List") DEFINE_MTYPE_STATIC(LIB, LINK_NODE, "Link Node") -/* Allocate new list. */ struct list *list_new(void) { return XCALLOC(MTYPE_LINK_LIST, sizeof(struct list)); @@ -51,7 +50,6 @@ static void listnode_free(struct listnode *node) XFREE(MTYPE_LINK_NODE, node); } -/* Add new data to the list. */ void listnode_add(struct list *list, void *val) { struct listnode *node; @@ -72,12 +70,6 @@ void listnode_add(struct list *list, void *val) list->count++; } -/* - * Add a node to the list. If the list was sorted according to the - * cmp function, insert a new node with the given val such that the - * list remains sorted. The new node is always inserted; there is no - * notion of omitting duplicates. - */ void listnode_add_sort(struct list *list, void *val) { struct listnode *n; @@ -186,14 +178,12 @@ struct listnode *listnode_add_before(struct list *list, struct listnode *pp, return nn; } -/* Move given listnode to tail of the list */ void listnode_move_to_tail(struct list *l, struct listnode *n) { LISTNODE_DETACH(l, n); LISTNODE_ATTACH(l, n); } -/* Delete specific date pointer from the list. */ void listnode_delete(struct list *list, void *val) { struct listnode *node; @@ -218,7 +208,6 @@ void listnode_delete(struct list *list, void *val) } } -/* Return first node's data if it is there. */ void *listnode_head(struct list *list) { struct listnode *node; @@ -231,7 +220,6 @@ void *listnode_head(struct list *list) return NULL; } -/* Delete all listnode from the list. */ void list_delete_all_node(struct list *list) { struct listnode *node; @@ -248,7 +236,6 @@ void list_delete_all_node(struct list *list) list->count = 0; } -/* Delete all listnode then free list itself. */ void list_delete_and_null(struct list **list) { assert(*list); @@ -262,7 +249,6 @@ void list_delete_original(struct list *list) list_delete_and_null(&list); } -/* Lookup the node which has given data. */ struct listnode *listnode_lookup(struct list *list, void *data) { struct listnode *node; @@ -274,7 +260,6 @@ struct listnode *listnode_lookup(struct list *list, void *data) return NULL; } -/* Delete the node from list. For ospfd and ospf6d. */ void list_delete_node(struct list *list, struct listnode *node) { if (node->prev) @@ -289,25 +274,24 @@ void list_delete_node(struct list *list, struct listnode *node) listnode_free(node); } -/* ospf_spf.c */ -void list_add_list(struct list *l, struct list *m) +void list_add_list(struct list *list, struct list *add) { struct listnode *n; - for (n = listhead(m); n; n = listnextnode(n)) - listnode_add(l, n->data); + for (n = listhead(add); n; n = listnextnode(n)) + listnode_add(list, n->data); } -struct list *list_dup(struct list *l) +struct list *list_dup(struct list *list) { struct list *new = list_new(); struct listnode *ln; void *data; - new->cmp = l->cmp; - new->del = l->del; + new->cmp = list->cmp; + new->del = list->del; - for (ALL_LIST_ELEMENTS_RO(l, ln, data)) + for (ALL_LIST_ELEMENTS_RO(list, ln, data)) listnode_add(new, data); return new; diff --git a/lib/linklist.h b/lib/linklist.h index d6d9b5e087..39e70293d2 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -59,23 +59,166 @@ struct list { /* return X->data only if X and X->data are not NULL */ #define listgetdata(X) (assert(X), assert((X)->data != NULL), (X)->data) -/* Prototypes. */ -extern struct list * -list_new(void); /* encouraged: set list.del callback on new lists */ - -extern void listnode_add(struct list *, void *); -extern void listnode_add_sort(struct list *, void *); -extern struct listnode *listnode_add_after(struct list *, struct listnode *, - void *); -extern struct listnode *listnode_add_before(struct list *, struct listnode *, - void *); -extern void listnode_move_to_tail(struct list *, struct listnode *); -extern void listnode_delete(struct list *, void *); -extern struct listnode *listnode_lookup(struct list *, void *); -extern void *listnode_head(struct list *); +/* + * Create a new linked list. + * + * Returns: + * the created linked list + */ +extern struct list *list_new(void); + +/* + * Add a new element to the tail of a list. + * + * Runtime is O(1). + * + * list + * list to operate on + * + * data + * element to add + */ +extern void listnode_add(struct list *list, void *data); + +/* + * Insert a new element into a list with insertion sort. + * + * If list->cmp is set, this function is used to determine the position to + * insert the new element. If it is not set, this function is equivalent to + * listnode_add. + * + * Runtime is O(N). + * + * list + * list to operate on + * + * val + * element to add + */ +extern void listnode_add_sort(struct list *list, void *val); + +/* + * Insert a new element into a list after another element. + * + * Runtime is O(1). + * + * list + * list to operate on + * + * pp + * listnode to insert after + * + * data + * data to insert + * + * Returns: + * pointer to newly created listnode that contains the inserted data + */ +extern struct listnode *listnode_add_after(struct list *list, + struct listnode *pp, void *data); + +/* + * Insert a new element into a list before another element. + * + * Runtime is O(1). + * + * list + * list to operate on + * + * pp + * listnode to insert before + * + * data + * data to insert + * + * Returns: + * pointer to newly created listnode that contains the inserted data + */ +extern struct listnode *listnode_add_before(struct list *list, + struct listnode *pp, void *data); + +/* + * Move a node to the tail of a list. + * + * Runtime is O(1). + * + * list + * list to operate on + * + * node + * node to move to tail + */ +extern void listnode_move_to_tail(struct list *list, struct listnode *node); + +/* + * Delete an element from a list. + * + * Runtime is O(N). + * + * list + * list to operate on + * + * data + * data to insert into list + */ +extern void listnode_delete(struct list *list, void *data); + +/* + * Find the listnode corresponding to an element in a list. + * + * list + * list to operate on + * + * data + * data to search for + * + * Returns: + * pointer to listnode storing the given data if found, NULL otherwise + */ +extern struct listnode *listnode_lookup(struct list *list, void *data); + +/* + * Retrieve the element at the head of a list. + * + * list + * list to operate on + * + * Returns: + * data at head of list, or NULL if list is empty + */ +extern void *listnode_head(struct list *list); + +/* + * Duplicate a list. + * + * list + * list to duplicate + * + * Returns: + * copy of the list + */ extern struct list *list_dup(struct list *l); + +/* + * Sort a list in place. + * + * The sorting algorithm used is quicksort. Runtimes are equivalent to those of + * quicksort plus N. The sort is not stable. + * + * For portability reasons, the comparison function takes a pointer to pointer + * to void. This pointer should be dereferenced to get the actual data pointer. + * It is always safe to do this. + * + * list + * list to sort + * + * cmp + * comparison function for quicksort. Should return less than, equal to or + * greater than zero if the first argument is less than, equal to or greater + * than the second argument. + */ extern void list_sort(struct list *list, - int (*cmp)(const void *, const void *)); + int (*cmp)(const void **, const void **)); /* * The usage of list_delete is being transitioned to pass in @@ -90,8 +233,27 @@ extern void list_sort(struct list *list, #if defined(VERSION_TYPE_DEV) && CONFDATE > 20181001 CPP_NOTICE("list_delete without double pointer is deprecated, please fixup") #endif -extern void list_delete_and_null(struct list **); -extern void list_delete_original(struct list *); + +/* + * Delete a list and NULL its pointer. + * + * If non-null, list->del is called with each data element. + * + * plist + * pointer to list pointer; this will be set to NULL after the list has been + * deleted + */ +extern void list_delete_and_null(struct list **plist); + +/* + * Delete a list. + * + * If non-null, list->del is called with each data element. + * + * plist + * pointer to list pointer + */ +extern void list_delete_original(struct list *list); #define list_delete(X) \ list_delete_original((X)) \ CPP_WARN("Please transition to using list_delete_and_null") @@ -99,13 +261,43 @@ extern void list_delete_original(struct list *); list_delete_original((X)) \ CPP_WARN("Please transition tousing list_delete_and_null") -extern void list_delete_all_node(struct list *); +/* + * Delete all nodes from a list without deleting the list itself. + * + * If non-null, list->del is called with each data element. + * + * list + * list to operate on + */ +extern void list_delete_all_node(struct list *list); -/* For ospfd and ospf6d. */ -extern void list_delete_node(struct list *, struct listnode *); +/* + * Delete a node from a list. + * + * list->del is not called with the data associated with the node. + * + * Runtime is O(1). + * + * list + * list to operate on + * + * node + * the node to delete + */ +extern void list_delete_node(struct list *list, struct listnode *node); -/* For ospf_spf.c */ -extern void list_add_list(struct list *, struct list *); +/* + * Append a list to an existing list. + * + * Runtime is O(N) where N = listcount(add). + * + * list + * list to append to + * + * add + * list to append + */ +extern void list_add_list(struct list *list, struct list *add); /* List iteration macro. * Usage: for (ALL_LIST_ELEMENTS (...) { ... }