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 <qlyoung@cumulusnetworks.com>
This commit is contained in:
Quentin Young 2018-05-24 18:43:57 +00:00
parent 91f1037064
commit 6fd8c487e1
4 changed files with 435 additions and 82 deletions

View File

@ -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);

View File

@ -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);
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 *);
/*
* 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);
extern void hash_iterate(struct hash *, void (*)(struct hash_backet *, void *),
void *);
/*
* 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 *));
extern void hash_walk(struct hash *, int (*)(struct hash_backet *, void *),
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);
extern void hash_clean(struct hash *, void (*)(void *));
extern void hash_free(struct hash *);
/*
* 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);
/*
* 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);
/*
* 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);
/*
* 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);
/*
* 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 */

View File

@ -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;

View File

@ -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 */
/*
* Create a new linked list.
*
* Returns:
* the created linked list
*/
extern struct list *list_new(void);
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 *);
/*
* 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 (...) { ... }