git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 03/10] mergesort: add macros for typed sort of linked lists

From
René Scharfe <l.s.r@web.de>
Date
Jul 16, 2022, 16:54 UTC
Message-ID
<f127d516-3951-830f-72d4-263557339ec9@web.de>
In-Reply-To
<4d7cd286-398e-215c-f2bd-aa7e8207be4f@web.de>

Add the macros DECLARE_LIST_SORT and DEFINE_LIST_SORT for building type-specific functions for sorting linked lists. The generated function expects a typed comparison function.

The programmer provides full type information (no void pointers). This allows the compiler to check whether the comparison function matches the list type. It can also inline the "next" pointer accessor functions and even the comparison function to get rid of the calling overhead.

Also provide a DECLARE_LIST_SORT_DEBUG macro that allows executing custom code whenever the accessor functions are used. It's intended to be used by test-mergesort, which counts these operations.

Signed-off-by: René Scharfe <l.s.r@web.de>
---
 mergesort.h | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)
diff --git a/mergesort.h b/mergesort.h
index 644cff1f96..7b44355283 100644
--- a/mergesort.h
+++ b/mergesort.h
@@ -14,4 +14,105 @@ void *llist_mergesort(void *list,
 		      void (*set_next_fn)(void *, void *),
 		      int (*compare_fn)(const void *, const void *));

+/* Combine two sorted lists.  Take from `list` on equality. */
+#define DEFINE_LIST_MERGE_INTERNAL(name, type)				\
+static type *name##__merge(type *list, type *other,			\
+			   int (*compare_fn)(const type *, const type *))\
+{									\
+	type *result = list, *tail;					\
+	int prefer_list = compare_fn(list, other) <= 0;			\
+									\
+	if (!prefer_list) {						\
+		result = other;						\
+		SWAP(list, other);					\
+	}								\
+	for (;;) {							\
+		do {							\
+			tail = list;					\
+			list = name##__get_next(list);			\
+			if (!list) {					\
+				name##__set_next(tail, other);		\
+				return result;				\
+			}						\
+		} while (compare_fn(list, other) < prefer_list);	\
+		name##__set_next(tail, other);				\
+		prefer_list ^= 1;					\
+		SWAP(list, other);					\
+	}								\
+}
+
+/*
+ * Perform an iterative mergesort using an array of sublists.
+ *
+ * n is the number of items.
+ * ranks[i] is undefined if n & 2^i == 0, and assumed empty.
+ * ranks[i] contains a sublist of length 2^i otherwise.
+ *
+ * The number of bits in a void pointer limits the number of objects
+ * that can be created, and thus the number of array elements necessary
+ * to be able to sort any valid list.
+ *
+ * Adding an item to this array is like incrementing a binary number;
+ * positional values for set bits correspond to sublist lengths.
+ */
+#define DEFINE_LIST_SORT_INTERNAL(scope, name, type)			\
+scope void name(type **listp,						\
+		int (*compare_fn)(const type *, const type *))		\
+{									\
+	type *list = *listp;						\
+	type *ranks[bitsizeof(type *)];					\
+	size_t n = 0;							\
+									\
+	if (!list)							\
+		return;							\
+									\
+	for (;;) {							\
+		int i;							\
+		size_t m;						\
+		type *next = name##__get_next(list);			\
+		if (next)						\
+			name##__set_next(list, NULL);			\
+		for (i = 0, m = n;; i++, m >>= 1) {			\
+			if (m & 1) {					\
+				list = name##__merge(ranks[i], list,	\
+						    compare_fn);	\
+			} else if (next) {				\
+				break;					\
+			} else if (!m) {				\
+				*listp = list;				\
+				return;					\
+			}						\
+		}							\
+		n++;							\
+		ranks[i] = list;					\
+		list = next;						\
+	}								\
+}
+
+#define DECLARE_LIST_SORT(scope, name, type)			\
+scope void name(type **listp,					\
+		int (*compare_fn)(const type *, const type *))
+
+#define DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member,	\
+			       on_get_next, on_set_next)	\
+								\
+static inline type *name##__get_next(const type *elem)		\
+{								\
+	on_get_next;						\
+	return elem->next_member;				\
+}								\
+								\
+static inline void name##__set_next(type *elem, type *next)	\
+{								\
+	on_set_next;						\
+	elem->next_member = next;				\
+}								\
+								\
+DEFINE_LIST_MERGE_INTERNAL(name, type)				\
+DEFINE_LIST_SORT_INTERNAL(scope, name, type)			\
+DECLARE_LIST_SORT(scope, name, type)
+
+#define DEFINE_LIST_SORT(scope, name, type, next_member) \
+DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member, (void)0, (void)0)
+
 #endif
--
2.37.1
Previous: René ScharfeNext: René Scharfe
Message 4 of 15 in “typed sort of linked lists”
  1. 00/10 typed sort of linked listsRené Scharfe, Jul 16, 2022
  2. 01/10 mergesort: unify ranks loopsRené Scharfe, Jul 16, 2022
  3. 02/10 mergesort: tighten merge loopRené Scharfe, Jul 16, 2022
  4. 03/10 mergesort: add macros for typed sort of linked listsRené Scharfe, Jul 16, 2022
  5. 04/10 test-mergesort: use DEFINE_LIST_SORT_DEBUGRené Scharfe, Jul 16, 2022
  6. 05/10 test-mergesort: use DEFINE_LIST_SORTRené Scharfe, Jul 16, 2022
  7. 06/10 blame: use DEFINE_LIST_SORTRené Scharfe, Jul 16, 2022
  8. 07/10 commit: use DEFINE_LIST_SORTRené Scharfe, Jul 16, 2022
  9. 08/10 fetch-pack: use DEFINE_LIST_SORTRené Scharfe, Jul 16, 2022
  10. 09/10 packfile: use DEFINE_LIST_SORTRené Scharfe, Jul 16, 2022
  11. 10/10 mergesort: remove llist_mergesort()René Scharfe, Jul 16, 2022
  12. Junio C HamanoJul 17, 2022
  13. Junio C HamanoJul 25, 2022
  14. Derrick StoleeJul 25, 2022
  15. Junio C HamanoJul 25, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.