]> git.neil.brown.name Git - edlib.git/commitdiff
Factor out list sorting into list.h
authorNeilBrown <neil@brown.name>
Thu, 27 Jul 2023 06:33:29 +0000 (16:33 +1000)
committerNeilBrown <neil@brown.name>
Thu, 27 Jul 2023 10:09:32 +0000 (20:09 +1000)
No point having two copies of the same code.

Signed-off-by: NeilBrown <neil@brown.name>
DOC/TODO.md
doc-dir.c
doc-list.c
list.h

index b19aa83d57c4b60a4b3d6f16e72300a447cf07cb..972c8dde0710962bb217295ecc12e046be9e124b 100644 (file)
@@ -9,7 +9,7 @@ the file.
 
 ### Triage
 
-- [ ] factor our list-sort code.
+- [X] factor our list-sort code.
 - [X] when cx-b and default doc name is v.long, shift gets confused
 - [ ] How to run shell command in "44" window??
 - [X] In c-mode, if ) is at end of line then highlighting it causes the
index 6d46daeda2e7787f3b6c721630cbd315fcbff8b3..a601404d2e32f6bfa25b05755159b054d0fb2f8e 100644 (file)
--- a/doc-dir.c
+++ b/doc-dir.c
@@ -73,77 +73,11 @@ struct directory {
 
 static void get_stat(struct directory *dr safe, struct dir_ent *de safe);
 
-#define nm(le) (list_entry(le, struct dir_ent, lst)->name)
-
-/* Natural merge sort of the linked list of directory names */
-static void sort_list(struct list_head *lst safe)
+static char *key(struct list_head *le, const void *data)
 {
-       struct list_head *de[2];
-       struct list_head *l;
-
-       if (list_empty(lst))
-               return;
-       /* Convert to NULL terminated singly-linked list for sorting */
-       lst->prev->next = safe_cast NULL;
-
-       de[0] = lst->next;
-       de[1] = NULL;
-
-       do {
-               struct list_head ** safe dep[2];
-               struct list_head *d[2];
-               int curr = 0;
-               char *prev = "";
-               int next = 0;
-
-               dep[0] = &de[0];
-               dep[1] = &de[1];
-               d[0] = de[0];
-               d[1] = de[1];
-
-               /* d[0] and d[1] are two lists to be merged and split.
-                * The results will be put in de[0] and de[1].
-                * dep[0] and dep[1] are end pointers to de[0] and de[1] so far.
-                *
-                * Take least of d[0] and d[1].
-                * If it is larger than prev, add to
-                * dep[curr], else swap curr then add
-                */
-               while (d[0] || d[1]) {
-                       if (d[next] == NULL ||
-                           (d[1-next] != NULL &&
-                            !((strcmp(prev, nm(d[1-next])) <= 0)
-                              ^(strcmp(nm(d[1-next]), nm(d[next])) <= 0)
-                              ^(strcmp(nm(d[next]), prev) <= 0)))
-                       )
-                               next = 1 - next;
-
-                       if (!d[next])
-                               break;
-                       if (strcmp(nm(d[next]), prev) < 0)
-                               curr = 1 - curr;
-                       prev = nm(d[next]);
-                       *dep[curr] = d[next];
-                       dep[curr] = &d[next]->next;
-                       d[next] = d[next]->next;
-               }
-               *dep[0] = NULL;
-               *dep[1] = NULL;
-       } while (de[0] && de[1]);
-
-       /* Now re-assemble the doublely-linked list */
-       if (de[0])
-               lst->next = de[0];
-       else
-               lst->next = safe_cast de[1];
-       l = lst;
-
-       while ((void*)l->next) {
-               l->next->prev = l;
-               l = l->next;
-       }
-       l->next = lst;
-       lst->prev = l;
+       if (le == NULL)
+               return NULL;
+       return list_entry(le, struct dir_ent, lst)->name;
 }
 
 static bool add_ent(struct list_head *lst safe, struct dirent *de safe)
@@ -186,7 +120,7 @@ static void load_dir(struct list_head *lst safe, int fd)
                return;
        while ((res = readdir(dir)) != NULL)
                add_ent(lst, res);
-       sort_list(lst);
+       sort_list(lst, key, NULL);
        closedir(dir);
 }
 
index d1dc9504d6a0450e4f1504435dfa18082e6ad22b..68d346b3f2c30f852a5ad728198dbf30fbbd2c2d 100644 (file)
@@ -144,93 +144,18 @@ DEF_CMD(list_add_elmnt)
        return 1;
 }
 
-static char *key(struct list_head *le, const char *keyattr safe)
+static char *key(struct list_head *le, const void *data)
 {
+       const char *keyattr = data;
        struct elmnt *e;
        char *ret;
-       if (le == NULL)
+       if (le == NULL || keyattr == NULL)
                return NULL;
        e = container_of(le, struct elmnt, list);
        ret = attr_find(e->attrs, keyattr);
        return ret ?: "";
 }
 
-static void sort_list(struct list_head *lst safe, const char *keyattr safe)
-{
-       struct list_head *de[2];
-       struct list_head *l;
-
-       if (list_empty(lst))
-               return;
-       /* Convert to NULL terminated singly-linked list for sorting */
-       lst->prev->next = safe_cast NULL;
-
-       de[0] = lst->next;
-       de[1] = NULL;
-
-       do {
-               struct list_head ** safe dep[2];
-               struct list_head *d[2];
-               int curr = 0;
-               char *prev = "";
-               int next = 0;
-
-               dep[0] = &de[0];
-               dep[1] = &de[1];
-               d[0] = de[0];
-               d[1] = de[1];
-
-               /* d[0] and d[1] are two lists to be merged and split.
-                * The results will be put in de[0] and de[1].
-                * dep[0] and dep[1] are end pointers to de[0] and de[1] so far.
-                *
-                * Take least of d[0] and d[1].
-                * If it is larger than prev, add to
-                * dep[curr], else swap curr then add
-                */
-               while (d[0] || d[1]) {
-                       char *kn = key(d[next], keyattr);
-                       char *kp = key(d[1-next], keyattr);
-                       if (kn == NULL ||
-                           (kp != NULL &&
-                            !((strcmp(prev, kp) <= 0)
-                              ^(strcmp(kp, kn) <= 0)
-                              ^(strcmp(kn, prev) <= 0)))
-                       ) {
-                               char *t = kn;
-                               kn = kp;
-                               kp = t;
-                               next = 1 - next;
-                       }
-
-                       if (!d[next] || !kn)
-                               break;
-                       if (strcmp(kn, prev) < 0)
-                               curr = 1 - curr;
-                       prev = kn;
-                       *dep[curr] = d[next];
-                       dep[curr] = &d[next]->next;
-                       d[next] = d[next]->next;
-               }
-               *dep[0] = NULL;
-               *dep[1] = NULL;
-       } while (de[0] && de[1]);
-
-       /* Now re-assemble the doublely-linked list */
-       if (de[0])
-               lst->next = de[0];
-       else
-               lst->next = safe_cast de[1];
-       l = lst;
-
-       while ((void*)l->next) {
-               l->next->prev = l;
-               l = l->next;
-       }
-       l->next = lst;
-       lst->prev = l;
-}
-
 DEF_CMD(list_sort)
 {
        struct list *l = &ci->home->doc_data;
@@ -243,7 +168,7 @@ DEF_CMD(list_sort)
                m->ref.p = NULL;
                m->ref.i = 0;
        }
-       sort_list(&l->content, ci->str);
+       sort_list(&l->content, key, ci->str);
        return 1;
 }
 
diff --git a/list.h b/list.h
index ca4ce4739f3dc67ebae8cd6e01a9d088a1ac6afe..0261289bfe16ea19ec5740f132726e709fc0c012 100644 (file)
--- a/list.h
+++ b/list.h
@@ -701,4 +701,82 @@ static inline void tlist_del_init(struct tlist_head *entry safe)
             TLIST_TYPE(&pos->member) != (head_type);                   \
             pos = tlist_prev_entry(pos, member))
 
+/* Natural merge sort of the linked list */
+static inline void sort_list(struct list_head *lst safe,
+                            char * (*key)(struct list_head *le, const void *data),
+                            const void *data)
+{
+       struct list_head *de[2];
+       struct list_head *l;
+
+       if (list_empty(lst))
+               return;
+       /* Convert to NULL terminated singly-linked list for sorting */
+       lst->prev->next = safe_cast NULL;
+
+       de[0] = lst->next;
+       de[1] = NULL;
+
+       do {
+               struct list_head ** safe dep[2];
+               struct list_head *d[2];
+               int curr = 0;
+               char *prev = "";
+               int next = 0;
+
+               dep[0] = &de[0];
+               dep[1] = &de[1];
+               d[0] = de[0];
+               d[1] = de[1];
+
+               /* d[0] and d[1] are two lists to be merged and split.
+                * The results will be put in de[0] and de[1].
+                * dep[0] and dep[1] are end pointers to de[0] and de[1] so far.
+                *
+                * Take least of d[0] and d[1].
+                * If it is larger than prev, add to
+                * dep[curr], else swap curr then add
+                */
+               while (d[0] || d[1]) {
+                       char *kn = key(d[next], data);
+                       char *kp = key(d[1-next], data);
+                       if (kn == NULL ||
+                           (kp != NULL &&
+                            !((strcmp(prev, kp) <= 0)
+                              ^(strcmp(kp, kn) <= 0)
+                              ^(strcmp(kn, prev) <= 0)))
+                       ) {
+                               char *t = kn;
+                               kn = kp;
+                               kp = t;
+                               next = 1 - next;
+                       }
+
+                       if (!d[next] || !kn)
+                               break;
+                       if (strcmp(kn, prev) < 0)
+                               curr = 1 - curr;
+                       prev = kn;
+                       *dep[curr] = d[next];
+                       dep[curr] = &d[next]->next;
+                       d[next] = d[next]->next;
+               }
+               *dep[0] = NULL;
+               *dep[1] = NULL;
+       } while (de[0] && de[1]);
+
+       /* Now re-assemble the doublely-linked list */
+       if (de[0])
+               lst->next = de[0];
+       else
+               lst->next = safe_cast de[1];
+       l = lst;
+
+       while ((void*)l->next) {
+               l->next->prev = l;
+               l = l->next;
+       }
+       l->next = lst;
+       lst->prev = l;
+}
 #endif /* __LIST_H__ */