adlist是redis实现的双端链表,这个双端链表和数据结构中的双链表类似。双端链表list有一个指向链表和一个指向链表尾的指针,list还包括一些函数指针。

如:void *(*dup)(void *ptr);          dup是一个函数指针,它指向的这个函数返回值是void *,参数是void *ptr

adlist.h

/* adlist.h - A generic doubly linked list implementation** Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>* All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are met:**   * Redistributions of source code must retain the above copyright notice,*     this list of conditions and the following disclaimer.*   * Redistributions in binary form must reproduce the above copyright*     notice, this list of conditions and the following disclaimer in the*     documentation and/or other materials provided with the distribution.*   * Neither the name of Redis nor the names of its contributors may be used*     to endorse or promote products derived from this software without*     specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE* POSSIBILITY OF SUCH DAMAGE.*/#ifndef __ADLIST_H__
#define __ADLIST_H__//双端链表实现:有一个指向表头的节点,有一个指向表尾的节点/* Node, List, and Iterator are the only data structures used currently. */typedef struct listNode { //双端链表节点struct listNode *prev;  // 前置节点struct listNode *next;  // 后置节点void *value;    // 节点的值
} listNode;typedef struct listIter { //双端链表迭代器listNode *next; // 当前迭代到的节点int direction;  // 迭代的方向
} listIter;typedef struct list { //双端链表结构listNode *head; // 表头节点listNode *tail; // 表尾节点void *(*dup)(void *ptr);  // 节点值复制函数void (*free)(void *ptr);  // 节点值释放函数int (*match)(void *ptr, void *key); // 节点值对比函数unsigned long len;  // 链表所包含的节点数量
} list; /* Functions implemented as macros */
#define listLength(l) ((l)->len)
#define listFirst(l) ((l)->head)
#define listLast(l) ((l)->tail)
#define listPrevNode(n) ((n)->prev)
#define listNextNode(n) ((n)->next)
#define listNodeValue(n) ((n)->value)#define listSetDupMethod(l,m) ((l)->dup = (m))
#define listSetFreeMethod(l,m) ((l)->free = (m))
#define listSetMatchMethod(l,m) ((l)->match = (m))#define listGetDupMethod(l) ((l)->dup)
#define listGetFree(l) ((l)->free)
#define listGetMatchMethod(l) ((l)->match)/* Prototypes */
list *listCreate(void);
void listRelease(list *list);
void listEmpty(list *list);
list *listAddNodeHead(list *list, void *value);
list *listAddNodeTail(list *list, void *value);
list *listInsertNode(list *list, listNode *old_node, void *value, int after);
void listDelNode(list *list, listNode *node);
listIter *listGetIterator(list *list, int direction);
listNode *listNext(listIter *iter);
void listReleaseIterator(listIter *iter);
list *listDup(list *orig);
listNode *listSearchKey(list *list, void *key);
listNode *listIndex(list *list, long index);
void listRewind(list *list, listIter *li);
void listRewindTail(list *list, listIter *li);
void listRotate(list *list);
void listJoin(list *l, list *o);/* Directions for iterators */
#define AL_START_HEAD 0
#define AL_START_TAIL 1#endif /* __ADLIST_H__ */

adlist.c

/* adlist.c - A generic doubly linked list implementation** Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>* All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions are met:**   * Redistributions of source code must retain the above copyright notice,*     this list of conditions and the following disclaimer.*   * Redistributions in binary form must reproduce the above copyright*     notice, this list of conditions and the following disclaimer in the*     documentation and/or other materials provided with the distribution.*   * Neither the name of Redis nor the names of its contributors may be used*     to endorse or promote products derived from this software without*     specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE* POSSIBILITY OF SUCH DAMAGE.*/#include <stdlib.h>
#include "adlist.h"
#include "zmalloc.h"/* Create a new list. The created list can be freed with* AlFreeList(), but private value of every node need to be freed* by the user before to call AlFreeList().** On error, NULL is returned. Otherwise the pointer to the new list. */
list *listCreate(void)  //创建一个新的链表
{struct list *list;if ((list = zmalloc(sizeof(*list))) == NULL)return NULL;list->head = list->tail = NULL;list->len = 0;list->dup = NULL;list->free = NULL;list->match = NULL;return list;
}/* Remove all the elements from the list without destroying the list itself. */
void listEmpty(list *list)
{unsigned long len;listNode *current, *next;current = list->head;//表头节点   len = list->len;while(len--) {next = current->next;if (list->free) list->free(current->value);  //释放节点对应的值zfree(current); //释放节点current = next;}list->head = list->tail = NULL;list->len = 0;
}/* Free the whole list.** This function can't fail. */
void listRelease(list *list)
{listEmpty(list);zfree(list);
}/* Add a new node to the list, to head, containing the specified 'value'* pointer as value.** On error, NULL is returned and no operation is performed (i.e. the* list remains unaltered).* On success the 'list' pointer you pass to the function is returned. */
list *listAddNodeHead(list *list, void *value)  //头部增加
{listNode *node;if ((node = zmalloc(sizeof(*node))) == NULL)return NULL;node->value = value;if (list->len == 0) {list->head = list->tail = node;node->prev = node->next = NULL;} else {node->prev = NULL;node->next = list->head;list->head->prev = node;list->head = node;}list->len++;return list;
}/* Add a new node to the list, to tail, containing the specified 'value'* pointer as value.** On error, NULL is returned and no operation is performed (i.e. the* list remains unaltered).* On success the 'list' pointer you pass to the function is returned. */
list *listAddNodeTail(list *list, void *value)
{listNode *node;if ((node = zmalloc(sizeof(*node))) == NULL)return NULL;node->value = value;if (list->len == 0) {list->head = list->tail = node;node->prev = node->next = NULL;} else {node->prev = list->tail;node->next = NULL;list->tail->next = node;list->tail = node;}list->len++;return list;
}/*创建一个包含值value的新节点,并将它插入到old_node的之前或之后
如果after为 0 ,将新节点插入到old_node之前。
如果after为 1 ,将新节点插入到old_node之后*/
list *listInsertNode(list *list, listNode *old_node, void *value, int after) {listNode *node;if ((node = zmalloc(sizeof(*node))) == NULL)return NULL;node->value = value;if (after) { //节点插入到old_node之前node->prev = old_node;node->next = old_node->next;if (list->tail == old_node) {list->tail = node;}} else { //新节点插入到old_node之后node->next = old_node;node->prev = old_node->prev;if (list->head == old_node) {list->head = node;}}if (node->prev != NULL) {node->prev->next = node;}if (node->next != NULL) {node->next->prev = node;}list->len++;return list;
}/* Remove the specified node from the specified list.* It's up to the caller to free the private value of the node.** This function can't fail. */
void listDelNode(list *list, listNode *node)
{if (node->prev)node->prev->next = node->next;elselist->head = node->next;if (node->next)node->next->prev = node->prev;elselist->tail = node->prev;if (list->free) list->free(node->value);zfree(node);list->len--;
}/* Returns a list iterator 'iter'. After the initialization every* call to listNext() will return the next element of the list.** This function can't fail. */
//为给定链表创建一个迭代器,之后每次对这个迭代器调用 listNext 都返回被迭代到的链表节点
listIter *listGetIterator(list *list, int direction)//direction 参数决定了迭代器的迭代方向
{listIter *iter;if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;if (direction == AL_START_HEAD)iter->next = list->head;elseiter->next = list->tail;iter->direction = direction;return iter;
}/* Release the iterator memory */
void listReleaseIterator(listIter *iter) {zfree(iter);
}/* Create an iterator in the list private iterator structure */
void listRewind(list *list, listIter *li) {li->next = list->head;li->direction = AL_START_HEAD;
}void listRewindTail(list *list, listIter *li) {li->next = list->tail;li->direction = AL_START_TAIL;
}/* Return the next element of an iterator.* It's valid to remove the currently returned element using* listDelNode(), but not to remove other elements.** The function returns a pointer to the next element of the list,* or NULL if there are no more elements, so the classical usage patter* is:** iter = listGetIterator(list,<direction>);* while ((node = listNext(iter)) != NULL) {*     doSomethingWith(listNodeValue(node));* }* */
listNode *listNext(listIter *iter)//返回迭代器当前所指向的节点
{listNode *current = iter->next;if (current != NULL) {if (iter->direction == AL_START_HEAD)iter->next = current->next;elseiter->next = current->prev;}return current;
}/* Duplicate the whole list. On out of memory NULL is returned.* On success a copy of the original list is returned.** The 'Dup' method set with listSetDupMethod() function is used* to copy the node value. Otherwise the same pointer value of* the original node is used as value of the copied node.** The original list both on success or error is never modified. */
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); //使iter指向list->headwhile((node = listNext(&iter)) != NULL) {void *value;if (copy->dup) {value = copy->dup(node->value);if (value == NULL) {listRelease(copy);return NULL;}} elsevalue = node->value;if (listAddNodeTail(copy, value) == NULL) {listRelease(copy);return NULL;}}return copy;
}/* Search the list for a node matching a given key.* The match is performed using the 'match' method* set with listSetMatchMethod(). If no 'match' method* is set, the 'value' pointer of every node is directly* compared with the 'key' pointer.** On success the first matching node pointer is returned* (search starts from head). If no matching node exists* NULL is returned. */
listNode *listSearchKey(list *list, void *key)//查找链表 list 中值和 key 匹配的节点
{listIter iter;listNode *node;listRewind(list, &iter);while((node = listNext(&iter)) != NULL) {if (list->match) {if (list->match(node->value, key)) {return node;}} else {if (key == node->value) {return node;}}}return NULL;
}/* Return the element at the specified zero-based index* where 0 is the head, 1 is the element next to head* and so on. Negative integers are used in order to count* from the tail, -1 is the last element, -2 the penultimate* and so on. If the index is out of range NULL is returned. */
listNode *listIndex(list *list, long index) {//返回链表在给定索引上的值;-1是最后一个元素,-2是倒数第二个listNode *n;if (index < 0) {index = (-index)-1;n = list->tail;while(index-- && n) n = n->prev;} else {n = list->head;while(index-- && n) n = n->next;}return n;
}/* Rotate the list removing the tail node and inserting it to the head. */
void listRotate(list *list) { /*旋转列表,删除尾节点并将其插入到头部*/listNode *tail = list->tail;if (listLength(list) <= 1) return;/* Detach current tail */list->tail = tail->prev;list->tail->next = NULL;/* Move it as head */list->head->prev = tail;tail->prev = NULL;tail->next = list->head;list->head = tail;
}/* Add all the elements of the list 'o' at the end of the* list 'l'. The list 'other' remains empty but otherwise valid. */
void listJoin(list *l, list *o) {  //将 o 连到 l 后面,然后释放 oif (o->head)o->head->prev = l->tail;if (l->tail)l->tail->next = o->head;elsel->head = o->head;if (o->tail) l->tail = o->tail;l->len += o->len;/* Setup other as an empty list. */o->head = o->tail = NULL;o->len = 0;
}

redis之adlist.c相关推荐

  1. npoi导出文件不保存在服务器,winform NPOI excel 导出并选择保存文件路径

    public void ExcelOp(DataGridView gdv,ArrayList selHead) { if (selHead.Count==0) { MessageBox.Show(&q ...

  2. redis源码笔记-adlist

    adlist是redis自己是实现的一个通用的双向链表. ------------------------------------------------adlist.h--------------- ...

  3. 安装redis出现cc adlist.o /bin/sh:1:cc:not found

    安装redis时 提示执行make命令时, 提示 CC adlist.o /bin/sh: cc: 未找到命令 问题原因:这是由于系统没有安装gcc环境,因此在进行编译时才会出现上面提示,当安装好gc ...

  4. Redis源码阅读-Adlist双向链表

    Redis源码阅读-链表部分- 链表数据结构在Adlist.h   Adlist.c Redis的链表是双向链表,内部定义了一个迭代器. 双向链表的函数主要是链表创建.删除.节点插入.头插入.尾插入. ...

  5. redis源码剖析(2):基础数据结构ADLIST

    目录 1.ADList概述 2.链表和链表节点定义 3.链表迭代器 4.总结 1.ADList概述        ADList(A generic doubly linked list)是 redis ...

  6. 安装redis时 提示执行make命令时提示 CC adlist.o /bin/sh: cc: 未找到命令

    安装redis时 提示执行make命令时提示 CC adlist.o /bin/sh: cc: 未找到命令 问题原因:这是由于系统没有安装gcc环境,因此在进行编译时才会出现上面提示,当安装好gcc后 ...

  7. 在Linux系统上安装Redis客户端报错:In file included from adlist.c:34 zmalloc.h:50:31: error: jemalloc......

    在Centos6.9系统上安装redis客户端时报错,步骤如下: 1.下载redis客户端源码包: wget  http://download.redis.io/releases/redis-3.0. ...

  8. Centos7 安装Redis,报错[adlist.o] Error jemalloc/jemalloc.h: No such file or directory

    redis官网 https://redis.io/download 安装 $ wget http://download.redis.io/releases/redis-5.0.4.tar.gz $ t ...

  9. Redis安装与调试

     Redis安装与调试 Redis安装与调试linux版本:64位CentOS 6.5 Redis版本:2.8.17  (更新到2014年10月31日) Redis官网:http://redis. ...

最新文章

  1. 基于 Java NIO 实现简单的 HTTP 服务器
  2. maven项目发布到tomcat里lib包没有发布的问题
  3. javascript数组去重方法性能测试比较
  4. Android系统架构开篇
  5. Solaris 的防火墙ipfilter设置
  6. php删除数组中的空行,php处理文件的思考(去除空行、每行多余字符)
  7. ctf xor题_CTF下的命令执行
  8. 用java输出语句_Java的常用输入输出语句
  9. Android应用程序开发
  10. 点餐推荐系统_类似美团外卖点餐系统APP开发平台模式
  11. 洛谷P5708 【深基2.习2】三角形面积__C++描述
  12. html css 浏览器 响应式 面试题持续更新!
  13. Windows XP使用技巧大全
  14. dos下拷贝服务器文件命令行,win7在DOS环境下怎么使用copy命令?使用copy命令复制文件的方法...
  15. 行人轨迹论文:STUGCN:A Social Spatio-Temporal Unifying Graph Convolutional Network for Trajectory Predictio
  16. 知识社会的到来:知识管理与知识协同
  17. python画水平线和垂直线横线 纵线
  18. 前端开发的workers——web workers、share workers和service workers
  19. java paint绘图添加组件不能显示_JAVA JFrame Graphics绘画不显示问题
  20. 大学——留德的路01

热门文章

  1. 【Android RTMP】RTMPDump 推流过程 ( 独立线程推流 | 创建推流器 | 初始化操作 | 设置推流地址 | 启用写出 | 连接 RTMP 服务器 | 发送 RTMP 数据包 )
  2. python3.6+RF环境搭建
  3. Redis主从+KeepAlived实现高可用
  4. 欢迎关注我的微信公众号 “我是一个假的程序猿”
  5. android 原色调渲染
  6. AlertDialog.Builder选择对话框
  7. Item 14: 如果函数不会抛出异常就把它们声明为noexcept
  8. entity.Database.SqlQuery() 和entity.Database.SqlCommand()
  9. 【视频】SQL Server 2008 R2 StreamInsight - 多源复杂事件处理
  10. Chrome 的又一个bug?