# 数据结构定义
# 比较函数指针
| typedef int (zlist_compare_fn) ( |
| void *item1, void *item2); |
# 析构函数指针
| typedef void (zlist_free_fn) ( |
| void *data); |
# 节点
| typedef struct _node_t { |
| struct _node_t *next; |
| void *item; |
| zlist_free_fn *free_fn; |
| } node_t; |
# 链表
| struct _zlist_t { |
| node_t *head; |
| node_t *tail; |
| node_t *cursor; |
| size_t size; |
| bool autofree; |
| zlist_compare_fn *compare_fn; |
| }; |
# 函数定义
# 创建链表对象
| |
| zlist_t * |
| zlist_new (void) |
| { |
| zlist_t *self = (zlist_t *) zmalloc (sizeof (zlist_t)); |
| assert (self); |
| return self; |
| } |
# 销毁链表对象
| |
| void |
| zlist_destroy (zlist_t **self_p) |
| { |
| assert (self_p); |
| if (*self_p) { |
| zlist_t *self = *self_p; |
| zlist_purge (self); |
| freen (self); |
| *self_p = NULL; |
| } |
| } |
# 访问链表第一个元素
| |
| Leaves cursor pointing at the head item, or NULL if the list is empty. */ |
| void * |
| zlist_first (zlist_t *self) |
| { |
| assert (self); |
| |
| self->cursor = self->head; |
| |
| if (self->cursor) |
| return self->cursor->item; |
| else |
| return NULL; |
| } |
# 访问链表下一个元素
| |
| the start of the list call zlist_first (). Advances the cursor. */ |
| void * |
| zlist_next (zlist_t *self) |
| { |
| assert (self); |
| |
| if (self->cursor) |
| self->cursor = self->cursor->next; |
| else |
| self->cursor = self->head; |
| |
| if (self->cursor) |
| return self->cursor->item; |
| else |
| return NULL; |
| } |
# 访问链表最后一个元素
| |
| Leaves cursor pointing at the tail item, or NULL if the list is empty. */ |
| void * |
| zlist_last (zlist_t *self) |
| { |
| assert (self); |
| |
| self->cursor = self->tail; |
| |
| if (self->cursor) |
| return self->cursor->item; |
| else |
| return NULL; |
| } |
# 访问链表当前元素
| |
| passed the end of the list, returns NULL. Does not change the cursor. */ |
| void * |
| zlist_item (zlist_t *self) |
| { |
| assert (self); |
| |
| if (self->cursor) |
| return self->cursor->item; |
| else |
| return NULL; |
| } |
# 添加链尾元素
| |
| failed for some reason. */ |
| int |
| zlist_append (zlist_t *self, void *item) |
| { |
| if (!item) |
| return -1; |
| |
| |
| node_t *node = (node_t *) zmalloc (sizeof (node_t)); |
| assert (node); |
| |
| |
| if (self->autofree) { |
| item = strdup ((char *) item); |
| assert (item); |
| } |
| |
| node->item = item; |
| |
| if (self->tail) |
| self->tail->next = node; |
| |
| else |
| self->head = node; |
| |
| |
| self->tail = node; |
| node->next = NULL; |
| |
| |
| self->size++; |
| |
| self->cursor = NULL; |
| return 0; |
| } |
# 添加链首元素
| |
| failed for some reason. */ |
| int |
| zlist_push (zlist_t *self, void *item) |
| { |
| if (!item) |
| return -1; |
| |
| node_t *node = (node_t *) zmalloc (sizeof (node_t)); |
| assert (node); |
| |
| |
| if (self->autofree) { |
| item = strdup ((char *) item); |
| assert (item); |
| } |
| node->item = item; |
| |
| node->next = self->head; |
| |
| self->head = node; |
| |
| if (self->tail == NULL) |
| self->tail = node; |
| |
| self->size++; |
| self->cursor = NULL; |
| return 0; |
| } |
# 删除链首元素
| |
| void * |
| zlist_pop (zlist_t *self) |
| { |
| node_t *node = self->head; |
| void *item = NULL; |
| if (node) { |
| |
| item = node->item; |
| |
| self->head = node->next; |
| |
| if (self->tail == node) |
| self->tail = NULL; |
| |
| freen (node); |
| |
| self->size--; |
| } |
| |
| self->cursor = NULL; |
| |
| return item; |
| } |
# 判断元素是否存在
| |
| items are equal. If the compare method is NULL the check will only compare |
| pointers. Returns true if item is present else false. */ |
| bool |
| zlist_exists (zlist_t *self, void *item) |
| { |
| assert (self); |
| assert (item); |
| node_t *node = self->head; |
| |
| while (node) { |
| |
| if (self->compare_fn) { |
| if ((*self->compare_fn)(node->item, item) == 0) |
| return true; |
| } |
| |
| else |
| if (node->item == item) |
| return true; |
| |
| node = node->next; |
| } |
| return false; |
| } |
# 查找并删除元素
| |
| are not in the list. */ |
| void |
| zlist_remove (zlist_t *self, void *item) |
| { |
| node_t *node, *prev = NULL; |
| |
| |
| for (node = self->head; node != NULL; node = node->next) { |
| if (self->compare_fn) { |
| if ((*self->compare_fn)(node->item, item) == 0) |
| break; |
| } |
| |
| else |
| if (node->item == item) |
| break; |
| |
| |
| prev = node; |
| } |
| |
| |
| if (node) { |
| |
| if (prev) |
| prev->next = node->next; |
| |
| else |
| self->head = node->next; |
| |
| |
| if (node->next == NULL) |
| |
| self->tail = prev; |
| |
| if (self->cursor == node) |
| |
| self->cursor = prev; |
| |
| |
| if (self->autofree) |
| |
| freen (node->item); |
| |
| else |
| if (node->free_fn) |
| (node->free_fn)(node->item); |
| |
| |
| freen (node); |
| |
| self->size--; |
| } |
| } |
# 复制链表对象
| |
| duplicate all items, which must be strings. Otherwise, the list will hold |
| pointers back to the items in the original list. If list is null, returns |
| NULL. */ |
| zlist_t * |
| zlist_dup (zlist_t *self) |
| { |
| if (!self) |
| return NULL; |
| |
| zlist_t *copy = zlist_new (); |
| assert (copy); |
| |
| if (self->autofree) |
| zlist_autofree(copy); |
| |
| copy->compare_fn = self->compare_fn; |
| |
| node_t *node; |
| for (node = self->head; node; node = node->next) { |
| if (zlist_append (copy, node->item) == -1) { |
| zlist_destroy (©); |
| break; |
| } |
| } |
| return copy; |
| } |
# 清理链表所有元素
| |
| void |
| zlist_purge (zlist_t *self) |
| { |
| assert (self); |
| node_t *node = self->head; |
| while (node) { |
| node_t *next = node->next; |
| if (self->autofree) |
| freen (node->item); |
| else |
| if (node->free_fn) |
| (node->free_fn)(node->item); |
| |
| freen (node); |
| node = next; |
| } |
| self->head = NULL; |
| self->tail = NULL; |
| self->cursor = NULL; |
| self->size = 0; |
| } |
# 获得链表大小
| |
| size_t |
| zlist_size (zlist_t *self) |
| { |
| return self->size; |
| } |
# 链表排序
| |
| ascending key value using a straight ASCII comparison. If you specify |
| a compare function, this decides how items are sorted. The sort is not |
| stable, so may reorder items with the same keys. The algorithm used is |
| combsort, a compromise between performance and simplicity. */ |
| void |
| zlist_sort (zlist_t *self, zlist_compare_fn compare_fn) |
| { |
| zlist_compare_fn *compare = compare_fn; |
| if (!compare) { |
| compare = self->compare_fn; |
| if (!compare) |
| compare = (zlist_compare_fn *) strcmp; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| size_t gap = self->size; |
| bool swapped = false; |
| while (gap > 1 || swapped) { |
| if (gap > 1) |
| gap = (size_t) ((double) gap / 1.3); |
| node_t *base = self->head; |
| node_t *test = self->head; |
| size_t jump = gap; |
| while (jump--) |
| test = test->next; |
| |
| swapped = false; |
| while (base && test) { |
| if ((*compare) (base->item, test->item) > 0) { |
| |
| void *item = base->item; |
| base->item = test->item; |
| test->item = item; |
| swapped = true; |
| } |
| base = base->next; |
| test = test->next; |
| } |
| } |
| } |
# 设置比较函数
| |
| It returns an integer less than, equal to, or greater than zero if the |
| first item is found, respectively, to be less than, to match, or be |
| greater than the second item. |
| This function is used for sorting, removal and exists checking. */ |
| void |
| zlist_comparefn (zlist_t *self, zlist_compare_fn fn) |
| { |
| assert (self); |
| self->compare_fn = fn; |
| } |
# 设置元素销毁函数
| |
| destroyed, the free function, if any, is called on that item. |
| Use this when list items are dynamically allocated, to ensure that |
| you don't have memory leaks. You can pass 'free' or NULL as a free_fn. |
| Returns the item, or NULL if there is no such item. */ |
| void * |
| zlist_freefn (zlist_t *self, void *item, zlist_free_fn fn, bool at_tail) |
| { |
| node_t *node = self->head; |
| |
| if (at_tail) |
| node = self->tail; |
| |
| |
| while (node) { |
| if (node->item == item) { |
| node->free_fn = fn; |
| return item; |
| } |
| node = node->next; |
| } |
| return NULL; |
| } |
# 设置自动销毁状态
| |
| By default a list item refers to a value held elsewhere. When you set |
| this, each time you append or push a list item, zlist will take a copy |
| of the string value. Then, when you destroy the list, it will free all |
| item values automatically. If you use any other technique to allocate |
| list values, you must free them explicitly before destroying the list. |
| The usual technique is to pop list items and destroy them, until the |
| list is empty. */ |
| void |
| zlist_autofree (zlist_t *self) |
| { |
| assert (self); |
| self->autofree = true; |
| } |