This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgrade Scalar-List-Utils from 1.29 to 1.30
authorSteve Hay <steve.m.hay@googlemail.com>
Mon, 5 Aug 2013 17:06:23 +0000 (18:06 +0100)
committerSteve Hay <steve.m.hay@googlemail.com>
Mon, 5 Aug 2013 17:06:47 +0000 (18:06 +0100)
Porting/Maintainers.pl
cpan/List-Util/Changes
cpan/List-Util/ListUtil.xs
cpan/List-Util/lib/List/Util.pm
cpan/List-Util/lib/List/Util/XS.pm
cpan/List-Util/lib/Scalar/Util.pm
cpan/List-Util/t/pair.t
pod/perldelta.pod

index d9191ce..dffe263 100755 (executable)
@@ -1539,7 +1539,7 @@ use File::Glob qw(:case);
 
     'Scalar-List-Utils' => {
         'MAINTAINER'   => 'gbarr',
-        'DISTRIBUTION' => 'PEVANS/Scalar-List-Utils-1.29.tar.gz',
+        'DISTRIBUTION' => 'PEVANS/Scalar-List-Utils-1.30.tar.gz',
 
         # Note that perl uses its own version of Makefile.PL
         'FILES'    => q[cpan/List-Util],
index 032b4ef..8de21e2 100644 (file)
@@ -1,3 +1,10 @@
+1.30 -- Mon Aug 05 13:09 UTC 2012
+
+  * Added pairfirst
+  * Added MULTICALL implementations to pairmap/pairgrep/pairfirst
+  * Fix declaration-after-code for C99-challenged compilers
+  * Documentation updates to List::Util
+
 1.29 -- Thu Aug 01 13:40 UTC 2013
 
   * Bugfix to pairmap/pairgrep when stack moves beneath them during operation
index d2f2f11..83cf82a 100644 (file)
@@ -339,6 +339,83 @@ CODE:
     XSRETURN_UNDEF;
 }
 
+#endif
+
+void
+pairfirst(block,...)
+    SV * block
+PROTOTYPE: &@
+PPCODE:
+{
+    GV *agv,*bgv,*gv;
+    HV *stash;
+    CV *cv    = sv_2cv(block, &stash, &gv, 0);
+    I32 ret_gimme = GIMME_V;
+    int argi = 1; // "shift" the block
+
+    agv = gv_fetchpv("a", GV_ADD, SVt_PV);
+    bgv = gv_fetchpv("b", GV_ADD, SVt_PV);
+    SAVESPTR(GvSV(agv));
+    SAVESPTR(GvSV(bgv));
+#ifdef dMULTICALL
+    if(!CvISXSUB(cv)) {
+       // Since MULTICALL is about to move it
+       SV **stack = PL_stack_base + ax;
+
+       dMULTICALL;
+       I32 gimme = G_SCALAR;
+
+       PUSH_MULTICALL(cv);
+       for(; argi < items; argi += 2) {
+           SV *a = GvSV(agv) = stack[argi];
+           SV *b = GvSV(bgv) = argi < items-1 ? stack[argi+1] : &PL_sv_undef;
+
+           MULTICALL;
+
+            if(!SvTRUEx(*PL_stack_sp))
+               continue;
+
+           POP_MULTICALL;
+           if(ret_gimme == G_ARRAY) {
+               ST(0) = sv_mortalcopy(a);
+               ST(1) = sv_mortalcopy(b);
+               XSRETURN(2);
+           }
+           else
+               XSRETURN_YES;
+       }
+       POP_MULTICALL;
+       XSRETURN(0);
+    }
+    else
+#endif
+    {
+       for(; argi < items; argi += 2) {
+           dSP;
+           SV *a = GvSV(agv) = ST(argi);
+           SV *b = GvSV(bgv) = argi < items-1 ? ST(argi+1) : &PL_sv_undef;
+
+           PUSHMARK(SP);
+           call_sv((SV*)cv, G_SCALAR);
+
+           SPAGAIN;
+
+            if(!SvTRUEx(*PL_stack_sp))
+               continue;
+
+           if(ret_gimme == G_ARRAY) {
+               ST(0) = sv_mortalcopy(a);
+               ST(1) = sv_mortalcopy(b);
+               XSRETURN(2);
+           }
+           else
+               XSRETURN_YES;
+       }
+    }
+
+    XSRETURN(0);
+}
+
 void
 pairgrep(block,...)
     SV * block
@@ -348,6 +425,7 @@ PPCODE:
     GV *agv,*bgv,*gv;
     HV *stash;
     CV *cv    = sv_2cv(block, &stash, &gv, 0);
+    I32 ret_gimme = GIMME_V;
 
     /* This function never returns more than it consumed in arguments. So we
      * can build the results "live", behind the arguments
@@ -359,7 +437,40 @@ PPCODE:
     bgv = gv_fetchpv("b", GV_ADD, SVt_PV);
     SAVESPTR(GvSV(agv));
     SAVESPTR(GvSV(bgv));
+#ifdef dMULTICALL
+    if(!CvISXSUB(cv)) {
+       // Since MULTICALL is about to move it
+       SV **stack = PL_stack_base + ax;
+       int i;
+
+       dMULTICALL;
+       I32 gimme = G_SCALAR;
+
+       PUSH_MULTICALL(cv);
+       for(; argi < items; argi += 2) {
+           SV *a = GvSV(agv) = stack[argi];
+           SV *b = GvSV(bgv) = argi < items-1 ? stack[argi+1] : &PL_sv_undef;
 
+           MULTICALL;
+
+            if(SvTRUEx(*PL_stack_sp)) {
+               if(ret_gimme == G_ARRAY) {
+                   // We can't mortalise yet or they'd be mortal too early
+                   stack[reti++] = newSVsv(a);
+                   stack[reti++] = newSVsv(b);
+               }
+               else if(ret_gimme == G_SCALAR)
+                   reti++;
+           }
+       }
+       POP_MULTICALL;
+
+       if(ret_gimme == G_ARRAY)
+           for(i = 0; i < reti; i++)
+               sv_2mortal(stack[i]);
+    }
+    else
+#endif
     {
        for(; argi < items; argi += 2) {
            dSP;
@@ -371,20 +482,20 @@ PPCODE:
 
            SPAGAIN;
 
-            if (SvTRUEx(*PL_stack_sp)) {
-               if(GIMME_V == G_ARRAY) {
+            if(SvTRUEx(*PL_stack_sp)) {
+               if(ret_gimme == G_ARRAY) {
                    ST(reti++) = sv_mortalcopy(a);
                    ST(reti++) = sv_mortalcopy(b);
                }
-               else if(GIMME_V == G_SCALAR)
+               else if(ret_gimme == G_SCALAR)
                    reti++;
            }
        }
     }
 
-    if(GIMME_V == G_ARRAY)
+    if(ret_gimme == G_ARRAY)
        XSRETURN(reti);
-    else if(GIMME_V == G_SCALAR) {
+    else if(ret_gimme == G_SCALAR) {
        ST(0) = newSViv(reti);
        XSRETURN(1);
     }
@@ -400,6 +511,7 @@ PPCODE:
     HV *stash;
     CV *cv    = sv_2cv(block, &stash, &gv, 0);
     SV **args_copy = NULL;
+    I32 ret_gimme = GIMME_V;
 
     int argi = 1; // "shift" the block
     int reti = 0;
@@ -408,19 +520,26 @@ PPCODE:
     bgv = gv_fetchpv("b", GV_ADD, SVt_PV);
     SAVESPTR(GvSV(agv));
     SAVESPTR(GvSV(bgv));
+#ifdef dMULTICALL
+    if(!CvISXSUB(cv)) {
+       // Since MULTICALL is about to move it
+       SV **stack = PL_stack_base + ax;
+       I32 ret_gimme = GIMME_V;
+       int i;
 
-    {
+       dMULTICALL;
+       I32 gimme = G_ARRAY;
+
+       PUSH_MULTICALL(cv);
        for(; argi < items; argi += 2) {
-           dSP;
-           SV *a = GvSV(agv) = args_copy ? args_copy[argi] : ST(argi);
+           SV *a = GvSV(agv) = args_copy ? args_copy[argi] : stack[argi];
            SV *b = GvSV(bgv) = argi < items-1 ? 
-               (args_copy ? args_copy[argi+1] : ST(argi+1)) :
+               (args_copy ? args_copy[argi+1] : stack[argi+1]) :
                &PL_sv_undef;
+           int count;
 
-           PUSHMARK(SP);
-           int count = call_sv((SV*)cv, G_ARRAY);
-
-           SPAGAIN;
+           MULTICALL;
+           count = PL_stack_sp - PL_stack_base;
 
            if(count > 2 && !args_copy) {
                /* We can't return more than 2 results for a given input pair
@@ -435,13 +554,49 @@ PPCODE:
                Newx(args_copy, n_args, SV *);
                SAVEFREEPV(args_copy);
 
-               Copy(&ST(argi), args_copy, n_args, SV *);
+               Copy(stack + argi, args_copy, n_args, SV *);
 
                argi = 0;
                items = n_args;
            }
 
+           for(i = 0; i < count; i++)
+               stack[reti++] = newSVsv(PL_stack_sp[i - count + 1]);
+       }
+       POP_MULTICALL;
+
+       if(ret_gimme == G_ARRAY)
+           for(i = 0; i < reti; i++)
+               sv_2mortal(stack[i]);
+    }
+    else
+#endif
+    {
+       for(; argi < items; argi += 2) {
+           dSP;
+           SV *a = GvSV(agv) = args_copy ? args_copy[argi] : ST(argi);
+           SV *b = GvSV(bgv) = argi < items-1 ? 
+               (args_copy ? args_copy[argi+1] : ST(argi+1)) :
+               &PL_sv_undef;
+           int count;
            int i;
+
+           PUSHMARK(SP);
+           count = call_sv((SV*)cv, G_ARRAY);
+
+           SPAGAIN;
+
+           if(count > 2 && !args_copy) {
+               int n_args = items - argi;
+               Newx(args_copy, n_args, SV *);
+               SAVEFREEPV(args_copy);
+
+               Copy(&ST(argi), args_copy, n_args, SV *);
+
+               argi = 0;
+               items = n_args;
+           }
+
            for(i = 0; i < count; i++)
                ST(reti++) = sv_mortalcopy(SP[i - count + 1]);
 
@@ -452,8 +607,6 @@ PPCODE:
     XSRETURN(reti);
 }
 
-#endif
-
 void
 pairs(...)
 PROTOTYPE: @
index 7801f6f..d8a838f 100644 (file)
@@ -12,8 +12,8 @@ use strict;
 require Exporter;
 
 our @ISA        = qw(Exporter);
-our @EXPORT_OK  = qw(first min max minstr maxstr reduce sum sum0 shuffle pairmap pairgrep pairs pairkeys pairvalues);
-our $VERSION    = "1.29";
+our @EXPORT_OK  = qw(first min max minstr maxstr reduce sum sum0 shuffle pairmap pairgrep pairfirst pairs pairkeys pairvalues);
+our $VERSION    = "1.30";
 our $XS_VERSION = $VERSION;
 $VERSION    = eval $VERSION;
 
@@ -45,12 +45,43 @@ expressed would be nice to have in the perl core, but the usage would
 not really be high enough to warrant the use of a keyword, and the size
 so small such that being individual extensions would be wasteful.
 
-By default C<List::Util> does not export any subroutines. The
-subroutines defined are
+By default C<List::Util> does not export any subroutines.
 
-=over 4
+=cut
+
+=head1 LIST-REDUCTION FUNCTIONS
+
+The following set of functions all reduce a list down to a single value.
+
+=cut
+
+=head2 reduce BLOCK LIST
+
+Reduces LIST by calling BLOCK, in a scalar context, multiple times,
+setting C<$a> and C<$b> each time. The first call will be with C<$a>
+and C<$b> set to the first two elements of the list, subsequent
+calls will be done by setting C<$a> to the result of the previous
+call and C<$b> to the next element in the list.
+
+Returns the result of the last call to BLOCK. If LIST is empty then
+C<undef> is returned. If LIST only contains one element then that
+element is returned and BLOCK is not executed.
 
-=item first BLOCK LIST
+    $foo = reduce { $a < $b ? $a : $b } 1..10       # min
+    $foo = reduce { $a lt $b ? $a : $b } 'aa'..'zz' # minstr
+    $foo = reduce { $a + $b } 1 .. 10               # sum
+    $foo = reduce { $a . $b } @bar                  # concat
+
+If your algorithm requires that C<reduce> produce an identity value, then
+make sure that you always pass that identity value as the first argument to prevent
+C<undef> being returned
+
+  $foo = reduce { $a + $b } 0, @values;             # sum with 0 identity value
+
+The remaining list-reduction functions are all specialisations of this
+generic idea.
+
+=head2 first BLOCK LIST
 
 Similar to C<grep> in that it evaluates BLOCK setting C<$_> to each element
 of LIST in turn. C<first> returns the first element where the result from
@@ -68,7 +99,7 @@ This function could be implemented using C<reduce> like this
 for example wanted() could be defined() which would return the first
 defined value in @list
 
-=item max LIST
+=head2 max LIST
 
 Returns the entry in the list with the highest numerical value. If the
 list is empty then C<undef> is returned.
@@ -81,7 +112,7 @@ This function could be implemented using C<reduce> like this
 
     $foo = reduce { $a > $b ? $a : $b } 1..10
 
-=item maxstr LIST
+=head2 maxstr LIST
 
 Similar to C<max>, but treats all the entries in the list as strings
 and returns the highest string as defined by the C<gt> operator.
@@ -95,7 +126,7 @@ This function could be implemented using C<reduce> like this
 
     $foo = reduce { $a gt $b ? $a : $b } 'A'..'Z'
 
-=item min LIST
+=head2 min LIST
 
 Similar to C<max> but returns the entry in the list with the lowest
 numerical value. If the list is empty then C<undef> is returned.
@@ -108,7 +139,7 @@ This function could be implemented using C<reduce> like this
 
     $foo = reduce { $a < $b ? $a : $b } 1..10
 
-=item minstr LIST
+=head2 minstr LIST
 
 Similar to C<min>, but treats all the entries in the list as strings
 and returns the lowest string as defined by the C<lt> operator.
@@ -122,7 +153,38 @@ This function could be implemented using C<reduce> like this
 
     $foo = reduce { $a lt $b ? $a : $b } 'A'..'Z'
 
-=item pairgrep BLOCK KVLIST
+=head2 sum LIST
+
+Returns the sum of all the elements in LIST. If LIST is empty then
+C<undef> is returned.
+
+    $foo = sum 1..10                # 55
+    $foo = sum 3,9,12               # 24
+    $foo = sum @bar, @baz           # whatever
+
+This function could be implemented using C<reduce> like this
+
+    $foo = reduce { $a + $b } 1..10
+
+=head2 sum0 LIST
+
+Similar to C<sum>, except this returns 0 when given an empty list, rather
+than C<undef>.
+
+=cut
+
+=head1 KEY/VALUE PAIR LIST FUNCTIONS
+
+The following set of functions, all inspired by L<List::Pairwise>, consume
+an even-sized list of pairs. The pairs may be key/value associations from a
+hash, or just a list of values. The functions will all preserve the original
+ordering of the pairs, and will not be confused by multiple pairs having the
+same "key" value - nor even do they require that the first of each pair be a
+plain string.
+
+=cut
+
+=head2 pairgrep BLOCK KVLIST
 
 Similar to perl's C<grep> keyword, but interprets the given list as an
 even-sized list of pairs. It invokes the BLOCK multiple times, in scalar
@@ -140,7 +202,25 @@ Similar to C<grep>, C<pairgrep> aliases C<$a> and C<$b> to elements of the
 given list. Any modifications of it by the code block will be visible to
 the caller.
 
-=item pairmap BLOCK KVLIST
+=head2 pairfirst BLOCK KVLIST
+
+Similar to the C<first> function, but interprets the given list as an
+even-sized list of pairs. It invokes the BLOCK multiple times, in scalar
+context, with C<$a> and C<$b> set to successive pairs of values from the
+KVLIST.
+
+Returns the first pair of values from the list for which the BLOCK returned
+true in list context, or an empty list of no such pair was found. In scalar
+context it returns a simple boolean value, rather than either the key or the
+value found.
+
+    ( $key, $value ) = pairfirst { $a =~ m/^[[:upper:]]+$/ } @kvlist
+
+Similar to C<grep>, C<pairfirst> aliases C<$a> and C<$b> to elements of the
+given list. Any modifications of it by the code block will be visible to
+the caller.
+
+=head2 pairmap BLOCK KVLIST
 
 Similar to perl's C<map> keyword, but interprets the given list as an
 even-sized list of pairs. It invokes the BLOCK multiple times, in list
@@ -157,7 +237,7 @@ Similar to C<map>, C<pairmap> aliases C<$a> and C<$b> to elements of the
 given list. Any modifications of it by the code block will be visible to
 the caller.
 
-=item pairs KVLIST
+=head2 pairs KVLIST
 
 A convenient shortcut to operating on even-sized lists of pairs, this
 function returns a list of ARRAY references, each containing two items from
@@ -172,7 +252,7 @@ It is most convenient to use in a C<foreach> loop, for example:
        ...
     }
 
-=item pairkeys KVLIST
+=head2 pairkeys KVLIST
 
 A convenient shortcut to operating on even-sized lists of pairs, this
 function returns a list of the the first values of each of the pairs in
@@ -180,7 +260,7 @@ the given list. It is a more efficient version of
 
     pairmap { $a } KVLIST
 
-=item pairvalues KVLIST
+=head2 pairvalues KVLIST
 
 A convenient shortcut to operating on even-sized lists of pairs, this
 function returns a list of the the second values of each of the pairs in
@@ -188,60 +268,19 @@ the given list. It is a more efficient version of
 
     pairmap { $b } KVLIST
 
-=item reduce BLOCK LIST
-
-Reduces LIST by calling BLOCK, in a scalar context, multiple times,
-setting C<$a> and C<$b> each time. The first call will be with C<$a>
-and C<$b> set to the first two elements of the list, subsequent
-calls will be done by setting C<$a> to the result of the previous
-call and C<$b> to the next element in the list.
-
-Returns the result of the last call to BLOCK. If LIST is empty then
-C<undef> is returned. If LIST only contains one element then that
-element is returned and BLOCK is not executed.
+=cut
 
-    $foo = reduce { $a < $b ? $a : $b } 1..10       # min
-    $foo = reduce { $a lt $b ? $a : $b } 'aa'..'zz' # minstr
-    $foo = reduce { $a + $b } 1 .. 10               # sum
-    $foo = reduce { $a . $b } @bar                  # concat
+=head1 OTHER FUNCTIONS
 
-If your algorithm requires that C<reduce> produce an identity value, then
-make sure that you always pass that identity value as the first argument to prevent
-C<undef> being returned
-
-  $foo = reduce { $a + $b } 0, @values;             # sum with 0 identity value
+=cut
 
-=item shuffle LIST
+=head2 shuffle LIST
 
 Returns the elements of LIST in a random order
 
     @cards = shuffle 0..51      # 0..51 in a random order
 
-=item sum LIST
-
-Returns the sum of all the elements in LIST. If LIST is empty then
-C<undef> is returned.
-
-    $foo = sum 1..10                # 55
-    $foo = sum 3,9,12               # 24
-    $foo = sum @bar, @baz           # whatever
-
-This function could be implemented using C<reduce> like this
-
-    $foo = reduce { $a + $b } 1..10
-
-If your algorithm requires that C<sum> produce an identity of 0, then
-make sure that you always pass C<0> as the first argument to prevent
-C<undef> being returned
-
-  $foo = sum 0, @values;
-
-=item sum0 LIST
-
-Similar to C<sum>, except this returns 0 when given an empty list, rather
-than C<undef>.
-
-=back
+=cut
 
 =head1 KNOWN BUGS
 
@@ -288,4 +327,7 @@ Copyright (c) 1997-2007 Graham Barr <gbarr@pobox.com>. All rights reserved.
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
+Recent additions and current maintenance by
+Paul Evans, <leonerd@leonerd.org.uk>.
+
 =cut
index e2167f8..efd084e 100644 (file)
@@ -2,7 +2,7 @@ package List::Util::XS;
 use strict;
 use List::Util;
 
-our $VERSION = "1.29";       # FIXUP
+our $VERSION = "1.30";       # FIXUP
 $VERSION = eval $VERSION;    # FIXUP
 
 1;
index ddfa0ef..75c03fa 100644 (file)
@@ -26,7 +26,7 @@ our @EXPORT_OK = qw(
   tainted
   weaken
 );
-our $VERSION    = "1.29";
+our $VERSION    = "1.30";
 $VERSION   = eval $VERSION;
 
 our @EXPORT_FAIL;
index f4c4289..59282b1 100644 (file)
@@ -1,8 +1,8 @@
 #!./perl
 
 use strict;
-use Test::More tests => 13;
-use List::Util qw(pairgrep pairmap pairs pairkeys pairvalues);
+use Test::More tests => 17;
+use List::Util qw(pairgrep pairfirst pairmap pairs pairkeys pairvalues);
 
 is_deeply( [ pairgrep { $b % 2 } one => 1, two => 2, three => 3 ],
            [ one => 1, three => 3 ],
@@ -22,6 +22,21 @@ is_deeply( [ pairgrep { $a } 0 => "zero", 1 => "one", 2 ],
   is_deeply( \@kvlist, [ one => 2, two => 3 ], 'pairgrep aliases elements' );
 }
 
+is_deeply( [ pairfirst { length $a == 5 } one => 1, two => 2, three => 3 ],
+           [ three => 3 ],
+           'pairfirst list' );
+
+is_deeply( [ pairfirst { length $a == 4 } one => 1, two => 2, three => 3 ],
+           [],
+           'pairfirst list empty' );
+
+is( scalar( pairfirst { length $a == 5 } one => 1, two => 2, three => 3 ),
+    1,
+    'pairfirst scalar true' );
+
+ok( !scalar( pairfirst { length $a == 4 } one => 1, two => 2, three => 3 ),
+    'pairfirst scalar false' );
+
 is_deeply( [ pairmap { uc $a => $b } one => 1, two => 2, three => 3 ],
            [ ONE => 1, TWO => 2, THREE => 3 ],
            'pairmap list' );
index 940f183..af7ad7d 100644 (file)
@@ -162,10 +162,11 @@ C<Exporter::Heavy>. [perl #39739]
 
 =item *
 
-L<List::Util> has been upgraded from version 1.27 to 1.29
+L<List::Util> has been upgraded from version 1.27 to 1.30
 
-L<List::Util> now includes C<pairgrep>, C<pairmap>, C<pairs>, C<pairkeys>
-and C<pairvalues> functions that operate on even-sized lists of pairs.
+L<List::Util> now includes C<pairgrep>, C<pairmap>, C<pairs>, C<pairkeys>,
+C<pairvalues> and C<pairfirst> functions that operate on even-sized lists of
+pairs.
 
 =item *