0. 前言

  Redis 中的链表是以通用链表的形式实现的,而对于链表的用途来说,主要的功能就是增删改查,所以对于查找来说,redis其提供了一个match函数指针,用户负责实现其具体的匹配操作,从而实现通用化。

  涉及的文件:adlist.h/adlist.c

1. 数据结构

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); //用于复制ptr值,实现深度复制
void (*free)(void *ptr); //释放对应类型结构的内存
int (*match)(void *ptr, void *key); //自定义匹配key
unsigned long len; //节点数量
} list;

 

#define listSetDupMethod(l,m) ((l)->dup = (m))
#define listSetFreeMethod(l,m) ((l)->free = (m))
#define listSetMatchMethod(l,m) ((l)->match = (m))

  其中提供了dup,free,match的函数指针,用户可以通过设置该函数指针,来存取特定类型的数据。

2. API实现:

  只提取几个主要的API,该文件完整的注释在GitHud上(用户名:jabnih)

a. listRelease

  对于释放链表的操作,其中对于每个节点的释放会判断用户是否设置了free函数,若有则执行用户的操作,用以释放特定类型数据。例如:value为指向一个从堆分配的字符数组,在释放该节点的时候,就需要先释放value内存

对于free可以实现为:

 void free(void * value)
{
if( value )
free( (char *)value );
}
  //释放链表
void listRelease(list *list)
{
unsigned long len;
listNode *current, *next; current = list->head;
len = list->len;
while(len--) {
next = current->next;
//若设置了free函数,则调用该自定义free函数
if (list->free) list->free(current->value); zfree(current);
current = next;
}
zfree(list);
}

b. listDup

  当执行复制的时候,对于设置了dup函数可以实现深度复制或自定义复制的功能。

 //复制链表,若有链表有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;
iter = listGetIterator(orig, AL_START_HEAD);
while((node = listNext(iter)) != NULL) {
//遍历整个链表
void *value; if (copy->dup) {
//深度复制
value = copy->dup(node->value);
if (value == NULL) {
//复制出错
listRelease(copy);
listReleaseIterator(iter);
return NULL;
}
} else
//浅复制
value = node->value; //将复制后的节点添加的copy链表尾部
if (listAddNodeTail(copy, value) == NULL) {
listRelease(copy);
listReleaseIterator(iter);
return NULL;
}
}
listReleaseIterator(iter);
return copy;
}

c. listSearchKey

  //查找节点,如果设置了match方法,则使用match方法比较,否则仅仅比较节点的value值
listNode *listSearchKey(list *list, void *key)
{
listIter *iter;
listNode *node; iter = listGetIterator(list, AL_START_HEAD);
while((node = listNext(iter)) != NULL) {
if (list->match) {
if (list->match(node->value, key)) {
//这里可以将下面两条语句改为break(下同),最后return NULL改为 return node
listReleaseIterator(iter);
return node;
}
} else {
if (key == node->value) {
listReleaseIterator(iter);
return node;
}
}
}
listReleaseIterator(iter);
return NULL;
}

3. 总结

  1. 通用链表实现

  2. 对外提供扩展,用户可以自定义查找,复制,释放的功能。

Redis学习——链表源码分析的更多相关文章

  1. DotNetty网络通信框架学习之源码分析

    DotNetty网络通信框架学习之源码分析 有关DotNetty框架,网上的详细资料不是很多,有不多的几个博友做了简单的介绍,也没有做深入的探究,我也根据源码中提供的demo做一下记录,方便后期查阅. ...

  2. Redis学习之底层链表源码分析

    Redis底层链表的源码分析: 一.链表结点的结构(单个结点): // listNode 双端链表节点 typedef struct listNode { // 前置节点 struct listNod ...

  3. Redis 内存管理 源码分析

    要想了解redis底层的内存管理是如何进行的,直接看源码绝对是一个很好的选择 下面是我添加了详细注释的源码,需要注意的是,为了便于源码分析,我把redis为了弥补平台差异的那部分代码删了,只需要知道有 ...

  4. Redis网络模型的源码分析

    Redis的网络模型是基于I/O多路复用程序来实现的.源码中包含四种多路复用函数库epoll.select.evport.kqueue.在程序编译时会根据系统自动选择这四种库其中之一.下面以epoll ...

  5. Redis之quicklist源码分析

    一.quicklist简介 Redis列表是简单的字符串列表,按照插入顺序排序.你可以添加一个元素到列表的头部(左边)或者尾部(右边). 一个列表最多可以包含 232 - 1 个元素 (4294967 ...

  6. Redis之ziplist源码分析

    一.ziplist简介 从上一篇分析我们知道quicklist的底层存储使用了ziplist(压缩列表),由于压缩列表本身也有不少内容,所以重新开了一篇,在正式源码之前,还是先看下ziplist的特点 ...

  7. Redis网络库源码分析(1)之介绍篇

    一.前言 Redis网络库是一个单线程EPOLL模型的网络库,和Memcached使用的libevent相比,它没有那么庞大,代码一共2000多行,因此比较容易分析.其实网上已经有非常多有关这个网络库 ...

  8. bootstrap-modal 学习笔记 源码分析

    Bootstrap是Twitter推出的一个开源的用于前端开发的工具包,怎么用直接官网 http://twitter.github.io/bootstrap/ 我博客的定位就是把这些年看过的源码给慢慢 ...

  9. Redis 数据结构-字符串源码分析

    相关文章 Redis 初探-安装与使用 Redis常用指令 本文将从以下几个部分进行介绍 1.前言 2.常用命令 3.字符串结构 4.字符串实现 5.命令是如果操作字符串的 前言 平时在使用 Redi ...

随机推荐

  1. c#学习<二>:数据类型

    基元类型 编译器直接支持的数据类型称为基元类型(primitive type).基元类型直接映射到Framework类库(FCL)中存在的类型(BCL是FCL的子集). C#中的基元类型 BCL类型 ...

  2. poj2762 缩点+topo排序

    Going from u to v or from v to u? Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16486 ...

  3. 100735G

    很明显,我们构造出一个串后,无非就是两个结果:最长的是黑的,最长的是白的,因此选两个中小的就可以了 #include<iostream> using namespace std; int ...

  4. Maven-常用命令

    mvn archetype:create :创建 Maven 项目 mvn compile :编译源代码 mvn deploy 发布项目 mvn test-compile :编译测试代码 mvn te ...

  5. MySQL 1045登录失败

    当你登录MySQL数据库出现:Error 1045错误时(如下图),就表明你输入的用户名或密码错误被拒绝访问了,最简单的解决方法就是将MySQL数据库卸载然后重装,但这样的缺点就是就以前的数据库中的信 ...

  6. bzoj4402: Claris的剑

    首先,对于本质相同的构造,我们只计算字典序最小的序列 假设序列中最大的元素为top 我们很容易发现这样的序列一定是1,2,..,1,2,3,2,3,...,2,3,4,3,4.........,top ...

  7. 细说new与malloc的10点区别

    前言 几个星期前去面试C++研发的实习岗位,面试官问了个问题: new与malloc有什么区别? 这是个老生常谈的问题.当时我回答new从自由存储区上分配内存,malloc从堆上分配内存:new/de ...

  8. 【codevs3945】 完美拓印

    http://codevs.cn/problem/3945/ (题目链接) 题意 给出一个诡异的图形,再给出一个歪七扭八的线,问图形上下两条边与线的匹配→_→ Solution 前后求差然后KMP,这 ...

  9. CSS文件开头到底声明@charset "utf-8"

    @charset "utf-8" 这个声明是告诉浏览器[我的CSS文件是UTF-8编码的],但实际上这个文件可以不用是UTF-8编码的,所以这个声明能达到欺骗浏览器的作用. 但实践 ...

  10. STM32F207和DM9161A的以太网实现方案

    摘要:电力抄表系统常通过网络采集和传输电网中的谐波等信息.本文提出了一种适合电力系统的网络设计方案.在STM32F207和DM9161A为核心的硬件平台上,完成了LwIP协议栈的移植,实现了远程终端和 ...