diff --git a/lib/linklist.c b/lib/linklist.c index 272e153276..2936c5b502 100644 --- a/lib/linklist.c +++ b/lib/linklist.c @@ -38,16 +38,30 @@ static void list_free_internal(struct list *l) XFREE(MTYPE_LINK_LIST, l); } + /* Allocate new listnode. Internal use only. */ -static struct listnode *listnode_new(void) +static struct listnode *listnode_new(struct list *list, void *val) { - return XCALLOC(MTYPE_LINK_NODE, sizeof(struct listnode)); + struct listnode *node; + + /* if listnode memory is managed by the app then the val + * passed in is the listnode + */ + if (list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP) { + node = val; + node->prev = node->next = NULL; + } else { + node = XCALLOC(MTYPE_LINK_NODE, sizeof(struct listnode)); + node->data = val; + } + return node; } /* Free listnode. */ -static void listnode_free(struct listnode *node) +static void listnode_free(struct list *list, struct listnode *node) { - XFREE(MTYPE_LINK_NODE, node); + if (!(list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP)) + XFREE(MTYPE_LINK_NODE, node); } struct listnode *listnode_add(struct list *list, void *val) @@ -56,10 +70,9 @@ struct listnode *listnode_add(struct list *list, void *val) assert(val != NULL); - node = listnode_new(); + node = listnode_new(list, val); node->prev = list->tail; - node->data = val; if (list->head == NULL) list->head = node; @@ -78,10 +91,9 @@ void listnode_add_head(struct list *list, void *val) assert(val != NULL); - node = listnode_new(); + node = listnode_new(list, val); node->next = list->head; - node->data = val; if (list->head == NULL) list->head = node; @@ -97,15 +109,22 @@ bool listnode_add_sort_nodup(struct list *list, void *val) struct listnode *n; struct listnode *new; int ret; + void *data; assert(val != NULL); + if (list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP) { + n = val; + data = n->data; + } else { + data = val; + } + if (list->cmp) { for (n = list->head; n; n = n->next) { - ret = (*list->cmp)(val, n->data); + ret = (*list->cmp)(data, n->data); if (ret < 0) { - new = listnode_new(); - new->data = val; + new = listnode_new(list, val); new->next = n; new->prev = n->prev; @@ -124,8 +143,7 @@ bool listnode_add_sort_nodup(struct list *list, void *val) } } - new = listnode_new(); - new->data = val; + new = listnode_new(list, val); LISTNODE_ATTACH(list, new); @@ -139,8 +157,8 @@ void listnode_add_sort(struct list *list, void *val) assert(val != NULL); - new = listnode_new(); - new->data = val; + new = listnode_new(list, val); + val = new->data; if (list->cmp) { for (n = list->head; n; n = n->next) { @@ -177,8 +195,7 @@ struct listnode *listnode_add_after(struct list *list, struct listnode *pp, assert(val != NULL); - nn = listnode_new(); - nn->data = val; + nn = listnode_new(list, val); if (pp == NULL) { if (list->head) @@ -212,8 +229,7 @@ struct listnode *listnode_add_before(struct list *list, struct listnode *pp, assert(val != NULL); - nn = listnode_new(); - nn->data = val; + nn = listnode_new(list, val); if (pp == NULL) { if (list->tail) @@ -276,7 +292,7 @@ void list_delete_all_node(struct list *list) next = node->next; if (*list->del) (*list->del)(node->data); - listnode_free(node); + listnode_free(list, node); } list->head = list->tail = NULL; list->count = 0; @@ -336,7 +352,7 @@ void list_delete_node(struct list *list, struct listnode *node) else list->tail = node->prev; list->count--; - listnode_free(node); + listnode_free(list, node); } void list_sort(struct list *list, int (*cmp)(const void **, const void **)) diff --git a/lib/linklist.h b/lib/linklist.h index 00cb9f8714..94a1a1604a 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -43,6 +43,12 @@ struct list { /* invariant: count is the number of listnodes in the list */ unsigned int count; + uint8_t flags; +/* Indicates that listnode memory is managed by the application and + * doesn't need to be freed by this library via listnode_delete etc. + */ +#define LINKLIST_FLAG_NODE_MEM_BY_APP (1 << 0) + /* * Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2. * Used as definition of sorted for listnode_add_sort @@ -60,10 +66,14 @@ struct list { #define listhead(X) ((X) ? ((X)->head) : NULL) #define listhead_unchecked(X) ((X)->head) #define listtail(X) ((X) ? ((X)->tail) : NULL) +#define listtail_unchecked(X) ((X)->tail) #define listcount(X) ((X)->count) #define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL) /* return X->data only if X and X->data are not NULL */ #define listgetdata(X) (assert(X), assert((X)->data != NULL), (X)->data) +/* App is going to manage listnode memory */ +#define listset_app_node_mem(X) ((X)->flags |= LINKLIST_FLAG_NODE_MEM_BY_APP) +#define listnode_init(X, val) ((X)->data = (val)) /* * Create a new linked list. @@ -95,7 +105,7 @@ extern struct listnode *listnode_add(struct list *list, void *data); * list to operate on * * data - * element to add + * If MEM_BY_APP is set this is listnode. Otherwise it is element to add. */ extern void listnode_add_head(struct list *list, void *data); @@ -112,7 +122,7 @@ extern void listnode_add_head(struct list *list, void *data); * list to operate on * * val - * element to add + * If MEM_BY_APP is set this is listnode. Otherwise it is element to add. */ extern void listnode_add_sort(struct list *list, void *val); @@ -128,7 +138,7 @@ extern void listnode_add_sort(struct list *list, void *val); * listnode to insert after * * data - * data to insert + * If MEM_BY_APP is set this is listnode. Otherwise it is element to add. * * Returns: * pointer to newly created listnode that contains the inserted data @@ -148,7 +158,7 @@ extern struct listnode *listnode_add_after(struct list *list, * listnode to insert before * * data - * data to insert + * If MEM_BY_APP is set this is listnode. Otherwise it is element to add. * * Returns: * pointer to newly created listnode that contains the inserted data @@ -313,7 +323,7 @@ extern void list_filter_out_nodes(struct list *list, bool (*cond)(void *data)); * list to operate on * * val - * element to add + * If MEM_BY_APP is set this is listnode. Otherwise it is element to add. */ extern bool listnode_add_sort_nodup(struct list *list, void *val);