Fix sorting tied arrays
This commit is contained in:
parent
5b4184a6e3
commit
c3f620d1d8
@ -0,0 +1,67 @@
|
||||
From 3eb35b099f783db0ec40f0ca9f20fd1666c54cdb Mon Sep 17 00:00:00 2001
|
||||
From: Yves Orton <demerphq@gmail.com>
|
||||
Date: Thu, 30 Jan 2020 09:36:37 +0100
|
||||
Subject: [PATCH] perltie.pod: rework example code so EXTEND is a no-op
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Most tied array implementations can and should NO-OP the EXTEND
|
||||
method, and the sample code should not conflate EXTEND with STORESIZE.
|
||||
|
||||
EXTEND is actually less usefully used by the core than it could be
|
||||
as AvMAX() does not have an equivalent tied method. So we cannot
|
||||
check if we need to extend for a tied array.
|
||||
|
||||
This is related to [rt.cpan.org #39196] / Issue #17496.
|
||||
|
||||
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
||||
---
|
||||
pod/perltie.pod | 18 +++++++++++++-----
|
||||
1 file changed, 13 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/pod/perltie.pod b/pod/perltie.pod
|
||||
index 2d433e8204..1bb220691b 100644
|
||||
--- a/pod/perltie.pod
|
||||
+++ b/pod/perltie.pod
|
||||
@@ -301,7 +301,7 @@ spaces so we have a little more work to do here:
|
||||
croak "length of $value is greater than $self->{ELEMSIZE}";
|
||||
}
|
||||
# fill in the blanks
|
||||
- $self->EXTEND( $index ) if $index > $self->FETCHSIZE();
|
||||
+ $self->STORESIZE( $index ) if $index > $self->FETCHSIZE();
|
||||
# right justify to keep element size for smaller elements
|
||||
$self->{ARRAY}->[$index] = sprintf "%$self->{ELEMSIZE}s", $value;
|
||||
}
|
||||
@@ -351,16 +351,24 @@ X<EXTEND>
|
||||
Informative call that array is likely to grow to have I<count> entries.
|
||||
Can be used to optimize allocation. This method need do nothing.
|
||||
|
||||
-In our example, we want to make sure there are no blank (C<undef>)
|
||||
-entries, so C<EXTEND> will make use of C<STORESIZE> to fill elements
|
||||
-as needed:
|
||||
+In our example there is no reason to implement this method, so we leave
|
||||
+it as a no-op. This method is only relevant to tied array implementations
|
||||
+where there is the possibility of having the allocated size of the array
|
||||
+be larger than is visible to a perl programmer inspecting the size of the
|
||||
+array. Many tied array implementations will have no reason to implement it.
|
||||
|
||||
sub EXTEND {
|
||||
my $self = shift;
|
||||
my $count = shift;
|
||||
- $self->STORESIZE( $count );
|
||||
+ # nothing to see here, move along.
|
||||
}
|
||||
|
||||
+B<NOTE:> It is generally an error to make this equivalent to STORESIZE.
|
||||
+Perl may from time to time call EXTEND without wanting to actually change
|
||||
+the array size directly. Any tied array should function correctly if this
|
||||
+method is a no-op, even if perhaps they might not be as efficient as they
|
||||
+would if this method was implemented.
|
||||
+
|
||||
=item EXISTS this, key
|
||||
X<EXISTS>
|
||||
|
||||
--
|
||||
2.21.1
|
||||
|
@ -0,0 +1,142 @@
|
||||
From 2b301921ff7682e54ab74ad30dbf2ce1c9fc24b1 Mon Sep 17 00:00:00 2001
|
||||
From: Yves Orton <demerphq@gmail.com>
|
||||
Date: Fri, 31 Jan 2020 15:34:48 +0100
|
||||
Subject: [PATCH] pp_sort.c: fix fencepost error in call to av_extend()
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
In [rt.cpan.org #39196] issue #17496 there is a report
|
||||
that Tie::File produced spurious blank lines in the file
|
||||
after
|
||||
|
||||
@tied= sort @tied;
|
||||
|
||||
it turns out that this is because Tie::File treats
|
||||
EXTEND similarly to STORESIZE (which is arguably not
|
||||
entirely correct, but also not that weird) coupled
|
||||
with an off by one error in the calls to av_extend()
|
||||
in pp_sort.
|
||||
|
||||
This patch fixes the fencepost error, adds some comments
|
||||
to av_extend() to make it clear what it is doing, and
|
||||
adds a test that EXTEND is called by this code with
|
||||
correct argument.
|
||||
|
||||
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
||||
---
|
||||
av.c | 18 ++++++++++++++++--
|
||||
pp_sort.c | 5 +++--
|
||||
t/op/sort.t | 23 +++++++++++++++++++++--
|
||||
3 files changed, 40 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/av.c b/av.c
|
||||
index 918844c376..27b2f12032 100644
|
||||
--- a/av.c
|
||||
+++ b/av.c
|
||||
@@ -55,8 +55,13 @@ Perl_av_reify(pTHX_ AV *av)
|
||||
/*
|
||||
=for apidoc av_extend
|
||||
|
||||
-Pre-extend an array. The C<key> is the index to which the array should be
|
||||
-extended.
|
||||
+Pre-extend an array so that it is capable of storing values at indexes
|
||||
+C<0..key>. Thus C<av_extend(av,99)> guarantees that the array can store 100
|
||||
+elements, i.e. that C<av_store(av, 0, sv)> through C<av_store(av, 99, sv)>
|
||||
+on a plain array will work without any further memory allocation.
|
||||
+
|
||||
+If the av argument is a tied array then will call the C<EXTEND> tied
|
||||
+array method with an argument of C<(key+1)>.
|
||||
|
||||
=cut
|
||||
*/
|
||||
@@ -72,6 +77,15 @@ Perl_av_extend(pTHX_ AV *av, SSize_t key)
|
||||
mg = SvTIED_mg((const SV *)av, PERL_MAGIC_tied);
|
||||
if (mg) {
|
||||
SV *arg1 = sv_newmortal();
|
||||
+ /* NOTE: the API for av_extend() is NOT the same as the tie method EXTEND.
|
||||
+ *
|
||||
+ * The C function takes an *index* (assumes 0 indexed arrays) and ensures
|
||||
+ * that the array is at least as large as the index provided.
|
||||
+ *
|
||||
+ * The tied array method EXTEND takes a *count* and ensures that the array
|
||||
+ * is at least that many elements large. Thus we have to +1 the key when
|
||||
+ * we call the tied method.
|
||||
+ */
|
||||
sv_setiv(arg1, (IV)(key + 1));
|
||||
Perl_magic_methcall(aTHX_ MUTABLE_SV(av), mg, SV_CONST(EXTEND), G_DISCARD, 1,
|
||||
arg1);
|
||||
diff --git a/pp_sort.c b/pp_sort.c
|
||||
index 0c5efb0869..4f81aaab7e 100644
|
||||
--- a/pp_sort.c
|
||||
+++ b/pp_sort.c
|
||||
@@ -1067,7 +1067,8 @@ PP(pp_sort)
|
||||
for (i = 0; i < max; i++)
|
||||
base[i] = newSVsv(base[i]);
|
||||
av_clear(av);
|
||||
- av_extend(av, max);
|
||||
+ if (max)
|
||||
+ av_extend(av, max-1);
|
||||
for (i=0; i < max; i++) {
|
||||
SV * const sv = base[i];
|
||||
SV ** const didstore = av_store(av, i, sv);
|
||||
@@ -1094,7 +1095,7 @@ PP(pp_sort)
|
||||
}
|
||||
av_clear(av);
|
||||
if (max > 0) {
|
||||
- av_extend(av, max);
|
||||
+ av_extend(av, max-1);
|
||||
Copy(base, AvARRAY(av), max, SV*);
|
||||
}
|
||||
AvFILLp(av) = max - 1;
|
||||
diff --git a/t/op/sort.t b/t/op/sort.t
|
||||
index d201f00afd..f2e139dff0 100644
|
||||
--- a/t/op/sort.t
|
||||
+++ b/t/op/sort.t
|
||||
@@ -7,7 +7,8 @@ BEGIN {
|
||||
set_up_inc('../lib');
|
||||
}
|
||||
use warnings;
|
||||
-plan(tests => 199);
|
||||
+plan(tests => 203);
|
||||
+use Tie::Array; # we need to test sorting tied arrays
|
||||
|
||||
# these shouldn't hang
|
||||
{
|
||||
@@ -433,7 +434,6 @@ cmp_ok($x,'eq','123',q(optimized-away comparison block doesn't take any other ar
|
||||
@a = qw(b c a); $r1 = \$a[1]; @a = sort mysort @a; $r2 = \$a[0];
|
||||
is "$$r1-$$r2-@a", "c-c-c b a", "inplace sort with function of lexical";
|
||||
|
||||
- use Tie::Array;
|
||||
my @t;
|
||||
tie @t, 'Tie::StdArray';
|
||||
|
||||
@@ -494,6 +494,25 @@ cmp_ok($x,'eq','123',q(optimized-away comparison block doesn't take any other ar
|
||||
is ("@a", "3 4 5", "RT #128340");
|
||||
|
||||
}
|
||||
+{
|
||||
+ @Tied_Array_EXTEND_Test::ISA= 'Tie::StdArray';
|
||||
+ my $extend_count;
|
||||
+ sub Tied_Array_EXTEND_Test::EXTEND {
|
||||
+ $extend_count= $_[1];
|
||||
+ return;
|
||||
+ }
|
||||
+ my @t;
|
||||
+ tie @t, "Tied_Array_EXTEND_Test";
|
||||
+ is($extend_count, undef, "test that EXTEND has not been called prior to initialization");
|
||||
+ $t[0]=3;
|
||||
+ $t[1]=1;
|
||||
+ $t[2]=2;
|
||||
+ is($extend_count, undef, "test that EXTEND has not been called during initialization");
|
||||
+ @t= sort @t;
|
||||
+ is($extend_count, 3, "test that EXTEND was called with an argument of 3 by pp_sort()");
|
||||
+ is("@t","1 2 3","test that sorting the tied array worked even though EXTEND is a no-op");
|
||||
+}
|
||||
+
|
||||
|
||||
# Test optimisations of reversed sorts. As we now guarantee stability by
|
||||
# default, # optimisations which do not provide this are bogus.
|
||||
--
|
||||
2.21.1
|
||||
|
@ -318,6 +318,10 @@ Patch78: perl-5.31.8-perlio.c-make-unix-close-method-call-underlaying-lay
|
||||
# in upstream after 5.31.8
|
||||
Patch79: perl-5.31.8-only-install-ExtUtils-XSSymSet-man-page-on-VMS.patch
|
||||
|
||||
# Fix sorting tied arrays, GH#17496, in upstream after 5.31.8
|
||||
Patch80: perl-5.31.8-perltie.pod-rework-example-code-so-EXTEND-is-a-no-op.patch
|
||||
Patch81: perl-5.31.8-pp_sort.c-fix-fencepost-error-in-call-to-av_extend.patch
|
||||
|
||||
# Link XS modules to libperl.so with EU::CBuilder on Linux, bug #960048
|
||||
Patch200: perl-5.16.3-Link-XS-modules-to-libperl.so-with-EU-CBuilder-on-Li.patch
|
||||
|
||||
@ -4383,6 +4387,8 @@ you're not running VMS, this module does nothing.
|
||||
%patch77 -p1
|
||||
%patch78 -p1
|
||||
%patch79 -p1
|
||||
%patch80 -p1
|
||||
%patch81 -p1
|
||||
%patch200 -p1
|
||||
%patch201 -p1
|
||||
|
||||
@ -4455,6 +4461,8 @@ perl -x patchlevel.h \
|
||||
'Fedora Patch77: Fix thread-safety of IO::Handle (GH#14816)' \
|
||||
'Fedora Patch78: Close :unix PerlIO layers properly' \
|
||||
'Fedora Patch79: Only install ExtUtils::XSSymSet manual page on VMS (GH#17424)' \
|
||||
'Fedora Patch80: Fix sorting tied arrays (GH#17496)' \
|
||||
'Fedora Patch81: Fix sorting tied arrays (GH#17496)' \
|
||||
'Fedora Patch200: Link XS modules to libperl.so with EU::CBuilder on Linux' \
|
||||
'Fedora Patch201: Link XS modules to libperl.so with EU::MM on Linux' \
|
||||
%{nil}
|
||||
@ -7216,6 +7224,7 @@ popd
|
||||
- Prevent from an integer overflow in POSIX::SigSet()
|
||||
- Fix thread-safety of IO::Handle (GH#14816)
|
||||
- Close :unix PerlIO layers properly
|
||||
- Fix sorting tied arrays (GH#17496)
|
||||
|
||||
* Mon Mar 16 2020 Jitka Plesnikova <jplesnik@redhat.com> - 4:5.30.2-452
|
||||
- 5.30.2 bump (see <https://metacpan.org/pod/release/SHAY/perl-5.30.2/pod/perldelta.pod>
|
||||
|
Loading…
Reference in New Issue
Block a user