The two-way linked list implemented by Redis is easy to understand. Its implementation principle is classic and the code is neat and clear. The following is a part of the translation of its source code comments and my comments. If you are biased, please note: * adlist. h
The two-way linked list implemented by Redis is easy to understand. Its implementation principle is classic and the code is neat and clear. The following is a part of the translation of its source code comments and my comments. If you are biased, please refer to/* adlist. h-implementation of universal two-way linked list */# ifndef _ ADLIST_H __# define _ ADLIST_H _/* The current data structure only uses
The two-way linked list implemented by Redis is easy to understand. Its implementation principle is classic and the code is neat and clear.
The following is a part of the translation of its source code comments and my opinions. If you are biased, please correct me:
/* Adlist. h-implementation of universal two-way linked List */# ifndef _ ADLIST_H __# define _ ADLIST_H _/* The current data structure only uses Node, List, and Iterator. * // * list node */typedef struct listNode {struct listNode * prev; // forward pointer struct listNode * next; // backward pointer void * value; // current node value} listNode;/* list iterator */typedef struct listIter {listNode * next; // node pointer int direction; // iteration direction} listIter; /* linked list structure */typedef struct list {listNode * head; // header node listNode * tail; // End Node void * (* dup) (void * ptr ); // copy function void (* free) (void * ptr); // release function int (* match) (void * ptr, void * key ); // pair function unsigned long len; // number of nodes} list;/* FUNCTION macro definition */# define listLength (l)-> len) // chain table length # define listFirst (l)-> head) // head node of the chain table # define listLast (l)-> tail) // The End Node of the linked list # define listPrevNode (n)-> prev) // The precursor node of the specified node # define listNextNode (n)-> next) // specify the successor node of the node # define listNodeValue (n)-> value) // specify the value of the node/* function pointer, set the custom method of the external call module */# define listSetDupMethod (l, m) (l)-> dup = (m )) // copy the linked list # define listSetFreeMethod (l, m) (l)-> free = (m) // release the linked list # define listSetMatchMethod (l, m) (l) -> match = (m) // match/* function pointer to obtain the custom method of the external call module */# define listGetDupMethod (l) -> dup) // obtain the custom replication method # define listGetFree (l)-> free) // obtain the released custom method # define listGetMatchMethod (l) (l)-> match) // obtain the matched custom method/* function prototype */list * listCreate (void ); // create the linked list void listRelease (list * list); // release the linked list * listAddNodeHead (list * list, void * value ); // Add the node list * listAddNodeTail (list * list, void * value) to the header; // Add the node list * listInsertNode (list * list, listNode * old_node, void * value, int after); // Add the node void listDelNode (list * list, listNode * node) after the specified position; // Delete the node listIter * listGetIterator (list * list, int direction); // obtain the listNode * listNext (listIter * iter) of the list iterator; // obtain the void listReleaseIterator (listIter * iter) of the next node ); // release list iterator list * listDup (list * orig); // copy the listNode * listSearchKey (list * list, void * key) of the linked list ); // query the listNode * listIndex (list * list, long index) for the given key; // void listRewind (list * list, listIter * li) for the given index query node ); // The iterator Pointer Points to the header node void listRewindTail (list * list, listIter * li) again; // The iterator Pointer Points to the last node void listRotate (list * list) again ); // flip the linked list and move the last node to the first node/* iteration direction of the iterator */# define AL_START_HEAD 0 # define AL_START_TAIL 1 # endif/* _ ADLIST_H __*/
/* Adlist. c-implementation of universal two-way linked list */# include
# Include "adlist. h "# include" zmalloc. h "/* Create a New linked list. the newly created linked list can be released using the * AlFreeList () function. However, before calling this function, you must manually release the private value space for each node. ** if an error occurs, NULL is returned, otherwise, the pointer */list * listCreate (void) {struct list * list is returned; if (list = zmalloc (sizeof (* list) = NULL) // use zmalloc encapsulated on malloc to apply for memory return NULL; list-> head = list-> tail = NULL; list-> len = 0; list-> dup = NULL; list-> free = NULL; list-> match = NULL; return list;}/* release the linked list. This method cannot fail. **/Void listRelease (list * list) {unsigned long len; listNode * current, * next; current = list-> head; len = list-> len; while (len --) {next = current-> next; if (list-> free) list-> free (current-> value ); // The space pointed to by each node will be released zfree (current); // zfree is based on the encapsulation of current = next;} zfree (list );} /* Insert the node containing the value pointed by the pointer into the head of the linked list. ** if an error occurs, NULL is returned and no operation is performed on the linked list. ** if the operation succeeds, the linked list pointer is returned. */list * listAddNodeHead (list * list, void * value) {ListNode * node; if (node = zmalloc (sizeof (* node) = NULL) return NULL; node-> value = value; if (list-> len = 0) {list-> head = list-> tail = node; node-> prev = node-> next = NULL ;} else {node-> prev = NULL; node-> next = list-> head; list-> head-> prev = node; list-> head = node ;} list-> len ++; return list;}/* Insert the node containing the pointer to the end of the linked list. * if an error occurs, NULL is returned and no operations are performed on the linked list, ** if successful, the linked list pointer is returned. */list * listAddNodeTail (lis T * list, void * value) {listNode * node; if (node = zmalloc (sizeof (* node) = NULL) return NULL; node-> value = value; if (list-> len = 0) {list-> head = list-> tail = node; node-> prev = node-> next = NULL;} else {node-> prev = list-> tail; node-> next = NULL; list-> tail-> next = node; list-> tail = node;} list-> len ++; return list ;} /* Insert a new node to the front or back of a node in the linked list. * if an error occurs, NULL is returned and no operation is performed on the linked list. ** if the operation succeeds, the linked list pointer is returned. */list * ListInsertNode (list * list, listNode * old_node, void * value, int after) {listNode * node; if (node = zmalloc (sizeof (* node) = NULL) return NULL; node-> value = value; if (after) {// after! = 0 indicates that the node is inserted after the old node; otherwise, node-> prev = old_node; node-> next = old_node-> next; if (list-> tail = old_node) {list-> tail = node ;}} else {node-> next = old_node; node-> prev = old_node-> prev; if (list-> head = old_node) {list-> head = node;} if (node-> prev! = NULL) {node-> prev-> next = node;} if (node-> next! = NULL) {node-> next-> prev = node;} list-> len ++; return list;}/* delete a node from the linked list. * The underlying function is called to release the Node space. ** this method cannot fail. */void listDelNode (list * list, listNode * node) {if (node-> prev) node-> prev-> next = node-> next; else list-> head = node-> next; if (node-> next) node-> next-> prev = node-> prev; else list-> tail = node-> prev; if (list-> free) list-> free (node-> value); zfree (node ); list-> len --;}/* Get the iterator object 'iter '. after initialization * Each call to listNext () will return the next element of the linked list. ** this method cannot fail. */listIter * listGetIterator (list * list, int direction) {listIter * iter; if (iter = zmalloc (sizeof (* iter) = NULL) return NULL; if (direction = AL_START_HEAD) iter-> next = list-> head; else iter-> next = list-> tail; iter-> direction = direction; return iter ;} /* release the space of the iterator object */void listReleaseIterator (listIter * iter) {zfree (iter);}/* re-point the iterator pointer to the header */void listRew Ind (list * list, listIter * li) {li-> next = list-> head; li-> direction = AL_START_HEAD ;} /* repoint the iterator pointer to the end of the table */void listRewindTail (list * list, listIter * li) {li-> next = list-> tail; li-> direction = AL_START_TAIL;}/* gets the next element of the iterator. * The listDelNode () method can be used to delete the currently returned node, but other nodes cannot be deleted. ** If successful, the next element of the iterator is returned. Otherwise, NULL is returned. * we recommend that you use the following: ** iter = listGetIterator (list,
); * While (node = listNext (iter ))! = NULL) {* doSomethingWith (listNodeValue (node); *} ***/listNode * listNext (listIter * iter) {listNode * current = iter-> next; if (current! = NULL) {if (iter-> direction = AL_START_HEAD) iter-> next = current-> next; else iter-> next = current-> prev;} return current ;} /* copy the entire linked list. * If the operation succeeds, the copied linked list pointer is returned. Otherwise, NULL is returned. ** the replication method is specified by listSetDupMethod (). * If the dup method is not specified, the value of the original node is completely copied. ** the original linked list will not be changed. */list * listDup (list * orig) // you have a question: Since you need to keep the original linked list unchanged, why not add const? {List * copy; listIter * iter; listNode * node; if (copy = listCreate () = NULL) return NULL; copy-> dup = orig-> dup; copy-> free = orig-> free; copy-> match = orig-> match; iter = listGetIterator (orig, AL_START_HEAD); while (node = listNext (iter ))! = NULL) {void * value; if (copy-> dup) {value = copy-> dup (node-> value); if (value = NULL) {listRelease (copy); listReleaseIterator (iter); return NULL ;}} else value = node-> value; if (listAddNodeTail (copy, value) = NULL) {listRelease (copy); listReleaseIterator (iter); return NULL ;}} listReleaseIterator (iter); return copy ;}/ * specifies a key to locate a node. * You can use listSetMatchMethod () to specify the matching method for the search node. * If the external call module does not specify a match Method to directly compare the key value and the value pointed to by the node pointer in the linked list. ** if normal, the first matched node pointer is returned. If no matching element is found, NULL is returned. */listNode * listSearchKey (list * list, void * key) {listIter * iter; listNode * node; iter = listGetIterator (list, AL_START_HEAD ); while (node = listNext (iter ))! = NULL) {if (list-> match) {// use the custom match method if (list-> match (node-> value, key )) {listReleaseIterator (iter); return node ;}} else {// directly compare the value if (key = node-> value) {listReleaseIterator (iter); return node ;}}} listReleaseIterator (iter); // release the iter object return NULL;}/* Get the element based on index. * If the input index is not negative, it indicates positive iteration: 0 indicates the first node, 1 indicates the next node, and so on. * if it is a negative value, it is reverse iteration:-1 is the last node,-2 is the second to last node, and so on * If the index is out of bounds, NULL is returned. */listNode * listIndex (list * list, long index) {listNode * n; if (index <0) {index = (-index)-1; n = list-> tail; while (index -- & n) n = n-> prev;} else {n = list-> head; while (index -- & n) n = n-> next;} return n;}/* flip the linked list and insert the last node into the linked list header. */void listRotate (list * list) {listNode * tail = list-> tail; if (listLength (list) <= 1) return; /* remove the current last node from the linked list */list-> tail = tail-> prev; list-> tail-> next = NULL; /* Insert the last node into the head of the linked list */list-> head-> prev = tail; tail-> prev = NULL; tail-> next = list-> head; list-> head = tail ;}
You need to continue to understand the following two points:
1) Since the creation and destruction of the list space in the source code is completed through zmalloc and zfree of the zmalloc module, how does zmalloc implement it?
2) I'm curious that so many object pointers do not have the const limit. Why can I omit it?