天天看点

NS2中的链表笔记

NS2中的链表采用了bsd-list.h头文件,内容如下:

#define LIST_HEAD(name, type)						\
struct name {								\
	type *lh_first;	/* first element */			\
}

#define LIST_ENTRY(type)						\
struct {								\
	type *le_next;	/* next element */			\
	type **le_prev;	/* address of previous next element */	\
}

/*
 * List functions.
 */
#define	LIST_INIT(head) {						\
	(head)->lh_first = NULL;					\
}

#define LIST_INSERT_AFTER(listelm, elm, field) {			\
	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
		(listelm)->field.le_next->field.le_prev =		\
		    &(elm)->field.le_next;				\
	(listelm)->field.le_next = (elm);				\
	(elm)->field.le_prev = &(listelm)->field.le_next;		\
}

#define LIST_INSERT_BEFORE(listelm, elm, field) {			\
	(elm)->field.le_prev = (listelm)->field.le_prev;		\
	(elm)->field.le_next = (listelm);				\
	*(listelm)->field.le_prev = (elm);				\
	(listelm)->field.le_prev = &(elm)->field.le_next;		\
}

#define LIST_INSERT_HEAD(head, elm, field) {				\
	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
	(head)->lh_first = (elm);					\
	(elm)->field.le_prev = &(head)->lh_first;			\
}
           

NS中大量使用了链表,因为所有的网络节点需要用链表串起来,然后才可以进行遍历,而每个节点可能具有多个链路头LinkHead和接口Phy(这里节点Node与LinkHead和Phy的if的关系还没搞太清除),这些LinkHead也要用链表串起来,用于遍历后,形成网络拓扑,然后计算路由。

所有的type都是链表元素的指针,比如节点的链表的type就是节点的指针,LinkHead链表的type就是LinkHead。

LIST_HEAD(name, type)
           

定义一个链表头结构体,注意只是定义结构体,还没有声明链表头结构体 变量,这个需要在类的变量中进行定义。

对于Node类,因为需要将所有Node类实例化的对象串成链表,链表头属于Node类的属性,不是任何一个Node对象的属性,所以用静态变量定义:

static struct node_head nodehead_;  // static head of list of nodes
           

而对于LinkHead的链表头则是Node下的一个属性,不用定义为静态变量

定义完链表头结构体,定义完链表头结构体变量,下一步是初始化链表头结构体变量,即

#define	LIST_INIT(head)
           

这个仅仅是将链表头赋初值NULL。

这里需要注意的是对于Node的链表头变量是静态变量,静态变量的在类中仅仅是声明,还需要定义,而定义不能在实例化的过程中完成,需要单独完成,定义的同时,进行初始化:

struct node_head Node::nodehead_ = { 0 }; // replaces LIST_INIT macro
           

而LinkHead和if则可以直接在Node的构造函数中,使用list的宏进行初始化

LIST_INIT(&ifhead_);
LIST_INIT(&linklisthead_);
           
#define LIST_ENTRY(type)
           

ENTRY表项宏,就是在类中加了两个指针,从而使类能够前后关联串起来成为链表

由于只是使用单向链表,所以插入元素只是使用了在Head插入。

最后,还要在Node类中定义两个函数,一个是将自己加入到链表中,一个是返回下一个链表元素:

inline void insert(struct node_head* head) {
		LIST_INSERT_HEAD(head, this, entry);
	}
inline Node* nextnode() { return entry.le_next; }
           

对于Node下的链路LinkHead和接口Phy if的关系还没太搞清楚,得再看看!

NS2