Implement list sorting.
* include/mailutils/list.h (mu_list_sort): New proto. * libmailutils/list/sort.c: New file. * libmailutils/list/Makefile.am (liblist_la_SOURCES): Add sort.c * libmailutils/tests/listop.c: Implement the sort command. * libmailutils/tests/list.at: Test list sorting.
Showing
5 changed files
with
215 additions
and
2 deletions
... | @@ -274,7 +274,9 @@ int mu_list_map (mu_list_t _list, mu_list_mapper_t _map, | ... | @@ -274,7 +274,9 @@ int mu_list_map (mu_list_t _list, mu_list_mapper_t _map, |
274 | void *_data, size_t _nelem, | 274 | void *_data, size_t _nelem, |
275 | mu_list_t *_res); | 275 | mu_list_t *_res); |
276 | 276 | ||
277 | /* List fold */ | 277 | /* ************************************************* */ |
278 | /* List folding */ | ||
279 | /* ************************************************* */ | ||
278 | 280 | ||
279 | typedef int (*mu_list_folder_t) (void *_item, void *_data, | 281 | typedef int (*mu_list_folder_t) (void *_item, void *_data, |
280 | void *_prev, void **_ret); | 282 | void *_prev, void **_ret); |
... | @@ -315,6 +317,18 @@ int mu_list_fold (mu_list_t _list, mu_list_folder_t _fold, void *_data, | ... | @@ -315,6 +317,18 @@ int mu_list_fold (mu_list_t _list, mu_list_folder_t _fold, void *_data, |
315 | void *_init, void *_return_value); | 317 | void *_init, void *_return_value); |
316 | int mu_list_rfold (mu_list_t _list, mu_list_folder_t _fold, void *_data, | 318 | int mu_list_rfold (mu_list_t _list, mu_list_folder_t _fold, void *_data, |
317 | void *_init, void *_return_value); | 319 | void *_init, void *_return_value); |
320 | |||
321 | /* ************************************************* */ | ||
322 | /* Sorting */ | ||
323 | /* ************************************************* */ | ||
324 | |||
325 | /* Sort _list using quicksort algorithm. Use _comp to compare elements. | ||
326 | If it is NULL, use the comparator method of _list. | ||
327 | |||
328 | Comparator must return 0 if the two elements are equal, -1 if | ||
329 | first of them is less than the second, and +1 otherwise. | ||
330 | */ | ||
331 | void mu_list_sort (mu_list_t _list, mu_list_comparator_t _comp); | ||
318 | 332 | ||
319 | #ifdef __cplusplus | 333 | #ifdef __cplusplus |
320 | } | 334 | } | ... | ... |
... | @@ -45,6 +45,7 @@ liblist_la_SOURCES = \ | ... | @@ -45,6 +45,7 @@ liblist_la_SOURCES = \ |
45 | setdestr.c\ | 45 | setdestr.c\ |
46 | slice.c\ | 46 | slice.c\ |
47 | slice2.c\ | 47 | slice2.c\ |
48 | sort.c\ | ||
48 | tail.c | 49 | tail.c |
49 | 50 | ||
50 | INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils | 51 | INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils | ... | ... |
libmailutils/list/sort.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Lesser General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 3 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Lesser General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Lesser General | ||
15 | Public License along with this library. If not, see | ||
16 | <http://www.gnu.org/licenses/>. */ | ||
17 | |||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <mailutils/errno.h> | ||
24 | #include <mailutils/sys/list.h> | ||
25 | |||
26 | static void | ||
27 | _list_append_entry (struct _mu_list *list, struct list_data *ent) | ||
28 | { | ||
29 | ent->prev = list->head.prev ? list->head.prev : &list->head; | ||
30 | ent->next = &list->head; | ||
31 | if (list->head.prev) | ||
32 | list->head.prev->next = ent; | ||
33 | else | ||
34 | list->head.next = ent; | ||
35 | list->head.prev = ent; | ||
36 | list->count++; | ||
37 | } | ||
38 | |||
39 | static void | ||
40 | _list_qsort (mu_list_t list, mu_list_comparator_t cmp) | ||
41 | { | ||
42 | struct list_data *cur, *middle; | ||
43 | struct _mu_list high_list, low_list; | ||
44 | int rc; | ||
45 | |||
46 | if (list->count < 2) | ||
47 | return; | ||
48 | if (list->count == 2) | ||
49 | { | ||
50 | if (cmp (list->head.prev->item, list->head.next->item) < 0) | ||
51 | { | ||
52 | cur = list->head.prev; | ||
53 | list->head.prev = list->head.next; | ||
54 | list->head.next = cur; | ||
55 | |||
56 | list->head.next->prev = &list->head; | ||
57 | list->head.next->next = list->head.prev; | ||
58 | |||
59 | list->head.prev->next = &list->head; | ||
60 | list->head.prev->prev = list->head.next; | ||
61 | } | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | cur = list->head.next; | ||
66 | do { | ||
67 | cur = cur->next; | ||
68 | if (!cur) | ||
69 | return; | ||
70 | } while ((rc = cmp (list->head.next->item, cur->item)) == 0); | ||
71 | |||
72 | /* Select the lower of the two as the middle value */ | ||
73 | middle = (rc > 0) ? cur : list->head.next; | ||
74 | |||
75 | /* Split into two sublists */ | ||
76 | memset (&high_list, 0, sizeof (high_list)); | ||
77 | memset (&low_list, 0, sizeof (low_list)); | ||
78 | |||
79 | for (cur = list->head.next; cur != &list->head; ) | ||
80 | { | ||
81 | struct list_data *next = cur->next; | ||
82 | cur->next = NULL; | ||
83 | |||
84 | if (cmp (middle->item, cur->item) < 0) | ||
85 | _list_append_entry (&high_list, cur); | ||
86 | else | ||
87 | _list_append_entry (&low_list, cur); | ||
88 | cur = next; | ||
89 | } | ||
90 | |||
91 | /* Sort both sublists recursively */ | ||
92 | _list_qsort (&low_list, cmp); | ||
93 | _list_qsort (&high_list, cmp); | ||
94 | |||
95 | /* Join both lists in order */ | ||
96 | if (low_list.head.prev) | ||
97 | cur = low_list.head.prev; | ||
98 | else | ||
99 | cur = &low_list.head; | ||
100 | cur->next = high_list.head.next; | ||
101 | if (high_list.head.next) | ||
102 | high_list.head.next->prev = cur; | ||
103 | |||
104 | low_list.head.prev = high_list.head.prev; | ||
105 | high_list.head.prev = &low_list.head; | ||
106 | low_list.count += high_list.count; | ||
107 | |||
108 | /* Return the resulting list */ | ||
109 | list->head = low_list.head; | ||
110 | if (list->head.next) | ||
111 | list->head.next->prev = &list->head; | ||
112 | if (list->head.prev) | ||
113 | list->head.prev->next = &list->head; | ||
114 | } | ||
115 | |||
116 | void | ||
117 | mu_list_sort (mu_list_t list, mu_list_comparator_t comp) | ||
118 | { | ||
119 | if (list) | ||
120 | _list_qsort (list, comp ? comp : list->comp); | ||
121 | } |
... | @@ -445,6 +445,68 @@ rfold | ... | @@ -445,6 +445,68 @@ rfold |
445 | 445 | ||
446 | m4_popdef([MU_TEST_KEYWORDS]) | 446 | m4_popdef([MU_TEST_KEYWORDS]) |
447 | 447 | ||
448 | # ------------------------------------------------------------ | ||
449 | # Sort | ||
450 | # ------------------------------------------------------------ | ||
451 | |||
452 | m4_define([MU_TEST_GROUP],[Sort]) | ||
453 | m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ sort]) | ||
454 | |||
455 | TESTLIST([empty list],[], | ||
456 | [sort | ||
457 | |||
458 | ], | ||
459 | [# items: 0 | ||
460 | ]) | ||
461 | |||
462 | TESTLIST([sorted list asc],[], | ||
463 | [add a b c d e f | ||
464 | sort | ||
465 | |||
466 | ], | ||
467 | [# items: 6 | ||
468 | a | ||
469 | b | ||
470 | c | ||
471 | d | ||
472 | e | ||
473 | f | ||
474 | ]) | ||
475 | |||
476 | TESTLIST([sorted list desc],[], | ||
477 | [add f e d c b a | ||
478 | sort | ||
479 | |||
480 | ], | ||
481 | [# items: 6 | ||
482 | a | ||
483 | b | ||
484 | c | ||
485 | d | ||
486 | e | ||
487 | f | ||
488 | ]) | ||
489 | |||
490 | TESTLIST([unsorted list],[], | ||
491 | [add en to tre fire fem seks syv atte ni ti | ||
492 | sort | ||
493 | |||
494 | ], | ||
495 | [# items: 10 | ||
496 | atte | ||
497 | en | ||
498 | fem | ||
499 | fire | ||
500 | ni | ||
501 | seks | ||
502 | syv | ||
503 | ti | ||
504 | to | ||
505 | tre | ||
506 | ]) | ||
507 | |||
508 | m4_popdef([MU_TEST_KEYWORDS]) | ||
509 | |||
448 | dnl ------------------------------------------------------------ | 510 | dnl ------------------------------------------------------------ |
449 | dnl Cleanup | 511 | dnl Cleanup |
450 | m4_popdef([TESTLIST]) | 512 | m4_popdef([TESTLIST]) | ... | ... |
... | @@ -773,7 +773,13 @@ rfold (mu_list_t list) | ... | @@ -773,7 +773,13 @@ rfold (mu_list_t list) |
773 | else | 773 | else |
774 | printf ("NULL\n"); | 774 | printf ("NULL\n"); |
775 | } | 775 | } |
776 | 776 | ||
777 | void | ||
778 | sort (mu_list_t list) | ||
779 | { | ||
780 | mu_list_sort (list, NULL); | ||
781 | } | ||
782 | |||
777 | void | 783 | void |
778 | help () | 784 | help () |
779 | { | 785 | { |
... | @@ -802,6 +808,7 @@ help () | ... | @@ -802,6 +808,7 @@ help () |
802 | printf ("help\n"); | 808 | printf ("help\n"); |
803 | printf ("head\n"); | 809 | printf ("head\n"); |
804 | printf ("tail\n"); | 810 | printf ("tail\n"); |
811 | printf ("sort\n"); | ||
805 | printf ("NUMBER\n"); | 812 | printf ("NUMBER\n"); |
806 | } | 813 | } |
807 | 814 | ||
... | @@ -921,6 +928,14 @@ shell (mu_list_t list) | ... | @@ -921,6 +928,14 @@ shell (mu_list_t list) |
921 | head (ws.ws_wordc, list); | 928 | head (ws.ws_wordc, list); |
922 | else if (strcmp (ws.ws_wordv[0], "tail") == 0) | 929 | else if (strcmp (ws.ws_wordv[0], "tail") == 0) |
923 | tail (ws.ws_wordc, list); | 930 | tail (ws.ws_wordc, list); |
931 | else if (strcmp (ws.ws_wordv[0], "sort") == 0) | ||
932 | { | ||
933 | int i; | ||
934 | sort (list); | ||
935 | |||
936 | for (i = 0; i < NITR; i++) | ||
937 | mu_iterator_destroy (&itr[i]); | ||
938 | } | ||
924 | else if (ws.ws_wordc == 1) | 939 | else if (ws.ws_wordc == 1) |
925 | { | 940 | { |
926 | char *p; | 941 | char *p; | ... | ... |
-
Please register or sign in to post a comment