Skip to content

Commit

Permalink
mx_util: Add mx_sort_linked_list
Browse files Browse the repository at this point in the history
This is a general purpose routine to sort a single linked list of
objects. It requires callbacks for comparison and for locating
the next pointer in the object.
  • Loading branch information
donald committed Jul 4, 2017
1 parent 24fe539 commit 8496f6a
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
27 changes: 27 additions & 0 deletions mx_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
4 changes: 4 additions & 0 deletions mx_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
81 changes: 81 additions & 0 deletions test_mx_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -469,5 +549,6 @@ int main(int argc, char *argv[])
test_mx_strvec_cachebug();
test_mx_strcat();
test_mx_cpuset();
test_listsort();
return 0;
}

0 comments on commit 8496f6a

Please sign in to comment.