summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-09-28 22:30:01 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-09-28 22:30:01 -0700
commit3d707aee9ae403bde7ffb69062a29086a7265a5d (patch)
tree57626943165c8626cb9549d16a266436fc7a6880
parent9c2cf56174660ec9e5382025003106a4986c8cb4 (diff)
downloadtxr-3d707aee9ae403bde7ffb69062a29086a7265a5d.tar.gz
txr-3d707aee9ae403bde7ffb69062a29086a7265a5d.tar.bz2
txr-3d707aee9ae403bde7ffb69062a29086a7265a5d.zip
Improve performance of lazy string forcing.
* lib (lazy_str_force, lazy_str_force_upto): The existing algorithm keeps catenating pieces onto a string, which triggers wasteful reallocations and is quadratic. This is replaced with a different approach: we collect pieces into a list, and then make a single call to cat_str.
-rw-r--r--lib.c36
1 files changed, 27 insertions, 9 deletions
diff --git a/lib.c b/lib.c
index 42f6cb04..36849c30 100644
--- a/lib.c
+++ b/lib.c
@@ -5685,14 +5685,15 @@ val lazy_str(val lst, val term, val limit)
val lazy_str_force(val lstr)
{
- val lim;
+ val lim, term;
+ list_collect_decl (strlist, ptail);
type_check(lstr, LSTR);
lim = cdr(lstr->ls.opts);
+ term = car(lstr->ls.opts);
while ((!lim || gt(lim, zero)) && lstr->ls.list) {
- val next = pop(&lstr->ls.list);
- val term = car(lstr->ls.opts);
- set(mkloc(lstr->ls.prefix, lstr), cat_str(list(lstr->ls.prefix, next, term, nao), nil));
+ ptail = list_collect(ptail, pop(&lstr->ls.list));
+ ptail = list_collect(ptail, term);
if (lim)
lim = minus(lim, one);
}
@@ -5700,29 +5701,46 @@ val lazy_str_force(val lstr)
if (lim)
set(cdr_l(lstr->ls.opts), lim);
+ if (strlist) {
+ push(lstr->ls.prefix, &strlist);
+ set(mkloc(lstr->ls.prefix, lstr), cat_str(strlist, nil));
+ }
+
return lstr->ls.prefix;
}
val lazy_str_force_upto(val lstr, val index)
{
uses_or2;
- val lim;
+ val lim, term, ltrm, len;
+ list_collect_decl (strlist, ptail);
type_check(lstr, LSTR);
lim = cdr(lstr->ls.opts);
+ term = car(lstr->ls.opts);
+ ltrm = length_str(term);
+ len = length_str(lstr->ls.prefix);
- while (ge(index, length_str(lstr->ls.prefix)) && lstr->ls.list &&
+ while (ge(index, len) && lstr->ls.list &&
or2(null(lim),gt(lim,zero)))
{
val next = pop(&lstr->ls.list);
- val term = car(lstr->ls.opts);
- set(mkloc(lstr->ls.prefix, lstr), cat_str(list(lstr->ls.prefix, next, term, nao), nil));
+ ptail = list_collect(ptail, next);
+ ptail = list_collect(ptail, term);
if (lim)
lim = minus(lim, one);
+ len = plus(len, length_str(next));
+ len = plus(len, ltrm);
}
if (lim)
set(cdr_l(lstr->ls.opts), lim);
- return lt(index, length_str(lstr->ls.prefix));
+
+ if (strlist) {
+ push(lstr->ls.prefix, &strlist);
+ set(mkloc(lstr->ls.prefix, lstr), cat_str(strlist, nil));
+ }
+
+ return lt(index, len);
}
val length_str_gt(val str, val len)