This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
s/re/rx/ in an assert overlooked during recent renovations
[perl5.git] / pp_sort.c
index 7c8ab2f..582b811 100644 (file)
--- a/pp_sort.c
+++ b/pp_sort.c
@@ -1,7 +1,7 @@
 /*    pp_sort.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, 2005, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
 #define sv_cmp_static Perl_sv_cmp
 #define sv_cmp_locale_static Perl_sv_cmp_locale
 
-#define dSORTHINTS   SV *hintsv = GvSV(gv_fetchpv("sort::hints", GV_ADDMULTI, SVt_IV))
-#define SORTHINTS    (SvIOK(hintsv) ? ((I32)SvIV(hintsv)) : 0)
-
 #ifndef SMALLSORT
 #define        SMALLSORT (200)
 #endif
 
+/* Flags for qsortsv and mergesortsv */
+#define SORTf_DESC   1
+#define SORTf_STABLE 2
+#define SORTf_QSORT  4
+
 /*
  * The mergesort implementation is by Peter M. Mcilroy <pmcilroy@lucent.com>.
  *
@@ -178,12 +180,11 @@ typedef SV * gptr;                /* pointers in our lists */
 
 
 static IV
-dynprep(pTHX_ gptr *list1, gptr *list2, size_t nmemb, SVCOMPARE_t cmp)
+dynprep(pTHX_ gptr *list1, gptr *list2, size_t nmemb, const SVCOMPARE_t cmp)
 {
     I32 sense;
     register gptr *b, *p, *q, *t, *p2;
-    register gptr c, *last, *r;
-    gptr *savep;
+    register gptr *last, *r;
     IV runs = 0;
 
     b = list1;
@@ -215,7 +216,8 @@ dynprep(pTHX_ gptr *list1, gptr *list2, size_t nmemb, SVCOMPARE_t cmp)
                }
            }
            if (q > b) {                /* run of greater than 2 at b */
-               savep = p;
+               gptr *savep = p;
+
                p = q += 2;
                /* pick up singleton, if possible */
                if ((p == t) &&
@@ -223,17 +225,18 @@ dynprep(pTHX_ gptr *list1, gptr *list2, size_t nmemb, SVCOMPARE_t cmp)
                    ((cmp(aTHX_ *(p-1), *p) > 0) == sense))
                    savep = r = p = q = last;
                p2 = NEXT(p2) = p2 + (p - b); ++runs;
-               if (sense) while (b < --p) {
-                   c = *b;
-                   *b++ = *p;
-                   *p = c;
-               }
+               if (sense)
+                   while (b < --p) {
+                       const gptr c = *b;
+                       *b++ = *p;
+                       *p = c;
+                   }
                p = savep;
            }
            while (q < p) {             /* simple pairs */
                p2 = NEXT(p2) = p2 + 2; ++runs;
                if (sense) {
-                   c = *q++;
+                   const gptr c = *q++;
                    *(q-1) = *q;
                    *q++ = c;
                } else q += 2;
@@ -339,12 +342,14 @@ typedef struct {
 static I32
 cmp_desc(pTHX_ gptr a, gptr b)
 {
+    dVAR;
     return -PL_sort_RealCmp(aTHX_ a, b);
 }
 
 STATIC void
 S_mergesortsv(pTHX_ gptr *base, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
 {
+    dVAR;
     IV i, run, offset;
     I32 sense, level;
     register gptr *f1, *f2, *t, *b, *p;
@@ -354,11 +359,11 @@ S_mergesortsv(pTHX_ gptr *base, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
     gptr small[SMALLSORT];
     gptr *which[3];
     off_runs stack[60], *stackp;
-    SVCOMPARE_t savecmp = 0;
+    SVCOMPARE_t savecmp = NULL;
 
     if (nmemb <= 1) return;                    /* sorted trivially */
 
-    if (flags) {
+    if ((flags & SORTf_DESC) != 0) {
        savecmp = PL_sort_RealCmp;      /* Save current comparison routine, if any */
        PL_sort_RealCmp = cmp;  /* Put comparison routine where cmp_desc can find it */
        cmp = cmp_desc;
@@ -1312,6 +1317,7 @@ S_qsortsvu(pTHX_ SV ** array, size_t num_elts, SVCOMPARE_t compare)
 static I32
 cmpindir(pTHX_ gptr a, gptr b)
 {
+    dVAR;
     gptr * const ap = (gptr *)a;
     gptr * const bp = (gptr *)b;
     const I32 sense = PL_sort_RealCmp(aTHX_ *ap, *bp);
@@ -1324,6 +1330,7 @@ cmpindir(pTHX_ gptr a, gptr b)
 static I32
 cmpindir_desc(pTHX_ gptr a, gptr b)
 {
+    dVAR;
     gptr * const ap = (gptr *)a;
     gptr * const bp = (gptr *)b;
     const I32 sense = PL_sort_RealCmp(aTHX_ *ap, *bp);
@@ -1339,10 +1346,8 @@ cmpindir_desc(pTHX_ gptr a, gptr b)
 STATIC void
 S_qsortsv(pTHX_ gptr *list1, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
 {
-
-    dSORTHINTS;
-
-    if (SORTHINTS & HINT_SORT_STABLE) {
+    dVAR;
+    if ((flags & SORTf_STABLE) != 0) {
         register gptr **pp, *q;
         register size_t n, j, i;
         gptr *small[SMALLSORT], **indir, tmp;
@@ -1360,8 +1365,10 @@ S_qsortsv(pTHX_ gptr *list1, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
         PL_sort_RealCmp = cmp; /* Put comparison routine where cmpindir can find it */
 
         /* sort, with indirection */
-        S_qsortsvu(aTHX_ (gptr *)indir, nmemb,
-                   flags ? cmpindir_desc : cmpindir);
+        if (flags & SORTf_DESC)
+           qsortsvu((gptr *)indir, nmemb, cmpindir_desc);
+       else
+           qsortsvu((gptr *)indir, nmemb, cmpindir);
 
         pp = indir;
         q = list1;
@@ -1404,15 +1411,15 @@ S_qsortsv(pTHX_ gptr *list1, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
         if (indir != small) { Safefree(indir); }
         /* restore prevailing comparison routine */
         PL_sort_RealCmp = savecmp;
-    } else if (flags) {
-        SVCOMPARE_t savecmp = PL_sort_RealCmp; /* Save current comparison routine, if any */
+    } else if ((flags & SORTf_DESC) != 0) {
+        const SVCOMPARE_t savecmp = PL_sort_RealCmp;   /* Save current comparison routine, if any */
         PL_sort_RealCmp = cmp; /* Put comparison routine where cmp_desc can find it */
         cmp = cmp_desc;
-        S_qsortsvu(aTHX_ list1, nmemb, cmp);
+        qsortsvu(list1, nmemb, cmp);
         /* restore prevailing comparison routine */
         PL_sort_RealCmp = savecmp;
     } else {
-        S_qsortsvu(aTHX_ list1, nmemb, cmp);
+        qsortsvu(list1, nmemb, cmp);
     }
 }
 
@@ -1425,7 +1432,8 @@ Sort an array. Here is an example:
 
     sortsv(AvARRAY(av), av_len(av)+1, Perl_sv_cmp_locale);
 
-See lib/sort.pm for details about controlling the sorting algorithm.
+Currently this always uses mergesort. See sortsv_flags for a more
+flexible routine.
 
 =cut
 */
@@ -1433,38 +1441,23 @@ See lib/sort.pm for details about controlling the sorting algorithm.
 void
 Perl_sortsv(pTHX_ SV **array, size_t nmemb, SVCOMPARE_t cmp)
 {
-    void (*sortsvp)(pTHX_ SV **array, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
-      = S_mergesortsv;
-    dSORTHINTS;
-    const I32 hints = SORTHINTS;
-    if (hints & HINT_SORT_QUICKSORT) {
-       sortsvp = S_qsortsv;
-    }
-    else {
-       /* The default as of 5.8.0 is mergesort */
-       sortsvp = S_mergesortsv;
-    }
-
-    sortsvp(aTHX_ array, nmemb, cmp, 0);
+    sortsv_flags(array, nmemb, cmp, 0);
 }
 
+/*
+=for apidoc sortsv_flags
 
-static void
-S_sortsv_desc(pTHX_ SV **array, size_t nmemb, SVCOMPARE_t cmp)
-{
-    void (*sortsvp)(pTHX_ SV **array, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
-      = S_mergesortsv;
-    dSORTHINTS;
-    const I32 hints = SORTHINTS;
-    if (hints & HINT_SORT_QUICKSORT) {
-       sortsvp = S_qsortsv;
-    }
-    else {
-       /* The default as of 5.8.0 is mergesort */
-       sortsvp = S_mergesortsv;
-    }
+Sort an array, with various options.
 
-    sortsvp(aTHX_ array, nmemb, cmp, 1);
+=cut
+*/
+void
+Perl_sortsv_flags(pTHX_ SV **array, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
+{
+    if (flags & SORTf_QSORT)
+       S_qsortsv(aTHX_ array, nmemb, cmp, flags);
+    else
+       S_mergesortsv(aTHX_ array, nmemb, cmp, flags);
 }
 
 #define SvNSIOK(sv) ((SvFLAGS(sv) & SVf_NOK) || ((SvFLAGS(sv) & (SVf_IOK|SVf_IVisUV)) == SVf_IOK))
@@ -1476,10 +1469,10 @@ PP(pp_sort)
     dVAR; dSP; dMARK; dORIGMARK;
     register SV **p1 = ORIGMARK+1, **p2;
     register I32 max, i;
-    AV* av = Nullav;
+    AV* av = NULL;
     HV *stash;
     GV *gv;
-    CV *cv = 0;
+    CV *cv = NULL;
     I32 gimme = GIMME;
     OP* const nextop = PL_op->op_next;
     I32 overloading = 0;
@@ -1488,10 +1481,18 @@ PP(pp_sort)
     I32 sorting_av = 0;
     const U8 priv = PL_op->op_private;
     const U8 flags = PL_op->op_flags;
-    void (*sortsvp)(pTHX_ SV **array, size_t nmemb, SVCOMPARE_t cmp)
-      = Perl_sortsv;
+    U32 sort_flags = 0;
+    void (*sortsvp)(pTHX_ SV **array, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
+      = Perl_sortsv_flags;
     I32 all_SIVs = 1;
 
+    if ((priv & OPpSORT_DESCEND) != 0)
+       sort_flags |= SORTf_DESC;
+    if ((priv & OPpSORT_QSORT) != 0)
+       sort_flags |= SORTf_QSORT;
+    if ((priv & OPpSORT_STABLE) != 0)
+       sort_flags |= SORTf_STABLE;
+
     if (gimme != G_ARRAY) {
        SP = MARK;
        EXTEND(SP,1);
@@ -1517,14 +1518,14 @@ PP(pp_sort)
                }
            }
            if (!(cv && CvROOT(cv))) {
-               if (cv && CvXSUB(cv)) {
+               if (cv && CvISXSUB(cv)) {
                    is_xsub = 1;
                }
                else if (gv) {
                    SV *tmpstr = sv_newmortal();
-                   gv_efullname3(tmpstr, gv, Nullch);
+                   gv_efullname3(tmpstr, gv, NULL);
                    DIE(aTHX_ "Undefined sort subroutine \"%"SVf"\" called",
-                       tmpstr);
+                       SVfARG(tmpstr));
                }
                else {
                    DIE(aTHX_ "Undefined subroutine in sort");
@@ -1538,7 +1539,7 @@ PP(pp_sort)
        }
     }
     else {
-       PL_sortcop = Nullop;
+       PL_sortcop = NULL;
        stash = CopSTASH(PL_curcop);
     }
 
@@ -1555,7 +1556,7 @@ PP(pp_sort)
            p2 = SP;
            for (i=0; i < max; i++) {
                SV **svp = av_fetch(av, i, FALSE);
-               *SP++ = (svp) ? *svp : Nullsv;
+               *SP++ = (svp) ? *svp : NULL;
            }
        }
        else {
@@ -1572,10 +1573,6 @@ PP(pp_sort)
        max = SP - MARK;
    }
 
-    if (priv & OPpSORT_DESCEND) {
-       sortsvp = S_sortsv_desc;
-    }
-
     /* shuffle stack down, removing optional initial cv (p1!=p2), plus
      * any nulls; also stringify or converting to integer or number as
      * required any args */
@@ -1637,8 +1634,8 @@ PP(pp_sort)
                SAVESPTR(PL_firstgv);
                SAVESPTR(PL_secondgv);
                SAVESPTR(PL_sortstash);
-               PL_firstgv = gv_fetchpv("a", TRUE, SVt_PV);
-               PL_secondgv = gv_fetchpv("b", TRUE, SVt_PV);
+               PL_firstgv = gv_fetchpvs("a", GV_ADD|GV_NOTQUAL, SVt_PV);
+               PL_secondgv = gv_fetchpvs("b", GV_ADD|GV_NOTQUAL, SVt_PV);
                PL_sortstash = stash;
                SAVESPTR(GvSV(PL_firstgv));
                SAVESPTR(GvSV(PL_secondgv));
@@ -1661,10 +1658,10 @@ PP(pp_sort)
 
                    if (hasargs) {
                        /* This is mostly copied from pp_entersub */
-                       AV *av = (AV*)PAD_SVl(0);
+                       AV * const av = (AV*)PAD_SVl(0);
 
                        cx->blk_sub.savearray = GvAV(PL_defgv);
-                       GvAV(PL_defgv) = (AV*)SvREFCNT_inc(av);
+                       GvAV(PL_defgv) = (AV*)SvREFCNT_inc_simple(av);
                        CX_CURPAD_SAVE(cx->blk_sub);
                        cx->blk_sub.argarray = av;
                    }
@@ -1675,7 +1672,8 @@ PP(pp_sort)
            
            start = p1 - max;
            sortsvp(aTHX_ start, max,
-                   is_xsub ? S_sortcv_xsub : hasargs ? S_sortcv_stacked : S_sortcv);
+                   (is_xsub ? S_sortcv_xsub : hasargs ? S_sortcv_stacked : S_sortcv),
+                   sort_flags);
 
            if (!(flags & OPf_SPECIAL)) {
                LEAVESUB(cv);
@@ -1697,11 +1695,12 @@ PP(pp_sort)
                            : ( overloading ? S_amagic_ncmp : S_sv_ncmp ) )
                        : ( IN_LOCALE_RUNTIME
                            ? ( overloading
-                               ? S_amagic_cmp_locale
-                               : sv_cmp_locale_static)
-                           : ( overloading ? S_amagic_cmp : sv_cmp_static)));
+                               ? (SVCOMPARE_t)S_amagic_cmp_locale
+                               : (SVCOMPARE_t)sv_cmp_locale_static)
+                           : ( overloading ? (SVCOMPARE_t)S_amagic_cmp : (SVCOMPARE_t)sv_cmp_static)),
+                   sort_flags);
        }
-       if (priv & OPpSORT_REVERSE) {
+       if ((priv & OPpSORT_REVERSE) != 0) {
            SV **q = start+max-1;
            while (start < q) {
                SV * const tmp = *start;
@@ -1771,12 +1770,12 @@ S_sortcv_stacked(pTHX_ SV *a, SV *b)
        SV** ary = AvALLOC(av);
        if (AvARRAY(av) != ary) {
            AvMAX(av) += AvARRAY(av) - AvALLOC(av);
-           SvPV_set(av, (char*)ary);
+           AvARRAY(av) = ary;
        }
        if (AvMAX(av) < 1) {
            AvMAX(av) = 1;
            Renew(ary,2,SV*);
-           SvPV_set(av, (char*)ary);
+           AvARRAY(av) = ary;
        }
     }
     AvFILLp(av) = 1;
@@ -1846,24 +1845,23 @@ S_sv_i_ncmp(pTHX_ SV *a, SV *b)
 #define tryCALL_AMAGICbin(left,right,meth) \
     (PL_amagic_generation && (SvAMAGIC(left)||SvAMAGIC(right))) \
        ? amagic_call(left, right, CAT2(meth,_amg), 0) \
-       : Nullsv;
+       : NULL;
+
+#define SORT_NORMAL_RETURN_VALUE(val)  (((val) > 0) ? 1 : ((val) ? -1 : 0))
 
 static I32
 S_amagic_ncmp(pTHX_ register SV *a, register SV *b)
 {
+    dVAR;
     SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp);
     if (tmpsv) {
         if (SvIOK(tmpsv)) {
             const I32 i = SvIVX(tmpsv);
-            if (i > 0)
-               return 1;
-            return i? -1 : 0;
+            return SORT_NORMAL_RETURN_VALUE(i);
         }
        else {
            const NV d = SvNV(tmpsv);
-           if (d > 0)
-              return 1;
-           return d ? -1 : 0;
+           return SORT_NORMAL_RETURN_VALUE(d);
        }
      }
      return S_sv_ncmp(aTHX_ a, b);
@@ -1872,19 +1870,16 @@ S_amagic_ncmp(pTHX_ register SV *a, register SV *b)
 static I32
 S_amagic_i_ncmp(pTHX_ register SV *a, register SV *b)
 {
+    dVAR;
     SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp);
     if (tmpsv) {
         if (SvIOK(tmpsv)) {
             const I32 i = SvIVX(tmpsv);
-            if (i > 0)
-               return 1;
-            return i? -1 : 0;
+            return SORT_NORMAL_RETURN_VALUE(i);
         }
        else {
            const NV d = SvNV(tmpsv);
-           if (d > 0)
-              return 1;
-           return d ? -1 : 0;
+           return SORT_NORMAL_RETURN_VALUE(d);
        }
     }
     return S_sv_i_ncmp(aTHX_ a, b);
@@ -1893,19 +1888,16 @@ S_amagic_i_ncmp(pTHX_ register SV *a, register SV *b)
 static I32
 S_amagic_cmp(pTHX_ register SV *str1, register SV *str2)
 {
+    dVAR;
     SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp);
     if (tmpsv) {
         if (SvIOK(tmpsv)) {
             const I32 i = SvIVX(tmpsv);
-            if (i > 0)
-               return 1;
-            return i? -1 : 0;
+            return SORT_NORMAL_RETURN_VALUE(i);
         }
        else {
            const NV d = SvNV(tmpsv);
-           if (d > 0)
-              return 1;
-           return d? -1 : 0;
+           return SORT_NORMAL_RETURN_VALUE(d);
        }
     }
     return sv_cmp(str1, str2);
@@ -1914,19 +1906,16 @@ S_amagic_cmp(pTHX_ register SV *str1, register SV *str2)
 static I32
 S_amagic_cmp_locale(pTHX_ register SV *str1, register SV *str2)
 {
+    dVAR;
     SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp);
     if (tmpsv) {
         if (SvIOK(tmpsv)) {
             const I32 i = SvIVX(tmpsv);
-            if (i > 0)
-               return 1;
-            return i? -1 : 0;
+            return SORT_NORMAL_RETURN_VALUE(i);
         }
        else {
            const NV d = SvNV(tmpsv);
-           if (d > 0)
-              return 1;
-           return d? -1 : 0;
+           return SORT_NORMAL_RETURN_VALUE(d);
        }
     }
     return sv_cmp_locale(str1, str2);