Add detached node functions to ilist
authorAndres Freund <andres@anarazel.de>
Wed, 18 Jan 2023 19:41:14 +0000 (11:41 -0800)
committerAndres Freund <andres@anarazel.de>
Wed, 18 Jan 2023 19:41:14 +0000 (11:41 -0800)
These allow to test whether an element is in a list by checking whether
prev/next are NULL. Needed to replace SHMQueueIsDetached() when converting
from SHM_QUEUE to ilist.h style lists.

Reviewed-by: Thomas Munro <thomas.munro@gmail.com>
Discussion: https://postgr.es/m/20221120055930.t6kl3tyivzhlrzu2@awork3.anarazel.de
Discussion: https://postgr.es/m/20200211042229.msv23badgqljrdg2@alap3.anarazel.de

src/include/lib/ilist.h

index d33048f3b383001c8a852e372217a84637775541..e03aa1c683b7dd84a6d0c94eed41d6033ef2e7da 100644 (file)
@@ -316,6 +316,17 @@ dlist_init(dlist_head *head)
    head->head.next = head->head.prev = &head->head;
 }
 
+/*
+ * Initialize a doubly linked list element.
+ *
+ * This is only needed when dlist_node_is_detached() may be needed.
+ */
+static inline void
+dlist_node_init(dlist_node *node)
+{
+   node->next = node->prev = NULL;
+}
+
 /*
  * Is the list empty?
  *
@@ -397,6 +408,19 @@ dlist_delete(dlist_node *node)
    node->next->prev = node->prev;
 }
 
+/*
+ * Like dlist_delete(), but also sets next/prev to NULL to signal not being in
+ * a list.
+ */
+static inline void
+dlist_delete_thoroughly(dlist_node *node)
+{
+   node->prev->next = node->next;
+   node->next->prev = node->prev;
+   node->next = NULL;
+   node->prev = NULL;
+}
+
 /*
  * Same as dlist_delete, but performs checks in ILIST_DEBUG builds to ensure
  * that 'node' belongs to 'head'.
@@ -408,6 +432,17 @@ dlist_delete_from(dlist_head *head, dlist_node *node)
    dlist_delete(node);
 }
 
+/*
+ * Like dlist_delete_from, but also sets next/prev to NULL to signal not
+ * being in a list.
+ */
+static inline void
+dlist_delete_from_thoroughly(dlist_head *head, dlist_node *node)
+{
+   dlist_member_check(head, node);
+   dlist_delete_thoroughly(node);
+}
+
 /*
  * Remove and return the first node from a list (there must be one).
  */
@@ -480,6 +515,21 @@ dlist_has_prev(const dlist_head *head, const dlist_node *node)
    return node->prev != &head->head;
 }
 
+/*
+ * Check if node is detached. A node is only detached if it either has been
+ * initialized with dlist_init_node(), or deleted with
+ * dlist_delete_thoroughly() / dlist_delete_from_thoroughly() /
+ * dclist_delete_from_thoroughly().
+ */
+static inline bool
+dlist_node_is_detached(const dlist_node *node)
+{
+   Assert((node->next == NULL && node->prev == NULL) ||
+          (node->next != NULL && node->prev != NULL));
+
+   return node->next == NULL;
+}
+
 /*
  * Return the next node in the list (there must be one).
  */
@@ -718,6 +768,19 @@ dclist_delete_from(dclist_head *head, dlist_node *node)
    head->count--;
 }
 
+/*
+ * Like dclist_delete_from(), but also sets next/prev to NULL to signal not
+ * being in a list.
+ */
+static inline void
+dclist_delete_from_thoroughly(dclist_head *head, dlist_node *node)
+{
+   Assert(head->count > 0);
+
+   dlist_delete_from_thoroughly(&head->dlist, node);
+   head->count--;
+}
+
 /*
  * dclist_pop_head_node
  *     Remove and return the first node from a list (there must be one).