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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值