diff --git a/mx_util.c b/mx_util.c index 809e1c63..0dd65101 100644 --- a/mx_util.c +++ b/mx_util.c @@ -1304,3 +1304,30 @@ int mx_daemon(int nochdir, int noclose) { return daemon(nochdir, noclose); } + +void _mx_sort_linked_list (void **list, int (*cmp)(void *o1,void *o2), void ** getnextptr(void *o)) { + + void *unsorted=*list; + void *sorted=NULL; + + while (unsorted) { + void *o; + void **s_ptr; + void *s; + + o=unsorted; + unsorted=*(getnextptr(o)); + + s_ptr=&sorted; + while(1) { + s=*s_ptr; + if (s==NULL || cmp(o,s)<0) { + break; + } + s_ptr=getnextptr(s); + } + *(getnextptr(o))=s; + *s_ptr=o; + } + *list=sorted; +} diff --git a/mx_util.h b/mx_util.h index f20fe38b..46107414 100644 --- a/mx_util.h +++ b/mx_util.h @@ -166,4 +166,8 @@ int mx_mkdir_p(char *path, mode_t mode); int mx_daemon(int nochdir, int noclose); +void _mx_sort_linked_list(void **list, int (*cmp)(void *o1,void *o2), void ** (*getnextptr)(void *o)); +#define mx_sort_linked_list(list,cmp,getnextptr) _mx_sort_linked_list((void **)(list),(int (*)(void *,void *))(cmp),(void ** (*)(void *))(getnextptr)) + + #endif diff --git a/test_mx_util.c b/test_mx_util.c index e127e570..05389f42 100644 --- a/test_mx_util.c +++ b/test_mx_util.c @@ -450,6 +450,86 @@ static void test_mx_cpuset(void) assert(mx_str_to_cpuset(&cpuset,"4-")<0); } +struct obj { + int i; + struct obj *next; +}; + +int obj_compare(struct obj *o1,struct obj *o2) +{ + return + o1->i > o2->i ? 1 + : o1->i < o2->i ? -1 + : 0; +} + +struct obj **obj_getnextptr(struct obj *o) { + return &o->next; +} + +static void test_listsort(void) +{ + struct obj o[10]; + struct obj *list; + + for (int i=0;i<10;i++) { + o[i].i=i; + o[i].next= i==9 ? NULL : &o[i+1]; + } + + /* () -> () */ + list=NULL; + mx_sort_linked_list(&list,obj_compare,obj_getnextptr); + assert(list==NULL); + + /* (9) -> (9) */ + + list=&o[9]; + mx_sort_linked_list(&list,obj_compare,obj_getnextptr); + assert(list==&o[9]); + assert(o[9].next==NULL); + + /* (9 8 7 6 5 4 3 2 1 0) -> (0 1 2 3 4 5 6 7 8 9) */ + + list=&o[0]; + for (int i=0;i<10;i++) { + o[i].i = 9-i; + } + mx_sort_linked_list(&list,obj_compare,obj_getnextptr); + assert(list==&o[9]); + for (int i=0;i<10;i++) { + assert(o[i].next == (i==0 ? NULL : &o[i-1])); + } + + /* (100 0 1 2 50 50 2 1 0 100) -> ( 0 0 1 1 2 2 50 50 100 100) stable */ + for (int i=0;i<10;i++) { + o[i].next= i==9 ? NULL : &o[i+1]; + } + list=&o[0]; + o[0].i=100; + o[1].i=0; + o[2].i=1; + o[3].i=2; + o[4].i=50; + o[5].i=50; + o[6].i=2; + o[7].i=1; + o[8].i=0; + o[9].i=100; + mx_sort_linked_list(&list,obj_compare,obj_getnextptr); + assert(list==&o[1]); + assert(o[1].next==&o[8]); + assert(o[8].next==&o[2]); + assert(o[2].next==&o[7]); + assert(o[7].next==&o[3]); + assert(o[3].next==&o[6]); + assert(o[6].next==&o[4]); + assert(o[4].next==&o[5]); + assert(o[5].next==&o[0]); + assert(o[0].next==&o[9]); + assert(o[9].next==NULL); +} + int main(int argc, char *argv[]) { test_mx_strskipwhitespaces(); @@ -469,5 +549,6 @@ int main(int argc, char *argv[]) test_mx_strvec_cachebug(); test_mx_strcat(); test_mx_cpuset(); + test_listsort(); return 0; }