Implement list folding functions.
* include/mailutils/list.h (mu_list_folder_t): New typedef. (mu_list_fold, mu_list_rfold): New functions. * libmailutils/list/fold.c: New file. * libmailutils/list/rfold.c: New file. * libmailutils/list/Makefile.am (liblist_la_SOURCES): Add fold.c and rfold.c * libmailutils/list/gmap.c (mu_list_gmap): Access list elements directly, instead of using iterators. * libmailutils/tests/list.at: Add test cases for list folding. * libmailutils/tests/listop.c: Add fold and rfold commands.
Showing
7 changed files
with
265 additions
and
15 deletions
... | @@ -238,7 +238,10 @@ typedef int (*mu_list_mapper_t) (void **_itmv, size_t _itmc, void *_call_data); | ... | @@ -238,7 +238,10 @@ typedef int (*mu_list_mapper_t) (void **_itmv, size_t _itmc, void *_call_data); |
238 | and until all elements from the array have been visited. | 238 | and until all elements from the array have been visited. |
239 | 239 | ||
240 | Mu_list_gmap returns 0 on success and a non-zero error code on failure. | 240 | Mu_list_gmap returns 0 on success and a non-zero error code on failure. |
241 | If _map returns non-zero, its return value is propagated to the caller. */ | 241 | If _map returns non-zero, its return value is propagated to the caller. |
242 | |||
243 | The _map function is not allowed to alter the _list. | ||
244 | */ | ||
242 | 245 | ||
243 | int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem, | 246 | int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem, |
244 | void *_data); | 247 | void *_data); |
... | @@ -263,11 +266,56 @@ int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem, | ... | @@ -263,11 +266,56 @@ int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem, |
263 | MU_LIST_MAP_SKIP bit set, the _itmv[0] element is appended to the new | 266 | MU_LIST_MAP_SKIP bit set, the _itmv[0] element is appended to the new |
264 | list. If it has MU_LIST_MAP_STOP bit set, iteration is stopped | 267 | list. If it has MU_LIST_MAP_STOP bit set, iteration is stopped |
265 | immediately and any remaining elements in _list are ignored. | 268 | immediately and any remaining elements in _list are ignored. |
269 | |||
270 | The mapper function (_map) is not allowed to alter the _list. | ||
266 | */ | 271 | */ |
267 | 272 | ||
268 | int mu_list_map (mu_list_t _list, mu_list_mapper_t _map, | 273 | int mu_list_map (mu_list_t _list, mu_list_mapper_t _map, |
269 | void *_data, size_t _nelem, | 274 | void *_data, size_t _nelem, |
270 | mu_list_t *_res); | 275 | mu_list_t *_res); |
276 | |||
277 | /* List fold */ | ||
278 | |||
279 | typedef int (*mu_list_folder_t) (void *_item, void *_data, | ||
280 | void *_prev, void **_ret); | ||
281 | |||
282 | /* mu_list_fold iterates over list elements from first to last. | ||
283 | For each element it calls _fold with the following arguments: | ||
284 | |||
285 | _item - the current list element, | ||
286 | _data - call-specific data, | ||
287 | _prev - on the first call, _init; on subsequent calls, | ||
288 | points to the value returned from the previous call | ||
289 | to _fold in the _ret varialble, | ||
290 | _ret - memory location where to store the result of this | ||
291 | call. | ||
292 | |||
293 | When all elements have been visited, mu_list_fold stores the result | ||
294 | of the last _fold invocation (as returned in *_ret) in the memory | ||
295 | location pointed to by _return_value. | ||
296 | |||
297 | If _fold returns a non-zero value, mu_list_fold stops iteration and | ||
298 | returns this value. The *_return_value is filled in this case as | ||
299 | well. | ||
300 | |||
301 | Possible return codes: | ||
302 | |||
303 | 0 - success, | ||
304 | EINVAL - _list or _fold is NULL, | ||
305 | MU_ERR_OUT_PTR_NULL - _return_code is NULL | ||
306 | other value - non-zero value returned by _fold. | ||
307 | |||
308 | The _fold function is not allowed to alter the list it is being applied | ||
309 | to. | ||
310 | |||
311 | The mu_list_rfold acts similarly, except that it iterates over list | ||
312 | elements from last to first. | ||
313 | */ | ||
314 | int mu_list_fold (mu_list_t _list, mu_list_folder_t _fold, void *_data, | ||
315 | void *_init, void *_return_value); | ||
316 | int mu_list_rfold (mu_list_t _list, mu_list_folder_t _fold, void *_data, | ||
317 | void *_init, void *_return_value); | ||
318 | |||
271 | #ifdef __cplusplus | 319 | #ifdef __cplusplus |
272 | } | 320 | } |
273 | #endif | 321 | #endif | ... | ... |
... | @@ -25,6 +25,7 @@ liblist_la_SOURCES = \ | ... | @@ -25,6 +25,7 @@ liblist_la_SOURCES = \ |
25 | create.c\ | 25 | create.c\ |
26 | destroy.c\ | 26 | destroy.c\ |
27 | empty.c\ | 27 | empty.c\ |
28 | fold.c\ | ||
28 | foreach.c\ | 29 | foreach.c\ |
29 | get.c\ | 30 | get.c\ |
30 | getcomp.c\ | 31 | getcomp.c\ |
... | @@ -39,6 +40,7 @@ liblist_la_SOURCES = \ | ... | @@ -39,6 +40,7 @@ liblist_la_SOURCES = \ |
39 | prepend.c\ | 40 | prepend.c\ |
40 | remove.c\ | 41 | remove.c\ |
41 | replace.c\ | 42 | replace.c\ |
43 | rfold.c\ | ||
42 | setcomp.c\ | 44 | setcomp.c\ |
43 | setdestr.c\ | 45 | setdestr.c\ |
44 | slice.c\ | 46 | slice.c\ | ... | ... |
libmailutils/list/fold.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 <mailutils/errno.h> | ||
23 | #include <mailutils/sys/list.h> | ||
24 | |||
25 | int | ||
26 | mu_list_fold (mu_list_t list, mu_list_folder_t fold, void *data, void *prev, | ||
27 | void *return_value) | ||
28 | { | ||
29 | struct list_data *current; | ||
30 | int status = 0; | ||
31 | |||
32 | if (list == NULL || fold == NULL) | ||
33 | return EINVAL; | ||
34 | if (return_value == NULL) | ||
35 | return MU_ERR_OUT_PTR_NULL; | ||
36 | |||
37 | for (current = list->head.next; current != &list->head; | ||
38 | current = current->next) | ||
39 | { | ||
40 | status = fold (current->item, data, prev, &prev); | ||
41 | if (status) | ||
42 | break; | ||
43 | } | ||
44 | *(void **) return_value = prev; | ||
45 | return status; | ||
46 | } |
... | @@ -27,28 +27,21 @@ int | ... | @@ -27,28 +27,21 @@ int |
27 | mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data) | 27 | mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data) |
28 | { | 28 | { |
29 | int rc; | 29 | int rc; |
30 | int status; | 30 | struct list_data *current; |
31 | mu_iterator_t itr; | ||
32 | void **buf; | 31 | void **buf; |
33 | size_t i; | 32 | size_t i; |
34 | 33 | ||
35 | if (!list || !map || nelem == 0) | 34 | if (!list || !map || nelem == 0) |
36 | return EINVAL; | 35 | return EINVAL; |
37 | rc = mu_list_get_iterator (list, &itr); | ||
38 | if (rc) | ||
39 | return status; | ||
40 | buf = calloc (nelem, sizeof (buf[0])); | 36 | buf = calloc (nelem, sizeof (buf[0])); |
41 | if (!buf) | 37 | if (!buf) |
42 | { | ||
43 | mu_iterator_destroy (&itr); | ||
44 | return ENOMEM; | 38 | return ENOMEM; |
45 | } | 39 | |
46 | for (i = 0, mu_iterator_first (itr); !mu_iterator_is_done (itr); | 40 | i = 0; |
47 | mu_iterator_next (itr)) | 41 | for (current = list->head.next; current != &list->head; |
42 | current = current->next) | ||
48 | { | 43 | { |
49 | void *item; | 44 | buf[i++] = current->item; |
50 | mu_iterator_current (itr, &item); | ||
51 | buf[i++] = item; | ||
52 | if (i == nelem) | 45 | if (i == nelem) |
53 | { | 46 | { |
54 | i = 0; | 47 | i = 0; |
... | @@ -59,7 +52,6 @@ mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data) | ... | @@ -59,7 +52,6 @@ mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data) |
59 | } | 52 | } |
60 | if (rc == 0 && i > 0 && i < nelem) | 53 | if (rc == 0 && i > 0 && i < nelem) |
61 | rc = map (buf, i, data); | 54 | rc = map (buf, i, data); |
62 | mu_iterator_destroy (&itr); | ||
63 | free (buf); | 55 | free (buf); |
64 | return rc; | 56 | return rc; |
65 | } | 57 | } | ... | ... |
libmailutils/list/rfold.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 <mailutils/errno.h> | ||
23 | #include <mailutils/sys/list.h> | ||
24 | |||
25 | int | ||
26 | mu_list_rfold (mu_list_t list, mu_list_folder_t fold, void *data, void *prev, | ||
27 | void *return_value) | ||
28 | { | ||
29 | struct list_data *current; | ||
30 | int status = 0; | ||
31 | |||
32 | if (list == NULL || fold == NULL) | ||
33 | return EINVAL; | ||
34 | if (return_value == NULL) | ||
35 | return MU_ERR_OUT_PTR_NULL; | ||
36 | |||
37 | for (current = list->head.prev; current != &list->head; | ||
38 | current = current->prev) | ||
39 | { | ||
40 | status = fold (current->item, data, prev, &prev); | ||
41 | if (status) | ||
42 | break; | ||
43 | } | ||
44 | *(void **) return_value = prev; | ||
45 | return status; | ||
46 | } |
... | @@ -388,6 +388,62 @@ ti | ... | @@ -388,6 +388,62 @@ ti |
388 | ]) | 388 | ]) |
389 | 389 | ||
390 | m4_popdef([MU_TEST_KEYWORDS]) | 390 | m4_popdef([MU_TEST_KEYWORDS]) |
391 | # ------------------------------------------------------------ | ||
392 | # Fold | ||
393 | # ------------------------------------------------------------ | ||
394 | |||
395 | m4_define([MU_TEST_GROUP],[Fold]) | ||
396 | m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ fold]) | ||
397 | |||
398 | TESTLIST([empty list],[], | ||
399 | [fold | ||
400 | ], | ||
401 | [NULL | ||
402 | ]) | ||
403 | |||
404 | TESTLIST([one element],[], | ||
405 | [add en | ||
406 | fold | ||
407 | ], | ||
408 | [en | ||
409 | ]) | ||
410 | |||
411 | TESTLIST([many elements],[], | ||
412 | [add en to tre fire fem | ||
413 | fold | ||
414 | ], | ||
415 | [entotrefirefem | ||
416 | ]) | ||
417 | |||
418 | m4_popdef([MU_TEST_KEYWORDS]) | ||
419 | # ------------------------------------------------------------ | ||
420 | # Reverse Fold | ||
421 | # ------------------------------------------------------------ | ||
422 | |||
423 | m4_define([MU_TEST_GROUP],[Reverse Fold]) | ||
424 | m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ rfold]) | ||
425 | |||
426 | TESTLIST([empty list],[], | ||
427 | [rfold | ||
428 | ], | ||
429 | [NULL | ||
430 | ]) | ||
431 | |||
432 | TESTLIST([one element],[], | ||
433 | [add en | ||
434 | rfold | ||
435 | ], | ||
436 | [en | ||
437 | ]) | ||
438 | |||
439 | TESTLIST([many elements],[], | ||
440 | [add en to tre fire fem | ||
441 | rfold | ||
442 | ], | ||
443 | [femfiretretoen | ||
444 | ]) | ||
445 | |||
446 | m4_popdef([MU_TEST_KEYWORDS]) | ||
391 | 447 | ||
392 | dnl ------------------------------------------------------------ | 448 | dnl ------------------------------------------------------------ |
393 | dnl Cleanup | 449 | dnl Cleanup | ... | ... |
... | @@ -720,6 +720,60 @@ tail (size_t argc, mu_list_t list) | ... | @@ -720,6 +720,60 @@ tail (size_t argc, mu_list_t list) |
720 | printf ("%s\n", text); | 720 | printf ("%s\n", text); |
721 | } | 721 | } |
722 | 722 | ||
723 | static int | ||
724 | fold_concat (void *item, void *data, void *prev, void **ret) | ||
725 | { | ||
726 | char *s; | ||
727 | size_t len = strlen (item); | ||
728 | size_t prevlen = 0; | ||
729 | |||
730 | if (prev) | ||
731 | prevlen = strlen (prev); | ||
732 | |||
733 | s = realloc (prev, len + prevlen + 1); | ||
734 | if (!s) | ||
735 | abort (); | ||
736 | strcpy (s + prevlen, item); | ||
737 | *ret = s; | ||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | void | ||
742 | fold (mu_list_t list) | ||
743 | { | ||
744 | char *text = NULL; | ||
745 | int rc; | ||
746 | |||
747 | rc = mu_list_fold (list, fold_concat, NULL, NULL, &text); | ||
748 | if (rc) | ||
749 | mu_diag_funcall (MU_DIAG_ERROR, "mu_list_fold", NULL, rc); | ||
750 | else if (text) | ||
751 | { | ||
752 | printf ("%s\n", text); | ||
753 | free (text); | ||
754 | } | ||
755 | else | ||
756 | printf ("NULL\n"); | ||
757 | } | ||
758 | |||
759 | void | ||
760 | rfold (mu_list_t list) | ||
761 | { | ||
762 | char *text = NULL; | ||
763 | int rc; | ||
764 | |||
765 | rc = mu_list_rfold (list, fold_concat, NULL, NULL, &text); | ||
766 | if (rc) | ||
767 | mu_diag_funcall (MU_DIAG_ERROR, "mu_list_fold", NULL, rc); | ||
768 | else if (text) | ||
769 | { | ||
770 | printf ("%s\n", text); | ||
771 | free (text); | ||
772 | } | ||
773 | else | ||
774 | printf ("NULL\n"); | ||
775 | } | ||
776 | |||
723 | void | 777 | void |
724 | help () | 778 | help () |
725 | { | 779 | { |
... | @@ -739,6 +793,8 @@ help () | ... | @@ -739,6 +793,8 @@ help () |
739 | printf ("ictl ins item [item*]\n"); | 793 | printf ("ictl ins item [item*]\n"); |
740 | printf ("ictl dir [backwards|forwards]\n"); | 794 | printf ("ictl dir [backwards|forwards]\n"); |
741 | printf ("map [-replace] NAME [ARGS]\n"); | 795 | printf ("map [-replace] NAME [ARGS]\n"); |
796 | printf ("fold\n"); | ||
797 | printf ("rfold\n"); | ||
742 | printf ("print\n"); | 798 | printf ("print\n"); |
743 | printf ("slice [-replace] num [num...]\n"); | 799 | printf ("slice [-replace] num [num...]\n"); |
744 | printf ("quit\n"); | 800 | printf ("quit\n"); |
... | @@ -813,6 +869,10 @@ shell (mu_list_t list) | ... | @@ -813,6 +869,10 @@ shell (mu_list_t list) |
813 | print (list); | 869 | print (list); |
814 | else if (strcmp (ws.ws_wordv[0], "cur") == 0) | 870 | else if (strcmp (ws.ws_wordv[0], "cur") == 0) |
815 | cur (num, itr[num]); | 871 | cur (num, itr[num]); |
872 | else if (strcmp (ws.ws_wordv[0], "fold") == 0) | ||
873 | fold (list); | ||
874 | else if (strcmp (ws.ws_wordv[0], "rfold") == 0) | ||
875 | rfold (list); | ||
816 | else if (strcmp (ws.ws_wordv[0], "map") == 0) | 876 | else if (strcmp (ws.ws_wordv[0], "map") == 0) |
817 | { | 877 | { |
818 | int i; | 878 | int i; | ... | ... |
-
Please register or sign in to post a comment