libevent base file compat/sys/queue.h

This file implements five data structures, all of which are implemented with macro definitions.

slist: simple linked list

list: The node has one more secondary pointer than a simple linked list

The head pointer of the queue also declares a secondary pointer sqh_last to hold the address of the next pointer of the last element in the queue, the purpose of which is:

When we insert data at the end of the queue, it is very convenient, we don't have to traverse the last node from the head pointer, and then copy the address of the node to be inserted to the next pointer of the last node. Because *(head->sqh_last) means the next pointer of the last node. The node of the tail queue has one more second-level pointer cqe_prev than the simple queue. The reason is the same as the list.

This should count as an improved singly linked list. If you have to use the container_of macro to be called twice, it can also be used as a double linked list.
140 #define LIST_HEAD(name, type) \
141 struct name { \
142 struct type *lh_first; /* first element */ \
143 }
144 
145 #define LIST_HEAD_INITIALIZER(head) \
146 { NULL }
147 
148 #define LIST_ENTRY(type ) \
149 struct { \
150 struct type *le_next; /* next element */ \
151 struct type **le_prev; /* address of previous next element */ \
152 }

This definition method and our commonly used definition method his Why aren't benefits
defined this way?

140 #define LIST_HEAD(name, type) \
141 struct name { \
142 struct type *lh_first; /* first element */ \
143 }
144 
145 #define LIST_HEAD_INITIALIZER(head) \
146 { NULL }
147 
148 #define LIST_ENTRY(type) \
149 struct { \
150 struct type * le_next; /* next element */ \
151 struct type *le_prev; /* here */ \
152 }


I thought about it, the advantage of the former definition method should be:
it is easy to use when inserting. Mainly, it is convenient to insert or delete the element pointed by the head, and it can also retain the validity of the head.
For example, this is a macro
182 when inserting in front of an element #define LIST_INSERT_BEFORE(listelm, elm, field) do { \
183 (elm)->field.le_prev = (listelm)->field.le_prev; \
184 (elm)->field.le_next = (listelm); \
185 *(listelm)->field.le_prev = (elm); \
186 (listelm)->field.le_prev = &(elm)->field.le_next ; \
187 } while (0)

In this way, even if the listelm in the linked list is pointed to by head->lh_first, the head will change after insertion. Because first->lh_first->le_prev == &first->lh_first

but if the usual double-linked list definition is used, head->lh_first cannot be changed! Because there is no way to get a pointer to head->lh_first. And the former has.

In the linux kernel, struct hlist is defined almost like this.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325398121&siteId=291194637