tailq介绍

TAILQ是linux内核对双向队列操作的一种抽象,能实现操作队列需要的各种操作:插入元素,删除元素,遍历队列等,其封装是对应的宏定义,下面详细说明tailq的操作,从定义,初始化,插入,删除和遍历这几个API来介绍,并且提供c++版本的tailq。

tailq的宏定义API

(1)定义:TAILQ_ENTRY(type) 初始化一个type类型的entry

#define TAILQ_ENTRY(type)	\
	struct {			\
		struct type *tqe_next;  /* next element */			\
		struct type **tqe_prev; /* address of previous next element */	\
		TRACEBUF 		\
	}
其中TRACEBUF是一个用来调试的宏
example:
struct node{
	int a, b, c;
	TAILQ_ENTRY(node);
};
展开以后如下:
struct node{
	int a, b, c;
    struct {
		struct node *tqe_next;  /* next element */ 
        sturct node **tqe_prev; /* address of previous next element */
    };
};

(2)定义:TAILQ_HEAD(name, type) 初始化name的结构体,类型为type,初始化头部

#define TAILQ_HEAD(name, type)		\
	struct name {		\
		struct type *tqh_first; /* first element */				\
		struct type **tqh_last; /* addr of last next element */	\
		TRACEBUF 		\
	}
example:
TAILQ_HEAD(head, node) q_head;
展开以后如下:
struct head {
	struct node *tqh_first; /* first element */
	struct node **tqh_last; /* addr of last next element */
} q_head;

(3)初始化:TAILQ_INIT(head) 初始化头部,其中head是上面的TAILQ_HEAD

#define TAILQ_INIT(head) do {                       \
	TAILQ_FIRST((head)) = NULL;                 	\
	(head)->tqh_last = &TAILQ_FIRST((head));		\
	QMD_TRACE_HEAD(head);                       	\
} while (0)
其中QMD_TRACE_HEAD为了debug而设置的

(4)插入:TAILQ_INSERT_TAIL(head, elm, field) head是TAILQ_HEAD的头部,elm是对应需要处理的节点,field就是对应上面的TAILQ_ENTRY

#define TAILQ_INSERT_TAIL(head, elm, field) do {            \
		QMD_TAILQ_CHECK_TAIL(head, field);              	\
		TAILQ_NEXT((elm), field) = NULL;                	\
		(elm)->field.tqe_prev = (head)->tqh_last;           \
		*(head)->tqh_last = (elm);                  		\
		(head)->tqh_last = &TAILQ_NEXT((elm), field);      	\
		QMD_TRACE_HEAD(head);                       		\
		QMD_TRACE_ELEM(&(elm)->field);                  	\
	} while (0)
其中插入方式是通过尾插法,QMD_TAILQ_CHECK_TAIL,QMD_TRACE_HEAD,QMD_TRACE_ELEM对应调试信息

(5)删除:TAILQ_REMOVE(head, elm, field) head是TAILQ_HEAD的头部,elm是对应需要处理的节点,field就是对应上面的TAILQ_ENTRY

#define TAILQ_REMOVE(head, elm, field) do {             \
	if ((TAILQ_NEXT((elm), field)) != NULL)             \
		TAILQ_NEXT((elm), field)->field.tqe_prev =      \
			(elm)->field.tqe_prev;              		\
		else {                              			\
			(head)->tqh_last = (elm)->field.tqe_prev;	\
		}                               				\
		*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);	\
	} while (0)
其中删除的方式是删除头部位置的最近的节点

(6)遍历:TAILQ_FOREACH(var, head, field) var是临时变量,head对应TAILQ_HEAD的定义,field对应TAILQ_ENTRY

#define TAILQ_FOREACH(var, head, field)                 \
		for ((var) = TAILQ_FIRST((head));               \
			(var);                          			\
			(var) = TAILQ_NEXT((var), field))

(7)其他

#define TAILQ_FIRST(head)   ((head)->tqh_first) // 队列的第一个节点
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) // 当前elm的下一个节点

tailq的c++实现

// 使用c++封装的linux的TAILQ_ENTRY
template<class T>
class CPP_TAILQ_ENTRY 
{
public:
    T *tqe_next;  // next element
    T **tqe_prev; // address of previous next element
};
template<class T>
class CPP_TAILQ_HEAD
{
public:
    T *tqh_first; // first element
    T **tqh_last; // addr of last next element
};
#define CPP_TAILQ_FIRST(head)       ((head)->tqh_first)
#define CPP_TAILQ_NEXT(elm, field)  ((elm)->field.tqe_next)
#define CPP_TAILQ_EMPTY(head)       ((head)->tqh_first == NULL) // 判断队列是否为空
#define CPP_TAILQ_INIT(head) do {                   \
    CPP_TAILQ_FIRST((head)) = NULL;                 \
    (head)->tqh_last = &CPP_TAILQ_FIRST((head));    \
} while (0)

#define CPP_TAILQ_FOREACH(var, head, field)         \
    for ((var) = CPP_TAILQ_FIRST((head));           \
        (var);                                      \
        (var) = CPP_TAILQ_NEXT((var), field))

#define CPP_TAILQ_FOREACH_SAFE(var, head, field, tvar)              \ 
         for ((var) = CPP_TAILQ_FIRST((head));                      \ 
             (var) && ((tvar) = CPP_TAILQ_NEXT((var), field), 1);   \ 
             (var) = (tvar)) 

#define CPP_TAILQ_REMOVE(head, elm, field) do {             \
    if ((CPP_TAILQ_NEXT((elm), field)) != NULL)             \
        CPP_TAILQ_NEXT((elm), field)->field.tqe_prev =      \
            (elm)->field.tqe_prev;                          \
    else {                                                  \
        (head)->tqh_last = (elm)->field.tqe_prev;           \
    }                                                       \
    *(elm)->field.tqe_prev = CPP_TAILQ_NEXT((elm), field);  \
} while (0)

#define CPP_TAILQ_INSERT_TAIL(head, elm, field) do {        \
    CPP_TAILQ_NEXT((elm), field) = NULL;                    \
    (elm)->field.tqe_prev = (head)->tqh_last;               \
    *(head)->tqh_last = (elm);                              \
    (head)->tqh_last = &CPP_TAILQ_NEXT((elm), field);       \
} while (0)

#define CPP_TAILQ_CONCAT(head1, head2, field) do {          \
    if (!CPP_TAILQ_EMPTY(head2)) {                          \
        *(head1)->tqh_last = (head2)->tqh_first;            \
        (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;     \
        (head1)->tqh_last = (head2)->tqh_last;                      \
        CPP_TAILQ_INIT((head2));                                    \
    }                                                               \
} while (0)

使用gtest写的部分的测试用例如下:
class TestInt;
typedef CPP_TAILQ_HEAD<TestInt> TestIntList;
class TestInt 
{
public:
    TestInt(int _d) : d_(_d)
    { }
public:
    CPP_TAILQ_ENTRY<TestInt> entry_;
    int d_;
};

// 插入的测试用例
TEST(TAILQTest, INSERT_TAIL) 
{
    int arr[10] = {1, 2, 3, 4, 5};
    TestIntList tset;
    CPP_TAILQ_INIT(&tset);
    TestInt* ti1 = NULL;
    int idx = 0;
    for (; idx < sizeof(arr)/sizeof(arr[0]); idx++)
    {
        ti1 = new TestInt(arr[idx]);
        CPP_TAILQ_INSERT_TAIL(&tset, ti1, entry_);
    }

    idx = 0;
    TestInt* ti2 = NULL;
    CPP_TAILQ_FOREACH(ti2, &tset, entry_)
    {
        //LOG_TRACE("ti2 value : %d", ti2->d_);
        EXPECT_EQ(arr[idx++], ti2->d_);
    }
}

....