tail queue是bdb中用的最多的数据结构. 定义在 src/dbinc/queue.h:
注: TRACEBUF,QMD_TRACE_HEAD等是为了 queue代码的debug, 这里移除出去. 数据结构
======== ```
// type 即为 用户定义的 类型. 比如 db.h,
// struct __db_txn {
// * TAILQ_HEAD(__kids, __db_txn) kids;
// */
// struct __kids { type 即为 _db_txn. 问题: 用什么不直接用 TAILQ_HEAD(__kids, __db_txn) kids?
// struct __db_txn *tqh_first;
// struct __db_txn **tqh_last;
// } kids; #define TAILQ_HEAD(name, type) \ // 理解为 "头结点"
struct name { \
struct type *tqh_first; /* first element */ \ // 此为具体的元素, 如 __db_txn
struct type **tqh_last; /* addr of last next element */ \ // "最后一个元素的tqe_next" 的地址
} #define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \ // 此为具体的元素, 如 __db_txn
struct type **tqe_prev; /* address of previous next element */ \ "前一个元素的tqe_next" 的地址
}
``` 方法定义
========= ```
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first) /**
* 这里做了一个trick. 看TAILQ_HEAD 和TAILQ_ENTRY的定义, 只有 TAILQ_HEAD给了struct name.
* 所以 强制转为 `(struct headname *)`, (而不是 `(struct entryname *)`). 但是 TAILQ_HEAD 和
* TAILQ_ENTRY 的定义是相同的, `(head)->tqh_last)` 为 最后一个元素的 tqe_next 的地址,
* 所以如果有 `struct entryname`的话, 即为 此 `struct entryname` 的地址.
* `(((struct headname *)((head)->tqh_last))->tqh_last)` 即为:
* `(((struct entryname *)((head)->tqh_last))->tqe_prev)`. 倒数第二个元素的 tqe_next.
* TAILQ_PREV 的定义也是这么理解.
*/
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last)) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) /**
* field 为type中, queue entry的field. 其 `(elm)->field.tqe_prev)` 为 前一个元素的 tqe_next 的地址,
* 所以如果有 `struct entryname`的话, 即为 前一个元素的 queue entry field 的地址.
* `(((struct headname *)((elm)->field.tqe_prev))->tqh_last)` 即为:
* `(((struct entryname *)((elm)->field.tqe_prev))->tqe_prev)`. 前第二个元素的 tqe_next.
*/
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field)) #define TAILQ_INIT(head) do {
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \ // tqh_last 为 头结点本身的 tqh_first指针的地址
} while () #define TAILQ_CONCAT(head1, head2, field) do { \ // 合并两个queue
if (!TAILQ_EMPTY(head2)) { \ // 若q2 不为空
*(head1)->tqh_last = (head2)->tqh_first;\ // 调整 q1 末尾节点的 tqe_next
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ // 调整q2 第一个节点的tqe_prev
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \ // 重置q2的头结点
} \
} while () #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ // 将elm 插到 listelm 后面
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ // elm->next=listelm->next
TAILQ_NEXT((elm), field)->field.tqe_prev = \ // 若listelm不为队尾, 调整elm->next->pre
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \ // listelm为队尾, 调整tqh_last
TAILQ_NEXT((listelm), field) = (elm); \ // 调整listelm->next
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ // 调整elm->pre
} while () #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \ // 若listelm为第一个元素, 则tqe_prev为 tqh_first \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
} while () #define TAILQ_INSERT_HEAD(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \ // queue为空的情况
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ // 第一个元素的 tqe_prev 指向头结点的tqh_first
} while () #define TAILQ_INSERT_TAIL(head, elm, field) do { \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \ // 若queue为空, tqh_last 指向 tqh_first
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
} while () #define TAILQ_REMOVE(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field)) != NULL) \ // elm 不为队尾, 调整elm->next->pre
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \ // elm 为队尾, 调整tqh_last
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ // 若 elm为队首, 其tqe_prev为 tqh_first
} while ()
```

tail queue代码阅读的更多相关文章

  1. 代码阅读分析工具Understand 2.0试用

    Understand 2.0是一款源代码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实可以大大提高代码阅读效率.由于Understand功能十分强大,本文不可能详尽地介绍它的所有功能,所 ...

  2. Android 上的代码阅读器 CoderBrowserHD 修改支持 go 语言代码

    我在Android上的代码阅读器用的是 https://github.com/zerob13/CoderBrowserHD 改造的版本,改造后的版本我放在 https://github.com/ghj ...

  3. Linux协议栈代码阅读笔记(二)网络接口的配置

    Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...

  4. [置顶] Linux协议栈代码阅读笔记(一)

    Linux协议栈代码阅读笔记(一) (基于linux-2.6.21.7) (一)用户态通过诸如下面的C库函数访问协议栈服务 int socket(int domain, int type, int p ...

  5. 图形化代码阅读工具——Scitools Understand

    Scitools出品的Understand 2.0.用了很多年了,比Source Insight强大很多.以前的名字叫Understand for C/C++,Understand for Java, ...

  6. Python - 关于代码阅读的一些建议

    初始能力 让阅读思路保持清晰连贯,主力关注在流程架构和逻辑实现上,不被语法.技巧和业务流程等频繁地阻碍和打断. 建议基本满足以下条件,再开始进行代码阅读: 具备一定的语言基础:熟悉基础语法,常用的函数 ...

  7. MediaInfo代码阅读

      MediaInfo是一个用来分析媒体文件的开源工具. 支持的文件非常全面,基本上支持所有的媒体文件. 最近是在做HEVC开发,所以比较关注MediaInfo中关于HEVC的分析与处理. 从Meid ...

  8. Tools - 一些代码阅读的方法

    1 初始能力 让阅读思路清晰连贯,保持在程序的流程架构和逻辑实现上,不被语法.编程技巧和业务流程等频繁地阻碍和打断. 语言基础:熟悉基础语法,常用的函数.库.编程技巧等: 了解设计模式.构建工具.代码 ...

  9. Bleve代码阅读(二)——Index Mapping

    引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java.在这里通过阅读其代码,来学习如何使用及定制检索功能.也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式. ...

随机推荐

  1. spring mvc 第二天【注解实现springmvc Handler处理ajax简单请求 的配置】

    这里使用的是在前台发起ajax请求Handler,后台伪造数据响应给前台, 配置对应ajax请求的Handler信息如下 @Controller public class MyController { ...

  2. C语言乱谈(一) 20行代码生成BMP

    在学习图形图像的过程中,最简单和常见的格式是BMP和PPM.下面将给出生成BMP的极度精简代码,然后讲解BMP格式. #include <stdio.h> #include <std ...

  3. h5 摄像头处理 在线视频

    http://www.360doc.com/content/08/0812/03/72059_1533104.shtml http://html5online.com.cn/articles/2012 ...

  4. 又一种XML的解析方法

    [Fact(DisplayName="用户名为空")] public void Should_UsernameEmpty() { var paras = new Dictionar ...

  5. [转]CryptographyHelper.cs

    using System; using System.IO; using System.Security.Cryptography; using System.Text; public class C ...

  6. IIS内存溢出-设置IIS的应用程序池

    在ASP.NET Web服务器上,ASP.NET所能够用到的内存,通常不会等同于所有的内存数量.在machine.config(C:/WINDOWS/Microsoft.NET/Framework/v ...

  7. php常用的字符串函数

    addslashes -- 使用反斜线引用字符串 chr -- 返回相对应于 ascii 码值所指定的单个字符. chunk_split -- 将字符串分割成小块 count_chars --  返回 ...

  8. flash拖动条移出flash无法拖动

    原因:flash拖动条的拖动事件被嵌入flash的div的鼠标事件给截获了!

  9. 用js将从后台得到的时间戳(毫秒数)转换为想要的日期格式

    得到后台从数据库中拿到的数据我们希望格式是 2016年10月25日 17时37分30秒 或者 2016/10/25 17:37:30 然而我们前台得到的却是一段数字(时间戳,毫秒数) 14773860 ...

  10. perl 引用

    数组的数组 $a = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] 哈希的哈希 my $student_properties_of = { 'zdd' => { 'ag ...