OpenGuass源码中对dllist.h的分析

对于dllist.h的分析

引言

该文件是典型的C/C++头文件,dllist是doubly linked list的缩写,即双向链表。双向链表是一种常用的数据结构,每个元素(节点)都包含了指向前一个节点和后一个节点的指针,因此可以双向遍历链表。

代码

代码地址

#ifndef DLLIST_H
#define DLLIST_H

struct Dllist;
struct Dlelem;

// Dlelem is a node in a doubly linked list.
typedef struct Dlelem {
    struct Dlelem* dle_next; /* next element */
    struct Dlelem* dle_prev; /* previous element */
    void* dle_val;           /* value of the element */
    struct Dllist* dle_list; /* what list this element is in */
} Dlelem;

typedef struct Dllist {
    Dlelem* dll_head;       /* head of list */
    Dlelem* dll_tail;       /* tail of list */
    uint64      dll_len;    /* number of elements in list */
} Dllist;

class DllistWithLock : public BaseObject {
    public:
    DllistWithLock();       // constructor
    ~DllistWithLock();      // destructor
    void Remove(Dlelem* e) {
        (void)RemoveConfirm(e);
    }
    bool RemoveConfirm(Dlelem* e);  // remove element from list, return true if removed
    void AddHead(Dlelem* e);    // add element to head of list
    void AddTail(Dlelem* e);    // add element to tail of list
    Dlelem* RemoveHead();       // remove element from head of list
    Dlelem* RemoveHeadNoLock(); // remove element from head of list without lock
    Dlelem* RemoveTail();       // remove element from tail of list
    bool IsEmpty();                     // is the list empty?
    Dlelem* GetHead();                  // get the head of the list
    void GetLock();                     // get the lock
    void ReleaseLock();                 // release the lock

    inline uint64 GetLength() {     // get the length of the list
        return m_list.dll_len;
    }

    private:
    slock_t m_lock;                 // lock for the list
    Dllist m_list;                  // the list
};

extern Dllist* DLNewList(void);       /* allocate and initialize a list header */
extern void DLInitList(Dllist* list); /* init a header alloced by caller */
extern void DLFreeList(Dllist* list); /* free up a list and all the nodes in
                                       * it */
extern Dlelem* DLNewElem(void* val);    /* allocate a new list element */
extern void DLInitElem(Dlelem* e, void* val);   /* initialize caller-allocated node */
extern void DLFreeElem(Dlelem* e);          /* free a list element */
extern void DLRemove(Dlelem* e); /* removes node from list */
extern void DLAddHead(Dllist* list, Dlelem* node);  /* add node to head of list */
extern void DLAddTail(Dllist* list, Dlelem* node);  /* add node to tail of list */
extern Dlelem* DLRemHead(Dllist* list); /* remove and return the head */
extern Dlelem* DLRemTail(Dllist* list); /* remove and return the tail */
extern void DLMoveToFront(Dlelem* e); /* move node to front of its list */
extern uint64 DLListLength(Dllist* list);

/* These are macros for speed */
#define DLGetHead(list) ((list)->dll_head)  /* get the head of the list */
#define DLGetTail(list) ((list)->dll_tail)  /* get the tail of the list */
#define DLIsNIL(list) ((list)->dll_head == NULL)    /* is the list empty? */
#define DLGetSucc(elem) ((elem)->dle_next)          /* get the successor */
#define DLGetPred(elem) ((elem)->dle_prev)          /* get the predecessor */
#define DLGetListHdr(elem) ((elem)->dle_list)       /* get the list header */

#define DLE_VAL(elem) ((elem)->dle_val)        /* get the value of the * element */

#endif /* DLLIST_H */

以下是代码的主要组成部分和功能:

  1. 结构体定义:

    • Dlelem 结构体定义了双向链表的节点(元素)结构。每个节点包括指向下一个节点和上一个节点的指针,以及一个 void* 类型的指针,用于存储节点的值,还有就是属于哪一个Dllist。
    • Dllist 结构体定义了双向链表的头部结构。它包含指向链表头和尾的指针,以及一个表示链表长度的整数。
  2. 类定义:

    • DllistWithLock 是一个类,它扩展了基类 BaseObject。这个类似乎是为了实现带锁的双向链表。它包括了一些基本的双向链表操作,如添加、删除、获取头节点等,同时提供了锁定和释放锁的方法,以确保线程安全性。
  3. 函数原型和宏定义:

    • DLNewList:分配并初始化一个新的链表头。
    • DLInitList:初始化一个由调用者分配的链表头。
    • DLFreeList:释放链表及其所有节点。
    • DLNewElem:创建一个包含特定值的新节点。
    • DLInitElem:初始化一个由调用者分配的节点。
    • DLFreeElem:释放一个节点。
    • DLRemove:从链表中移除一个节点。
    • DLAddHead:将节点添加到链表的头部。
    • DLAddTail:将节点添加到链表的尾部。
    • DLRemHead:移除并返回链表头部的节点。
    • DLRemTail:移除并返回链表尾部的节点。
    • DLMoveToFront:将节点移动到其所在链表的头部。
    • DLListLength:返回链表的长度。
  4. 宏定义:

    • 一些宏(macros)用于简化双向链表操作,包括获取链表头、获取链表尾、检查链表是否为空、获取节点的后继和前驱节点以及获取节点所在的链表头和节点值。

extern 关键字用于声明变量或函数的外部链接性,以告诉编译器在其他地方定义了这些变量或函数,但当前文件只需要知道它们的存在。这有助于编写模块化的代码,并将代码分解成多个文件,以便更好地组织和管理项目。

这个头文件提供了一组用于管理双向链表的基本操作,可以用于各种不同的应用中。具体的实现代码需要在其他文件中实现,通过包含这个头文件来使用这些操作。

示例

以下是双向链表的使用示例

// Here's a small example of how to use Dllists:
 Dllist *lst;
 Dlelem *elt;
 void	*in_stuff;	  // stuff to stick in the list
 void	*out_stuff
 lst = DLNewList();	 // make a new dllist
 DLAddHead(lst, DLNewElem(in_stuff)); 
//add a new element to the list with in_stuff as the value

 elt = DLGetHead(lst);  // retrieve the head element
 out_stuff = (void*)DLE_VAL(elt);  // get the stuff out
 DLRemove(elt);		// removes the element from its list
 DLFreeElem(elt);   
// free the element since we don't use it anymore

这段代码演示了如何使用双向链表(Dllist)进行基本操作:

  1. 首先,声明了一个指向双向链表的指针 lst 和一个指向链表元素的指针 elt
  2. 使用 DLNewList() 创建了一个新的双向链表,并将其地址分配给 lst
  3. 使用 DLAddHead() 在链表的头部添加了一个新元素,该元素的值为 in_stuff
  4. 使用 DLGetHead() 获取链表的头元素,并将其地址分配给 elt
  5. 使用 DLE_VAL() 获取元素中的数据,然后将其存储在 out_stuff 中。
  6. 使用 DLRemove() 从链表中移除元素,以确保元素不再属于链表。
  7. 最后,使用 DLFreeElem() 释放元素的内存,因为不再需要它。

示意图如下:

双向链表

这个示例展示了如何创建、添加、检索、移除和释放双向链表中的元素。双向链表是一种常见的数据结构,用于在程序中组织和管理数据。

总结

双向链表(Doubly Linked List)是一种常见的线性数据结构,与普通链表(单向链表)相似,但每个节点除了指向下一个节点外,还指向前一个节点,因此可以在两个方向上遍历链表。

双向链表是一种灵活的数据结构,可以在两个方向上遍历,适用于需要频繁插入和删除节点的场景。然而,由于额外的指针开销,它可能占用更多的内存。在选择数据结构时,需要根据具体的需求来权衡其优势和劣势。

的线性数据结构,与普通链表(单向链表)相似,但每个节点除了指向下一个节点外,还指向前一个节点,因此可以在两个方向上遍历链表。

双向链表是一种灵活的数据结构,可以在两个方向上遍历,适用于需要频繁插入和删除节点的场景。然而,由于额外的指针开销,它可能占用更多的内存。在选择数据结构时,需要根据具体的需求来权衡其优势和劣势。

本文从dllist的头文件出发,了解了双向链表的基本构成和使用方法,此外在项目文件中,为了便于查找和维护链表,添加了诸多函数宏和extern外部函数声明,这种开发模式给我们在实际开发过程中给予重要的指导作用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值