1. 程式人生 > >redis原始碼閱讀—adlist.c

redis原始碼閱讀—adlist.c

adlist.c

adlist.c檔案中主要是一些雙向連結串列的操作的實現。

listCreate函式

//listCreate函式類似於一個list的建構函式
//直接通過zmalloc函式申請list大小的空間,並且將pre,next指標都置為NULL
//另外,dup,free,match函式指標也設定為NULL
list *listCreate(void)
{
    struct list *list;

    if ((list = zmalloc(sizeof(*list))) == NULL)		//申請空間
        return NULL;									//申請失敗的時候返回NULL
list->head = list->tail = NULL; list->len = 0; list->dup = NULL; list->free = NULL; list->match = NULL; return list; }

listEmpty函式

listEmpty函式作用是移除所有的元素,但是保留list本身

void listEmpty(list *list)
{
    unsigned long len;		//list長度
    listNode *current, *next;
//兩個指標一個儲存當前節點,一個指向next節點 current = list->head; //將current置為list的頭結點 len = list->len; //len設定為list的len while(len--) { next = current->next; if (list->free) list->free(current->value); //呼叫struct內部的free函式 zfree(current); //刪除節點 current =
next; //current 設定為next } list->head = list->tail = NULL; //頭尾節點轉為NULL list->len = 0; //長度設定為0 }

listRelease函式

//這個函式比較簡單,先呼叫listEmpty函式,後直接zfree掉整個list
void listRelease(list *list)
{
    listEmpty(list);
    zfree(list);
}

listAddNodeHead函式

listAddNodeHead函式作用是將個值為valus的node插入到list的頭部
類似於STL中的push_front()函式

//將一個value插入list頭部
list *listAddNodeHead(list *list, void *value)
{
    listNode *node;		//新的節點node

	//為節點申請空間,如果申請失敗的話直接返回NULL
    if ((node = zmalloc(sizeof(*node))) == NULL)
        return NULL;
    node->value = value;			//node的value設定為value
	
	//如果list為空,那麼list的頭指標和尾指標都為node,並且node的前向指標與後向指標都為NULL
    if (list->len == 0) {
        list->head = list->tail = node;
        node->prev = node->next = NULL;
    } else {
        node->prev = NULL;		//node的prev指標指向NULL
        node->next = list->head;	//node的next指標指向以前的頭指標
        list->head->prev = node;		//head的prev指標指向node
        list->head = node;		//更新head
    }
    list->len++;		//長度增加
    return list;
}

listAddNodeTail函式

與listAddNodeHead函式對應,是在list尾部插入一個值為value的節點,具體實現方式與listAddNodeHead也基本類似

list *listAddNodeTail(list *list, void *value)
{
	//同樣的申請空間
    listNode *node;

    if ((node = zmalloc(sizeof(*node))) == NULL)
        return NULL;
    node->value = value;
	//如果list為空,那麼直接head和tail節點都是node
    if (list->len == 0) {
        list->head = list->tail = node;
        node->prev = node->next = NULL;
    } else {
		//否則將tail節點指向node之後更新tail節點
        node->prev = list->tail;
        node->next = NULL;
        list->tail->next = node;
        list->tail = node;
    }
    list->len++;
    return list;
}

listInsertNode函式

listInsertNode函式作用主要是在指定節點之前或者之後插入一個新的節點,
這裡引入了一個after變數,如果after變數為0,那麼就是在指定節點之前插入,否則
就在指定節點之後插入一個新的節點

程式碼如下:

list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
	//node就是新節點,依舊是先為新節點分配記憶體
    listNode *node;

    if ((node = zmalloc(sizeof(*node))) == NULL)
        return NULL;
    node->value = value;

	//如果afer不為零的話,那麼就是在old_node之後插入新節點
    if (after) {
        node->prev = old_node;		//node的prev指標指向old_node
        node->next = old_node->next;		//node的next指標指向old_node的下一個節點
        if (list->tail == old_node) {		//如果old_node之前是作為list的尾節點,那麼此時更新一次尾節點
            list->tail = node;
        }
	//如果after為0,那麼就在old_node之前插入節點
    } else {
        node->next = old_node;			
        node->prev = old_node->prev;
        if (list->head == old_node) {
            list->head = node;
        }
    }

	//這裡的操作是將node和old_node連線起來
	//例如,node插入到old_node之後,此時僅僅設定了node -> prev = old_node,還需要設定old_node -> next = node,所以就有了下述兩個操作
    if (node->prev != NULL) {
        node->prev->next = node;
    }
    if (node->next != NULL) {
        node->next->prev = node;
    }
    list->len++;
    return list;
}

listDelNode

listDelNode是list中刪除節點的函式

//操作就是基本的雙向連結串列的刪除操作
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--;
}

listGetIterator

listGetIterator函式將根據型別返回一個迭代器

listIter *listGetIterator(list *list, int direction)
{

	//宣告一個迭代器並且為其分配記憶體
    listIter *iter;

    if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
	//根據direction初始化迭代器
    if (direction == AL_START_HEAD)
        iter->next = list->head;
    else
        iter->next = list->tail;
    iter->direction = direction;
    return iter;
}

listReleaseIterator

釋放迭代器操作,利用zfree釋放迭代器

void listReleaseIterator(listIter *iter) {
    zfree(iter);
}

listRewind

重置迭代器

//將迭代器li重置為正向迭代器
void listRewind(list *list, listIter *li) {
    li->next = list->head;
    li->direction = AL_START_HEAD;
}

listRewindTail

將迭代去重置為逆向迭代器

void listRewindTail(list *list, listIter *li) {
    li->next = list->tail;
    li->direction = AL_START_TAIL;
}

listNext

listNext函式的主要作用是根據返回迭代器指向的下一個元素
並且迭代器的指向將會發生移動

listNode *listNext(listIter *iter)
{

	//得到iter指向的節點
    listNode *current = iter->next;
	
	//如果current不為NULL的話,迭代器將會根據方向發生移動
    if (current != NULL) {
        if (iter->direction == AL_START_HEAD)
            iter->next = current->next;
        else
            iter->next = current->prev;
    }
    return current;
}
#### listDup

listDup的作用是複製整個list,如果記憶體溢位的話,將會返回
NULL。否則將會返回新list

list *listDup(list *orig)
{
	//先宣告一個list為copy,並且為其分配空間
    list *copy;
    listIter iter;
    listNode *node;
	
if ((copy = listCreate()) == NULL)
    return NULL;
//成員函式指標的複製
copy->dup = orig->dup;
copy->free = orig->free;
copy->match = orig->match;
//初始化迭代器,通過迭代器來遍歷list,並且複製每一個節點
listRewind(orig, &iter);
while((node = listNext(&iter)) != NULL) {
    void *value;
	//如果存在節點複製函式,那麼直接使用節點複製函式複製即可
    if (copy->dup) {
        value = copy->dup(node->value);
        if (value == NULL) {
			//複製失敗的情況下,返回NULL
            listRelease(copy);
            return NULL;
        }
    } else
		//如果沒有節點複製函式的話,那麼就直接賦值
        value = node->value;
	//加入尾部
    if (listAddNodeTail(copy, value) == NULL) {
        listRelease(copy);
        return NULL;
    }
}
return copy;

}

listSearchKey

在list中搜索key值

listNode *listSearchKey(list *list, void *key)
{
    listIter iter;		//依舊是通過迭代器來遍歷
    listNode *node;

    listRewind(list, &iter);
    while((node = listNext(&iter)) != NULL) {
        if (list->match) {		//如果存在match函式,那麼直接使用match函式
            if (list->match(node->value, key)) {
                return node;
            }
        } else {	
			//如果不存在match函式的話,直接對比既可
            if (key == node->value) {
                return node;
            }
        }
    }
    return NULL;
}

listIndex 返回指定下標的節點

這裡的index為0的情況下表示頭結點,為1的情況下表示第二個節點以此類推
同理,在index為負數的情況下表示從尾部開始搜尋,如果index為-1的情況下,表示tail節點。以此類推

listNode *listIndex(list *list, long index) {
    listNode *n;

	//如果index < 0,那麼就是從後往前搜尋。
    if (index < 0) {
        index = (-index)-1;	//注意這裡的-1操作,因為index = -1表示tail節點
        n = list->tail;
        while(index-- && n) n = n->prev;
    } else {
        n = list->head;
        while(index-- && n) n = n->next;
    }
    return n;
}

listRotate

listRotate的作用是將尾節點旋轉到頭部

void listRotate(list *list) {
    listNode *tail = list->tail;		//獲取尾節點

    if (listLength(list) <= 1) return;	//如果長度小於等於1的話,無需操作

    list->tail = tail->prev;		//先更新尾節點
    list->tail->next = NULL;		//新的尾節點後置為NULL
    list->head->prev = tail;		//將tail插入頭部
    tail->prev = NULL;
    tail->next = list->head;
    list->head = tail;				//更新head
}

listJoin

listJoin函式作用是將兩個list連線起來

//將o連線在l的尾部
void listJoin(list *l, list *o) {
    if (o->head)		//如果o連結串列不為空的話,直接將o->head連線在l->tail後面即可
        o->head->prev = l->tail;
    if (l->tail)		//如果l的尾節點不為空,那麼tail指向o -> head
        l->tail->next = o->head;
    else
		//否則l為空,直接將o的head賦值給l-> head既可
        l->head = o->head;
    if (o->tail) l->tail = o->tail;		//更新l -> tail
    l->len += o->len;		//更新長度

    o->head = o->tail = NULL;		//o連結串列置零(因為連線之後僅剩一條連結串列了)
    o->len = 0;
}