* Re: Node to first or last element of a sequential list in module list/xlist
2021-04-03 10:26 ` Marc Nieper-Wißkirchen
@ 2021-04-03 16:28 ` Bruno Haible
2021-04-03 16:46 ` Marc Nieper-Wißkirchen
[not found] ` <CAEYrNrTatLc1QcBPzhbs9b64Dv5P5J7HuR+Tj8o6QKh91u1jZw@mail.gmail.com>
0 siblings, 2 replies; 12+ messages in thread
From: Bruno Haible @ 2021-04-03 16:28 UTC (permalink / raw)
To: Marc Nieper-Wißkirchen; +Cc: bug-gnulib
[-- Attachment #1: Type: text/plain, Size: 3197 bytes --]
Marc Nieper-Wißkirchen wrote:
> For example, given a list of fruits, insert "pear" after each "apple" and
> "peach" before each "apple". This can be easily done through
> gl_list_add_before/gl_list_add_after/gl_list_next_node without using
> invalidated nodes.
Now I see what you mean. Quasi companion functions to gl_list_next_node
and gl_list_previous_node: gl_list_first_node and gl_list_last_node,
respectively.
> What I want to propose is to allow the NULL value in
> gl_next_node/gl_previous_node. In this case, gl_next_node shall return the
> first node and gl_previous_node shall return the last node.
I don't think this encourages robust programs. If a program passes a NULL
pointer to gl_list_next_node or gl_list_previous_node, the program should
better crash.
> PS What can't be done (because gl_list_remove doesn't return a valid
> (next?) node) is list walking algorithms that both remove and insert nodes.
> For removal, one has to use an iterator.
Yes, some algorithms need a second, temporary list. Not all algorithms
can be written to use the original list, be efficient in O() terms, and
be implementation-independent.
2021-04-03 Bruno Haible <bruno@clisp.org>
*-list tests: Add more tests.
* tests/test-array_list.c (check_equals_by_forward_iteration,
check_equals_by_backward_iteration): New functions.
(main): Invoke them.
* tests/test-carray_list.c: Likewise.
* tests/test-linked_list.c: Likewise.
* tests/test-linkedhash_list.c: Likewise.
* tests/test-avltree_list.c: Likewise.
* tests/test-avltreehash_list.c: Likewise.
* tests/test-rbtree_list.c: Likewise.
* tests/test-rbtreehash_list.c: Likewise.
list: Add operations first_node, last_node.
Reported by Marc Nieper-Wißkirchen in
<https://lists.gnu.org/archive/html/bug-gnulib/2021-04/msg00005.html>.
* lib/gl_list.h (gl_list_first_node, gl_list_last_node): New functions.
(struct gl_list_implementation): Add members first_node, last_node.
* lib/gl_array_list.c (gl_array_first_node, gl_array_last_node): New
functions.
(gl_array_list_implementation): Add the new operations.
* lib/gl_carray_list.c (gl_carray_first_node, gl_carray_last_node): New
functions.
(gl_carray_list_implementation): Add the new operations.
* lib/gl_anylinked_list2.h (gl_linked_first_node, gl_linked_last_node):
New functions.
* lib/gl_linked_list.c (gl_linked_list_implementation): Add the new
operations.
* lib/gl_linkedhash_list.c (gl_linkedhash_list_implementation):
Likewise.
* lib/gl_anytree_list2.h (gl_tree_first_node, gl_tree_last_node): New
functions.
* lib/gl_avltree_list.c (gl_avltree_list_implementation): Add the new
operations.
* lib/gl_avltreehash_list.c (gl_avltreehash_list_implementation):
Likewise.
* lib/gl_rbtree_list.c (gl_rbtree_list_implementation): Likewise.
* lib/gl_rbtreehash_list.c (gl_rbtreehash_list_implementation):
Likewise.
* lib/gl_sublist.c (gl_sublist_first_node, gl_sublist_last_node): New
functions.
(gl_sublist_list_implementation): Add the new operations.
* lib/gl_list.hh (class gl_List): Add member functions first_node,
last_node.
* doc/containers.texi: Update table.
[-- Attachment #2: 0001-list-Add-operations-first_node-last_node.patch --]
[-- Type: text/x-patch, Size: 16642 bytes --]
From cce713624d68c60d9d6eeb11747500db998821a2 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 3 Apr 2021 17:59:47 +0200
Subject: [PATCH 1/2] list: Add operations first_node, last_node.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reported by Marc Nieper-Wißkirchen in
<https://lists.gnu.org/archive/html/bug-gnulib/2021-04/msg00005.html>.
* lib/gl_list.h (gl_list_first_node, gl_list_last_node): New functions.
(struct gl_list_implementation): Add members first_node, last_node.
* lib/gl_array_list.c (gl_array_first_node, gl_array_last_node): New
functions.
(gl_array_list_implementation): Add the new operations.
* lib/gl_carray_list.c (gl_carray_first_node, gl_carray_last_node): New
functions.
(gl_carray_list_implementation): Add the new operations.
* lib/gl_anylinked_list2.h (gl_linked_first_node, gl_linked_last_node):
New functions.
* lib/gl_linked_list.c (gl_linked_list_implementation): Add the new
operations.
* lib/gl_linkedhash_list.c (gl_linkedhash_list_implementation):
Likewise.
* lib/gl_anytree_list2.h (gl_tree_first_node, gl_tree_last_node): New
functions.
* lib/gl_avltree_list.c (gl_avltree_list_implementation): Add the new
operations.
* lib/gl_avltreehash_list.c (gl_avltreehash_list_implementation):
Likewise.
* lib/gl_rbtree_list.c (gl_rbtree_list_implementation): Likewise.
* lib/gl_rbtreehash_list.c (gl_rbtreehash_list_implementation):
Likewise.
* lib/gl_sublist.c (gl_sublist_first_node, gl_sublist_last_node): New
functions.
(gl_sublist_list_implementation): Add the new operations.
* lib/gl_list.hh (class gl_List): Add member functions first_node,
last_node.
* doc/containers.texi: Update table.
---
ChangeLog | 35 +++++++++++++++++++++++++++++++++++
doc/containers.texi | 18 ++++++++++++++++++
lib/gl_anylinked_list2.h | 18 ++++++++++++++++++
lib/gl_anytree_list2.h | 26 ++++++++++++++++++++++++++
lib/gl_array_list.c | 20 ++++++++++++++++++++
lib/gl_avltree_list.c | 2 ++
lib/gl_avltreehash_list.c | 2 ++
lib/gl_carray_list.c | 20 ++++++++++++++++++++
lib/gl_linked_list.c | 2 ++
lib/gl_linkedhash_list.c | 2 ++
lib/gl_list.h | 35 +++++++++++++++++++++++++++++++++++
lib/gl_list.hh | 8 ++++++++
lib/gl_rbtree_list.c | 2 ++
lib/gl_rbtreehash_list.c | 2 ++
lib/gl_sublist.c | 21 +++++++++++++++++++++
15 files changed, 213 insertions(+)
diff --git a/ChangeLog b/ChangeLog
index 9323aa9..958ad02 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,40 @@
2021-04-03 Bruno Haible <bruno@clisp.org>
+ list: Add operations first_node, last_node.
+ Reported by Marc Nieper-Wißkirchen in
+ <https://lists.gnu.org/archive/html/bug-gnulib/2021-04/msg00005.html>.
+ * lib/gl_list.h (gl_list_first_node, gl_list_last_node): New functions.
+ (struct gl_list_implementation): Add members first_node, last_node.
+ * lib/gl_array_list.c (gl_array_first_node, gl_array_last_node): New
+ functions.
+ (gl_array_list_implementation): Add the new operations.
+ * lib/gl_carray_list.c (gl_carray_first_node, gl_carray_last_node): New
+ functions.
+ (gl_carray_list_implementation): Add the new operations.
+ * lib/gl_anylinked_list2.h (gl_linked_first_node, gl_linked_last_node):
+ New functions.
+ * lib/gl_linked_list.c (gl_linked_list_implementation): Add the new
+ operations.
+ * lib/gl_linkedhash_list.c (gl_linkedhash_list_implementation):
+ Likewise.
+ * lib/gl_anytree_list2.h (gl_tree_first_node, gl_tree_last_node): New
+ functions.
+ * lib/gl_avltree_list.c (gl_avltree_list_implementation): Add the new
+ operations.
+ * lib/gl_avltreehash_list.c (gl_avltreehash_list_implementation):
+ Likewise.
+ * lib/gl_rbtree_list.c (gl_rbtree_list_implementation): Likewise.
+ * lib/gl_rbtreehash_list.c (gl_rbtreehash_list_implementation):
+ Likewise.
+ * lib/gl_sublist.c (gl_sublist_first_node, gl_sublist_last_node): New
+ functions.
+ (gl_sublist_list_implementation): Add the new operations.
+ * lib/gl_list.hh (class gl_List): Add member functions first_node,
+ last_node.
+ * doc/containers.texi: Update table.
+
+2021-04-03 Bruno Haible <bruno@clisp.org>
+
xalloc-die: Fix compilation error (regression from 2021-03-28).
* lib/xalloc.h: Don't include idx.h and xalloc-oversized.h if the module
'xalloc' is not in use.
diff --git a/doc/containers.texi b/doc/containers.texi
index cb0c22a..15c915b 100644
--- a/doc/containers.texi
+++ b/doc/containers.texi
@@ -151,6 +151,24 @@ for the ``sequential list'' data type are:
@tab @math{O(1)}
@tab @math{O(@log n)}
@tab @math{O(@log n)}
+@item @code{gl_list_first_node}
+@tab @math{O(1)}
+@tab @math{O(1)}
+@tab @math{O(1)}
+@tab @math{O(@log n)}
+@tab @math{O(1)}
+@tab @math{O(1)}
+@tab @math{O(@log n)}
+@tab @math{O(@log n)}
+@item @code{gl_list_last_node}
+@tab @math{O(1)}
+@tab @math{O(1)}
+@tab @math{O(1)}
+@tab @math{O(@log n)}
+@tab @math{O(1)}
+@tab @math{O(1)}
+@tab @math{O(@log n)}
+@tab @math{O(@log n)}
@item @code{gl_list_get_at}
@tab @math{O(1)}
@tab @math{O(1)}
diff --git a/lib/gl_anylinked_list2.h b/lib/gl_anylinked_list2.h
index 1434d59..6af3f76 100644
--- a/lib/gl_anylinked_list2.h
+++ b/lib/gl_anylinked_list2.h
@@ -229,6 +229,24 @@ gl_linked_previous_node (gl_list_t list, gl_list_node_t node)
return (node->prev != &list->root ? node->prev : NULL);
}
+static gl_list_node_t _GL_ATTRIBUTE_PURE
+gl_linked_first_node (gl_list_t list)
+{
+ if (list->count > 0)
+ return list->root.next;
+ else
+ return NULL;
+}
+
+static gl_list_node_t _GL_ATTRIBUTE_PURE
+gl_linked_last_node (gl_list_t list)
+{
+ if (list->count > 0)
+ return list->root.prev;
+ else
+ return NULL;
+}
+
static const void * _GL_ATTRIBUTE_PURE
gl_linked_get_at (gl_list_t list, size_t position)
{
diff --git a/lib/gl_anytree_list2.h b/lib/gl_anytree_list2.h
index 59fe01d..fbf514b 100644
--- a/lib/gl_anytree_list2.h
+++ b/lib/gl_anytree_list2.h
@@ -140,6 +140,32 @@ gl_tree_previous_node (gl_list_t list _GL_ATTRIBUTE_MAYBE_UNUSED,
return node;
}
+static gl_list_node_t _GL_ATTRIBUTE_PURE
+gl_tree_first_node (gl_list_t list _GL_ATTRIBUTE_MAYBE_UNUSED)
+{
+ gl_list_node_t node = list->root;
+
+ if (node != NULL)
+ {
+ while (node->left != NULL)
+ node = node->left;
+ }
+ return node;
+}
+
+static gl_list_node_t _GL_ATTRIBUTE_PURE
+gl_tree_last_node (gl_list_t list _GL_ATTRIBUTE_MAYBE_UNUSED)
+{
+ gl_list_node_t node = list->root;
+
+ if (node != NULL)
+ {
+ while (node->right != NULL)
+ node = node->right;
+ }
+ return node;
+}
+
/* Returns the node at the given position < gl_tree_size (list). */
static gl_list_node_t _GL_ATTRIBUTE_PURE
node_at (gl_list_node_t root, size_t position)
diff --git a/lib/gl_array_list.c b/lib/gl_array_list.c
index e30b881..203e618 100644
--- a/lib/gl_array_list.c
+++ b/lib/gl_array_list.c
@@ -166,6 +166,24 @@ gl_array_previous_node (gl_list_t list, gl_list_node_t node)
return NULL;
}
+static gl_list_node_t _GL_ATTRIBUTE_PURE
+gl_array_first_node (gl_list_t list)
+{
+ if (list->count > 0)
+ return INDEX_TO_NODE (0);
+ else
+ return NULL;
+}
+
+static gl_list_node_t _GL_ATTRIBUTE_PURE
+gl_array_last_node (gl_list_t list)
+{
+ if (list->count > 0)
+ return INDEX_TO_NODE (list->count - 1);
+ else
+ return NULL;
+}
+
static const void * _GL_ATTRIBUTE_PURE
gl_array_get_at (gl_list_t list, size_t position)
{
@@ -651,6 +669,8 @@ const struct gl_list_implementation gl_array_list_implementation =
gl_array_node_nx_set_value,
gl_array_next_node,
gl_array_previous_node,
+ gl_array_first_node,
+ gl_array_last_node,
gl_array_get_at,
gl_array_nx_set_at,
gl_array_search_from_to,
diff --git a/lib/gl_avltree_list.c b/lib/gl_avltree_list.c
index 241949a..801b141 100644
--- a/lib/gl_avltree_list.c
+++ b/lib/gl_avltree_list.c
@@ -77,6 +77,8 @@ const struct gl_list_implementation gl_avltree_list_implementation =
gl_tree_node_nx_set_value,
gl_tree_next_node,
gl_tree_previous_node,
+ gl_tree_first_node,
+ gl_tree_last_node,
gl_tree_get_at,
gl_tree_nx_set_at,
gl_tree_search_from_to,
diff --git a/lib/gl_avltreehash_list.c b/lib/gl_avltreehash_list.c
index 5d0be7e..9a96f68 100644
--- a/lib/gl_avltreehash_list.c
+++ b/lib/gl_avltreehash_list.c
@@ -100,6 +100,8 @@ const struct gl_list_implementation gl_avltreehash_list_implementation =
gl_tree_node_nx_set_value,
gl_tree_next_node,
gl_tree_previous_node,
+ gl_tree_first_node,
+ gl_tree_last_node,
gl_tree_get_at,
gl_tree_nx_set_at,
gl_tree_search_from_to,
diff --git a/lib/gl_carray_list.c b/lib/gl_carray_list.c
index a50f093..add4cc3 100644
--- a/lib/gl_carray_list.c
+++ b/lib/gl_carray_list.c
@@ -181,6 +181,24 @@ gl_carray_previous_node (gl_list_t list, gl_list_node_t node)
return NULL;
}
+static gl_list_node_t _GL_ATTRIBUTE_PURE
+gl_carray_first_node (gl_list_t list)
+{
+ if (list->count > 0)
+ return INDEX_TO_NODE (0);
+ else
+ return NULL;
+}
+
+static gl_list_node_t _GL_ATTRIBUTE_PURE
+gl_carray_last_node (gl_list_t list)
+{
+ if (list->count > 0)
+ return INDEX_TO_NODE (list->count - 1);
+ else
+ return NULL;
+}
+
static const void * _GL_ATTRIBUTE_PURE
gl_carray_get_at (gl_list_t list, size_t position)
{
@@ -844,6 +862,8 @@ const struct gl_list_implementation gl_carray_list_implementation =
gl_carray_node_nx_set_value,
gl_carray_next_node,
gl_carray_previous_node,
+ gl_carray_first_node,
+ gl_carray_last_node,
gl_carray_get_at,
gl_carray_nx_set_at,
gl_carray_search_from_to,
diff --git a/lib/gl_linked_list.c b/lib/gl_linked_list.c
index f46d45b..087968e 100644
--- a/lib/gl_linked_list.c
+++ b/lib/gl_linked_list.c
@@ -38,6 +38,8 @@ const struct gl_list_implementation gl_linked_list_implementation =
gl_linked_node_nx_set_value,
gl_linked_next_node,
gl_linked_previous_node,
+ gl_linked_first_node,
+ gl_linked_last_node,
gl_linked_get_at,
gl_linked_nx_set_at,
gl_linked_search_from_to,
diff --git a/lib/gl_linkedhash_list.c b/lib/gl_linkedhash_list.c
index 2c76bae..70eca52 100644
--- a/lib/gl_linkedhash_list.c
+++ b/lib/gl_linkedhash_list.c
@@ -86,6 +86,8 @@ const struct gl_list_implementation gl_linkedhash_list_implementation =
gl_linked_node_nx_set_value,
gl_linked_next_node,
gl_linked_previous_node,
+ gl_linked_first_node,
+ gl_linked_last_node,
gl_linked_get_at,
gl_linked_nx_set_at,
gl_linked_search_from_to,
diff --git a/lib/gl_list.h b/lib/gl_list.h
index 3c1aede..7fc22bb 100644
--- a/lib/gl_list.h
+++ b/lib/gl_list.h
@@ -73,6 +73,8 @@ extern "C" {
gl_list_node_set_value O(1) O(1) O(1) O(1) O((log n)²)/O(1)
gl_list_next_node O(1) O(1) O(log n) O(1) O(log n)
gl_list_previous_node O(1) O(1) O(log n) O(1) O(log n)
+ gl_list_first_node O(1) O(1) O(log n) O(1) O(log n)
+ gl_list_last_node O(1) O(1) O(log n) O(1) O(log n)
gl_list_get_at O(1) O(n) O(log n) O(n) O(log n)
gl_list_get_first O(1) O(1) O(log n) O(1) O(log n)
gl_list_get_last O(1) O(1) O(log n) O(1) O(log n)
@@ -207,6 +209,23 @@ extern gl_list_node_t gl_list_next_node (gl_list_t list, gl_list_node_t node);
if the given node is the first (leftmost) one in the list. */
extern gl_list_node_t gl_list_previous_node (gl_list_t list, gl_list_node_t node);
+/* Returns the first node in the list, or NULL if the list is empty.
+ This function is useful for iterating through the list like this:
+ gl_list_node_t node;
+ for (node = gl_list_first_node (list); node != NULL; node = gl_list_next_node (node))
+ ...
+ */
+extern gl_list_node_t gl_list_first_node (gl_list_t list);
+
+/* Returns the last node in the list, or NULL if the list is empty.
+ This function is useful for iterating through the list in backward order,
+ like this:
+ gl_list_node_t node;
+ for (node = gl_list_last_node (list); node != NULL; node = gl_list_previous_node (node))
+ ...
+ */
+extern gl_list_node_t gl_list_last_node (gl_list_t list);
+
/* Returns the element at a given position in the list.
POSITION must be >= 0 and < gl_list_size (list). */
extern const void * gl_list_get_at (gl_list_t list, size_t position);
@@ -507,6 +526,8 @@ struct gl_list_implementation
const void *elt);
gl_list_node_t (*next_node) (gl_list_t list, gl_list_node_t node);
gl_list_node_t (*previous_node) (gl_list_t list, gl_list_node_t node);
+ gl_list_node_t (*first_node) (gl_list_t list);
+ gl_list_node_t (*last_node) (gl_list_t list);
const void * (*get_at) (gl_list_t list, size_t position);
gl_list_node_t (*nx_set_at) (gl_list_t list, size_t position,
const void *elt);
@@ -631,6 +652,20 @@ gl_list_previous_node (gl_list_t list, gl_list_node_t node)
->previous_node (list, node);
}
+GL_LIST_INLINE gl_list_node_t
+gl_list_first_node (gl_list_t list)
+{
+ return ((const struct gl_list_impl_base *) list)->vtable
+ ->first_node (list);
+}
+
+GL_LIST_INLINE gl_list_node_t
+gl_list_last_node (gl_list_t list)
+{
+ return ((const struct gl_list_impl_base *) list)->vtable
+ ->last_node (list);
+}
+
GL_LIST_INLINE const void *
gl_list_get_at (gl_list_t list, size_t position)
{
diff --git a/lib/gl_list.hh b/lib/gl_list.hh
index 7bff5dd..af2ca67 100644
--- a/lib/gl_list.hh
+++ b/lib/gl_list.hh
@@ -134,6 +134,14 @@ public:
gl_list_node_t previous_node (gl_list_node_t node) const
{ return gl_list_previous_node (_ptr, node); }
+ /* Returns the first node in the list, or NULL if the list is empty. */
+ gl_list_node_t first_node () const
+ { return gl_list_first_node (_ptr); }
+
+ /* Returns the last node in the list, or NULL if the list is empty. */
+ gl_list_node_t last_node () const
+ { return gl_list_last_node (_ptr); }
+
/* Returns the element at a given position in the list.
POSITION must be >= 0 and < gl_list_size (list). */
ELTYPE * get_at (size_t position) const
diff --git a/lib/gl_rbtree_list.c b/lib/gl_rbtree_list.c
index 185ed82..9a053b4 100644
--- a/lib/gl_rbtree_list.c
+++ b/lib/gl_rbtree_list.c
@@ -78,6 +78,8 @@ const struct gl_list_implementation gl_rbtree_list_implementation =
gl_tree_node_nx_set_value,
gl_tree_next_node,
gl_tree_previous_node,
+ gl_tree_first_node,
+ gl_tree_last_node,
gl_tree_get_at,
gl_tree_nx_set_at,
gl_tree_search_from_to,
diff --git a/lib/gl_rbtreehash_list.c b/lib/gl_rbtreehash_list.c
index c4a3c7d..d8fcb8e 100644
--- a/lib/gl_rbtreehash_list.c
+++ b/lib/gl_rbtreehash_list.c
@@ -101,6 +101,8 @@ const struct gl_list_implementation gl_rbtreehash_list_implementation =
gl_tree_node_nx_set_value,
gl_tree_next_node,
gl_tree_previous_node,
+ gl_tree_first_node,
+ gl_tree_last_node,
gl_tree_get_at,
gl_tree_nx_set_at,
gl_tree_search_from_to,
diff --git a/lib/gl_sublist.c b/lib/gl_sublist.c
index bdd7d50..63359b8 100644
--- a/lib/gl_sublist.c
+++ b/lib/gl_sublist.c
@@ -122,6 +122,25 @@ gl_sublist_previous_node (gl_list_t list, gl_list_node_t node)
return NULL;
}
+static gl_list_node_t
+gl_sublist_first_node (gl_list_t list)
+{
+ if (list->end > list->start)
+ return INDEX_TO_NODE (0);
+ else
+ return NULL;
+}
+
+static gl_list_node_t
+gl_sublist_last_node (gl_list_t list)
+{
+ size_t count = list->end - list->start;
+ if (count > 0)
+ return INDEX_TO_NODE (count - 1);
+ else
+ return NULL;
+}
+
static const void *
gl_sublist_get_at (gl_list_t list, size_t position)
{
@@ -413,6 +432,8 @@ static const struct gl_list_implementation gl_sublist_list_implementation =
gl_sublist_node_nx_set_value,
gl_sublist_next_node,
gl_sublist_previous_node,
+ gl_sublist_first_node,
+ gl_sublist_last_node,
gl_sublist_get_at,
gl_sublist_nx_set_at,
gl_sublist_search_from_to,
--
2.7.4
[-- Attachment #3: 0002-list-tests-Add-more-tests.patch --]
[-- Type: text/x-patch, Size: 15792 bytes --]
From 781f81012720e7f9f4c50630f37dfc73e2ad4906 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 3 Apr 2021 18:25:56 +0200
Subject: [PATCH 2/2] *-list tests: Add more tests.
* tests/test-array_list.c (check_equals_by_forward_iteration,
check_equals_by_backward_iteration): New functions.
(main): Invoke them.
* tests/test-carray_list.c: Likewise.
* tests/test-linked_list.c: Likewise.
* tests/test-linkedhash_list.c: Likewise.
* tests/test-avltree_list.c: Likewise.
* tests/test-avltreehash_list.c: Likewise.
* tests/test-rbtree_list.c: Likewise.
* tests/test-rbtreehash_list.c: Likewise.
---
ChangeLog | 12 ++++++++++++
tests/test-array_list.c | 39 +++++++++++++++++++++++++++++++++++++++
tests/test-avltree_list.c | 33 +++++++++++++++++++++++++++++++++
tests/test-avltreehash_list.c | 33 +++++++++++++++++++++++++++++++++
tests/test-carray_list.c | 33 +++++++++++++++++++++++++++++++++
tests/test-linked_list.c | 33 +++++++++++++++++++++++++++++++++
tests/test-linkedhash_list.c | 33 +++++++++++++++++++++++++++++++++
tests/test-rbtree_list.c | 33 +++++++++++++++++++++++++++++++++
tests/test-rbtreehash_list.c | 33 +++++++++++++++++++++++++++++++++
9 files changed, 282 insertions(+)
diff --git a/ChangeLog b/ChangeLog
index 958ad02..117ea44 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
2021-04-03 Bruno Haible <bruno@clisp.org>
+ *-list tests: Add more tests.
+ * tests/test-array_list.c (check_equals_by_forward_iteration,
+ check_equals_by_backward_iteration): New functions.
+ (main): Invoke them.
+ * tests/test-carray_list.c: Likewise.
+ * tests/test-linked_list.c: Likewise.
+ * tests/test-linkedhash_list.c: Likewise.
+ * tests/test-avltree_list.c: Likewise.
+ * tests/test-avltreehash_list.c: Likewise.
+ * tests/test-rbtree_list.c: Likewise.
+ * tests/test-rbtreehash_list.c: Likewise.
+
list: Add operations first_node, last_node.
Reported by Marc Nieper-Wißkirchen in
<https://lists.gnu.org/archive/html/bug-gnulib/2021-04/msg00005.html>.
diff --git a/tests/test-array_list.c b/tests/test-array_list.c
index 1c736ee..fa60691 100644
--- a/tests/test-array_list.c
+++ b/tests/test-array_list.c
@@ -44,6 +44,42 @@ check_equals (gl_list_t list1, gl_list_t list2)
}
}
+static void
+check_equals_by_forward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ size_t n = gl_list_size (list1);
+ size_t i;
+ gl_list_node_t node2;
+
+ i = 0;
+ node2 = gl_list_first_node (list2);
+ while (i < n && node2 != NULL)
+ {
+ ASSERT (gl_list_get_at (list1, i) == gl_list_node_value (list2, node2));
+ i++;
+ node2 = gl_list_next_node (list2, node2);
+ }
+ ASSERT ((i == n) == (node2 == NULL));
+}
+
+static void
+check_equals_by_backward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ size_t n = gl_list_size (list1);
+ size_t i;
+ gl_list_node_t node2;
+
+ i = n - 1;
+ node2 = gl_list_last_node (list2);
+ while (i != (size_t)(-1) && node2 != NULL)
+ {
+ ASSERT (gl_list_get_at (list1, i) == gl_list_node_value (list2, node2));
+ i--;
+ node2 = gl_list_previous_node (list2, node2);
+ }
+ ASSERT ((i == (size_t)(-1)) == (node2 == NULL));
+}
+
int
main (int argc, char *argv[])
{
@@ -75,6 +111,9 @@ main (int argc, char *argv[])
check_equals (list1, list2);
+ check_equals_by_forward_iteration (list1, list2);
+ check_equals_by_backward_iteration (list1, list2);
+
for (repeat = 0; repeat < 10000; repeat++)
{
unsigned int operation = RANDOM (18);
diff --git a/tests/test-avltree_list.c b/tests/test-avltree_list.c
index c4c0f02..b4938c4 100644
--- a/tests/test-avltree_list.c
+++ b/tests/test-avltree_list.c
@@ -48,6 +48,36 @@ check_equals (gl_list_t list1, gl_list_t list2)
}
static void
+check_equals_by_forward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_first_node (list1);
+ gl_list_node_t node2 = gl_list_first_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_next_node (list1, node1);
+ node2 = gl_list_next_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
+check_equals_by_backward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_last_node (list1);
+ gl_list_node_t node2 = gl_list_last_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_previous_node (list1, node1);
+ node2 = gl_list_previous_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
check_all (gl_list_t list1, gl_list_t list2, gl_list_t list3)
{
gl_avltree_list_check_invariants (list2);
@@ -92,6 +122,9 @@ main (int argc, char *argv[])
check_all (list1, list2, list3);
+ check_equals_by_forward_iteration (list1, list2);
+ check_equals_by_backward_iteration (list1, list2);
+
for (repeat = 0; repeat < 10000; repeat++)
{
unsigned int operation = RANDOM (18);
diff --git a/tests/test-avltreehash_list.c b/tests/test-avltreehash_list.c
index a77ee86..040efd3 100644
--- a/tests/test-avltreehash_list.c
+++ b/tests/test-avltreehash_list.c
@@ -75,6 +75,36 @@ check_equals (gl_list_t list1, gl_list_t list2)
}
static void
+check_equals_by_forward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_first_node (list1);
+ gl_list_node_t node2 = gl_list_first_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_next_node (list1, node1);
+ node2 = gl_list_next_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
+check_equals_by_backward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_last_node (list1);
+ gl_list_node_t node2 = gl_list_last_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_previous_node (list1, node1);
+ node2 = gl_list_previous_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
check_all (gl_list_t list1, gl_list_t list2, gl_list_t list3)
{
gl_avltreehash_list_check_invariants (list2);
@@ -122,6 +152,9 @@ main (int argc, char *argv[])
check_all (list1, list2, list3);
+ check_equals_by_forward_iteration (list1, list2);
+ check_equals_by_backward_iteration (list1, list2);
+
for (repeat = 0; repeat < 10000; repeat++)
{
unsigned int operation = RANDOM (18);
diff --git a/tests/test-carray_list.c b/tests/test-carray_list.c
index 53ab6f5..4077571 100644
--- a/tests/test-carray_list.c
+++ b/tests/test-carray_list.c
@@ -46,6 +46,36 @@ check_equals (gl_list_t list1, gl_list_t list2)
}
static void
+check_equals_by_forward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_first_node (list1);
+ gl_list_node_t node2 = gl_list_first_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_next_node (list1, node1);
+ node2 = gl_list_next_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
+check_equals_by_backward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_last_node (list1);
+ gl_list_node_t node2 = gl_list_last_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_previous_node (list1, node1);
+ node2 = gl_list_previous_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
check_all (gl_list_t list1, gl_list_t list2, gl_list_t list3)
{
check_equals (list1, list2);
@@ -88,6 +118,9 @@ main (int argc, char *argv[])
check_all (list1, list2, list3);
+ check_equals_by_forward_iteration (list1, list2);
+ check_equals_by_backward_iteration (list1, list2);
+
for (repeat = 0; repeat < 10000; repeat++)
{
unsigned int operation = RANDOM (18);
diff --git a/tests/test-linked_list.c b/tests/test-linked_list.c
index 4f3ec5d..fff7e06 100644
--- a/tests/test-linked_list.c
+++ b/tests/test-linked_list.c
@@ -46,6 +46,36 @@ check_equals (gl_list_t list1, gl_list_t list2)
}
static void
+check_equals_by_forward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_first_node (list1);
+ gl_list_node_t node2 = gl_list_first_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_next_node (list1, node1);
+ node2 = gl_list_next_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
+check_equals_by_backward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_last_node (list1);
+ gl_list_node_t node2 = gl_list_last_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_previous_node (list1, node1);
+ node2 = gl_list_previous_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
check_all (gl_list_t list1, gl_list_t list2, gl_list_t list3)
{
check_equals (list1, list2);
@@ -88,6 +118,9 @@ main (int argc, char *argv[])
check_all (list1, list2, list3);
+ check_equals_by_forward_iteration (list1, list2);
+ check_equals_by_backward_iteration (list1, list2);
+
for (repeat = 0; repeat < 10000; repeat++)
{
unsigned int operation = RANDOM (18);
diff --git a/tests/test-linkedhash_list.c b/tests/test-linkedhash_list.c
index b61feda..fc2a8a05 100644
--- a/tests/test-linkedhash_list.c
+++ b/tests/test-linkedhash_list.c
@@ -73,6 +73,36 @@ check_equals (gl_list_t list1, gl_list_t list2)
}
static void
+check_equals_by_forward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_first_node (list1);
+ gl_list_node_t node2 = gl_list_first_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_next_node (list1, node1);
+ node2 = gl_list_next_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
+check_equals_by_backward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_last_node (list1);
+ gl_list_node_t node2 = gl_list_last_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_previous_node (list1, node1);
+ node2 = gl_list_previous_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
check_all (gl_list_t list1, gl_list_t list2, gl_list_t list3)
{
check_equals (list1, list2);
@@ -118,6 +148,9 @@ main (int argc, char *argv[])
check_all (list1, list2, list3);
+ check_equals_by_forward_iteration (list1, list2);
+ check_equals_by_backward_iteration (list1, list2);
+
for (repeat = 0; repeat < 10000; repeat++)
{
unsigned int operation = RANDOM (18);
diff --git a/tests/test-rbtree_list.c b/tests/test-rbtree_list.c
index 9c403f7..d3ea656 100644
--- a/tests/test-rbtree_list.c
+++ b/tests/test-rbtree_list.c
@@ -48,6 +48,36 @@ check_equals (gl_list_t list1, gl_list_t list2)
}
static void
+check_equals_by_forward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_first_node (list1);
+ gl_list_node_t node2 = gl_list_first_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_next_node (list1, node1);
+ node2 = gl_list_next_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
+check_equals_by_backward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_last_node (list1);
+ gl_list_node_t node2 = gl_list_last_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_previous_node (list1, node1);
+ node2 = gl_list_previous_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
check_all (gl_list_t list1, gl_list_t list2, gl_list_t list3)
{
gl_rbtree_list_check_invariants (list2);
@@ -92,6 +122,9 @@ main (int argc, char *argv[])
check_all (list1, list2, list3);
+ check_equals_by_forward_iteration (list1, list2);
+ check_equals_by_backward_iteration (list1, list2);
+
for (repeat = 0; repeat < 10000; repeat++)
{
unsigned int operation = RANDOM (18);
diff --git a/tests/test-rbtreehash_list.c b/tests/test-rbtreehash_list.c
index 41ef5c4..89fc3eb 100644
--- a/tests/test-rbtreehash_list.c
+++ b/tests/test-rbtreehash_list.c
@@ -75,6 +75,36 @@ check_equals (gl_list_t list1, gl_list_t list2)
}
static void
+check_equals_by_forward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_first_node (list1);
+ gl_list_node_t node2 = gl_list_first_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_next_node (list1, node1);
+ node2 = gl_list_next_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
+check_equals_by_backward_iteration (gl_list_t list1, gl_list_t list2)
+{
+ gl_list_node_t node1 = gl_list_last_node (list1);
+ gl_list_node_t node2 = gl_list_last_node (list2);
+ while (node1 != NULL && node2 != NULL)
+ {
+ ASSERT (gl_list_node_value (list1, node1)
+ == gl_list_node_value (list2, node2));
+ node1 = gl_list_previous_node (list1, node1);
+ node2 = gl_list_previous_node (list2, node2);
+ }
+ ASSERT ((node1 == NULL) == (node2 == NULL));
+}
+
+static void
check_all (gl_list_t list1, gl_list_t list2, gl_list_t list3)
{
gl_rbtreehash_list_check_invariants (list2);
@@ -122,6 +152,9 @@ main (int argc, char *argv[])
check_all (list1, list2, list3);
+ check_equals_by_forward_iteration (list1, list2);
+ check_equals_by_backward_iteration (list1, list2);
+
for (repeat = 0; repeat < 10000; repeat++)
{
unsigned int operation = RANDOM (18);
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread