Implement list slicing functions.
* include/mailutils/list.h (mu_list_slice_dup,mu_list_slice) (mu_list_slice2_dup,mu_list_slice2): New protos. * libmailutils/list/slice.c: New file. * libmailutils/list/slice2.c: New file. * libmailutils/list/Makefile.am: Add slice.c and slice2.c * libmailutils/tests/list.at: Add slicing tests. * libmailutils/tests/listop.c: New command: "slice"
Showing
6 changed files
with
337 additions
and
3 deletions
... | @@ -177,7 +177,45 @@ int mu_list_intersect_dup (mu_list_t *_pdest, | ... | @@ -177,7 +177,45 @@ int mu_list_intersect_dup (mu_list_t *_pdest, |
177 | void *_dup_data); | 177 | void *_dup_data); |
178 | 178 | ||
179 | /* Same as mu_list_intersect_dup with _dup_item = NULL */ | 179 | /* Same as mu_list_intersect_dup with _dup_item = NULL */ |
180 | int mu_list_intersect (mu_list_t *, mu_list_t, mu_list_t); | 180 | int mu_list_intersect (mu_list_t *, mu_list_t, mu_list_t); |
181 | |||
182 | /* ************************************************* */ | ||
183 | /* List slicing */ | ||
184 | /* ************************************************* */ | ||
185 | /* Create a new list from elements of _list located between | ||
186 | indices in _posv. Return the result in _pdest. | ||
187 | The resulting list will contain elements between _posv[0] and | ||
188 | _posv[1], _posv[2] and _posv[3], ..., _posv[_posc-2] | ||
189 | and _posv[_posc-1], inclusive. If _posc is an odd number, an extra | ||
190 | element with the value [count-1] (where count is the number of | ||
191 | elements in _list) is implied. | ||
192 | |||
193 | The elements in _posv are sorted in ascending order prior to use. | ||
194 | |||
195 | See mu_list_intersect_dup for a description of _dup_item and | ||
196 | _dup_data */ | ||
197 | int mu_list_slice_dup (mu_list_t *_pdest, mu_list_t _list, | ||
198 | size_t *_posv, size_t _posc, | ||
199 | int (*_dup_item) (void **, void *, void *), | ||
200 | void *_dup_data); | ||
201 | /* Same as mu_list_slice_dup invoked with _dup_item=NULL */ | ||
202 | int mu_list_slice (mu_list_t *_pdest, mu_list_t _list, | ||
203 | size_t *_posv, size_t _posc); | ||
204 | |||
205 | /* Two functions for the most common case: */ | ||
206 | /* Create a slice containing elements between indices _from and | ||
207 | _to in the _list. | ||
208 | |||
209 | See mu_list_intersect_dup for a description of _dup_item and | ||
210 | _dup_data */ | ||
211 | int mu_list_slice2_dup (mu_list_t *_pdest, mu_list_t _list, | ||
212 | size_t _from, size_t _to, | ||
213 | int (*_dup_item) (void **, void *, void *), | ||
214 | void *_dup_data); | ||
215 | /* Same as mu_list_slice2_dup with _dup_item=NULL */ | ||
216 | int mu_list_slice2 (mu_list_t *_pdest, mu_list_t _list, | ||
217 | size_t _from, size_t _to); | ||
218 | |||
181 | 219 | ||
182 | /* ************************************************* */ | 220 | /* ************************************************* */ |
183 | /* List mapper functions */ | 221 | /* List mapper functions */ | ... | ... |
... | @@ -39,7 +39,9 @@ liblist_la_SOURCES = \ | ... | @@ -39,7 +39,9 @@ liblist_la_SOURCES = \ |
39 | remove.c\ | 39 | remove.c\ |
40 | replace.c\ | 40 | replace.c\ |
41 | setcomp.c\ | 41 | setcomp.c\ |
42 | setdestr.c | 42 | setdestr.c\ |
43 | slice.c\ | ||
44 | slice2.c | ||
43 | 45 | ||
44 | INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils | 46 | INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils |
45 | 47 | ... | ... |
libmailutils/list/slice.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/list.h> | ||
23 | #include <mailutils/sys/list.h> | ||
24 | |||
25 | struct slice_info | ||
26 | { | ||
27 | size_t cur; | ||
28 | size_t *posv; | ||
29 | size_t posc; | ||
30 | size_t idx; | ||
31 | int (*dup_item) (void **, void *, void *); | ||
32 | void *dup_data; | ||
33 | int err; | ||
34 | }; | ||
35 | |||
36 | static int | ||
37 | _slice_mapper (void **itmv, size_t itmc, void *call_data) | ||
38 | { | ||
39 | struct slice_info *si = call_data; | ||
40 | size_t cur = si->cur++; | ||
41 | |||
42 | while (1) | ||
43 | { | ||
44 | if (cur < si->posv[si->idx]) | ||
45 | return MU_LIST_MAP_SKIP; | ||
46 | if (si->idx + 1 < si->posc && cur > si->posv[si->idx + 1]) | ||
47 | { | ||
48 | si->idx += 2; | ||
49 | if (si->idx >= si->posc) | ||
50 | return MU_LIST_MAP_STOP|MU_LIST_MAP_SKIP; | ||
51 | } | ||
52 | else | ||
53 | break; | ||
54 | } | ||
55 | |||
56 | if (si->dup_item && itmv[0]) | ||
57 | { | ||
58 | void *p; | ||
59 | int rc = si->dup_item (&p, itmv[0], si->dup_data); | ||
60 | if (rc) | ||
61 | { | ||
62 | si->err = rc; | ||
63 | return MU_LIST_MAP_STOP|MU_LIST_MAP_SKIP; | ||
64 | } | ||
65 | itmv[0] = p; | ||
66 | } | ||
67 | return MU_LIST_MAP_OK; | ||
68 | } | ||
69 | |||
70 | static int | ||
71 | poscmp (const void *a, const void *b) | ||
72 | { | ||
73 | size_t posa = *(size_t*)a; | ||
74 | size_t posb = *(size_t*)b; | ||
75 | |||
76 | if (posa < posb) | ||
77 | return -1; | ||
78 | else if (posa > posb) | ||
79 | return 1; | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | int | ||
84 | mu_list_slice_dup (mu_list_t *pdest, mu_list_t list, size_t *posv, size_t posc, | ||
85 | int (*dup_item) (void **, void *, void *), | ||
86 | void *dup_data) | ||
87 | { | ||
88 | int rc; | ||
89 | struct slice_info si; | ||
90 | mu_list_t dest; | ||
91 | |||
92 | si.cur = 0; | ||
93 | si.idx = 0; | ||
94 | si.posv = posv; | ||
95 | si.posc = posc; | ||
96 | si.dup_item = dup_item; | ||
97 | si.dup_data = dup_data; | ||
98 | si.err = 0; | ||
99 | |||
100 | qsort (posv, posc, sizeof (posv[0]), poscmp); | ||
101 | |||
102 | rc = mu_list_map (list, _slice_mapper, &si, 1, &dest); | ||
103 | |||
104 | if (rc == 0) | ||
105 | { | ||
106 | if (si.err) | ||
107 | { | ||
108 | mu_list_destroy (&dest); | ||
109 | rc = si.err; | ||
110 | } | ||
111 | else | ||
112 | { | ||
113 | if (dup_item) | ||
114 | mu_list_set_destroy_item (dest, list->destroy_item); | ||
115 | *pdest = dest; | ||
116 | } | ||
117 | } | ||
118 | return rc; | ||
119 | } | ||
120 | |||
121 | int | ||
122 | mu_list_slice (mu_list_t *pdest, mu_list_t list, size_t *posv, size_t posc) | ||
123 | { | ||
124 | return mu_list_slice_dup (pdest, list, posv, posc, NULL, NULL); | ||
125 | } |
libmailutils/list/slice2.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/list.h> | ||
23 | #include <mailutils/sys/list.h> | ||
24 | |||
25 | int | ||
26 | mu_list_slice2_dup (mu_list_t *pdest, mu_list_t list, | ||
27 | size_t from, size_t to, | ||
28 | int (*dup_item) (void **, void *, void *), | ||
29 | void *dup_data) | ||
30 | { | ||
31 | size_t arr[2] = { from, to }; | ||
32 | return mu_list_slice_dup (pdest, list, arr, 2, dup_item, dup_data); | ||
33 | } | ||
34 | |||
35 | int | ||
36 | mu_list_slice2 (mu_list_t *pdest, mu_list_t list, size_t from, size_t to) | ||
37 | { | ||
38 | return mu_list_slice2_dup (pdest, list, from, to, NULL, NULL); | ||
39 | } | ||
40 | |||
41 | |||
42 |
... | @@ -323,7 +323,60 @@ to | ... | @@ -323,7 +323,60 @@ to |
323 | ]) | 323 | ]) |
324 | 324 | ||
325 | m4_popdef([MU_TEST_KEYWORDS]) | 325 | m4_popdef([MU_TEST_KEYWORDS]) |
326 | |||
327 | # ------------------------------------------------------------ | ||
328 | # Slices | ||
329 | # ------------------------------------------------------------ | ||
330 | |||
331 | m4_define([MU_TEST_GROUP],[Slice]) | ||
332 | m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ slice]) | ||
333 | |||
334 | TESTLIST([one limit],[], | ||
335 | [add null en to tre fire | ||
336 | slice 3 | ||
337 | ], | ||
338 | [# items: 2 | ||
339 | tre | ||
340 | fire | ||
341 | ]) | ||
342 | |||
343 | TESTLIST([two limits],[], | ||
344 | [add null en to tre fire fem seks syv atte ni ti | ||
345 | slice 4 7 | ||
346 | ], | ||
347 | [# items: 4 | ||
348 | fire | ||
349 | fem | ||
350 | seks | ||
351 | syv | ||
352 | ]) | ||
326 | 353 | ||
354 | TESTLIST([four limits],[], | ||
355 | [add null en to tre fire fem seks syv atte ni ti | ||
356 | slice 4 6 9 10 | ||
357 | ], | ||
358 | [# items: 5 | ||
359 | fire | ||
360 | fem | ||
361 | seks | ||
362 | ni | ||
363 | ti | ||
364 | ]) | ||
365 | |||
366 | TESTLIST([four limits unsorted],[], | ||
367 | [add null en to tre fire fem seks syv atte ni ti | ||
368 | slice 10 6 9 4 | ||
369 | ], | ||
370 | [# items: 5 | ||
371 | fire | ||
372 | fem | ||
373 | seks | ||
374 | ni | ||
375 | ti | ||
376 | ]) | ||
377 | |||
378 | m4_popdef([MU_TEST_KEYWORDS]) | ||
379 | |||
327 | dnl ------------------------------------------------------------ | 380 | dnl ------------------------------------------------------------ |
328 | dnl Cleanup | 381 | dnl Cleanup |
329 | m4_popdef([TESTLIST]) | 382 | m4_popdef([TESTLIST]) | ... | ... |
... | @@ -619,6 +619,71 @@ map (mu_list_t *plist, int argc, char **argv) | ... | @@ -619,6 +619,71 @@ map (mu_list_t *plist, int argc, char **argv) |
619 | return 0; | 619 | return 0; |
620 | } | 620 | } |
621 | 621 | ||
622 | static int | ||
623 | dup_string (void **res, void *itm, void *closure) | ||
624 | { | ||
625 | *res = strdup (itm); | ||
626 | return *res ? 0 : ENOMEM; | ||
627 | } | ||
628 | |||
629 | int | ||
630 | slice (mu_list_t *plist, int argc, char **argv) | ||
631 | { | ||
632 | mu_list_t list = *plist; | ||
633 | mu_list_t result; | ||
634 | int rc, i; | ||
635 | int replace = 0; | ||
636 | size_t *buf; | ||
637 | |||
638 | argc--; | ||
639 | argv++; | ||
640 | |||
641 | if (argc > 0 && strcmp (argv[0], "-replace") == 0) | ||
642 | { | ||
643 | replace = 1; | ||
644 | argc--; | ||
645 | argv++; | ||
646 | } | ||
647 | |||
648 | if (argc < 1) | ||
649 | { | ||
650 | fprintf (stderr, "slice [-replace] num [num...]\n"); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | buf = calloc (argc, sizeof (buf[0])); | ||
655 | if (!buf) | ||
656 | abort (); | ||
657 | for (i = 0; i < argc; i++) | ||
658 | buf[i] = atoi (argv[i]); | ||
659 | |||
660 | rc = mu_list_slice_dup (&result, list, buf, argc, | ||
661 | dup_string, NULL); | ||
662 | if (rc) | ||
663 | { | ||
664 | mu_error ("slice failed: %s", mu_strerror (rc)); | ||
665 | return 0; | ||
666 | } | ||
667 | if (replace) | ||
668 | { | ||
669 | size_t count[2]; | ||
670 | mu_list_count (list, &count[0]); | ||
671 | mu_list_count (result, &count[1]); | ||
672 | |||
673 | printf ("%lu in, %lu out\n", (unsigned long) count[0], | ||
674 | (unsigned long) count[1]); | ||
675 | mu_list_destroy (&list); | ||
676 | *plist = result; | ||
677 | return 1; | ||
678 | } | ||
679 | else | ||
680 | { | ||
681 | print (result); | ||
682 | mu_list_destroy (&result); | ||
683 | } | ||
684 | return 0; | ||
685 | } | ||
686 | |||
622 | void | 687 | void |
623 | help () | 688 | help () |
624 | { | 689 | { |
... | @@ -637,8 +702,9 @@ help () | ... | @@ -637,8 +702,9 @@ help () |
637 | printf ("ictl repl item\n"); | 702 | printf ("ictl repl item\n"); |
638 | printf ("ictl ins item [item*]\n"); | 703 | printf ("ictl ins item [item*]\n"); |
639 | printf ("ictl dir [backwards|forwards]\n"); | 704 | printf ("ictl dir [backwards|forwards]\n"); |
640 | printf ("map NAME [ARGS]\n"); | 705 | printf ("map [-replace] NAME [ARGS]\n"); |
641 | printf ("print\n"); | 706 | printf ("print\n"); |
707 | printf ("slice [-replace] num [num...]\n"); | ||
642 | printf ("quit\n"); | 708 | printf ("quit\n"); |
643 | printf ("iter num\n"); | 709 | printf ("iter num\n"); |
644 | printf ("help\n"); | 710 | printf ("help\n"); |
... | @@ -717,6 +783,14 @@ shell (mu_list_t list) | ... | @@ -717,6 +783,14 @@ shell (mu_list_t list) |
717 | for (i = 0; i < NITR; i++) | 783 | for (i = 0; i < NITR; i++) |
718 | mu_iterator_destroy (&itr[i]); | 784 | mu_iterator_destroy (&itr[i]); |
719 | } | 785 | } |
786 | else if (strcmp (ws.ws_wordv[0], "slice") == 0) | ||
787 | { | ||
788 | int i; | ||
789 | |||
790 | if (slice (&list, ws.ws_wordc, ws.ws_wordv)) | ||
791 | for (i = 0; i < NITR; i++) | ||
792 | mu_iterator_destroy (&itr[i]); | ||
793 | } | ||
720 | else if (strcmp (ws.ws_wordv[0], "quit") == 0) | 794 | else if (strcmp (ws.ws_wordv[0], "quit") == 0) |
721 | return; | 795 | return; |
722 | else if (strcmp (ws.ws_wordv[0], "iter") == 0) | 796 | else if (strcmp (ws.ws_wordv[0], "iter") == 0) | ... | ... |
-
Please register or sign in to post a comment