1. 程式人生 > >Redis原始碼學習(1):adlist

Redis原始碼學習(1):adlist

redis中的adlist是一個簡單的無環雙向連結串列,主要邏輯在這兩個檔案中實現:

  • adlist.h
  • adlist.c

結構也很簡單,資料結構中最基本的結構。
這裡寫圖片描述
新增節點程式碼:

if (after) {
    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; } }

after控制是在old_node前面新增還是在後面新增。
adlist中實現了一個簡單的迭代器:

typedef struct listIter {
    //指向迭代方向的下一個節點
    listNode *next;
    //迭代節點
    int direction;
} listIter;

迭代器的一些方法:

//建立一個迭代器
listIter *listGetIterator(list
*list, int direction); //返回迭代器指向的節點並加一 listNode *listNext(listIter *iter); void listReleaseIterator(listIter *iter); //將迭代器指標指向頭 void listRewind(list *list, listIter *li); //將迭代器指標指向尾巴 void listRewindTail(list *list, listIter *li);

這樣可以以如下程式碼來遍歷整個連結串列:

listIter iter;
listNode *node;

listRewind(list, &
iter); while((node = listNext(&iter)) != NULL) { ...... }

因為連結串列結構是無環的,所以只需要判斷prev或者next是不是NULL就知道有沒有到兩端,缺點是沒法直接在中間某個節點重新遍歷整個連結串列。
連結串列結構提供了dup方法用於對每個節點進行拷貝。如果使用者沒有提供這個方法,那就進行淺拷貝複製指標,否則進行使用者自定義拷貝。

list *listDup(list *orig)
{
    list *copy;
    listIter iter;
    listNode *node;

    if ((copy = listCreate()) == NULL)
        return NULL;
    //複製三個輔助函式
    copy->dup = orig->dup;
    copy->free = orig->free;
    copy->match = orig->match;
    listRewind(orig, &iter);
    //遍歷連結串列
    while((node = listNext(&iter)) != NULL) {
        void *value;

        if (copy->dup) {
            value = copy->dup(node->value);
            if (value == NULL) {
                listRelease(copy);
                return NULL;
            }
        } else
            value = node->value;
        if (listAddNodeTail(copy, value) == NULL) {
            listRelease(copy);
            return NULL;
        }
    }
    return copy;
}