From: NeilBrown Date: Thu, 27 Jul 2023 06:33:29 +0000 (+1000) Subject: Factor out list sorting into list.h X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=adf0062e47ca7a09b88cdd984c817be430cdd2f4;p=edlib.git Factor out list sorting into list.h No point having two copies of the same code. Signed-off-by: NeilBrown --- diff --git a/DOC/TODO.md b/DOC/TODO.md index b19aa83d..972c8dde 100644 --- a/DOC/TODO.md +++ b/DOC/TODO.md @@ -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 diff --git a/doc-dir.c b/doc-dir.c index 6d46daed..a601404d 100644 --- 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); } diff --git a/doc-list.c b/doc-list.c index d1dc9504..68d346b3 100644 --- a/doc-list.c +++ b/doc-list.c @@ -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 ca4ce473..0261289b 100644 --- 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__ */