Commit c2dcdc0c c2dcdc0c950c030f96cabcafd9d860327bf02d71 by Sergey Poznyakoff

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"
1 parent 58d01e1e
...@@ -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
......
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 }
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)
......