summaryrefslogtreecommitdiff
path: root/pp_ctl.c
diff options
context:
space:
mode:
authorGurusamy Sarathy <gsar@cpan.org>2000-07-15 09:05:09 -0700
committerJarkko Hietaniemi <jhi@iki.fi>2000-07-24 02:58:52 +0000
commit544f31531e7cbe3b4e7571d94c56f36d53f647fa (patch)
tree4d466bf2d469fbf2933216cd4017063f3627c4e5 /pp_ctl.c
parent66417f8481fa145150d67cc9c9373be6a91826a9 (diff)
downloadperl-544f31531e7cbe3b4e7571d94c56f36d53f647fa.tar.gz
Documentation to explain the behaviour of map().
Subject: Re: Map is still slow Message-Id: <200007152305.QAA26887@molotok.activestate.com> p4raw-id: //depot/perl@6428
Diffstat (limited to 'pp_ctl.c')
-rw-r--r--pp_ctl.c34
1 files changed, 24 insertions, 10 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index a924d2ebe3..75673dc50f 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -725,36 +725,49 @@ PP(pp_mapstart)
PP(pp_mapwhile)
{
djSP;
- I32 diff = (SP - PL_stack_base) - *PL_markstack_ptr;
+ I32 items = (SP - PL_stack_base) - *PL_markstack_ptr; /* how many new items */
I32 count;
I32 shift;
SV** src;
SV** dst;
+ /* first, move source pointer to the next item in the source list */
++PL_markstack_ptr[-1];
- if (diff) {
- if (diff > PL_markstack_ptr[-1] - PL_markstack_ptr[-2]) {
- shift = diff - (PL_markstack_ptr[-1] - PL_markstack_ptr[-2]);
- count = (SP - PL_stack_base) - PL_markstack_ptr[-1] + 2;
+
+ /* if there are new items, push them into the destination list */
+ if (items) {
+ /* might need to make room back there first */
+ if (items > PL_markstack_ptr[-1] - PL_markstack_ptr[-2]) {
+ /* XXX this implementation is very pessimal because the stack
+ * is repeatedly extended for every set of items. Is possible
+ * to do this without any stack extension or copying at all
+ * by maintaining a separate list over which the map iterates
+ * (like foreach does). */
+
+ /* everything in the stack after the destination list moves
+ * towards the end the stack by the amount of room needed */
+ shift = items - (PL_markstack_ptr[-1] - PL_markstack_ptr[-2]);
+
+ /* items to shift up (accounting for the moved source pointer) */
+ count = (SP - PL_stack_base) - (PL_markstack_ptr[-1] - 1);
EXTEND(SP,shift);
src = SP;
dst = (SP += shift);
PL_markstack_ptr[-1] += shift;
*PL_markstack_ptr += shift;
- while (--count)
+ while (count--)
*dst-- = *src--;
}
- dst = PL_stack_base + (PL_markstack_ptr[-2] += diff) - 1;
- ++diff;
- while (--diff)
+ /* copy the new items down to the destination list */
+ dst = PL_stack_base + (PL_markstack_ptr[-2] += items) - 1;
+ while (items--)
*dst-- = SvTEMP(TOPs) ? POPs : sv_mortalcopy(POPs);
}
LEAVE; /* exit inner scope */
/* All done yet? */
if (PL_markstack_ptr[-1] > *PL_markstack_ptr) {
- I32 items;
I32 gimme = GIMME_V;
(void)POPMARK; /* pop top */
@@ -777,6 +790,7 @@ PP(pp_mapwhile)
ENTER; /* enter inner scope */
SAVEVPTR(PL_curpm);
+ /* set $_ to the new source item */
src = PL_stack_base[PL_markstack_ptr[-1]];
SvTEMP_off(src);
DEFSV = src;