summaryrefslogtreecommitdiff
path: root/libguile/srfi-13.c
diff options
context:
space:
mode:
authorKevin Ryde <user42@zip.com.au>2005-07-11 23:59:57 +0000
committerKevin Ryde <user42@zip.com.au>2005-07-11 23:59:57 +0000
commit8591234398e64f7dbcc673788eecea4fbb86ec3b (patch)
tree39a151e04f4f921faade6157996bcf07a651e190 /libguile/srfi-13.c
parentf71e4d8c09210b68a1108418ba1473e0b985f5b1 (diff)
downloadguile-8591234398e64f7dbcc673788eecea4fbb86ec3b.tar.gz
(scm_string_filter, scm_string_delete): Strip leading and
trailing deletions, so as to return a substring if those are the only changes.
Diffstat (limited to 'libguile/srfi-13.c')
-rw-r--r--libguile/srfi-13.c59
1 files changed, 50 insertions, 9 deletions
diff --git a/libguile/srfi-13.c b/libguile/srfi-13.c
index d0c626231..d4bd53b73 100644
--- a/libguile/srfi-13.c
+++ b/libguile/srfi-13.c
@@ -3254,8 +3254,7 @@ SCM_DEFINE (scm_string_split, "string-split", 2, 0, 0,
SCM_DEFINE (scm_string_filter, "string-filter", 2, 2, 0,
(SCM s, SCM char_pred, SCM start, SCM end),
"Filter the string @var{s}, retaining only those characters\n"
- "which satisfy @var{char_pred}. The result may share storage\n"
- "with @var{s}.\n"
+ "which satisfy @var{char_pred}.\n"
"\n"
"If @var{char_pred} is a procedure, it is applied to each\n"
"character as a predicate, if it is a character, it is tested\n"
@@ -3271,21 +3270,36 @@ SCM_DEFINE (scm_string_filter, "string-filter", 2, 2, 0,
MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
3, start, cstart,
4, end, cend);
+
+ /* The explicit loops below stripping leading and trailing non-matches
+ mean we can return a substring if those are the only deletions, making
+ string-filter as efficient as string-trim-both in that case. */
+
if (SCM_CHARP (char_pred))
{
size_t count;
char chr;
- /* count chars to keep */
chr = SCM_CHAR (char_pred);
+
+ /* strip leading non-matches by incrementing cstart */
+ while (cstart < cend && cstr[cstart] != chr)
+ cstart++;
+
+ /* strip trailing non-matches by decrementing cend */
+ while (cend > cstart && cstr[cend-1] != chr)
+ cend--;
+
+ /* count chars to keep */
count = 0;
for (idx = cstart; idx < cend; idx++)
if (cstr[idx] == chr)
count++;
- /* if whole of start to end kept then return substring */
if (count == cend - cstart)
{
+ /* whole of cstart to cend is to be kept, return a copy-on-write
+ substring */
result_substring:
result = scm_i_substring (s, cstart, cend);
}
@@ -3296,6 +3310,14 @@ SCM_DEFINE (scm_string_filter, "string-filter", 2, 2, 0,
{
size_t count;
+ /* strip leading non-matches by incrementing cstart */
+ while (cstart < cend && ! SCM_CHARSET_GET (char_pred, cstr[cstart]))
+ cstart++;
+
+ /* strip trailing non-matches by decrementing cend */
+ while (cend > cstart && ! SCM_CHARSET_GET (char_pred, cstr[cend-1]))
+ cend--;
+
/* count chars to be kept */
count = 0;
for (idx = cstart; idx < cend; idx++)
@@ -3351,8 +3373,7 @@ SCM_DEFINE (scm_string_filter, "string-filter", 2, 2, 0,
SCM_DEFINE (scm_string_delete, "string-delete", 2, 2, 0,
(SCM s, SCM char_pred, SCM start, SCM end),
- "Delete characters satisfying @var{char_pred} from @var{s}. The\n"
- "result may share storage with @var{s}.\n"
+ "Delete characters satisfying @var{char_pred} from @var{s}.\n"
"\n"
"If @var{char_pred} is a procedure, it is applied to each\n"
"character as a predicate, if it is a character, it is tested\n"
@@ -3368,6 +3389,11 @@ SCM_DEFINE (scm_string_delete, "string-delete", 2, 2, 0,
MY_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr,
3, start, cstart,
4, end, cend);
+
+ /* The explicit loops below stripping leading and trailing matches mean we
+ can return a substring if those are the only deletions, making
+ string-delete as efficient as string-trim-both in that case. */
+
if (SCM_CHARP (char_pred))
{
size_t count;
@@ -3375,15 +3401,24 @@ SCM_DEFINE (scm_string_delete, "string-delete", 2, 2, 0,
chr = SCM_CHAR (char_pred);
+ /* strip leading matches by incrementing cstart */
+ while (cstart < cend && cstr[cstart] == chr)
+ cstart++;
+
+ /* strip trailing matches by decrementing cend */
+ while (cend > cstart && cstr[cend-1] == chr)
+ cend--;
+
/* count chars to be kept */
count = 0;
for (idx = cstart; idx < cend; idx++)
if (cstr[idx] != chr)
count++;
- /* if whole of start to end kept then return substring */
if (count == cend - cstart)
{
+ /* whole of cstart to cend is to be kept, return a copy-on-write
+ substring */
result_substring:
result = scm_i_substring (s, cstart, cend);
}
@@ -3411,14 +3446,20 @@ SCM_DEFINE (scm_string_delete, "string-delete", 2, 2, 0,
{
size_t count;
+ /* strip leading matches by incrementing cstart */
+ while (cstart < cend && SCM_CHARSET_GET (char_pred, cstr[cstart]))
+ cstart++;
+
+ /* strip trailing matches by decrementing cend */
+ while (cend > cstart && SCM_CHARSET_GET (char_pred, cstr[cend-1]))
+ cend--;
+
/* count chars to be kept */
count = 0;
for (idx = cstart; idx < cend; idx++)
if (! SCM_CHARSET_GET (char_pred, cstr[idx]))
count++;
- /* if whole of start to end kept then return substring, including
- possibly s itself */
if (count == cend - cstart)
goto result_substring;
else