summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-12-28 19:53:13 +0100
committerThomas Haller <thaller@redhat.com>2018-01-03 16:41:47 +0100
commit916f53ac24ddc57efc2e016778c4996ef3b3d09c (patch)
tree093a58e5e43b6c25e8864a6691d14da56bf8df12
parentfeeb70ef8928a92c392ad3ef6d032f3df8b125cb (diff)
downloadNetworkManager-916f53ac24ddc57efc2e016778c4996ef3b3d09c.tar.gz
shared: implement c_list_sort() as non-recursive merge-sort
This is still the very same approach (in the way the array is split and how elements are compared). The only difference is that the recursive implementation is replaced by a non-recursive one. It's (still) stable, top-down merge-sort. The non-recursive implementation better, because it avoids the overhead of the function call to recurse.
-rw-r--r--shared/nm-utils/c-list-util.c52
1 files changed, 39 insertions, 13 deletions
diff --git a/shared/nm-utils/c-list-util.c b/shared/nm-utils/c-list-util.c
index 509f4e12ab..44ca26a558 100644
--- a/shared/nm-utils/c-list-util.c
+++ b/shared/nm-utils/c-list-util.c
@@ -111,26 +111,52 @@ _c_list_srt_merge (CList *ls1,
return head.next;
}
+typedef struct {
+ CList *ls1;
+ CList *ls2;
+ char ls1_sorted;
+} SortStack;
+
static CList *
_c_list_sort (CList *ls,
CListSortCmp cmp,
const void *user_data)
{
- CList *ls1, *ls2;
-
- if (!ls->next)
- return ls;
- ls1 = ls;
-
- ls2 = _c_list_srt_split (ls1);
-
- ls1 = _c_list_sort (ls1, cmp, user_data);
- if (!ls2)
- return ls1;
+ /* reserve a huge stack-size. We need roughly log2(n) entries, hence this
+ * is much more we will ever need. We don't guard for stack-overflow either. */
+ SortStack stack_arr[70];
+ SortStack *stack_head = stack_arr;
+
+ stack_arr[0].ls1 = ls;
+
+ /* A simple top-down, non-recursive, stable merge-sort.
+ *
+ * Maybe natural merge-sort would be better, to do better for
+ * partially sorted lists. */
+_split:
+ stack_head[0].ls2 = _c_list_srt_split (stack_head[0].ls1);
+ if (stack_head[0].ls2) {
+ stack_head[0].ls1_sorted = 0;
+ stack_head[1].ls1 = stack_head[0].ls1;
+ stack_head++;
+ goto _split;
+ }
- ls2 = _c_list_sort (ls2, cmp, user_data);
+_backtrack:
+ if (stack_head == stack_arr)
+ return stack_arr[0].ls1;
+
+ stack_head--;
+ if (!stack_head[0].ls1_sorted) {
+ stack_head[0].ls1 = stack_head[1].ls1;
+ stack_head[0].ls1_sorted = 1;
+ stack_head[1].ls1 = stack_head[0].ls2;
+ stack_head++;
+ goto _split;
+ }
- return _c_list_srt_merge (ls1, ls2, cmp, user_data);
+ stack_head[0].ls1 = _c_list_srt_merge (stack_head[0].ls1, stack_head[1].ls1, cmp, user_data);
+ goto _backtrack;
}
/**