ilist-4-circular.patch
text/x-diff
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/utils/cache/catcache.c | 1 | 0 |
| src/include/lib/ilist.h | 66 | 4 |
*** a/src/backend/utils/cache/catcache.c
--- b/src/backend/utils/cache/catcache.c
***************
*** 791,799 **** InitCatCache(int id,
cp->cc_key[i] = key[i];
dlist_init(&cp->cc_lists);
!
! for (i = 0; i < nbuckets; i++)
! dlist_init(&cp->cc_bucket[i]);
/*
* new cache is initialized as far as we can go for now. print some
--- 791,797 ----
cp->cc_key[i] = key[i];
dlist_init(&cp->cc_lists);
! MemSet(&cp->cc_bucket, 0, nbuckets * sizeof(dlist_head));
/*
* new cache is initialized as far as we can go for now. print some
*** a/src/include/lib/ilist.h
--- b/src/include/lib/ilist.h
***************
*** 6,15 ****
* This implementation is as efficient as possible: the lists don't have
* any memory management overhead, because the list pointers are embedded
* within some larger structure.
!
! * Also, the doubly-linked lists are always circularly linked, even when empty;
! * this enables many manipulations to be done without branches, which is
! * beneficial performance-wise.
*
* NOTES
* This is intended to be used in situations where memory for a struct and
--- 6,18 ----
* This implementation is as efficient as possible: the lists don't have
* any memory management overhead, because the list pointers are embedded
* within some larger structure.
! *
! * There are two kinds of empty doubly linked lists: those that have been
! * initialized to NULL, and those that have been initialized to circularity.
! * The second kind is useful for tight optimization, because there are some
! * operations that can be done without branches (and thus faster) on lists that
! * have been initialized to circularity. Most users don't care all that much,
! * and so can skip the initialization step until really required.
*
* NOTES
* This is intended to be used in situations where memory for a struct and
***************
*** 120,137 **** struct dlist_node
/*
* Head of a doubly linked list.
*
! * Lists are internally *always* circularly linked, even when empty. Circular
! * lists have the advantage of not needing any branches in the most common list
! * manipulations.
*/
typedef struct dlist_head
{
/*
! * head->next either points to the first element of the list or to &head
! * if empty.
*
! * head->prev either points to the last element of the list or to &head if
! * empty.
*/
dlist_node head;
} dlist_head;
--- 123,141 ----
/*
* 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;
***************
*** 265,271 **** extern void slist_check(slist_head *head);
--- 269,277 ----
extern void dlist_init(dlist_head *head);
extern bool dlist_is_empty(dlist_head *head);
extern void dlist_push_head(dlist_head *head, dlist_node *node);
+ extern void dlisti_push_head(dlist_head *head, dlist_node *node);
extern void dlist_push_tail(dlist_head *head, dlist_node *node);
+ extern void dlisti_push_tail(dlist_head *head, dlist_node *node);
extern void dlist_insert_after(dlist_head *head,
dlist_node *after, dlist_node *node);
extern void dlist_insert_before(dlist_head *head,
***************
*** 304,309 **** dlist_init(dlist_head *head)
--- 310,334 ----
STATIC_IF_INLINE void
dlist_push_head(dlist_head *head, dlist_node *node)
{
+ if (head->head.next == NULL)
+ dlist_init(head);
+
+ node->next = head->head.next;
+ node->prev = &head->head;
+ node->next->prev = node;
+ head->head.next = node;
+
+ dlist_check(head);
+ }
+
+ /*
+ * As above, except assume the list has been initialized to circularity.
+ */
+ STATIC_IF_INLINE void
+ dlisti_push_head(dlist_head *head, dlist_node *node)
+ {
+ Assert(head->head.next != NULL);
+
node->next = head->head.next;
node->prev = &head->head;
node->next->prev = node;
***************
*** 318,323 **** dlist_push_head(dlist_head *head, dlist_node *node)
--- 343,367 ----
STATIC_IF_INLINE void
dlist_push_tail(dlist_head *head, dlist_node *node)
{
+ if (head->head.next == NULL)
+ dlist_init(head);
+
+ node->next = &head->head;
+ node->prev = head->head.prev;
+ node->prev->next = node;
+ head->head.prev = node;
+
+ dlist_check(head);
+ }
+
+ /*
+ * As above, except assume the list has been initialized to circularity.
+ */
+ STATIC_IF_INLINE void
+ dlisti_push_tail(dlist_head *head, dlist_node *node)
+ {
+ Assert(head->head.next != NULL);
+
node->next = &head->head;
node->prev = head->head.prev;
node->prev->next = node;
***************
*** 379,385 **** dlist_delete(dlist_head *head, dlist_node *node)
/*
* Delete and return the first node from a list.
*
! * Undefined behaviour when the list is empty. Check with dlist_is_empty if
* necessary.
*/
STATIC_IF_INLINE dlist_node *
--- 423,429 ----
/*
* Delete and return the first node from a list.
*
! * Undefined behaviour when the list is empty. Check with dlist_is_empty if
* necessary.
*/
STATIC_IF_INLINE dlist_node *
***************
*** 459,469 **** dlist_prev_node(dlist_head *head, dlist_node *node)
/*
* Return whether the list is empty.
*/
STATIC_IF_INLINE bool
dlist_is_empty(dlist_head *head)
{
! return head->head.next == &(head->head);
}
/* internal support function */
--- 503,517 ----
/*
* Return whether the list is empty.
+ *
+ * An empty list has either its first 'next' pointer set to NULL, or to itself.
*/
STATIC_IF_INLINE bool
dlist_is_empty(dlist_head *head)
{
! dlist_check(head);
!
! return head->head.next == NULL || head->head.next == &(head->head);
}
/* internal support function */
***************
*** 553,559 **** dlist_tail_node(dlist_head *head)
#define dlist_foreach(iter, ptr) \
AssertVariableIsOfType(iter, dlist_iter); \
AssertVariableIsOfType(ptr, dlist_head *); \
! for (iter.end = &(ptr)->head, iter.cur = iter.end->next; \
iter.cur != iter.end; \
iter.cur = iter.cur->next)
--- 601,608 ----
#define dlist_foreach(iter, ptr) \
AssertVariableIsOfType(iter, dlist_iter); \
AssertVariableIsOfType(ptr, dlist_head *); \
! for (iter.end = &(ptr)->head, \
! iter.cur = iter.end->next ? iter.end->next : iter.end; \
iter.cur != iter.end; \
iter.cur = iter.cur->next)
***************
*** 568,575 **** dlist_tail_node(dlist_head *head)
#define dlist_foreach_modify(iter, ptr) \
AssertVariableIsOfType(iter, dlist_mutable_iter); \
AssertVariableIsOfType(ptr, dlist_head *); \
! for (iter.end = &(ptr)->head, iter.cur = iter.end->next, \
! iter.next = iter.cur->next; \
iter.cur != iter.end; \
iter.cur = iter.next, iter.next = iter.cur->next)
--- 617,625 ----
#define dlist_foreach_modify(iter, ptr) \
AssertVariableIsOfType(iter, dlist_mutable_iter); \
AssertVariableIsOfType(ptr, dlist_head *); \
! for (iter.end = &(ptr)->head, \
! iter.cur = iter.end->next ? iter.end->next : iter.end, \
! iter.next = iter.cur->next; \
iter.cur != iter.end; \
iter.cur = iter.next, iter.next = iter.cur->next)