Redis原始碼學習(1):adlist
阿新 • • 發佈:2019-01-23
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;
}