redis原始碼閱讀—adlist.c
阿新 • • 發佈:2019-02-16
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;
}