当前位置:网站首页>IList of PostgreSQL
IList of PostgreSQL
2022-06-24 14:20:00 【happytree001】
One 、 brief introduction
postgresql In its own library, it implements one-way linked list and two-way linked list , Involving documents src/include/lib/ilist.h and src/backend/lib/ilist.c, Most functions are in ilist.h To realize .
Two 、 Structure definition
2.1 Double linked list
2.1.1 Structure definition
typedef struct dlist_node dlist_node;
struct dlist_node
{
dlist_node *prev;
dlist_node *next;
};
/* * Head of a doubly linked list. * * Non-empty lists are internally circularly linked. Circular lists have the * advantage of not needing any branches in the most common list manipulations. * An empty list can also be represented as a pair of NULL pointers, making * initialization easier. */
typedef struct dlist_head
{
/* * head.next either points to the first element of the list; to &head if * it's a circular empty list; or to NULL if empty and not circular. * * head.prev either points to the last element of the list; to &head if * it's a circular empty list; or to NULL if empty and not circular. */
dlist_node head;
} dlist_head;
2.1.2 iterator
/* * Doubly linked list iterator. * * Used as state in dlist_foreach() and dlist_reverse_foreach(). To get the * current element of the iteration use the 'cur' member. * * Iterations using this are *not* allowed to change the list while iterating! * * NB: We use an extra "end" field here to avoid multiple evaluations of * arguments in the dlist_foreach() macro. */
typedef struct dlist_iter
{
dlist_node *cur; /* current element */
dlist_node *end; /* last node we'll iterate to */
} dlist_iter;
/* * Doubly linked list iterator allowing some modifications while iterating. * * Used as state in dlist_foreach_modify(). To get the current element of the * iteration use the 'cur' member. * * Iterations using this are only allowed to change the list at the current * point of iteration. It is fine to delete the current node, but it is *not* * fine to insert or delete adjacent nodes. * * NB: We need a separate type for mutable iterations so that we can store * the 'next' node of the current node in case it gets deleted or modified. */
typedef struct dlist_mutable_iter
{
dlist_node *cur; /* current element */
dlist_node *next; /* next node we'll iterate to */
dlist_node *end; /* last node we'll iterate to */
} dlist_mutable_iter;
2.2 One way linked list
2.2.1 Structure definition
/* * Node of a singly linked list. * * Embed this in structs that need to be part of a singly linked list. */
typedef struct slist_node slist_node;
struct slist_node
{
slist_node *next;
};
/* * Head of a singly linked list. * * Singly linked lists are not circularly linked, in contrast to doubly linked * lists; we just set head.next to NULL if empty. This doesn't incur any * additional branches in the usual manipulations. */
typedef struct slist_head
{
slist_node head;
} slist_head;
2.2.2 iterator
/* * Singly linked list iterator. * * Used as state in slist_foreach(). To get the current element of the * iteration use the 'cur' member. * * It's allowed to modify the list while iterating, with the exception of * deleting the iterator's current node; deletion of that node requires * care if the iteration is to be continued afterward. (Doing so and also * deleting or inserting adjacent list elements might misbehave; also, if * the user frees the current node's storage, continuing the iteration is * not safe.) * * NB: this wouldn't really need to be an extra struct, we could use an * slist_node * directly. We prefer a separate type for consistency. */
typedef struct slist_iter
{
slist_node *cur;
} slist_iter;
/* * Singly linked list iterator allowing some modifications while iterating. * * Used as state in slist_foreach_modify(). To get the current element of the * iteration use the 'cur' member. * * The only list modification allowed while iterating is to remove the current * node via slist_delete_current() (*not* slist_delete()). Insertion or * deletion of nodes adjacent to the current node would misbehave. */
typedef struct slist_mutable_iter
{
slist_node *cur; /* current element */
slist_node *next; /* next node we'll iterate to */
slist_node *prev; /* prev node, for deletions */
} slist_mutable_iter;
3、 ... and 、 API
3.1 Double linked list
/* * Initialize a doubly linked list. * Previous state will be thrown away without any cleanup. */
static inline void dlist_init(dlist_head *head);
/* * Is the list empty? * * An empty list has either its first 'next' pointer set to NULL, or to itself. */
static inline bool dlist_is_empty(dlist_head *head);
/* * Insert a node at the beginning of the list. */
static inline void dlist_push_head(dlist_head *head, dlist_node *node);
/* * Insert a node at the end of the list. */
static inline void dlist_push_tail(dlist_head *head, dlist_node *node);
/* * Insert a node after another *in the same list* */
static inline void
dlist_insert_after(dlist_node *after, dlist_node *node);
/* * Insert a node before another *in the same list* */
static inline void
dlist_insert_before(dlist_node *before, dlist_node *node);
/* * Delete 'node' from its list (it must be in one). */
static inline void dlist_delete(dlist_node *node);
/* * Remove and return the first node from a list (there must be one). */
static inline dlist_node *dlist_pop_head_node(dlist_head *head);
/* * Move element from its current position in the list to the head position in * the same list. * * Undefined behaviour if 'node' is not already part of the list. */
static inline void dlist_move_head(dlist_head *head, dlist_node *node);
/* * Move element from its current position in the list to the tail position in * the same list. * * Undefined behaviour if 'node' is not already part of the list. */
static inline void dlist_move_tail(dlist_head *head, dlist_node *node);
/* * Check whether 'node' has a following node. * Caution: unreliable if 'node' is not in the list. */
static inline bool dlist_has_next(dlist_head *head, dlist_node *node);
/* * Check whether 'node' has a preceding node. * Caution: unreliable if 'node' is not in the list. */
static inline bool dlist_has_prev(dlist_head *head, dlist_node *node);
/* * Return the next node in the list (there must be one). */
static inline dlist_node * dlist_next_node(dlist_head *head, dlist_node *node);
/* * Return previous node in the list (there must be one). */
static inline dlist_node * dlist_prev_node(dlist_head *head, dlist_node *node);
/* internal support function to get address of head element's struct */
static inline void * dlist_head_element_off(dlist_head *head, size_t off);
/* * Return the first node in the list (there must be one). */
static inline dlist_node * dlist_head_node(dlist_head *head);
/* internal support function to get address of tail element's struct */
static inline void * dlist_tail_element_off(dlist_head *head, size_t off);
/* * Return the last node in the list (there must be one). */
static inline dlist_node * dlist_tail_node(dlist_head *head);
3.2 One way linked list
/* * Initialize a singly linked list. * Previous state will be thrown away without any cleanup. */
static inline void slist_init(slist_head *head);
/* * Is the list empty? */
static inline bool slist_is_empty(slist_head *head);
/* * Insert a node at the beginning of the list. */
static inline void slist_push_head(slist_head *head, slist_node *node);
/* * Insert a node after another *in the same list* */
static inline void slist_insert_after(slist_node *after, slist_node *node);
/* * Remove and return the first node from a list (there must be one). */
static inline slist_node * slist_pop_head_node(slist_head *head);
/* * Check whether 'node' has a following node. */
static inline bool slist_has_next(slist_head *head, slist_node *node);
/* * Return the next node in the list (there must be one). */
static inline slist_node * slist_next_node(slist_head *head, slist_node *node);
/* internal support function to get address of head element's struct */
static inline void * slist_head_element_off(slist_head *head, size_t off);
/* * Return the first node in the list (there must be one). */
static inline slist_node * slist_head_node(slist_head *head);
/* * Delete the list element the iterator currently points to. * * Caution: this modifies iter->cur, so don't use that again in the current * loop iteration. */
static inline void slist_delete_current(slist_mutable_iter *iter);
Four 、 summary
Are short, compact inline functions , Embedded in the caller , No function call consumption
Well designed , Considerate , Avoid accidents
/* * Insert a node at the beginning of the list. */ static inline void dlist_push_head(dlist_head *head, dlist_node *node) { if (head->head.next == NULL) /* convert NULL header to circular */ dlist_init(head); node->next = head->head.next; node->prev = &head->head; node->next->prev = node; head->head.next = node; dlist_check(head); }The insertion of this two-way linked list , first if Judge , Without this judgment , Callers are prone to errors .
For example, the caller uses the following code , Use memest Instead of dlist_init.
dlist_head head; memset(&head, 0, sizeof(head)); // dlist_init(&head); dlist_node *node = malloc(sizeof(node)); dlist_push_head(&head, node);without if Judge , This will cause the linked list to be destroyed , Not a two-way linked list , Subsequent operations on this linked list will cause unexpected problems , For example, collapse , It may be that other places use this linked list , So the scope is expanded , It is even harder to troubleshoot problems
The function is basic and powerful , You can build a new model by stacking wood
such as The following two functions can be combined to build a chained stack model .
static inline void dlist_push_head(dlist_head *head, dlist_node *node); // Push
static inline dlist_node *dlist_pop_head_node(dlist_head *head); // Out of the stack
static inline dlist_node * dlist_head_node(dlist_head *head); // Look at the top of the stack elements
such as The following two functions can be combined to build a chained queue model .
static inline void dlist_push_tail(dlist_head *head, dlist_node *node); // The team
static inline dlist_node *dlist_pop_head_node(dlist_head *head); // Out of the team
such as The following combination can build a LRU Queues
static inline void dlist_push_head(dlist_head *head, dlist_node *node); // The team
// Iteration queue , Find the node to access
#define dlist_foreach(iter, lhead) ...
static inline void dlist_move_head(dlist_head *head, dlist_node *node); // Move the currently accessed node to the queue head
// When the queue length reaches a certain threshold , Delete the last element
static inline dlist_node * dlist_tail_node(dlist_head *head);
static inline void dlist_delete(dlist_node *node);
- Code comments are detailed , There are also some precautions for use
/* * Remove and return the first node from a list (there must be one). */
static inline dlist_node *
dlist_pop_head_node(dlist_head *head)
{
dlist_node *node;
Assert(!dlist_is_empty(head));
node = head->head.next;
dlist_delete(node);
return node;
}
such as dlist_pop_head_node Comments on functions , Just make it clear list There must be an element in the , It can also be seen from the implementation , call Assert Assertion judgement list Is it empty , If it is blank, it will abort.
include/c.h
#ifndef USE_ASSERT_CHECKING
#define Assert(condition) ((void)true)
...
#elif defined(FRONTEND)
#include <assert.h>
#define Assert(p) assert(p)
...
#else /* USE_ASSERT_CHECKING && !FRONTEND */
...
#define Assert(condition) \ do {
\ if (!(condition)) \ ExceptionalCondition(#condition, "FailedAssertion", \ __FILE__, __LINE__); \ } while (0)
...
#endif /* USE_ASSERT_CHECKING && !FRONTEND */
configure.ac
...
#
# Enable assert checks
# PGAC_ARG_BOOL(enable, cassert, no, [enable assertion checks (for debugging)],
[AC_DEFINE([USE_ASSERT_CHECKING], 1,
[Define to 1 to build with assertion checks. (--enable-cassert)])])
...
You can see that the default is defined USE_ASSERT_CHECKING, So eventually they call abort To terminate the program .
So in calling dlist_pop_head_node You need to call dlist_is_empty Judge , If the linked list is not empty, you can call dlist_pop_head_node.
- A clear division of responsibilities
Like iterators , It is divided into read-only iterators and iterators that can modify linked lists .
边栏推荐
- win10系统问题
- Autorf: learn the radiation field of 3D objects from single view (CVPR 2022)
- Jupiter notebook operation
- Daily knowledge popularization
- Research on MySQL composite index
- Win10 system problems
- MySQL日志管理、备份与恢复
- Jerry's test mic energy automatic recording automatic playback reference [article]
- leetcode:1504. 统计全 1 子矩形的个数
- 遠程辦公之:在家露營辦公小工具| 社區征文
猜你喜欢

【从零开始学zabbix】一丶Zabbix的介绍与部署Zabbix

Getting to know cloud native security for the first time: the best guarantee in the cloud Era

puzzle(016.2)指画星河

MySQL log management, backup and recovery

Rasa 3. X learning series - it is a great honor to be a source code contributor of Rasa contributors, and to build and share the rasa community with rasa source code contributors all over the world!

Rasa 3.x 学习系列-非常荣幸成为 Rasa contributors 源码贡献者,和全世界的Rasa源码贡献者共建共享Rasa社区!

Puzzle (016.2) finger painting Galaxy

【深度学习】NCHW、NHWC和CHWN格式数据的存储形式

Py之toad:toad的简介、安装、使用方法之详细攻略

Method of inputting dots under letters in markdown/latex
随机推荐
Kunpeng arm server compilation and installation paddlepaddle
Antd checkbox, limit the selected quantity
Research on MySQL composite index
09_一种比较高效的记忆方法
A review of text contrastive learning
Rasa 3.x 学习系列-非常荣幸成为 Rasa contributors 源码贡献者,和全世界的Rasa源码贡献者共建共享Rasa社区!
返回新列表
NPM package [details] (including NPM package development, release, installation, update, search, uninstall, view, version number update rules, package.json details, etc.)
记录一次Mongotemplate的And和Or的各种套
【深度学习】NCHW、NHWC和CHWN格式数据的存储形式
ASCII code table extracted from tanhaoqiang's C program design (comparison table of common characters and ASCII codes)
业务与技术双向结合构建银行数据安全管理体系
Maximum path sum in binary tree [handle any subtree, then handle the whole tree]
4 reasons for "safe left shift"
10_那些格调很高的个性签名
MySQL log management, backup and recovery
[environment setup] zip volume compression
4个不可不知的“安全左移”的理由
Jupyter notebook操作
laravel下视图间共享数据