On Wed, Jul 25, 2001 at 05:05:03PM -0700, Randal L. Schwartz wrote:
> For this to work, the element indirected by $a would have to always be
> to the left of the element indirected by $b, and that's probably not
> true. In fact, we can see this:
I noticed that in a few of my tests and never really connected why
this happens. Thanks Randal.
So I decided to make a quick experimental hack on perl's source and
change sortcv_stacked a bit. (C source at the end of this message,
changes indicated in /**/'s). This is the comparison function that gets
called when you have a prototyped sort function.
So now when you have a prototyped sortsub:
sub foo ($$) {
}
The third argument passed is the relative position of the two
comparison values either 1 or -1. So here's the new sort function:
sub foo ($$) {
if ($_[0] < $_[1] and $_[2] > 1) {
($_[0],$_[1])=($_[1],$_[0]);
}
}
And calling it with:
for(0..20) { push(@r, int rand(50)) }
@s=sort foo @r;
Yeilds an @r that's properly re-ordered! An in-place sort? At least
that's what I thought when I said:
print join(',', @s), "\n";
print join(',', @r), "\n";
I got the correct results. Now the problem is that even though this
appears to work -- it doesn't. Saying:
for(0..20) { push(@r, int rand(50)) }
@s=sort foo @r;
print join(',', @r), "\n"; # Prints sorted
@s=();
print join(',', @r), "\n"; # Prints unsorted!
Yeilds the original unsorted list. WTF? It's as though the elements
of @r were masked by the elements of @s. It's not the patch. Without
the patch, the "Prints sorted" line above just "Prints in weird order".
*scratching head*
Maybe this is why no-one's really looked at modifying $a and $b
within a sortsub. :)
If someone can explain *this* to me, I could probably finish a patch
for in-place sorting in Perl. But I'm lost as to why (or HOW) @r
can be "unwound" like this well after the fact.
-------------
C Source change from pp_ctl.c, sortcv_stacked(). I'm out of practice
hacking C, and the Perl source mystifies me most of the time. 5.7.0
if (AvMAX(av) < 2) { /* Was 1 */
SV** ary = AvALLOC(av);
if (AvARRAY(av) != ary) {
AvMAX(av) += AvARRAY(av) - AvALLOC(av);
SvPVX(av) = (char*)ary;
}
if (AvMAX(av) < 2) { /* was 1 */
AvMAX(av) = 2; /* was 1 */
Renew(ary,3,SV*); /* was 2 */
SvPVX(av) = (char*)ary;
}
}
AvFILLp(av) = 2; /* was 1 */
AvARRAY(av)[0] = a;
AvARRAY(av)[1] = b;
AvARRAY(av)[2] = newSViv(a>b?1:-1); /* Relative positions */
--
Clinton A. Pierce Teach Yourself Perl in 24 Hours *and*
[EMAIL PROTECTED] Perl Developer's Dictionary
"If you rush a Miracle Man, for details, see http://geeksalad.org
you get rotten Miracles." --Miracle Max, The Princess Bride