2767 lines
96 KiB
Diff
2767 lines
96 KiB
Diff
From e40367c0b1f4f0b32ef7aef56d0c3f8c39bacec9 Mon Sep 17 00:00:00 2001
|
|
From: xuraoqing <xuraoqing@huawei.com>
|
|
Date: Tue, 9 Apr 2024 15:47:38 +0800
|
|
Subject: [PATCH] add gnulib files
|
|
|
|
Reference: https://gitlab.com/libidn/gnulib-mirror/-/tree/master/lib
|
|
Conflict: NA
|
|
|
|
files(*.c,*.h) below from gnulib, but no commit id in gnutls repository.
|
|
fix CVE-2024-28835 need those files.
|
|
|
|
Makefile.am and Makefile.in generated by automake.
|
|
|
|
---
|
|
gl/Makefile.am | 13 +
|
|
gl/Makefile.in | 61 +-
|
|
gl/gl_anyhash1.h | 31 +
|
|
gl/gl_anyhash2.h | 82 +++
|
|
gl/gl_anyhash_primes.h | 87 +++
|
|
gl/gl_anylinked_list1.h | 48 ++
|
|
gl/gl_anylinked_list2.h | 1215 +++++++++++++++++++++++++++++++++++++++
|
|
gl/gl_linkedhash_list.c | 114 ++++
|
|
gl/gl_linkedhash_list.h | 34 ++
|
|
gl/gl_list.c | 3 +
|
|
gl/gl_list.h | 914 +++++++++++++++++++++++++++++
|
|
11 files changed, 2578 insertions(+), 24 deletions(-)
|
|
create mode 100644 gl/gl_anyhash1.h
|
|
create mode 100644 gl/gl_anyhash2.h
|
|
create mode 100644 gl/gl_anyhash_primes.h
|
|
create mode 100644 gl/gl_anylinked_list1.h
|
|
create mode 100644 gl/gl_anylinked_list2.h
|
|
create mode 100644 gl/gl_linkedhash_list.c
|
|
create mode 100644 gl/gl_linkedhash_list.h
|
|
create mode 100644 gl/gl_list.c
|
|
create mode 100644 gl/gl_list.h
|
|
|
|
diff --git a/gl/Makefile.am b/gl/Makefile.am
|
|
index 89a5c6a..31e62b2 100644
|
|
--- a/gl/Makefile.am
|
|
+++ b/gl/Makefile.am
|
|
@@ -59,6 +59,7 @@
|
|
# ldd \
|
|
# lib-msvc-compat \
|
|
# lib-symbol-versions \
|
|
+# linkedhash-list \
|
|
# maintainer-makefile \
|
|
# manywarnings \
|
|
# memmem-simple \
|
|
@@ -663,6 +664,18 @@ EXTRA_DIST += limits.in.h
|
|
|
|
## end gnulib module limits-h
|
|
|
|
+## begin gnulib module linkedhash-list
|
|
+
|
|
+libgnu_la_SOURCES += gl_linkedhash_list.h gl_linkedhash_list.c gl_anyhash1.h gl_anyhash2.h gl_anyhash_primes.h gl_anylinked_list1.h gl_anylinked_list2.h
|
|
+
|
|
+## end gnulib module linkedhash-list
|
|
+
|
|
+## begin gnulib module list
|
|
+
|
|
+libgnu_la_SOURCES += gl_list.h gl_list.c
|
|
+
|
|
+## end gnulib module list
|
|
+
|
|
## begin gnulib module lseek
|
|
|
|
|
|
diff --git a/gl/Makefile.in b/gl/Makefile.in
|
|
index b1ece83..f57ecfb 100644
|
|
--- a/gl/Makefile.in
|
|
+++ b/gl/Makefile.in
|
|
@@ -73,6 +73,7 @@
|
|
# ldd \
|
|
# lib-msvc-compat \
|
|
# lib-symbol-versions \
|
|
+# linkedhash-list \
|
|
# maintainer-makefile \
|
|
# manywarnings \
|
|
# memmem-simple \
|
|
@@ -358,8 +359,9 @@ am__DEPENDENCIES_1 =
|
|
am__dirstamp = $(am__leading_dot)dirstamp
|
|
am_libgnu_la_OBJECTS = bitrotate.lo c-ctype.lo c-strcasecmp.lo \
|
|
c-strncasecmp.lo cloexec.lo fd-hook.lo hash.lo \
|
|
- hash-pjw-bare.lo malloca.lo read-file.lo stat-time.lo \
|
|
- sys_socket.lo glthread/threadlib.lo unistd.lo xsize.lo
|
|
+ hash-pjw-bare.lo gl_linkedhash_list.lo gl_list.lo malloca.lo \
|
|
+ read-file.lo stat-time.lo sys_socket.lo glthread/threadlib.lo \
|
|
+ unistd.lo xsize.lo
|
|
libgnu_la_OBJECTS = $(am_libgnu_la_OBJECTS)
|
|
AM_V_lt = $(am__v_lt_@AM_V@)
|
|
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
|
@@ -394,26 +396,28 @@ am__depfiles_remade = ./$(DEPDIR)/alloca.Plo ./$(DEPDIR)/asnprintf.Plo \
|
|
./$(DEPDIR)/fstat.Plo ./$(DEPDIR)/ftell.Plo \
|
|
./$(DEPDIR)/ftello.Plo ./$(DEPDIR)/getdelim.Plo \
|
|
./$(DEPDIR)/getdtablesize.Plo ./$(DEPDIR)/getline.Plo \
|
|
- ./$(DEPDIR)/gettimeofday.Plo ./$(DEPDIR)/hash-pjw-bare.Plo \
|
|
- ./$(DEPDIR)/hash.Plo ./$(DEPDIR)/inet_ntop.Plo \
|
|
- ./$(DEPDIR)/inet_pton.Plo ./$(DEPDIR)/itold.Plo \
|
|
- ./$(DEPDIR)/lseek.Plo ./$(DEPDIR)/malloc.Plo \
|
|
- ./$(DEPDIR)/malloca.Plo ./$(DEPDIR)/memchr.Plo \
|
|
- ./$(DEPDIR)/memmem.Plo ./$(DEPDIR)/msvc-inval.Plo \
|
|
- ./$(DEPDIR)/msvc-nothrow.Plo ./$(DEPDIR)/open.Plo \
|
|
- ./$(DEPDIR)/printf-args.Plo ./$(DEPDIR)/printf-parse.Plo \
|
|
- ./$(DEPDIR)/read-file.Plo ./$(DEPDIR)/realloc.Plo \
|
|
- ./$(DEPDIR)/secure_getenv.Plo ./$(DEPDIR)/setsockopt.Plo \
|
|
- ./$(DEPDIR)/snprintf.Plo ./$(DEPDIR)/stat-time.Plo \
|
|
- ./$(DEPDIR)/stat-w32.Plo ./$(DEPDIR)/stat.Plo \
|
|
- ./$(DEPDIR)/stpcpy.Plo ./$(DEPDIR)/strcasecmp.Plo \
|
|
- ./$(DEPDIR)/strdup.Plo ./$(DEPDIR)/strncasecmp.Plo \
|
|
- ./$(DEPDIR)/strndup.Plo ./$(DEPDIR)/strnlen.Plo \
|
|
- ./$(DEPDIR)/strtok_r.Plo ./$(DEPDIR)/strverscmp.Plo \
|
|
- ./$(DEPDIR)/sys_socket.Plo ./$(DEPDIR)/time_r.Plo \
|
|
- ./$(DEPDIR)/unistd.Plo ./$(DEPDIR)/vasnprintf.Plo \
|
|
- ./$(DEPDIR)/vasprintf.Plo ./$(DEPDIR)/vsnprintf.Plo \
|
|
- ./$(DEPDIR)/xsize.Plo glthread/$(DEPDIR)/threadlib.Plo
|
|
+ ./$(DEPDIR)/gettimeofday.Plo \
|
|
+ ./$(DEPDIR)/gl_linkedhash_list.Plo ./$(DEPDIR)/gl_list.Plo \
|
|
+ ./$(DEPDIR)/hash-pjw-bare.Plo ./$(DEPDIR)/hash.Plo \
|
|
+ ./$(DEPDIR)/inet_ntop.Plo ./$(DEPDIR)/inet_pton.Plo \
|
|
+ ./$(DEPDIR)/itold.Plo ./$(DEPDIR)/lseek.Plo \
|
|
+ ./$(DEPDIR)/malloc.Plo ./$(DEPDIR)/malloca.Plo \
|
|
+ ./$(DEPDIR)/memchr.Plo ./$(DEPDIR)/memmem.Plo \
|
|
+ ./$(DEPDIR)/msvc-inval.Plo ./$(DEPDIR)/msvc-nothrow.Plo \
|
|
+ ./$(DEPDIR)/open.Plo ./$(DEPDIR)/printf-args.Plo \
|
|
+ ./$(DEPDIR)/printf-parse.Plo ./$(DEPDIR)/read-file.Plo \
|
|
+ ./$(DEPDIR)/realloc.Plo ./$(DEPDIR)/secure_getenv.Plo \
|
|
+ ./$(DEPDIR)/setsockopt.Plo ./$(DEPDIR)/snprintf.Plo \
|
|
+ ./$(DEPDIR)/stat-time.Plo ./$(DEPDIR)/stat-w32.Plo \
|
|
+ ./$(DEPDIR)/stat.Plo ./$(DEPDIR)/stpcpy.Plo \
|
|
+ ./$(DEPDIR)/strcasecmp.Plo ./$(DEPDIR)/strdup.Plo \
|
|
+ ./$(DEPDIR)/strncasecmp.Plo ./$(DEPDIR)/strndup.Plo \
|
|
+ ./$(DEPDIR)/strnlen.Plo ./$(DEPDIR)/strtok_r.Plo \
|
|
+ ./$(DEPDIR)/strverscmp.Plo ./$(DEPDIR)/sys_socket.Plo \
|
|
+ ./$(DEPDIR)/time_r.Plo ./$(DEPDIR)/unistd.Plo \
|
|
+ ./$(DEPDIR)/vasnprintf.Plo ./$(DEPDIR)/vasprintf.Plo \
|
|
+ ./$(DEPDIR)/vsnprintf.Plo ./$(DEPDIR)/xsize.Plo \
|
|
+ glthread/$(DEPDIR)/threadlib.Plo
|
|
am__mv = mv -f
|
|
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
|
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
|
@@ -2275,8 +2279,11 @@ AM_CFLAGS =
|
|
libgnu_la_SOURCES = bitrotate.h bitrotate.c c-ctype.h c-ctype.c \
|
|
c-strcase.h c-strcasecmp.c c-strncasecmp.c cloexec.c fd-hook.c \
|
|
gettext.h hash.c hash-pjw-bare.h hash-pjw-bare.c idx.h \
|
|
- malloca.c minmax.h read-file.c size_max.h stat-time.c \
|
|
- sys_socket.c glthread/threadlib.c unistd.c xsize.h xsize.c
|
|
+ gl_linkedhash_list.h gl_linkedhash_list.c gl_anyhash1.h \
|
|
+ gl_anyhash2.h gl_anyhash_primes.h gl_anylinked_list1.h \
|
|
+ gl_anylinked_list2.h gl_list.h gl_list.c malloca.c minmax.h \
|
|
+ read-file.c size_max.h stat-time.c sys_socket.c \
|
|
+ glthread/threadlib.c unistd.c xsize.h xsize.c
|
|
libgnu_la_LIBADD = $(gl_LTLIBOBJS) @LTALLOCA@
|
|
libgnu_la_DEPENDENCIES = $(gl_LTLIBOBJS) @LTALLOCA@
|
|
EXTRA_libgnu_la_SOURCES = alloca.c close.c dup2.c explicit_bzero.c \
|
|
@@ -2407,6 +2414,8 @@ distclean-compile:
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdtablesize.Plo@am__quote@ # am--include-marker
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getline.Plo@am__quote@ # am--include-marker
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gettimeofday.Plo@am__quote@ # am--include-marker
|
|
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gl_linkedhash_list.Plo@am__quote@ # am--include-marker
|
|
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gl_list.Plo@am__quote@ # am--include-marker
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash-pjw-bare.Plo@am__quote@ # am--include-marker
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Plo@am__quote@ # am--include-marker
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inet_ntop.Plo@am__quote@ # am--include-marker
|
|
@@ -2714,6 +2723,8 @@ distclean: distclean-recursive
|
|
-rm -f ./$(DEPDIR)/getdtablesize.Plo
|
|
-rm -f ./$(DEPDIR)/getline.Plo
|
|
-rm -f ./$(DEPDIR)/gettimeofday.Plo
|
|
+ -rm -f ./$(DEPDIR)/gl_linkedhash_list.Plo
|
|
+ -rm -f ./$(DEPDIR)/gl_list.Plo
|
|
-rm -f ./$(DEPDIR)/hash-pjw-bare.Plo
|
|
-rm -f ./$(DEPDIR)/hash.Plo
|
|
-rm -f ./$(DEPDIR)/inet_ntop.Plo
|
|
@@ -2821,6 +2832,8 @@ maintainer-clean: maintainer-clean-recursive
|
|
-rm -f ./$(DEPDIR)/getdtablesize.Plo
|
|
-rm -f ./$(DEPDIR)/getline.Plo
|
|
-rm -f ./$(DEPDIR)/gettimeofday.Plo
|
|
+ -rm -f ./$(DEPDIR)/gl_linkedhash_list.Plo
|
|
+ -rm -f ./$(DEPDIR)/gl_list.Plo
|
|
-rm -f ./$(DEPDIR)/hash-pjw-bare.Plo
|
|
-rm -f ./$(DEPDIR)/hash.Plo
|
|
-rm -f ./$(DEPDIR)/inet_ntop.Plo
|
|
diff --git a/gl/gl_anyhash1.h b/gl/gl_anyhash1.h
|
|
new file mode 100644
|
|
index 0000000..3253673
|
|
--- /dev/null
|
|
+++ b/gl/gl_anyhash1.h
|
|
@@ -0,0 +1,31 @@
|
|
+/* Hash table for sequential list, set, and map data type.
|
|
+ Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
|
|
+ Written by Bruno Haible <bruno@clisp.org>, 2006.
|
|
+
|
|
+ This program is free software: you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+/* Common code of
|
|
+ gl_linkedhash_list.c, gl_avltreehash_list.c, gl_rbtreehash_list.c,
|
|
+ gl_linkedhash_set.c, gl_hash_set.c,
|
|
+ gl_linkedhash_map.c, gl_hash_map.c. */
|
|
+
|
|
+/* Hash table entry. */
|
|
+struct gl_hash_entry
|
|
+{
|
|
+ struct gl_hash_entry *hash_next; /* chain of entries in same bucket */
|
|
+ size_t hashcode; /* cache of the hash code of
|
|
+ - the key (for map data type) or
|
|
+ - the value (for list, set data types) */
|
|
+};
|
|
+typedef struct gl_hash_entry * gl_hash_entry_t;
|
|
diff --git a/gl/gl_anyhash2.h b/gl/gl_anyhash2.h
|
|
new file mode 100644
|
|
index 0000000..d8b5fb0
|
|
--- /dev/null
|
|
+++ b/gl/gl_anyhash2.h
|
|
@@ -0,0 +1,82 @@
|
|
+/* Hash table for sequential list, set, and map data type.
|
|
+ Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
|
|
+ Written by Bruno Haible <bruno@clisp.org>, 2006.
|
|
+
|
|
+ This program is free software: you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+/* Common code of
|
|
+ gl_linkedhash_list.c, gl_avltreehash_list.c, gl_rbtreehash_list.c,
|
|
+ gl_linkedhash_set.c, gl_hash_set.c,
|
|
+ gl_linkedhash_map.c, gl_hash_map.c. */
|
|
+
|
|
+#include "gl_anyhash_primes.h"
|
|
+
|
|
+/* Resizes the hash table with a new estimated size. */
|
|
+static void
|
|
+hash_resize (CONTAINER_T container, size_t estimate)
|
|
+{
|
|
+ size_t new_size = next_prime (estimate);
|
|
+
|
|
+ if (new_size > container->table_size)
|
|
+ {
|
|
+ gl_hash_entry_t *old_table = container->table;
|
|
+ /* Allocate the new table. */
|
|
+ gl_hash_entry_t *new_table;
|
|
+ size_t i;
|
|
+
|
|
+ if (size_overflow_p (xtimes (new_size, sizeof (gl_hash_entry_t))))
|
|
+ goto fail;
|
|
+ new_table =
|
|
+ (gl_hash_entry_t *) calloc (new_size, sizeof (gl_hash_entry_t));
|
|
+ if (new_table == NULL)
|
|
+ goto fail;
|
|
+
|
|
+ /* Iterate through the entries of the old table. */
|
|
+ for (i = container->table_size; i > 0; )
|
|
+ {
|
|
+ gl_hash_entry_t node = old_table[--i];
|
|
+
|
|
+ while (node != NULL)
|
|
+ {
|
|
+ gl_hash_entry_t next = node->hash_next;
|
|
+ /* Add the entry to the new table. */
|
|
+ size_t bucket = node->hashcode % new_size;
|
|
+ node->hash_next = new_table[bucket];
|
|
+ new_table[bucket] = node;
|
|
+
|
|
+ node = next;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ container->table = new_table;
|
|
+ container->table_size = new_size;
|
|
+ free (old_table);
|
|
+ }
|
|
+ return;
|
|
+
|
|
+ fail:
|
|
+ /* Just continue without resizing the table. */
|
|
+ return;
|
|
+}
|
|
+
|
|
+/* Resizes the hash table if needed, after CONTAINER_COUNT (container) was
|
|
+ incremented. */
|
|
+static void
|
|
+hash_resize_after_add (CONTAINER_T container)
|
|
+{
|
|
+ size_t count = CONTAINER_COUNT (container);
|
|
+ size_t estimate = xsum (count, count / 2); /* 1.5 * count */
|
|
+ if (estimate > container->table_size)
|
|
+ hash_resize (container, estimate);
|
|
+}
|
|
diff --git a/gl/gl_anyhash_primes.h b/gl/gl_anyhash_primes.h
|
|
new file mode 100644
|
|
index 0000000..b723e64
|
|
--- /dev/null
|
|
+++ b/gl/gl_anyhash_primes.h
|
|
@@ -0,0 +1,87 @@
|
|
+/* Table of primes, for use by hash tables.
|
|
+ Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
|
|
+ Written by Bruno Haible <bruno@clisp.org>, 2006.
|
|
+
|
|
+ This program is free software: you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+/* Array of primes, approximately in steps of factor 1.2.
|
|
+ This table was computed by executing the Common Lisp expression
|
|
+ (dotimes (i 244) (format t "nextprime(~D)~%" (ceiling (expt 1.2d0 i))))
|
|
+ and feeding the result to PARI/gp. */
|
|
+static const size_t primes[] =
|
|
+ {
|
|
+ 11, 13, 17, 19, 23, 29, 37, 41, 47, 59, 67, 83, 97, 127, 139, 167, 199,
|
|
+ 239, 293, 347, 419, 499, 593, 709, 853, 1021, 1229, 1471, 1777, 2129, 2543,
|
|
+ 3049, 3659, 4391, 5273, 6323, 7589, 9103, 10937, 13109, 15727, 18899,
|
|
+ 22651, 27179, 32609, 39133, 46957, 56359, 67619, 81157, 97369, 116849,
|
|
+ 140221, 168253, 201907, 242309, 290761, 348889, 418667, 502409, 602887,
|
|
+ 723467, 868151, 1041779, 1250141, 1500181, 1800191, 2160233, 2592277,
|
|
+ 3110741, 3732887, 4479463, 5375371, 6450413, 7740517, 9288589, 11146307,
|
|
+ 13375573, 16050689, 19260817, 23112977, 27735583, 33282701, 39939233,
|
|
+ 47927081, 57512503, 69014987, 82818011, 99381577, 119257891, 143109469,
|
|
+ 171731387, 206077643, 247293161, 296751781, 356102141, 427322587,
|
|
+ 512787097, 615344489, 738413383, 886096061, 1063315271, 1275978331,
|
|
+ 1531174013, 1837408799, 2204890543UL, 2645868653UL, 3175042391UL,
|
|
+ 3810050851UL,
|
|
+#if SIZE_MAX > 4294967295UL
|
|
+ 4572061027UL, 5486473229UL, 6583767889UL, 7900521449UL, 9480625733UL,
|
|
+ 11376750877UL, 13652101063UL, 16382521261UL, 19659025513UL, 23590830631UL,
|
|
+ 28308996763UL, 33970796089UL, 40764955463UL, 48917946377UL, 58701535657UL,
|
|
+ 70441842749UL, 84530211301UL, 101436253561UL, 121723504277UL,
|
|
+ 146068205131UL, 175281846149UL, 210338215379UL, 252405858521UL,
|
|
+ 302887030151UL, 363464436191UL, 436157323417UL, 523388788231UL,
|
|
+ 628066545713UL, 753679854847UL, 904415825857UL, 1085298991109UL,
|
|
+ 1302358789181UL, 1562830547009UL, 1875396656429UL, 2250475987709UL,
|
|
+ 2700571185239UL, 3240685422287UL, 3888822506759UL, 4666587008147UL,
|
|
+ 5599904409713UL, 6719885291641UL, 8063862349969UL, 9676634819959UL,
|
|
+ 11611961783951UL, 13934354140769UL, 16721224968907UL, 20065469962669UL,
|
|
+ 24078563955191UL, 28894276746229UL, 34673132095507UL, 41607758514593UL,
|
|
+ 49929310217531UL, 59915172260971UL, 71898206713183UL, 86277848055823UL,
|
|
+ 103533417666967UL, 124240101200359UL, 149088121440451UL, 178905745728529UL,
|
|
+ 214686894874223UL, 257624273849081UL, 309149128618903UL, 370978954342639UL,
|
|
+ 445174745211143UL, 534209694253381UL, 641051633104063UL, 769261959724877UL,
|
|
+ 923114351670013UL, 1107737222003791UL, 1329284666404567UL,
|
|
+ 1595141599685509UL, 1914169919622551UL, 2297003903547091UL,
|
|
+ 2756404684256459UL, 3307685621107757UL, 3969222745329323UL,
|
|
+ 4763067294395177UL, 5715680753274209UL, 6858816903929113UL,
|
|
+ 8230580284714831UL, 9876696341657791UL, 11852035609989371UL,
|
|
+ 14222442731987227UL, 17066931278384657UL, 20480317534061597UL,
|
|
+ 24576381040873903UL, 29491657249048679UL, 35389988698858471UL,
|
|
+ 42467986438630267UL, 50961583726356109UL, 61153900471627387UL,
|
|
+ 73384680565952851UL, 88061616679143347UL, 105673940014972061UL,
|
|
+ 126808728017966413UL, 152170473621559703UL, 182604568345871671UL,
|
|
+ 219125482015045997UL, 262950578418055169UL, 315540694101666193UL,
|
|
+ 378648832921999397UL, 454378599506399233UL, 545254319407679131UL,
|
|
+ 654305183289214771UL, 785166219947057701UL, 942199463936469157UL,
|
|
+ 1130639356723763129UL, 1356767228068515623UL, 1628120673682218619UL,
|
|
+ 1953744808418662409UL, 2344493770102394881UL, 2813392524122873857UL,
|
|
+ 3376071028947448339UL, 4051285234736937517UL, 4861542281684325481UL,
|
|
+ 5833850738021191727UL, 7000620885625427969UL, 8400745062750513217UL,
|
|
+ 10080894075300616261UL, 12097072890360739951UL, 14516487468432885797UL,
|
|
+ 17419784962119465179UL,
|
|
+#endif
|
|
+ SIZE_MAX /* sentinel, to ensure the search terminates */
|
|
+ };
|
|
+
|
|
+/* Returns a suitable prime >= ESTIMATE. */
|
|
+static size_t
|
|
+next_prime (size_t estimate)
|
|
+{
|
|
+ size_t i;
|
|
+
|
|
+ for (i = 0; i < sizeof (primes) / sizeof (primes[0]); i++)
|
|
+ if (primes[i] >= estimate)
|
|
+ return primes[i];
|
|
+ return SIZE_MAX; /* not a prime, but better than nothing */
|
|
+}
|
|
diff --git a/gl/gl_anylinked_list1.h b/gl/gl_anylinked_list1.h
|
|
new file mode 100644
|
|
index 0000000..caaaa4a
|
|
--- /dev/null
|
|
+++ b/gl/gl_anylinked_list1.h
|
|
@@ -0,0 +1,48 @@
|
|
+/* Sequential list data type implemented by a linked list.
|
|
+ Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
|
|
+ Written by Bruno Haible <bruno@clisp.org>, 2006.
|
|
+
|
|
+ This program is free software: you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+/* Common code of gl_linked_list.c and gl_linkedhash_list.c. */
|
|
+
|
|
+/* -------------------------- gl_list_t Data Type -------------------------- */
|
|
+
|
|
+/* Concrete list node implementation, valid for this file only. */
|
|
+struct gl_list_node_impl
|
|
+{
|
|
+#if WITH_HASHTABLE
|
|
+ struct gl_hash_entry h; /* hash table entry fields; must be first */
|
|
+#endif
|
|
+ struct gl_list_node_impl *next;
|
|
+ struct gl_list_node_impl *prev;
|
|
+ const void *value;
|
|
+};
|
|
+
|
|
+/* Concrete gl_list_impl type, valid for this file only. */
|
|
+struct gl_list_impl
|
|
+{
|
|
+ struct gl_list_impl_base base;
|
|
+#if WITH_HASHTABLE
|
|
+ /* A hash table: managed as an array of collision lists. */
|
|
+ struct gl_hash_entry **table;
|
|
+ size_t table_size;
|
|
+#endif
|
|
+ /* A circular list anchored at root.
|
|
+ The first node is = root.next, the last node is = root.prev.
|
|
+ The root's value is unused. */
|
|
+ struct gl_list_node_impl root;
|
|
+ /* Number of list nodes, excluding the root. */
|
|
+ size_t count;
|
|
+};
|
|
diff --git a/gl/gl_anylinked_list2.h b/gl/gl_anylinked_list2.h
|
|
new file mode 100644
|
|
index 0000000..6af3f76
|
|
--- /dev/null
|
|
+++ b/gl/gl_anylinked_list2.h
|
|
@@ -0,0 +1,1215 @@
|
|
+/* Sequential list data type implemented by a linked list.
|
|
+ Copyright (C) 2006-2021 Free Software Foundation, Inc.
|
|
+ Written by Bruno Haible <bruno@clisp.org>, 2006.
|
|
+
|
|
+ This program is free software: you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+/* Common code of gl_linked_list.c and gl_linkedhash_list.c. */
|
|
+
|
|
+/* If the symbol SIGNAL_SAFE_LIST is defined, the code is compiled in such
|
|
+ a way that a gl_list_t data structure may be used from within a signal
|
|
+ handler. The operations allowed in the signal handler are:
|
|
+ gl_list_iterator, gl_list_iterator_next, gl_list_iterator_free.
|
|
+ The list and node fields that are therefore accessed from the signal handler
|
|
+ are:
|
|
+ list->root, node->next, node->value.
|
|
+ We are careful to make modifications to these fields only in an order
|
|
+ that maintains the consistency of the list data structure at any moment,
|
|
+ and we use 'volatile' assignments to prevent the compiler from reordering
|
|
+ such assignments. */
|
|
+#ifdef SIGNAL_SAFE_LIST
|
|
+# define ASYNCSAFE(type) *(type volatile *)&
|
|
+#else
|
|
+# define ASYNCSAFE(type)
|
|
+#endif
|
|
+
|
|
+/* -------------------------- gl_list_t Data Type -------------------------- */
|
|
+
|
|
+static gl_list_t
|
|
+gl_linked_nx_create_empty (gl_list_implementation_t implementation,
|
|
+ gl_listelement_equals_fn equals_fn,
|
|
+ gl_listelement_hashcode_fn hashcode_fn,
|
|
+ gl_listelement_dispose_fn dispose_fn,
|
|
+ bool allow_duplicates)
|
|
+{
|
|
+ struct gl_list_impl *list =
|
|
+ (struct gl_list_impl *) malloc (sizeof (struct gl_list_impl));
|
|
+
|
|
+ if (list == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ list->base.vtable = implementation;
|
|
+ list->base.equals_fn = equals_fn;
|
|
+ list->base.hashcode_fn = hashcode_fn;
|
|
+ list->base.dispose_fn = dispose_fn;
|
|
+ list->base.allow_duplicates = allow_duplicates;
|
|
+#if WITH_HASHTABLE
|
|
+ list->table_size = 11;
|
|
+ list->table =
|
|
+ (gl_hash_entry_t *) calloc (list->table_size, sizeof (gl_hash_entry_t));
|
|
+ if (list->table == NULL)
|
|
+ goto fail;
|
|
+#endif
|
|
+ list->root.next = &list->root;
|
|
+ list->root.prev = &list->root;
|
|
+ list->count = 0;
|
|
+
|
|
+ return list;
|
|
+
|
|
+#if WITH_HASHTABLE
|
|
+ fail:
|
|
+ free (list);
|
|
+ return NULL;
|
|
+#endif
|
|
+}
|
|
+
|
|
+static gl_list_t
|
|
+gl_linked_nx_create (gl_list_implementation_t implementation,
|
|
+ gl_listelement_equals_fn equals_fn,
|
|
+ gl_listelement_hashcode_fn hashcode_fn,
|
|
+ gl_listelement_dispose_fn dispose_fn,
|
|
+ bool allow_duplicates,
|
|
+ size_t count, const void **contents)
|
|
+{
|
|
+ struct gl_list_impl *list =
|
|
+ (struct gl_list_impl *) malloc (sizeof (struct gl_list_impl));
|
|
+ gl_list_node_t tail;
|
|
+
|
|
+ if (list == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ list->base.vtable = implementation;
|
|
+ list->base.equals_fn = equals_fn;
|
|
+ list->base.hashcode_fn = hashcode_fn;
|
|
+ list->base.dispose_fn = dispose_fn;
|
|
+ list->base.allow_duplicates = allow_duplicates;
|
|
+#if WITH_HASHTABLE
|
|
+ {
|
|
+ size_t estimate = xsum (count, count / 2); /* 1.5 * count */
|
|
+ if (estimate < 10)
|
|
+ estimate = 10;
|
|
+ list->table_size = next_prime (estimate);
|
|
+ if (size_overflow_p (xtimes (list->table_size, sizeof (gl_hash_entry_t))))
|
|
+ goto fail1;
|
|
+ list->table =
|
|
+ (gl_hash_entry_t *) calloc (list->table_size, sizeof (gl_hash_entry_t));
|
|
+ if (list->table == NULL)
|
|
+ goto fail1;
|
|
+ }
|
|
+#endif
|
|
+ list->count = count;
|
|
+ tail = &list->root;
|
|
+ for (; count > 0; contents++, count--)
|
|
+ {
|
|
+ gl_list_node_t node =
|
|
+ (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
|
|
+
|
|
+ if (node == NULL)
|
|
+ goto fail2;
|
|
+
|
|
+ node->value = *contents;
|
|
+#if WITH_HASHTABLE
|
|
+ node->h.hashcode =
|
|
+ (list->base.hashcode_fn != NULL
|
|
+ ? list->base.hashcode_fn (node->value)
|
|
+ : (size_t)(uintptr_t) node->value);
|
|
+
|
|
+ /* Add node to the hash table. */
|
|
+ if (add_to_bucket (list, node) < 0)
|
|
+ {
|
|
+ free (node);
|
|
+ goto fail2;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /* Add node to the list. */
|
|
+ node->prev = tail;
|
|
+ tail->next = node;
|
|
+ tail = node;
|
|
+ }
|
|
+ tail->next = &list->root;
|
|
+ list->root.prev = tail;
|
|
+
|
|
+ return list;
|
|
+
|
|
+ fail2:
|
|
+ {
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ for (node = tail; node != &list->root; )
|
|
+ {
|
|
+ gl_list_node_t prev = node->prev;
|
|
+
|
|
+ free (node);
|
|
+ node = prev;
|
|
+ }
|
|
+ }
|
|
+#if WITH_HASHTABLE
|
|
+ free (list->table);
|
|
+ fail1:
|
|
+#endif
|
|
+ free (list);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static size_t _GL_ATTRIBUTE_PURE
|
|
+gl_linked_size (gl_list_t list)
|
|
+{
|
|
+ return list->count;
|
|
+}
|
|
+
|
|
+static const void * _GL_ATTRIBUTE_PURE
|
|
+gl_linked_node_value (gl_list_t list _GL_ATTRIBUTE_MAYBE_UNUSED,
|
|
+ gl_list_node_t node)
|
|
+{
|
|
+ return node->value;
|
|
+}
|
|
+
|
|
+static int
|
|
+gl_linked_node_nx_set_value (gl_list_t list _GL_ATTRIBUTE_MAYBE_UNUSED,
|
|
+ gl_list_node_t node,
|
|
+ const void *elt)
|
|
+{
|
|
+#if WITH_HASHTABLE
|
|
+ if (elt != node->value)
|
|
+ {
|
|
+ size_t new_hashcode =
|
|
+ (list->base.hashcode_fn != NULL
|
|
+ ? list->base.hashcode_fn (elt)
|
|
+ : (size_t)(uintptr_t) elt);
|
|
+
|
|
+ if (new_hashcode != node->h.hashcode)
|
|
+ {
|
|
+ remove_from_bucket (list, node);
|
|
+ node->value = elt;
|
|
+ node->h.hashcode = new_hashcode;
|
|
+ if (add_to_bucket (list, node) < 0)
|
|
+ {
|
|
+ /* Out of memory. We removed node from a bucket but cannot add
|
|
+ it to another bucket. In order to avoid inconsistencies, we
|
|
+ must remove node entirely from the list. */
|
|
+ gl_list_node_t before_removed = node->prev;
|
|
+ gl_list_node_t after_removed = node->next;
|
|
+ ASYNCSAFE(gl_list_node_t) before_removed->next = after_removed;
|
|
+ after_removed->prev = before_removed;
|
|
+ list->count--;
|
|
+ free (node);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ node->value = elt;
|
|
+ }
|
|
+#else
|
|
+ node->value = elt;
|
|
+#endif
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static gl_list_node_t _GL_ATTRIBUTE_PURE
|
|
+gl_linked_next_node (gl_list_t list, gl_list_node_t node)
|
|
+{
|
|
+ return (node->next != &list->root ? node->next : NULL);
|
|
+}
|
|
+
|
|
+static gl_list_node_t _GL_ATTRIBUTE_PURE
|
|
+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)
|
|
+{
|
|
+ size_t count = list->count;
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ if (!(position < count))
|
|
+ /* Invalid argument. */
|
|
+ abort ();
|
|
+ /* Here we know count > 0. */
|
|
+ if (position <= ((count - 1) / 2))
|
|
+ {
|
|
+ node = list->root.next;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->next;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ position = count - 1 - position;
|
|
+ node = list->root.prev;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->prev;
|
|
+ }
|
|
+ return node->value;
|
|
+}
|
|
+
|
|
+static gl_list_node_t
|
|
+gl_linked_nx_set_at (gl_list_t list, size_t position, const void *elt)
|
|
+{
|
|
+ size_t count = list->count;
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ if (!(position < count))
|
|
+ /* Invalid argument. */
|
|
+ abort ();
|
|
+ /* Here we know count > 0. */
|
|
+ if (position <= ((count - 1) / 2))
|
|
+ {
|
|
+ node = list->root.next;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->next;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ position = count - 1 - position;
|
|
+ node = list->root.prev;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->prev;
|
|
+ }
|
|
+#if WITH_HASHTABLE
|
|
+ if (elt != node->value)
|
|
+ {
|
|
+ size_t new_hashcode =
|
|
+ (list->base.hashcode_fn != NULL
|
|
+ ? list->base.hashcode_fn (elt)
|
|
+ : (size_t)(uintptr_t) elt);
|
|
+
|
|
+ if (new_hashcode != node->h.hashcode)
|
|
+ {
|
|
+ remove_from_bucket (list, node);
|
|
+ node->value = elt;
|
|
+ node->h.hashcode = new_hashcode;
|
|
+ if (add_to_bucket (list, node) < 0)
|
|
+ {
|
|
+ /* Out of memory. We removed node from a bucket but cannot add
|
|
+ it to another bucket. In order to avoid inconsistencies, we
|
|
+ must remove node entirely from the list. */
|
|
+ gl_list_node_t before_removed = node->prev;
|
|
+ gl_list_node_t after_removed = node->next;
|
|
+ ASYNCSAFE(gl_list_node_t) before_removed->next = after_removed;
|
|
+ after_removed->prev = before_removed;
|
|
+ list->count--;
|
|
+ free (node);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ node->value = elt;
|
|
+ }
|
|
+#else
|
|
+ node->value = elt;
|
|
+#endif
|
|
+ return node;
|
|
+}
|
|
+
|
|
+static gl_list_node_t _GL_ATTRIBUTE_PURE
|
|
+gl_linked_search_from_to (gl_list_t list, size_t start_index, size_t end_index,
|
|
+ const void *elt)
|
|
+{
|
|
+ size_t count = list->count;
|
|
+
|
|
+ if (!(start_index <= end_index && end_index <= count))
|
|
+ /* Invalid arguments. */
|
|
+ abort ();
|
|
+ {
|
|
+#if WITH_HASHTABLE
|
|
+ size_t hashcode =
|
|
+ (list->base.hashcode_fn != NULL
|
|
+ ? list->base.hashcode_fn (elt)
|
|
+ : (size_t)(uintptr_t) elt);
|
|
+ size_t bucket = hashcode % list->table_size;
|
|
+ gl_listelement_equals_fn equals = list->base.equals_fn;
|
|
+
|
|
+ if (!list->base.allow_duplicates)
|
|
+ {
|
|
+ /* Look for the first match in the hash bucket. */
|
|
+ gl_list_node_t found = NULL;
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ for (node = (gl_list_node_t) list->table[bucket];
|
|
+ node != NULL;
|
|
+ node = (gl_list_node_t) node->h.hash_next)
|
|
+ if (node->h.hashcode == hashcode
|
|
+ && (equals != NULL
|
|
+ ? equals (elt, node->value)
|
|
+ : elt == node->value))
|
|
+ {
|
|
+ found = node;
|
|
+ break;
|
|
+ }
|
|
+ if (start_index > 0)
|
|
+ /* Look whether found's index is < start_index. */
|
|
+ for (node = list->root.next; ; node = node->next)
|
|
+ {
|
|
+ if (node == found)
|
|
+ return NULL;
|
|
+ if (--start_index == 0)
|
|
+ break;
|
|
+ }
|
|
+ if (end_index < count)
|
|
+ /* Look whether found's index is >= end_index. */
|
|
+ {
|
|
+ end_index = count - end_index;
|
|
+ for (node = list->root.prev; ; node = node->prev)
|
|
+ {
|
|
+ if (node == found)
|
|
+ return NULL;
|
|
+ if (--end_index == 0)
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return found;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* Look whether there is more than one match in the hash bucket. */
|
|
+ bool multiple_matches = false;
|
|
+ gl_list_node_t first_match = NULL;
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ for (node = (gl_list_node_t) list->table[bucket];
|
|
+ node != NULL;
|
|
+ node = (gl_list_node_t) node->h.hash_next)
|
|
+ if (node->h.hashcode == hashcode
|
|
+ && (equals != NULL
|
|
+ ? equals (elt, node->value)
|
|
+ : elt == node->value))
|
|
+ {
|
|
+ if (first_match == NULL)
|
|
+ first_match = node;
|
|
+ else
|
|
+ {
|
|
+ multiple_matches = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (multiple_matches)
|
|
+ {
|
|
+ /* We need the match with the smallest index. But we don't have
|
|
+ a fast mapping node -> index. So we have to walk the list. */
|
|
+ end_index -= start_index;
|
|
+ node = list->root.next;
|
|
+ for (; start_index > 0; start_index--)
|
|
+ node = node->next;
|
|
+
|
|
+ for (;
|
|
+ end_index > 0;
|
|
+ node = node->next, end_index--)
|
|
+ if (node->h.hashcode == hashcode
|
|
+ && (equals != NULL
|
|
+ ? equals (elt, node->value)
|
|
+ : elt == node->value))
|
|
+ return node;
|
|
+ /* The matches must have all been at indices < start_index or
|
|
+ >= end_index. */
|
|
+ return NULL;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (start_index > 0)
|
|
+ /* Look whether first_match's index is < start_index. */
|
|
+ for (node = list->root.next; node != &list->root; node = node->next)
|
|
+ {
|
|
+ if (node == first_match)
|
|
+ return NULL;
|
|
+ if (--start_index == 0)
|
|
+ break;
|
|
+ }
|
|
+ if (end_index < list->count)
|
|
+ /* Look whether first_match's index is >= end_index. */
|
|
+ {
|
|
+ end_index = list->count - end_index;
|
|
+ for (node = list->root.prev; ; node = node->prev)
|
|
+ {
|
|
+ if (node == first_match)
|
|
+ return NULL;
|
|
+ if (--end_index == 0)
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return first_match;
|
|
+ }
|
|
+ }
|
|
+#else
|
|
+ gl_listelement_equals_fn equals = list->base.equals_fn;
|
|
+ gl_list_node_t node = list->root.next;
|
|
+
|
|
+ end_index -= start_index;
|
|
+ for (; start_index > 0; start_index--)
|
|
+ node = node->next;
|
|
+
|
|
+ if (equals != NULL)
|
|
+ {
|
|
+ for (; end_index > 0; node = node->next, end_index--)
|
|
+ if (equals (elt, node->value))
|
|
+ return node;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ for (; end_index > 0; node = node->next, end_index--)
|
|
+ if (elt == node->value)
|
|
+ return node;
|
|
+ }
|
|
+ return NULL;
|
|
+#endif
|
|
+ }
|
|
+}
|
|
+
|
|
+static size_t _GL_ATTRIBUTE_PURE
|
|
+gl_linked_indexof_from_to (gl_list_t list, size_t start_index, size_t end_index,
|
|
+ const void *elt)
|
|
+{
|
|
+ size_t count = list->count;
|
|
+
|
|
+ if (!(start_index <= end_index && end_index <= count))
|
|
+ /* Invalid arguments. */
|
|
+ abort ();
|
|
+ {
|
|
+#if WITH_HASHTABLE
|
|
+ /* Here the hash table doesn't help much. It only allows us to minimize
|
|
+ the number of equals() calls, by looking up first the node and then
|
|
+ its index. */
|
|
+ size_t hashcode =
|
|
+ (list->base.hashcode_fn != NULL
|
|
+ ? list->base.hashcode_fn (elt)
|
|
+ : (size_t)(uintptr_t) elt);
|
|
+ size_t bucket = hashcode % list->table_size;
|
|
+ gl_listelement_equals_fn equals = list->base.equals_fn;
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ /* First step: Look up the node. */
|
|
+ if (!list->base.allow_duplicates)
|
|
+ {
|
|
+ /* Look for the first match in the hash bucket. */
|
|
+ for (node = (gl_list_node_t) list->table[bucket];
|
|
+ node != NULL;
|
|
+ node = (gl_list_node_t) node->h.hash_next)
|
|
+ if (node->h.hashcode == hashcode
|
|
+ && (equals != NULL
|
|
+ ? equals (elt, node->value)
|
|
+ : elt == node->value))
|
|
+ break;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* Look whether there is more than one match in the hash bucket. */
|
|
+ bool multiple_matches = false;
|
|
+ gl_list_node_t first_match = NULL;
|
|
+
|
|
+ for (node = (gl_list_node_t) list->table[bucket];
|
|
+ node != NULL;
|
|
+ node = (gl_list_node_t) node->h.hash_next)
|
|
+ if (node->h.hashcode == hashcode
|
|
+ && (equals != NULL
|
|
+ ? equals (elt, node->value)
|
|
+ : elt == node->value))
|
|
+ {
|
|
+ if (first_match == NULL)
|
|
+ first_match = node;
|
|
+ else
|
|
+ {
|
|
+ multiple_matches = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (multiple_matches)
|
|
+ {
|
|
+ /* We need the match with the smallest index. But we don't have
|
|
+ a fast mapping node -> index. So we have to walk the list. */
|
|
+ size_t index;
|
|
+
|
|
+ index = start_index;
|
|
+ node = list->root.next;
|
|
+ for (; start_index > 0; start_index--)
|
|
+ node = node->next;
|
|
+
|
|
+ for (;
|
|
+ index < end_index;
|
|
+ node = node->next, index++)
|
|
+ if (node->h.hashcode == hashcode
|
|
+ && (equals != NULL
|
|
+ ? equals (elt, node->value)
|
|
+ : elt == node->value))
|
|
+ return index;
|
|
+ /* The matches must have all been at indices < start_index or
|
|
+ >= end_index. */
|
|
+ return (size_t)(-1);
|
|
+ }
|
|
+ node = first_match;
|
|
+ }
|
|
+
|
|
+ /* Second step: Look up the index of the node. */
|
|
+ if (node == NULL)
|
|
+ return (size_t)(-1);
|
|
+ else
|
|
+ {
|
|
+ size_t index = 0;
|
|
+
|
|
+ for (; node->prev != &list->root; node = node->prev)
|
|
+ index++;
|
|
+
|
|
+ if (index >= start_index && index < end_index)
|
|
+ return index;
|
|
+ else
|
|
+ return (size_t)(-1);
|
|
+ }
|
|
+#else
|
|
+ gl_listelement_equals_fn equals = list->base.equals_fn;
|
|
+ size_t index = start_index;
|
|
+ gl_list_node_t node = list->root.next;
|
|
+
|
|
+ for (; start_index > 0; start_index--)
|
|
+ node = node->next;
|
|
+
|
|
+ if (equals != NULL)
|
|
+ {
|
|
+ for (;
|
|
+ index < end_index;
|
|
+ node = node->next, index++)
|
|
+ if (equals (elt, node->value))
|
|
+ return index;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ for (;
|
|
+ index < end_index;
|
|
+ node = node->next, index++)
|
|
+ if (elt == node->value)
|
|
+ return index;
|
|
+ }
|
|
+ return (size_t)(-1);
|
|
+#endif
|
|
+ }
|
|
+}
|
|
+
|
|
+static gl_list_node_t
|
|
+gl_linked_nx_add_first (gl_list_t list, const void *elt)
|
|
+{
|
|
+ gl_list_node_t node =
|
|
+ (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
|
|
+
|
|
+ if (node == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ ASYNCSAFE(const void *) node->value = elt;
|
|
+#if WITH_HASHTABLE
|
|
+ node->h.hashcode =
|
|
+ (list->base.hashcode_fn != NULL
|
|
+ ? list->base.hashcode_fn (node->value)
|
|
+ : (size_t)(uintptr_t) node->value);
|
|
+
|
|
+ /* Add node to the hash table. */
|
|
+ if (add_to_bucket (list, node) < 0)
|
|
+ {
|
|
+ free (node);
|
|
+ return NULL;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /* Add node to the list. */
|
|
+ node->prev = &list->root;
|
|
+ ASYNCSAFE(gl_list_node_t) node->next = list->root.next;
|
|
+ node->next->prev = node;
|
|
+ ASYNCSAFE(gl_list_node_t) list->root.next = node;
|
|
+ list->count++;
|
|
+
|
|
+#if WITH_HASHTABLE
|
|
+ hash_resize_after_add (list);
|
|
+#endif
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+static gl_list_node_t
|
|
+gl_linked_nx_add_last (gl_list_t list, const void *elt)
|
|
+{
|
|
+ gl_list_node_t node =
|
|
+ (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
|
|
+
|
|
+ if (node == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ ASYNCSAFE(const void *) node->value = elt;
|
|
+#if WITH_HASHTABLE
|
|
+ node->h.hashcode =
|
|
+ (list->base.hashcode_fn != NULL
|
|
+ ? list->base.hashcode_fn (node->value)
|
|
+ : (size_t)(uintptr_t) node->value);
|
|
+
|
|
+ /* Add node to the hash table. */
|
|
+ if (add_to_bucket (list, node) < 0)
|
|
+ {
|
|
+ free (node);
|
|
+ return NULL;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /* Add node to the list. */
|
|
+ ASYNCSAFE(gl_list_node_t) node->next = &list->root;
|
|
+ node->prev = list->root.prev;
|
|
+ ASYNCSAFE(gl_list_node_t) node->prev->next = node;
|
|
+ list->root.prev = node;
|
|
+ list->count++;
|
|
+
|
|
+#if WITH_HASHTABLE
|
|
+ hash_resize_after_add (list);
|
|
+#endif
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+static gl_list_node_t
|
|
+gl_linked_nx_add_before (gl_list_t list, gl_list_node_t node, const void *elt)
|
|
+{
|
|
+ gl_list_node_t new_node =
|
|
+ (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
|
|
+
|
|
+ if (new_node == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ ASYNCSAFE(const void *) new_node->value = elt;
|
|
+#if WITH_HASHTABLE
|
|
+ new_node->h.hashcode =
|
|
+ (list->base.hashcode_fn != NULL
|
|
+ ? list->base.hashcode_fn (new_node->value)
|
|
+ : (size_t)(uintptr_t) new_node->value);
|
|
+
|
|
+ /* Add new_node to the hash table. */
|
|
+ if (add_to_bucket (list, new_node) < 0)
|
|
+ {
|
|
+ free (new_node);
|
|
+ return NULL;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /* Add new_node to the list. */
|
|
+ ASYNCSAFE(gl_list_node_t) new_node->next = node;
|
|
+ new_node->prev = node->prev;
|
|
+ ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node;
|
|
+ node->prev = new_node;
|
|
+ list->count++;
|
|
+
|
|
+#if WITH_HASHTABLE
|
|
+ hash_resize_after_add (list);
|
|
+#endif
|
|
+
|
|
+ return new_node;
|
|
+}
|
|
+
|
|
+static gl_list_node_t
|
|
+gl_linked_nx_add_after (gl_list_t list, gl_list_node_t node, const void *elt)
|
|
+{
|
|
+ gl_list_node_t new_node =
|
|
+ (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
|
|
+
|
|
+ if (new_node == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ ASYNCSAFE(const void *) new_node->value = elt;
|
|
+#if WITH_HASHTABLE
|
|
+ new_node->h.hashcode =
|
|
+ (list->base.hashcode_fn != NULL
|
|
+ ? list->base.hashcode_fn (new_node->value)
|
|
+ : (size_t)(uintptr_t) new_node->value);
|
|
+
|
|
+ /* Add new_node to the hash table. */
|
|
+ if (add_to_bucket (list, new_node) < 0)
|
|
+ {
|
|
+ free (new_node);
|
|
+ return NULL;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /* Add new_node to the list. */
|
|
+ new_node->prev = node;
|
|
+ ASYNCSAFE(gl_list_node_t) new_node->next = node->next;
|
|
+ new_node->next->prev = new_node;
|
|
+ ASYNCSAFE(gl_list_node_t) node->next = new_node;
|
|
+ list->count++;
|
|
+
|
|
+#if WITH_HASHTABLE
|
|
+ hash_resize_after_add (list);
|
|
+#endif
|
|
+
|
|
+ return new_node;
|
|
+}
|
|
+
|
|
+static gl_list_node_t
|
|
+gl_linked_nx_add_at (gl_list_t list, size_t position, const void *elt)
|
|
+{
|
|
+ size_t count = list->count;
|
|
+ gl_list_node_t new_node;
|
|
+
|
|
+ if (!(position <= count))
|
|
+ /* Invalid argument. */
|
|
+ abort ();
|
|
+
|
|
+ new_node = (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
|
|
+ if (new_node == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ ASYNCSAFE(const void *) new_node->value = elt;
|
|
+#if WITH_HASHTABLE
|
|
+ new_node->h.hashcode =
|
|
+ (list->base.hashcode_fn != NULL
|
|
+ ? list->base.hashcode_fn (new_node->value)
|
|
+ : (size_t)(uintptr_t) new_node->value);
|
|
+
|
|
+ /* Add new_node to the hash table. */
|
|
+ if (add_to_bucket (list, new_node) < 0)
|
|
+ {
|
|
+ free (new_node);
|
|
+ return NULL;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /* Add new_node to the list. */
|
|
+ if (position <= (count / 2))
|
|
+ {
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ node = &list->root;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->next;
|
|
+ new_node->prev = node;
|
|
+ ASYNCSAFE(gl_list_node_t) new_node->next = node->next;
|
|
+ new_node->next->prev = new_node;
|
|
+ ASYNCSAFE(gl_list_node_t) node->next = new_node;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ position = count - position;
|
|
+ node = &list->root;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->prev;
|
|
+ ASYNCSAFE(gl_list_node_t) new_node->next = node;
|
|
+ new_node->prev = node->prev;
|
|
+ ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node;
|
|
+ node->prev = new_node;
|
|
+ }
|
|
+ list->count++;
|
|
+
|
|
+#if WITH_HASHTABLE
|
|
+ hash_resize_after_add (list);
|
|
+#endif
|
|
+
|
|
+ return new_node;
|
|
+}
|
|
+
|
|
+static bool
|
|
+gl_linked_remove_node (gl_list_t list, gl_list_node_t node)
|
|
+{
|
|
+ gl_list_node_t prev;
|
|
+ gl_list_node_t next;
|
|
+
|
|
+#if WITH_HASHTABLE
|
|
+ /* Remove node from the hash table. */
|
|
+ remove_from_bucket (list, node);
|
|
+#endif
|
|
+
|
|
+ /* Remove node from the list. */
|
|
+ prev = node->prev;
|
|
+ next = node->next;
|
|
+
|
|
+ ASYNCSAFE(gl_list_node_t) prev->next = next;
|
|
+ next->prev = prev;
|
|
+ list->count--;
|
|
+
|
|
+ if (list->base.dispose_fn != NULL)
|
|
+ list->base.dispose_fn (node->value);
|
|
+ free (node);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static bool
|
|
+gl_linked_remove_at (gl_list_t list, size_t position)
|
|
+{
|
|
+ size_t count = list->count;
|
|
+ gl_list_node_t removed_node;
|
|
+
|
|
+ if (!(position < count))
|
|
+ /* Invalid argument. */
|
|
+ abort ();
|
|
+ /* Here we know count > 0. */
|
|
+ if (position <= ((count - 1) / 2))
|
|
+ {
|
|
+ gl_list_node_t node;
|
|
+ gl_list_node_t after_removed;
|
|
+
|
|
+ node = &list->root;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->next;
|
|
+ removed_node = node->next;
|
|
+ after_removed = node->next->next;
|
|
+ ASYNCSAFE(gl_list_node_t) node->next = after_removed;
|
|
+ after_removed->prev = node;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ gl_list_node_t node;
|
|
+ gl_list_node_t before_removed;
|
|
+
|
|
+ position = count - 1 - position;
|
|
+ node = &list->root;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->prev;
|
|
+ removed_node = node->prev;
|
|
+ before_removed = node->prev->prev;
|
|
+ node->prev = before_removed;
|
|
+ ASYNCSAFE(gl_list_node_t) before_removed->next = node;
|
|
+ }
|
|
+#if WITH_HASHTABLE
|
|
+ remove_from_bucket (list, removed_node);
|
|
+#endif
|
|
+ list->count--;
|
|
+
|
|
+ if (list->base.dispose_fn != NULL)
|
|
+ list->base.dispose_fn (removed_node->value);
|
|
+ free (removed_node);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static bool
|
|
+gl_linked_remove (gl_list_t list, const void *elt)
|
|
+{
|
|
+ gl_list_node_t node = gl_linked_search_from_to (list, 0, list->count, elt);
|
|
+
|
|
+ if (node != NULL)
|
|
+ return gl_linked_remove_node (list, node);
|
|
+ else
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static void
|
|
+gl_linked_list_free (gl_list_t list)
|
|
+{
|
|
+ gl_listelement_dispose_fn dispose = list->base.dispose_fn;
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ for (node = list->root.next; node != &list->root; )
|
|
+ {
|
|
+ gl_list_node_t next = node->next;
|
|
+ if (dispose != NULL)
|
|
+ dispose (node->value);
|
|
+ free (node);
|
|
+ node = next;
|
|
+ }
|
|
+#if WITH_HASHTABLE
|
|
+ free (list->table);
|
|
+#endif
|
|
+ free (list);
|
|
+}
|
|
+
|
|
+/* --------------------- gl_list_iterator_t Data Type --------------------- */
|
|
+
|
|
+static gl_list_iterator_t _GL_ATTRIBUTE_PURE
|
|
+gl_linked_iterator (gl_list_t list)
|
|
+{
|
|
+ gl_list_iterator_t result;
|
|
+
|
|
+ result.vtable = list->base.vtable;
|
|
+ result.list = list;
|
|
+ result.p = list->root.next;
|
|
+ result.q = &list->root;
|
|
+#if defined GCC_LINT || defined lint
|
|
+ result.i = 0;
|
|
+ result.j = 0;
|
|
+ result.count = 0;
|
|
+#endif
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static gl_list_iterator_t _GL_ATTRIBUTE_PURE
|
|
+gl_linked_iterator_from_to (gl_list_t list,
|
|
+ size_t start_index, size_t end_index)
|
|
+{
|
|
+ gl_list_iterator_t result;
|
|
+ size_t n1, n2, n3;
|
|
+
|
|
+ if (!(start_index <= end_index && end_index <= list->count))
|
|
+ /* Invalid arguments. */
|
|
+ abort ();
|
|
+ result.vtable = list->base.vtable;
|
|
+ result.list = list;
|
|
+ n1 = start_index;
|
|
+ n2 = end_index - start_index;
|
|
+ n3 = list->count - end_index;
|
|
+ /* Find the maximum among n1, n2, n3, so as to reduce the number of
|
|
+ loop iterations to n1 + n2 + n3 - max(n1,n2,n3). */
|
|
+ if (n1 > n2 && n1 > n3)
|
|
+ {
|
|
+ /* n1 is the maximum, use n2 and n3. */
|
|
+ gl_list_node_t node;
|
|
+ size_t i;
|
|
+
|
|
+ node = &list->root;
|
|
+ for (i = n3; i > 0; i--)
|
|
+ node = node->prev;
|
|
+ result.q = node;
|
|
+ for (i = n2; i > 0; i--)
|
|
+ node = node->prev;
|
|
+ result.p = node;
|
|
+ }
|
|
+ else if (n2 > n3)
|
|
+ {
|
|
+ /* n2 is the maximum, use n1 and n3. */
|
|
+ gl_list_node_t node;
|
|
+ size_t i;
|
|
+
|
|
+ node = list->root.next;
|
|
+ for (i = n1; i > 0; i--)
|
|
+ node = node->next;
|
|
+ result.p = node;
|
|
+
|
|
+ node = &list->root;
|
|
+ for (i = n3; i > 0; i--)
|
|
+ node = node->prev;
|
|
+ result.q = node;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* n3 is the maximum, use n1 and n2. */
|
|
+ gl_list_node_t node;
|
|
+ size_t i;
|
|
+
|
|
+ node = list->root.next;
|
|
+ for (i = n1; i > 0; i--)
|
|
+ node = node->next;
|
|
+ result.p = node;
|
|
+ for (i = n2; i > 0; i--)
|
|
+ node = node->next;
|
|
+ result.q = node;
|
|
+ }
|
|
+
|
|
+#if defined GCC_LINT || defined lint
|
|
+ result.i = 0;
|
|
+ result.j = 0;
|
|
+ result.count = 0;
|
|
+#endif
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static bool
|
|
+gl_linked_iterator_next (gl_list_iterator_t *iterator,
|
|
+ const void **eltp, gl_list_node_t *nodep)
|
|
+{
|
|
+ if (iterator->p != iterator->q)
|
|
+ {
|
|
+ gl_list_node_t node = (gl_list_node_t) iterator->p;
|
|
+ *eltp = node->value;
|
|
+ if (nodep != NULL)
|
|
+ *nodep = node;
|
|
+ iterator->p = node->next;
|
|
+ return true;
|
|
+ }
|
|
+ else
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static void
|
|
+gl_linked_iterator_free (gl_list_iterator_t *iterator _GL_ATTRIBUTE_MAYBE_UNUSED)
|
|
+{
|
|
+}
|
|
+
|
|
+/* ---------------------- Sorted gl_list_t Data Type ---------------------- */
|
|
+
|
|
+static gl_list_node_t _GL_ATTRIBUTE_PURE
|
|
+gl_linked_sortedlist_search (gl_list_t list, gl_listelement_compar_fn compar,
|
|
+ const void *elt)
|
|
+{
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ for (node = list->root.next; node != &list->root; node = node->next)
|
|
+ {
|
|
+ int cmp = compar (node->value, elt);
|
|
+
|
|
+ if (cmp > 0)
|
|
+ break;
|
|
+ if (cmp == 0)
|
|
+ return node;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static gl_list_node_t _GL_ATTRIBUTE_PURE
|
|
+gl_linked_sortedlist_search_from_to (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ size_t low, size_t high,
|
|
+ const void *elt)
|
|
+{
|
|
+ size_t count = list->count;
|
|
+
|
|
+ if (!(low <= high && high <= list->count))
|
|
+ /* Invalid arguments. */
|
|
+ abort ();
|
|
+
|
|
+ high -= low;
|
|
+ if (high > 0)
|
|
+ {
|
|
+ /* Here we know low < count. */
|
|
+ size_t position = low;
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ if (position <= ((count - 1) / 2))
|
|
+ {
|
|
+ node = list->root.next;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->next;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ position = count - 1 - position;
|
|
+ node = list->root.prev;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->prev;
|
|
+ }
|
|
+
|
|
+ do
|
|
+ {
|
|
+ int cmp = compar (node->value, elt);
|
|
+
|
|
+ if (cmp > 0)
|
|
+ break;
|
|
+ if (cmp == 0)
|
|
+ return node;
|
|
+ node = node->next;
|
|
+ }
|
|
+ while (--high > 0);
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static size_t _GL_ATTRIBUTE_PURE
|
|
+gl_linked_sortedlist_indexof (gl_list_t list, gl_listelement_compar_fn compar,
|
|
+ const void *elt)
|
|
+{
|
|
+ gl_list_node_t node;
|
|
+ size_t index;
|
|
+
|
|
+ for (node = list->root.next, index = 0;
|
|
+ node != &list->root;
|
|
+ node = node->next, index++)
|
|
+ {
|
|
+ int cmp = compar (node->value, elt);
|
|
+
|
|
+ if (cmp > 0)
|
|
+ break;
|
|
+ if (cmp == 0)
|
|
+ return index;
|
|
+ }
|
|
+ return (size_t)(-1);
|
|
+}
|
|
+
|
|
+static size_t _GL_ATTRIBUTE_PURE
|
|
+gl_linked_sortedlist_indexof_from_to (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ size_t low, size_t high,
|
|
+ const void *elt)
|
|
+{
|
|
+ size_t count = list->count;
|
|
+
|
|
+ if (!(low <= high && high <= list->count))
|
|
+ /* Invalid arguments. */
|
|
+ abort ();
|
|
+
|
|
+ high -= low;
|
|
+ if (high > 0)
|
|
+ {
|
|
+ /* Here we know low < count. */
|
|
+ size_t index = low;
|
|
+ size_t position = low;
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ if (position <= ((count - 1) / 2))
|
|
+ {
|
|
+ node = list->root.next;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->next;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ position = count - 1 - position;
|
|
+ node = list->root.prev;
|
|
+ for (; position > 0; position--)
|
|
+ node = node->prev;
|
|
+ }
|
|
+
|
|
+ do
|
|
+ {
|
|
+ int cmp = compar (node->value, elt);
|
|
+
|
|
+ if (cmp > 0)
|
|
+ break;
|
|
+ if (cmp == 0)
|
|
+ return index;
|
|
+ node = node->next;
|
|
+ index++;
|
|
+ }
|
|
+ while (--high > 0);
|
|
+ }
|
|
+ return (size_t)(-1);
|
|
+}
|
|
+
|
|
+static gl_list_node_t
|
|
+gl_linked_sortedlist_nx_add (gl_list_t list, gl_listelement_compar_fn compar,
|
|
+ const void *elt)
|
|
+{
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ for (node = list->root.next; node != &list->root; node = node->next)
|
|
+ if (compar (node->value, elt) >= 0)
|
|
+ return gl_linked_nx_add_before (list, node, elt);
|
|
+ return gl_linked_nx_add_last (list, elt);
|
|
+}
|
|
+
|
|
+static bool
|
|
+gl_linked_sortedlist_remove (gl_list_t list, gl_listelement_compar_fn compar,
|
|
+ const void *elt)
|
|
+{
|
|
+ gl_list_node_t node;
|
|
+
|
|
+ for (node = list->root.next; node != &list->root; node = node->next)
|
|
+ {
|
|
+ int cmp = compar (node->value, elt);
|
|
+
|
|
+ if (cmp > 0)
|
|
+ break;
|
|
+ if (cmp == 0)
|
|
+ return gl_linked_remove_node (list, node);
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
diff --git a/gl/gl_linkedhash_list.c b/gl/gl_linkedhash_list.c
|
|
new file mode 100644
|
|
index 0000000..70eca52
|
|
--- /dev/null
|
|
+++ b/gl/gl_linkedhash_list.c
|
|
@@ -0,0 +1,114 @@
|
|
+/* Sequential list data type implemented by a hash table with a linked list.
|
|
+ Copyright (C) 2006, 2008-2021 Free Software Foundation, Inc.
|
|
+ Written by Bruno Haible <bruno@clisp.org>, 2006.
|
|
+
|
|
+ This program is free software: you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include <config.h>
|
|
+
|
|
+/* Specification. */
|
|
+#include "gl_linkedhash_list.h"
|
|
+
|
|
+#include <stdint.h> /* for uintptr_t, SIZE_MAX */
|
|
+#include <stdlib.h>
|
|
+
|
|
+#include "xsize.h"
|
|
+
|
|
+#define WITH_HASHTABLE 1
|
|
+
|
|
+/* -------------------------- gl_list_t Data Type -------------------------- */
|
|
+
|
|
+/* Generic hash-table code. */
|
|
+#include "gl_anyhash1.h"
|
|
+
|
|
+/* Generic linked list code. */
|
|
+#include "gl_anylinked_list1.h"
|
|
+
|
|
+/* Generic hash-table code. */
|
|
+#define CONTAINER_T gl_list_t
|
|
+#define CONTAINER_COUNT(list) (list)->count
|
|
+#include "gl_anyhash2.h"
|
|
+
|
|
+/* Add a node to the hash table structure. */
|
|
+static void
|
|
+add_to_bucket (gl_list_t list, gl_list_node_t node)
|
|
+{
|
|
+ size_t bucket = node->h.hashcode % list->table_size;
|
|
+
|
|
+ node->h.hash_next = list->table[bucket];
|
|
+ list->table[bucket] = &node->h;
|
|
+}
|
|
+/* Tell all compilers that the return value is 0. */
|
|
+#define add_to_bucket(list,node) ((add_to_bucket) (list, node), 0)
|
|
+
|
|
+/* Remove a node from the hash table structure. */
|
|
+static void
|
|
+remove_from_bucket (gl_list_t list, gl_list_node_t node)
|
|
+{
|
|
+ size_t bucket = node->h.hashcode % list->table_size;
|
|
+ gl_hash_entry_t *p;
|
|
+
|
|
+ for (p = &list->table[bucket]; ; p = &(*p)->hash_next)
|
|
+ {
|
|
+ if (*p == &node->h)
|
|
+ {
|
|
+ *p = node->h.hash_next;
|
|
+ break;
|
|
+ }
|
|
+ if (*p == NULL)
|
|
+ /* node is not in the right bucket. Did the hash codes
|
|
+ change inadvertently? */
|
|
+ abort ();
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Generic linked list code. */
|
|
+#include "gl_anylinked_list2.h"
|
|
+
|
|
+
|
|
+const struct gl_list_implementation gl_linkedhash_list_implementation =
|
|
+ {
|
|
+ gl_linked_nx_create_empty,
|
|
+ gl_linked_nx_create,
|
|
+ gl_linked_size,
|
|
+ gl_linked_node_value,
|
|
+ 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,
|
|
+ gl_linked_indexof_from_to,
|
|
+ gl_linked_nx_add_first,
|
|
+ gl_linked_nx_add_last,
|
|
+ gl_linked_nx_add_before,
|
|
+ gl_linked_nx_add_after,
|
|
+ gl_linked_nx_add_at,
|
|
+ gl_linked_remove_node,
|
|
+ gl_linked_remove_at,
|
|
+ gl_linked_remove,
|
|
+ gl_linked_list_free,
|
|
+ gl_linked_iterator,
|
|
+ gl_linked_iterator_from_to,
|
|
+ gl_linked_iterator_next,
|
|
+ gl_linked_iterator_free,
|
|
+ gl_linked_sortedlist_search,
|
|
+ gl_linked_sortedlist_search_from_to,
|
|
+ gl_linked_sortedlist_indexof,
|
|
+ gl_linked_sortedlist_indexof_from_to,
|
|
+ gl_linked_sortedlist_nx_add,
|
|
+ gl_linked_sortedlist_remove
|
|
+ };
|
|
diff --git a/gl/gl_linkedhash_list.h b/gl/gl_linkedhash_list.h
|
|
new file mode 100644
|
|
index 0000000..f908588
|
|
--- /dev/null
|
|
+++ b/gl/gl_linkedhash_list.h
|
|
@@ -0,0 +1,34 @@
|
|
+/* Sequential list data type implemented by a hash table with a linked list.
|
|
+ Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
|
|
+ Written by Bruno Haible <bruno@clisp.org>, 2006.
|
|
+
|
|
+ This program is free software: you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#ifndef _GL_LINKEDHASH_LIST_H
|
|
+#define _GL_LINKEDHASH_LIST_H
|
|
+
|
|
+#include "gl_list.h"
|
|
+
|
|
+#ifdef __cplusplus
|
|
+extern "C" {
|
|
+#endif
|
|
+
|
|
+extern const struct gl_list_implementation gl_linkedhash_list_implementation;
|
|
+#define GL_LINKEDHASH_LIST &gl_linkedhash_list_implementation
|
|
+
|
|
+#ifdef __cplusplus
|
|
+}
|
|
+#endif
|
|
+
|
|
+#endif /* _GL_LINKEDHASH_LIST_H */
|
|
diff --git a/gl/gl_list.c b/gl/gl_list.c
|
|
new file mode 100644
|
|
index 0000000..8793298
|
|
--- /dev/null
|
|
+++ b/gl/gl_list.c
|
|
@@ -0,0 +1,3 @@
|
|
+#include <config.h>
|
|
+#define GL_LIST_INLINE _GL_EXTERN_INLINE
|
|
+#include "gl_list.h"
|
|
diff --git a/gl/gl_list.h b/gl/gl_list.h
|
|
new file mode 100644
|
|
index 0000000..7fc22bb
|
|
--- /dev/null
|
|
+++ b/gl/gl_list.h
|
|
@@ -0,0 +1,914 @@
|
|
+/* Abstract sequential list data type. -*- coding: utf-8 -*-
|
|
+ Copyright (C) 2006-2021 Free Software Foundation, Inc.
|
|
+ Written by Bruno Haible <bruno@clisp.org>, 2006.
|
|
+
|
|
+ This program is free software: you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ This program is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#ifndef _GL_LIST_H
|
|
+#define _GL_LIST_H
|
|
+
|
|
+#include <stdbool.h>
|
|
+#include <stddef.h>
|
|
+
|
|
+#ifndef _GL_INLINE_HEADER_BEGIN
|
|
+ #error "Please include config.h first."
|
|
+#endif
|
|
+_GL_INLINE_HEADER_BEGIN
|
|
+#ifndef GL_LIST_INLINE
|
|
+# define GL_LIST_INLINE _GL_INLINE
|
|
+#endif
|
|
+
|
|
+#ifdef __cplusplus
|
|
+extern "C" {
|
|
+#endif
|
|
+
|
|
+
|
|
+/* gl_list is an abstract list data type. It can contain any number of
|
|
+ objects ('void *' or 'const void *' pointers) in any given order.
|
|
+ Duplicates are allowed, but can optionally be forbidden.
|
|
+
|
|
+ There are several implementations of this list datatype, optimized for
|
|
+ different operations or for memory. You can start using the simplest list
|
|
+ implementation, GL_ARRAY_LIST, and switch to a different implementation
|
|
+ later, when you realize which operations are performed the most frequently.
|
|
+ The API of the different implementations is exactly the same; when
|
|
+ switching to a different implementation, you only have to change the
|
|
+ gl_list_create call.
|
|
+
|
|
+ The implementations are:
|
|
+ GL_ARRAY_LIST a growable array
|
|
+ GL_CARRAY_LIST a growable circular array
|
|
+ GL_LINKED_LIST a linked list
|
|
+ GL_AVLTREE_LIST a binary tree (AVL tree)
|
|
+ GL_RBTREE_LIST a binary tree (red-black tree)
|
|
+ GL_LINKEDHASH_LIST a hash table with a linked list
|
|
+ GL_AVLTREEHASH_LIST a hash table with a binary tree (AVL tree)
|
|
+ GL_RBTREEHASH_LIST a hash table with a binary tree (red-black tree)
|
|
+
|
|
+ The memory consumption is asymptotically the same: O(1) for every object
|
|
+ in the list. When looking more closely at the average memory consumed
|
|
+ for an object, GL_ARRAY_LIST is the most compact representation, and
|
|
+ GL_LINKEDHASH_LIST and GL_TREEHASH_LIST need more memory.
|
|
+
|
|
+ The guaranteed average performance of the operations is, for a list of
|
|
+ n elements:
|
|
+
|
|
+ Operation ARRAY LINKED TREE LINKEDHASH TREEHASH
|
|
+ CARRAY with|without with|without
|
|
+ duplicates duplicates
|
|
+
|
|
+ gl_list_size O(1) O(1) O(1) O(1) O(1)
|
|
+ gl_list_node_value O(1) O(1) O(1) O(1) O(1)
|
|
+ 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)
|
|
+ gl_list_set_at O(1) O(n) O(log n) O(n) O((log n)²)/O(log n)
|
|
+ gl_list_set_first O(1) O(1) O(log n) O(n)/O(1) O((log n)²)/O(log n)
|
|
+ gl_list_set_last O(1) O(1) O(log n) O(n)/O(1) O((log n)²)/O(log n)
|
|
+ gl_list_search O(n) O(n) O(n) O(n)/O(1) O(log n)/O(1)
|
|
+ gl_list_search_from O(n) O(n) O(n) O(n)/O(1) O((log n)²)/O(log n)
|
|
+ gl_list_search_from_to O(n) O(n) O(n) O(n)/O(1) O((log n)²)/O(log n)
|
|
+ gl_list_indexof O(n) O(n) O(n) O(n) O(log n)
|
|
+ gl_list_indexof_from O(n) O(n) O(n) O(n) O((log n)²)/O(log n)
|
|
+ gl_list_indexof_from_to O(n) O(n) O(n) O(n) O((log n)²)/O(log n)
|
|
+ gl_list_add_first O(n)/O(1) O(1) O(log n) O(1) O((log n)²)/O(log n)
|
|
+ gl_list_add_last O(1) O(1) O(log n) O(1) O((log n)²)/O(log n)
|
|
+ gl_list_add_before O(n) O(1) O(log n) O(1) O((log n)²)/O(log n)
|
|
+ gl_list_add_after O(n) O(1) O(log n) O(1) O((log n)²)/O(log n)
|
|
+ gl_list_add_at O(n) O(n) O(log n) O(n) O((log n)²)/O(log n)
|
|
+ gl_list_remove_node O(n) O(1) O(log n) O(n)/O(1) O((log n)²)/O(log n)
|
|
+ gl_list_remove_at O(n) O(n) O(log n) O(n) O((log n)²)/O(log n)
|
|
+ gl_list_remove_first O(n)/O(1) O(1) O(log n) O(n)/O(1) O((log n)²)/O(log n)
|
|
+ gl_list_remove_last O(1) O(1) O(log n) O(n)/O(1) O((log n)²)/O(log n)
|
|
+ gl_list_remove O(n) O(n) O(n) O(n)/O(1) O((log n)²)/O(log n)
|
|
+ gl_list_iterator O(1) O(1) O(log n) O(1) O(log n)
|
|
+ gl_list_iterator_from_to O(1) O(n) O(log n) O(n) O(log n)
|
|
+ gl_list_iterator_next O(1) O(1) O(log n) O(1) O(log n)
|
|
+ gl_sortedlist_search O(log n) O(n) O(log n) O(n) O(log n)
|
|
+ gl_sortedlist_search_from O(log n) O(n) O(log n) O(n) O(log n)
|
|
+ gl_sortedlist_indexof O(log n) O(n) O(log n) O(n) O(log n)
|
|
+ gl_sortedlist_indexof_fro O(log n) O(n) O(log n) O(n) O(log n)
|
|
+ gl_sortedlist_add O(n) O(n) O(log n) O(n) O((log n)²)/O(log n)
|
|
+ gl_sortedlist_remove O(n) O(n) O(log n) O(n) O((log n)²)/O(log n)
|
|
+ */
|
|
+
|
|
+/* -------------------------- gl_list_t Data Type -------------------------- */
|
|
+
|
|
+/* Type of function used to compare two elements.
|
|
+ NULL denotes pointer comparison. */
|
|
+typedef bool (*gl_listelement_equals_fn) (const void *elt1, const void *elt2);
|
|
+
|
|
+/* Type of function used to compute a hash code.
|
|
+ NULL denotes a function that depends only on the pointer itself. */
|
|
+typedef size_t (*gl_listelement_hashcode_fn) (const void *elt);
|
|
+
|
|
+/* Type of function used to dispose an element once it's removed from a list.
|
|
+ NULL denotes a no-op. */
|
|
+typedef void (*gl_listelement_dispose_fn) (const void *elt);
|
|
+
|
|
+struct gl_list_impl;
|
|
+/* Type representing an entire list. */
|
|
+typedef struct gl_list_impl * gl_list_t;
|
|
+
|
|
+struct gl_list_node_impl;
|
|
+/* Type representing the position of an element in the list, in a way that
|
|
+ is more adapted to the list implementation than a plain index.
|
|
+ Note: It is invalidated by insertions and removals! */
|
|
+typedef struct gl_list_node_impl * gl_list_node_t;
|
|
+
|
|
+struct gl_list_implementation;
|
|
+/* Type representing a list datatype implementation. */
|
|
+typedef const struct gl_list_implementation * gl_list_implementation_t;
|
|
+
|
|
+#if 0 /* Unless otherwise specified, these are defined inline below. */
|
|
+
|
|
+/* Creates an empty list.
|
|
+ IMPLEMENTATION is one of GL_ARRAY_LIST, GL_CARRAY_LIST, GL_LINKED_LIST,
|
|
+ GL_AVLTREE_LIST, GL_RBTREE_LIST, GL_LINKEDHASH_LIST, GL_AVLTREEHASH_LIST,
|
|
+ GL_RBTREEHASH_LIST.
|
|
+ EQUALS_FN is an element comparison function or NULL.
|
|
+ HASHCODE_FN is an element hash code function or NULL.
|
|
+ DISPOSE_FN is an element disposal function or NULL.
|
|
+ ALLOW_DUPLICATES is false if duplicate elements shall not be allowed in
|
|
+ the list. The implementation may verify this at runtime. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_t gl_list_create_empty (gl_list_implementation_t implementation,
|
|
+ gl_listelement_equals_fn equals_fn,
|
|
+ gl_listelement_hashcode_fn hashcode_fn,
|
|
+ gl_listelement_dispose_fn dispose_fn,
|
|
+ bool allow_duplicates);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_t gl_list_nx_create_empty (gl_list_implementation_t implementation,
|
|
+ gl_listelement_equals_fn equals_fn,
|
|
+ gl_listelement_hashcode_fn hashcode_fn,
|
|
+ gl_listelement_dispose_fn dispose_fn,
|
|
+ bool allow_duplicates);
|
|
+
|
|
+/* Creates a list with given contents.
|
|
+ IMPLEMENTATION is one of GL_ARRAY_LIST, GL_CARRAY_LIST, GL_LINKED_LIST,
|
|
+ GL_AVLTREE_LIST, GL_RBTREE_LIST, GL_LINKEDHASH_LIST, GL_AVLTREEHASH_LIST,
|
|
+ GL_RBTREEHASH_LIST.
|
|
+ EQUALS_FN is an element comparison function or NULL.
|
|
+ HASHCODE_FN is an element hash code function or NULL.
|
|
+ DISPOSE_FN is an element disposal function or NULL.
|
|
+ ALLOW_DUPLICATES is false if duplicate elements shall not be allowed in
|
|
+ the list. The implementation may verify this at runtime.
|
|
+ COUNT is the number of initial elements.
|
|
+ CONTENTS[0..COUNT-1] is the initial contents. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_t gl_list_create (gl_list_implementation_t implementation,
|
|
+ gl_listelement_equals_fn equals_fn,
|
|
+ gl_listelement_hashcode_fn hashcode_fn,
|
|
+ gl_listelement_dispose_fn dispose_fn,
|
|
+ bool allow_duplicates,
|
|
+ size_t count, const void **contents);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_t gl_list_nx_create (gl_list_implementation_t implementation,
|
|
+ gl_listelement_equals_fn equals_fn,
|
|
+ gl_listelement_hashcode_fn hashcode_fn,
|
|
+ gl_listelement_dispose_fn dispose_fn,
|
|
+ bool allow_duplicates,
|
|
+ size_t count, const void **contents);
|
|
+
|
|
+/* Returns the current number of elements in a list. */
|
|
+extern size_t gl_list_size (gl_list_t list);
|
|
+
|
|
+/* Returns the element value represented by a list node. */
|
|
+extern const void * gl_list_node_value (gl_list_t list, gl_list_node_t node);
|
|
+
|
|
+/* Replaces the element value represented by a list node. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern void gl_list_node_set_value (gl_list_t list, gl_list_node_t node,
|
|
+ const void *elt);
|
|
+/* Likewise. Returns 0 upon success, -1 upon out-of-memory. */
|
|
+extern int gl_list_node_nx_set_value (gl_list_t list, gl_list_node_t node,
|
|
+ const void *elt)
|
|
+ _GL_ATTRIBUTE_NODISCARD;
|
|
+
|
|
+/* Returns the node immediately after the given node in the list, or NULL
|
|
+ if the given node is the last (rightmost) one in the list. */
|
|
+extern gl_list_node_t gl_list_next_node (gl_list_t list, gl_list_node_t node);
|
|
+
|
|
+/* Returns the node immediately before the given node in the list, or NULL
|
|
+ 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);
|
|
+
|
|
+/* Returns the element at the first position in the list.
|
|
+ The list must be non-empty. */
|
|
+extern const void * gl_list_get_first (gl_list_t list);
|
|
+
|
|
+/* Returns the element at the last position in the list.
|
|
+ The list must be non-empty. */
|
|
+extern const void * gl_list_get_last (gl_list_t list);
|
|
+
|
|
+/* Replaces the element at a given position in the list.
|
|
+ POSITION must be >= 0 and < gl_list_size (list).
|
|
+ Returns its node. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_node_t gl_list_set_at (gl_list_t list, size_t position,
|
|
+ const void *elt);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_node_t gl_list_nx_set_at (gl_list_t list, size_t position,
|
|
+ const void *elt)
|
|
+ _GL_ATTRIBUTE_NODISCARD;
|
|
+
|
|
+/* Replaces the element at the first position in the list.
|
|
+ Returns its node.
|
|
+ The list must be non-empty. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_node_t gl_list_set_first (gl_list_t list, const void *elt);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_node_t gl_list_nx_set_first (gl_list_t list, const void *elt)
|
|
+ _GL_ATTRIBUTE_NODISCARD;
|
|
+
|
|
+/* Replaces the element at the last position in the list.
|
|
+ Returns its node.
|
|
+ The list must be non-empty. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_node_t gl_list_set_last (gl_list_t list, const void *elt);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_node_t gl_list_nx_set_last (gl_list_t list, const void *elt)
|
|
+ _GL_ATTRIBUTE_NODISCARD;
|
|
+
|
|
+/* Searches whether an element is already in the list.
|
|
+ Returns its node if found, or NULL if not present in the list. */
|
|
+extern gl_list_node_t gl_list_search (gl_list_t list, const void *elt);
|
|
+
|
|
+/* Searches whether an element is already in the list,
|
|
+ at a position >= START_INDEX.
|
|
+ Returns its node if found, or NULL if not present in the list. */
|
|
+extern gl_list_node_t gl_list_search_from (gl_list_t list, size_t start_index,
|
|
+ const void *elt);
|
|
+
|
|
+/* Searches whether an element is already in the list,
|
|
+ at a position >= START_INDEX and < END_INDEX.
|
|
+ Returns its node if found, or NULL if not present in the list. */
|
|
+extern gl_list_node_t gl_list_search_from_to (gl_list_t list,
|
|
+ size_t start_index,
|
|
+ size_t end_index,
|
|
+ const void *elt);
|
|
+
|
|
+/* Searches whether an element is already in the list.
|
|
+ Returns its position if found, or (size_t)(-1) if not present in the list. */
|
|
+extern size_t gl_list_indexof (gl_list_t list, const void *elt);
|
|
+
|
|
+/* Searches whether an element is already in the list,
|
|
+ at a position >= START_INDEX.
|
|
+ Returns its position if found, or (size_t)(-1) if not present in the list. */
|
|
+extern size_t gl_list_indexof_from (gl_list_t list, size_t start_index,
|
|
+ const void *elt);
|
|
+
|
|
+/* Searches whether an element is already in the list,
|
|
+ at a position >= START_INDEX and < END_INDEX.
|
|
+ Returns its position if found, or (size_t)(-1) if not present in the list. */
|
|
+extern size_t gl_list_indexof_from_to (gl_list_t list,
|
|
+ size_t start_index, size_t end_index,
|
|
+ const void *elt);
|
|
+
|
|
+/* Adds an element as the first element of the list.
|
|
+ Returns its node. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_node_t gl_list_add_first (gl_list_t list, const void *elt);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_node_t gl_list_nx_add_first (gl_list_t list, const void *elt)
|
|
+ _GL_ATTRIBUTE_NODISCARD;
|
|
+
|
|
+/* Adds an element as the last element of the list.
|
|
+ Returns its node. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_node_t gl_list_add_last (gl_list_t list, const void *elt);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_node_t gl_list_nx_add_last (gl_list_t list, const void *elt)
|
|
+ _GL_ATTRIBUTE_NODISCARD;
|
|
+
|
|
+/* Adds an element before a given element node of the list.
|
|
+ Returns its node. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_node_t gl_list_add_before (gl_list_t list, gl_list_node_t node,
|
|
+ const void *elt);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_node_t gl_list_nx_add_before (gl_list_t list,
|
|
+ gl_list_node_t node,
|
|
+ const void *elt)
|
|
+ _GL_ATTRIBUTE_NODISCARD;
|
|
+
|
|
+/* Adds an element after a given element node of the list.
|
|
+ Returns its node. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_node_t gl_list_add_after (gl_list_t list, gl_list_node_t node,
|
|
+ const void *elt);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_node_t gl_list_nx_add_after (gl_list_t list, gl_list_node_t node,
|
|
+ const void *elt)
|
|
+ _GL_ATTRIBUTE_NODISCARD;
|
|
+
|
|
+/* Adds an element at a given position in the list.
|
|
+ POSITION must be >= 0 and <= gl_list_size (list). */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_node_t gl_list_add_at (gl_list_t list, size_t position,
|
|
+ const void *elt);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_node_t gl_list_nx_add_at (gl_list_t list, size_t position,
|
|
+ const void *elt)
|
|
+ _GL_ATTRIBUTE_NODISCARD;
|
|
+
|
|
+/* Removes an element from the list.
|
|
+ Returns true. */
|
|
+extern bool gl_list_remove_node (gl_list_t list, gl_list_node_t node);
|
|
+
|
|
+/* Removes an element at a given position from the list.
|
|
+ POSITION must be >= 0 and < gl_list_size (list).
|
|
+ Returns true. */
|
|
+extern bool gl_list_remove_at (gl_list_t list, size_t position);
|
|
+
|
|
+/* Removes the element at the first position from the list.
|
|
+ Returns true if it was found and removed, or false if the list was empty. */
|
|
+extern bool gl_list_remove_first (gl_list_t list);
|
|
+
|
|
+/* Removes the element at the last position from the list.
|
|
+ Returns true if it was found and removed, or false if the list was empty. */
|
|
+extern bool gl_list_remove_last (gl_list_t list);
|
|
+
|
|
+/* Searches and removes an element from the list.
|
|
+ Returns true if it was found and removed. */
|
|
+extern bool gl_list_remove (gl_list_t list, const void *elt);
|
|
+
|
|
+/* Frees an entire list.
|
|
+ (But this call does not free the elements of the list. It only invokes
|
|
+ the DISPOSE_FN on each of the elements of the list, and only if the list
|
|
+ is not a sublist.) */
|
|
+extern void gl_list_free (gl_list_t list);
|
|
+
|
|
+#endif /* End of inline and gl_xlist.h-defined functions. */
|
|
+
|
|
+/* --------------------- gl_list_iterator_t Data Type --------------------- */
|
|
+
|
|
+/* Functions for iterating through a list. */
|
|
+
|
|
+/* Type of an iterator that traverses a list.
|
|
+ This is a fixed-size struct, so that creation of an iterator doesn't need
|
|
+ memory allocation on the heap. */
|
|
+typedef struct
|
|
+{
|
|
+ /* For fast dispatch of gl_list_iterator_next. */
|
|
+ const struct gl_list_implementation *vtable;
|
|
+ /* For detecting whether the last returned element was removed. */
|
|
+ gl_list_t list;
|
|
+ size_t count;
|
|
+ /* Other, implementation-private fields. */
|
|
+ void *p; void *q;
|
|
+ size_t i; size_t j;
|
|
+} gl_list_iterator_t;
|
|
+
|
|
+#if 0 /* These are defined inline below. */
|
|
+
|
|
+/* Creates an iterator traversing a list.
|
|
+ The list contents must not be modified while the iterator is in use,
|
|
+ except for replacing or removing the last returned element. */
|
|
+extern gl_list_iterator_t gl_list_iterator (gl_list_t list);
|
|
+
|
|
+/* Creates an iterator traversing the element with indices i,
|
|
+ start_index <= i < end_index, of a list.
|
|
+ The list contents must not be modified while the iterator is in use,
|
|
+ except for replacing or removing the last returned element. */
|
|
+extern gl_list_iterator_t gl_list_iterator_from_to (gl_list_t list,
|
|
+ size_t start_index,
|
|
+ size_t end_index);
|
|
+
|
|
+/* If there is a next element, stores the next element in *ELTP, stores its
|
|
+ node in *NODEP if NODEP is non-NULL, advances the iterator and returns true.
|
|
+ Otherwise, returns false. */
|
|
+extern bool gl_list_iterator_next (gl_list_iterator_t *iterator,
|
|
+ const void **eltp, gl_list_node_t *nodep);
|
|
+
|
|
+/* Frees an iterator. */
|
|
+extern void gl_list_iterator_free (gl_list_iterator_t *iterator);
|
|
+
|
|
+#endif /* End of inline functions. */
|
|
+
|
|
+/* ---------------------- Sorted gl_list_t Data Type ---------------------- */
|
|
+
|
|
+/* The following functions are for lists without duplicates where the
|
|
+ order is given by a sort criterion. */
|
|
+
|
|
+/* Type of function used to compare two elements. Same as for qsort().
|
|
+ NULL denotes pointer comparison. */
|
|
+typedef int (*gl_listelement_compar_fn) (const void *elt1, const void *elt2);
|
|
+
|
|
+#if 0 /* Unless otherwise specified, these are defined inline below. */
|
|
+
|
|
+/* Searches whether an element is already in the list.
|
|
+ The list is assumed to be sorted with COMPAR.
|
|
+ Returns its node if found, or NULL if not present in the list.
|
|
+ If the list contains several copies of ELT, the node of the leftmost one is
|
|
+ returned. */
|
|
+extern gl_list_node_t gl_sortedlist_search (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ const void *elt);
|
|
+
|
|
+/* Searches whether an element is already in the list.
|
|
+ The list is assumed to be sorted with COMPAR.
|
|
+ Only list elements with indices >= START_INDEX and < END_INDEX are
|
|
+ considered; the implementation uses these bounds to minimize the number
|
|
+ of COMPAR invocations.
|
|
+ Returns its node if found, or NULL if not present in the list.
|
|
+ If the list contains several copies of ELT, the node of the leftmost one is
|
|
+ returned. */
|
|
+extern gl_list_node_t gl_sortedlist_search_from_to (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ size_t start_index,
|
|
+ size_t end_index,
|
|
+ const void *elt);
|
|
+
|
|
+/* Searches whether an element is already in the list.
|
|
+ The list is assumed to be sorted with COMPAR.
|
|
+ Returns its position if found, or (size_t)(-1) if not present in the list.
|
|
+ If the list contains several copies of ELT, the position of the leftmost one
|
|
+ is returned. */
|
|
+extern size_t gl_sortedlist_indexof (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ const void *elt);
|
|
+
|
|
+/* Searches whether an element is already in the list.
|
|
+ The list is assumed to be sorted with COMPAR.
|
|
+ Only list elements with indices >= START_INDEX and < END_INDEX are
|
|
+ considered; the implementation uses these bounds to minimize the number
|
|
+ of COMPAR invocations.
|
|
+ Returns its position if found, or (size_t)(-1) if not present in the list.
|
|
+ If the list contains several copies of ELT, the position of the leftmost one
|
|
+ is returned. */
|
|
+extern size_t gl_sortedlist_indexof_from_to (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ size_t start_index,
|
|
+ size_t end_index,
|
|
+ const void *elt);
|
|
+
|
|
+/* Adds an element at the appropriate position in the list.
|
|
+ The list is assumed to be sorted with COMPAR.
|
|
+ Returns its node. */
|
|
+/* declared in gl_xlist.h */
|
|
+extern gl_list_node_t gl_sortedlist_add (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ const void *elt);
|
|
+/* Likewise. Returns NULL upon out-of-memory. */
|
|
+extern gl_list_node_t gl_sortedlist_nx_add (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ const void *elt)
|
|
+ _GL_ATTRIBUTE_NODISCARD;
|
|
+
|
|
+/* Searches and removes an element from the list.
|
|
+ The list is assumed to be sorted with COMPAR.
|
|
+ Returns true if it was found and removed.
|
|
+ If the list contains several copies of ELT, only the leftmost one is
|
|
+ removed. */
|
|
+extern bool gl_sortedlist_remove (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ const void *elt);
|
|
+
|
|
+#endif /* End of inline and gl_xlist.h-defined functions. */
|
|
+
|
|
+/* ------------------------ Implementation Details ------------------------ */
|
|
+
|
|
+struct gl_list_implementation
|
|
+{
|
|
+ /* gl_list_t functions. */
|
|
+ gl_list_t (*nx_create_empty) (gl_list_implementation_t implementation,
|
|
+ gl_listelement_equals_fn equals_fn,
|
|
+ gl_listelement_hashcode_fn hashcode_fn,
|
|
+ gl_listelement_dispose_fn dispose_fn,
|
|
+ bool allow_duplicates);
|
|
+ gl_list_t (*nx_create) (gl_list_implementation_t implementation,
|
|
+ gl_listelement_equals_fn equals_fn,
|
|
+ gl_listelement_hashcode_fn hashcode_fn,
|
|
+ gl_listelement_dispose_fn dispose_fn,
|
|
+ bool allow_duplicates,
|
|
+ size_t count, const void **contents);
|
|
+ size_t (*size) (gl_list_t list);
|
|
+ const void * (*node_value) (gl_list_t list, gl_list_node_t node);
|
|
+ int (*node_nx_set_value) (gl_list_t list, gl_list_node_t node,
|
|
+ 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);
|
|
+ gl_list_node_t (*search_from_to) (gl_list_t list, size_t start_index,
|
|
+ size_t end_index, const void *elt);
|
|
+ size_t (*indexof_from_to) (gl_list_t list, size_t start_index,
|
|
+ size_t end_index, const void *elt);
|
|
+ gl_list_node_t (*nx_add_first) (gl_list_t list, const void *elt);
|
|
+ gl_list_node_t (*nx_add_last) (gl_list_t list, const void *elt);
|
|
+ gl_list_node_t (*nx_add_before) (gl_list_t list, gl_list_node_t node,
|
|
+ const void *elt);
|
|
+ gl_list_node_t (*nx_add_after) (gl_list_t list, gl_list_node_t node,
|
|
+ const void *elt);
|
|
+ gl_list_node_t (*nx_add_at) (gl_list_t list, size_t position,
|
|
+ const void *elt);
|
|
+ bool (*remove_node) (gl_list_t list, gl_list_node_t node);
|
|
+ bool (*remove_at) (gl_list_t list, size_t position);
|
|
+ bool (*remove_elt) (gl_list_t list, const void *elt);
|
|
+ void (*list_free) (gl_list_t list);
|
|
+ /* gl_list_iterator_t functions. */
|
|
+ gl_list_iterator_t (*iterator) (gl_list_t list);
|
|
+ gl_list_iterator_t (*iterator_from_to) (gl_list_t list,
|
|
+ size_t start_index,
|
|
+ size_t end_index);
|
|
+ bool (*iterator_next) (gl_list_iterator_t *iterator,
|
|
+ const void **eltp, gl_list_node_t *nodep);
|
|
+ void (*iterator_free) (gl_list_iterator_t *iterator);
|
|
+ /* Sorted gl_list_t functions. */
|
|
+ gl_list_node_t (*sortedlist_search) (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ const void *elt);
|
|
+ gl_list_node_t (*sortedlist_search_from_to) (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ size_t start_index,
|
|
+ size_t end_index,
|
|
+ const void *elt);
|
|
+ size_t (*sortedlist_indexof) (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ const void *elt);
|
|
+ size_t (*sortedlist_indexof_from_to) (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ size_t start_index, size_t end_index,
|
|
+ const void *elt);
|
|
+ gl_list_node_t (*sortedlist_nx_add) (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ const void *elt);
|
|
+ bool (*sortedlist_remove) (gl_list_t list,
|
|
+ gl_listelement_compar_fn compar,
|
|
+ const void *elt);
|
|
+};
|
|
+
|
|
+struct gl_list_impl_base
|
|
+{
|
|
+ const struct gl_list_implementation *vtable;
|
|
+ gl_listelement_equals_fn equals_fn;
|
|
+ gl_listelement_hashcode_fn hashcode_fn;
|
|
+ gl_listelement_dispose_fn dispose_fn;
|
|
+ bool allow_duplicates;
|
|
+};
|
|
+
|
|
+/* Define all functions of this file as accesses to the
|
|
+ struct gl_list_implementation. */
|
|
+
|
|
+GL_LIST_INLINE gl_list_t
|
|
+gl_list_nx_create_empty (gl_list_implementation_t implementation,
|
|
+ gl_listelement_equals_fn equals_fn,
|
|
+ gl_listelement_hashcode_fn hashcode_fn,
|
|
+ gl_listelement_dispose_fn dispose_fn,
|
|
+ bool allow_duplicates)
|
|
+{
|
|
+ return implementation->nx_create_empty (implementation, equals_fn,
|
|
+ hashcode_fn, dispose_fn,
|
|
+ allow_duplicates);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE gl_list_t
|
|
+gl_list_nx_create (gl_list_implementation_t implementation,
|
|
+ gl_listelement_equals_fn equals_fn,
|
|
+ gl_listelement_hashcode_fn hashcode_fn,
|
|
+ gl_listelement_dispose_fn dispose_fn,
|
|
+ bool allow_duplicates,
|
|
+ size_t count, const void **contents)
|
|
+{
|
|
+ return implementation->nx_create (implementation, equals_fn, hashcode_fn,
|
|
+ dispose_fn, allow_duplicates, count,
|
|
+ contents);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE size_t
|
|
+gl_list_size (gl_list_t list)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->size (list);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE const void *
|
|
+gl_list_node_value (gl_list_t list, gl_list_node_t node)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->node_value (list, node);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE _GL_ATTRIBUTE_NODISCARD int
|
|
+gl_list_node_nx_set_value (gl_list_t list, gl_list_node_t node,
|
|
+ const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->node_nx_set_value (list, node, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE gl_list_node_t
|
|
+gl_list_next_node (gl_list_t list, gl_list_node_t node)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->next_node (list, node);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE gl_list_node_t
|
|
+gl_list_previous_node (gl_list_t list, gl_list_node_t node)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->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)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->get_at (list, position);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE const void *
|
|
+gl_list_get_first (gl_list_t list)
|
|
+{
|
|
+ return gl_list_get_at (list, 0);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE const void *
|
|
+gl_list_get_last (gl_list_t list)
|
|
+{
|
|
+ return gl_list_get_at (list, gl_list_size (list) - 1);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE _GL_ATTRIBUTE_NODISCARD gl_list_node_t
|
|
+gl_list_nx_set_at (gl_list_t list, size_t position, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->nx_set_at (list, position, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE _GL_ATTRIBUTE_NODISCARD gl_list_node_t
|
|
+gl_list_nx_set_first (gl_list_t list, const void *elt)
|
|
+{
|
|
+ return gl_list_nx_set_at (list, 0, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE _GL_ATTRIBUTE_NODISCARD gl_list_node_t
|
|
+gl_list_nx_set_last (gl_list_t list, const void *elt)
|
|
+{
|
|
+ return gl_list_nx_set_at (list, gl_list_size (list) - 1, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE gl_list_node_t
|
|
+gl_list_search (gl_list_t list, const void *elt)
|
|
+{
|
|
+ size_t size = ((const struct gl_list_impl_base *) list)->vtable->size (list);
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->search_from_to (list, 0, size, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE gl_list_node_t
|
|
+gl_list_search_from (gl_list_t list, size_t start_index, const void *elt)
|
|
+{
|
|
+ size_t size = ((const struct gl_list_impl_base *) list)->vtable->size (list);
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->search_from_to (list, start_index, size, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE gl_list_node_t
|
|
+gl_list_search_from_to (gl_list_t list, size_t start_index, size_t end_index,
|
|
+ const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->search_from_to (list, start_index, end_index, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE size_t
|
|
+gl_list_indexof (gl_list_t list, const void *elt)
|
|
+{
|
|
+ size_t size = ((const struct gl_list_impl_base *) list)->vtable->size (list);
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->indexof_from_to (list, 0, size, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE size_t
|
|
+gl_list_indexof_from (gl_list_t list, size_t start_index, const void *elt)
|
|
+{
|
|
+ size_t size = ((const struct gl_list_impl_base *) list)->vtable->size (list);
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->indexof_from_to (list, start_index, size, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE size_t
|
|
+gl_list_indexof_from_to (gl_list_t list, size_t start_index, size_t end_index,
|
|
+ const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->indexof_from_to (list, start_index, end_index, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE _GL_ATTRIBUTE_NODISCARD gl_list_node_t
|
|
+gl_list_nx_add_first (gl_list_t list, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->nx_add_first (list, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE _GL_ATTRIBUTE_NODISCARD gl_list_node_t
|
|
+gl_list_nx_add_last (gl_list_t list, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->nx_add_last (list, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE _GL_ATTRIBUTE_NODISCARD gl_list_node_t
|
|
+gl_list_nx_add_before (gl_list_t list, gl_list_node_t node, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->nx_add_before (list, node, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE _GL_ATTRIBUTE_NODISCARD gl_list_node_t
|
|
+gl_list_nx_add_after (gl_list_t list, gl_list_node_t node, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->nx_add_after (list, node, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE _GL_ATTRIBUTE_NODISCARD gl_list_node_t
|
|
+gl_list_nx_add_at (gl_list_t list, size_t position, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->nx_add_at (list, position, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE bool
|
|
+gl_list_remove_node (gl_list_t list, gl_list_node_t node)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->remove_node (list, node);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE bool
|
|
+gl_list_remove_at (gl_list_t list, size_t position)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->remove_at (list, position);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE bool
|
|
+gl_list_remove_first (gl_list_t list)
|
|
+{
|
|
+ size_t size = gl_list_size (list);
|
|
+ if (size > 0)
|
|
+ return gl_list_remove_at (list, 0);
|
|
+ else
|
|
+ return false;
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE bool
|
|
+gl_list_remove_last (gl_list_t list)
|
|
+{
|
|
+ size_t size = gl_list_size (list);
|
|
+ if (size > 0)
|
|
+ return gl_list_remove_at (list, size - 1);
|
|
+ else
|
|
+ return false;
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE bool
|
|
+gl_list_remove (gl_list_t list, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->remove_elt (list, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE void
|
|
+gl_list_free (gl_list_t list)
|
|
+{
|
|
+ ((const struct gl_list_impl_base *) list)->vtable->list_free (list);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE gl_list_iterator_t
|
|
+gl_list_iterator (gl_list_t list)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->iterator (list);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE gl_list_iterator_t
|
|
+gl_list_iterator_from_to (gl_list_t list, size_t start_index, size_t end_index)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->iterator_from_to (list, start_index, end_index);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE bool
|
|
+gl_list_iterator_next (gl_list_iterator_t *iterator,
|
|
+ const void **eltp, gl_list_node_t *nodep)
|
|
+{
|
|
+ return iterator->vtable->iterator_next (iterator, eltp, nodep);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE void
|
|
+gl_list_iterator_free (gl_list_iterator_t *iterator)
|
|
+{
|
|
+ iterator->vtable->iterator_free (iterator);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE gl_list_node_t
|
|
+gl_sortedlist_search (gl_list_t list, gl_listelement_compar_fn compar, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->sortedlist_search (list, compar, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE gl_list_node_t
|
|
+gl_sortedlist_search_from_to (gl_list_t list, gl_listelement_compar_fn compar, size_t start_index, size_t end_index, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->sortedlist_search_from_to (list, compar, start_index, end_index,
|
|
+ elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE size_t
|
|
+gl_sortedlist_indexof (gl_list_t list, gl_listelement_compar_fn compar, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->sortedlist_indexof (list, compar, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE size_t
|
|
+gl_sortedlist_indexof_from_to (gl_list_t list, gl_listelement_compar_fn compar, size_t start_index, size_t end_index, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->sortedlist_indexof_from_to (list, compar, start_index, end_index,
|
|
+ elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE _GL_ATTRIBUTE_NODISCARD gl_list_node_t
|
|
+gl_sortedlist_nx_add (gl_list_t list, gl_listelement_compar_fn compar, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->sortedlist_nx_add (list, compar, elt);
|
|
+}
|
|
+
|
|
+GL_LIST_INLINE bool
|
|
+gl_sortedlist_remove (gl_list_t list, gl_listelement_compar_fn compar, const void *elt)
|
|
+{
|
|
+ return ((const struct gl_list_impl_base *) list)->vtable
|
|
+ ->sortedlist_remove (list, compar, elt);
|
|
+}
|
|
+
|
|
+#ifdef __cplusplus
|
|
+}
|
|
+#endif
|
|
+
|
|
+_GL_INLINE_HEADER_END
|
|
+
|
|
+#endif /* _GL_LIST_H */
|
|
--
|
|
2.33.0
|
|
|