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,
void *_dup_data);
/* Same as mu_list_intersect_dup with _dup_item = NULL */
int mu_list_intersect (mu_list_t *, mu_list_t, mu_list_t);
int mu_list_intersect (mu_list_t *, mu_list_t, mu_list_t);
/* ************************************************* */
/* List slicing */
/* ************************************************* */
/* Create a new list from elements of _list located between
indices in _posv. Return the result in _pdest.
The resulting list will contain elements between _posv[0] and
_posv[1], _posv[2] and _posv[3], ..., _posv[_posc-2]
and _posv[_posc-1], inclusive. If _posc is an odd number, an extra
element with the value [count-1] (where count is the number of
elements in _list) is implied.
The elements in _posv are sorted in ascending order prior to use.
See mu_list_intersect_dup for a description of _dup_item and
_dup_data */
int mu_list_slice_dup (mu_list_t *_pdest, mu_list_t _list,
size_t *_posv, size_t _posc,
int (*_dup_item) (void **, void *, void *),
void *_dup_data);
/* Same as mu_list_slice_dup invoked with _dup_item=NULL */
int mu_list_slice (mu_list_t *_pdest, mu_list_t _list,
size_t *_posv, size_t _posc);
/* Two functions for the most common case: */
/* Create a slice containing elements between indices _from and
_to in the _list.
See mu_list_intersect_dup for a description of _dup_item and
_dup_data */
int mu_list_slice2_dup (mu_list_t *_pdest, mu_list_t _list,
size_t _from, size_t _to,
int (*_dup_item) (void **, void *, void *),
void *_dup_data);
/* Same as mu_list_slice2_dup with _dup_item=NULL */
int mu_list_slice2 (mu_list_t *_pdest, mu_list_t _list,
size_t _from, size_t _to);
/* ************************************************* */
/* List mapper functions */
......
......@@ -39,7 +39,9 @@ liblist_la_SOURCES = \
remove.c\
replace.c\
setcomp.c\
setdestr.c
setdestr.c\
slice.c\
slice2.c
INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2011 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <mailutils/list.h>
#include <mailutils/sys/list.h>
struct slice_info
{
size_t cur;
size_t *posv;
size_t posc;
size_t idx;
int (*dup_item) (void **, void *, void *);
void *dup_data;
int err;
};
static int
_slice_mapper (void **itmv, size_t itmc, void *call_data)
{
struct slice_info *si = call_data;
size_t cur = si->cur++;
while (1)
{
if (cur < si->posv[si->idx])
return MU_LIST_MAP_SKIP;
if (si->idx + 1 < si->posc && cur > si->posv[si->idx + 1])
{
si->idx += 2;
if (si->idx >= si->posc)
return MU_LIST_MAP_STOP|MU_LIST_MAP_SKIP;
}
else
break;
}
if (si->dup_item && itmv[0])
{
void *p;
int rc = si->dup_item (&p, itmv[0], si->dup_data);
if (rc)
{
si->err = rc;
return MU_LIST_MAP_STOP|MU_LIST_MAP_SKIP;
}
itmv[0] = p;
}
return MU_LIST_MAP_OK;
}
static int
poscmp (const void *a, const void *b)
{
size_t posa = *(size_t*)a;
size_t posb = *(size_t*)b;
if (posa < posb)
return -1;
else if (posa > posb)
return 1;
return 0;
}
int
mu_list_slice_dup (mu_list_t *pdest, mu_list_t list, size_t *posv, size_t posc,
int (*dup_item) (void **, void *, void *),
void *dup_data)
{
int rc;
struct slice_info si;
mu_list_t dest;
si.cur = 0;
si.idx = 0;
si.posv = posv;
si.posc = posc;
si.dup_item = dup_item;
si.dup_data = dup_data;
si.err = 0;
qsort (posv, posc, sizeof (posv[0]), poscmp);
rc = mu_list_map (list, _slice_mapper, &si, 1, &dest);
if (rc == 0)
{
if (si.err)
{
mu_list_destroy (&dest);
rc = si.err;
}
else
{
if (dup_item)
mu_list_set_destroy_item (dest, list->destroy_item);
*pdest = dest;
}
}
return rc;
}
int
mu_list_slice (mu_list_t *pdest, mu_list_t list, size_t *posv, size_t posc)
{
return mu_list_slice_dup (pdest, list, posv, posc, NULL, NULL);
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2011 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <mailutils/list.h>
#include <mailutils/sys/list.h>
int
mu_list_slice2_dup (mu_list_t *pdest, mu_list_t list,
size_t from, size_t to,
int (*dup_item) (void **, void *, void *),
void *dup_data)
{
size_t arr[2] = { from, to };
return mu_list_slice_dup (pdest, list, arr, 2, dup_item, dup_data);
}
int
mu_list_slice2 (mu_list_t *pdest, mu_list_t list, size_t from, size_t to)
{
return mu_list_slice2_dup (pdest, list, from, to, NULL, NULL);
}
......@@ -323,7 +323,60 @@ to
])
m4_popdef([MU_TEST_KEYWORDS])
# ------------------------------------------------------------
# Slices
# ------------------------------------------------------------
m4_define([MU_TEST_GROUP],[Slice])
m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ slice])
TESTLIST([one limit],[],
[add null en to tre fire
slice 3
],
[# items: 2
tre
fire
])
TESTLIST([two limits],[],
[add null en to tre fire fem seks syv atte ni ti
slice 4 7
],
[# items: 4
fire
fem
seks
syv
])
TESTLIST([four limits],[],
[add null en to tre fire fem seks syv atte ni ti
slice 4 6 9 10
],
[# items: 5
fire
fem
seks
ni
ti
])
TESTLIST([four limits unsorted],[],
[add null en to tre fire fem seks syv atte ni ti
slice 10 6 9 4
],
[# items: 5
fire
fem
seks
ni
ti
])
m4_popdef([MU_TEST_KEYWORDS])
dnl ------------------------------------------------------------
dnl Cleanup
m4_popdef([TESTLIST])
......
......@@ -619,6 +619,71 @@ map (mu_list_t *plist, int argc, char **argv)
return 0;
}
static int
dup_string (void **res, void *itm, void *closure)
{
*res = strdup (itm);
return *res ? 0 : ENOMEM;
}
int
slice (mu_list_t *plist, int argc, char **argv)
{
mu_list_t list = *plist;
mu_list_t result;
int rc, i;
int replace = 0;
size_t *buf;
argc--;
argv++;
if (argc > 0 && strcmp (argv[0], "-replace") == 0)
{
replace = 1;
argc--;
argv++;
}
if (argc < 1)
{
fprintf (stderr, "slice [-replace] num [num...]\n");
return 0;
}
buf = calloc (argc, sizeof (buf[0]));
if (!buf)
abort ();
for (i = 0; i < argc; i++)
buf[i] = atoi (argv[i]);
rc = mu_list_slice_dup (&result, list, buf, argc,
dup_string, NULL);
if (rc)
{
mu_error ("slice failed: %s", mu_strerror (rc));
return 0;
}
if (replace)
{
size_t count[2];
mu_list_count (list, &count[0]);
mu_list_count (result, &count[1]);
printf ("%lu in, %lu out\n", (unsigned long) count[0],
(unsigned long) count[1]);
mu_list_destroy (&list);
*plist = result;
return 1;
}
else
{
print (result);
mu_list_destroy (&result);
}
return 0;
}
void
help ()
{
......@@ -637,8 +702,9 @@ help ()
printf ("ictl repl item\n");
printf ("ictl ins item [item*]\n");
printf ("ictl dir [backwards|forwards]\n");
printf ("map NAME [ARGS]\n");
printf ("map [-replace] NAME [ARGS]\n");
printf ("print\n");
printf ("slice [-replace] num [num...]\n");
printf ("quit\n");
printf ("iter num\n");
printf ("help\n");
......@@ -717,6 +783,14 @@ shell (mu_list_t list)
for (i = 0; i < NITR; i++)
mu_iterator_destroy (&itr[i]);
}
else if (strcmp (ws.ws_wordv[0], "slice") == 0)
{
int i;
if (slice (&list, ws.ws_wordc, ws.ws_wordv))
for (i = 0; i < NITR; i++)
mu_iterator_destroy (&itr[i]);
}
else if (strcmp (ws.ws_wordv[0], "quit") == 0)
return;
else if (strcmp (ws.ws_wordv[0], "iter") == 0)
......