X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/551405c409d33bc8cd0a20177c4ee21a204d18b5..895e2c0f6b4f6e66f85fb2df734c74c6d722d2a3:/pp_sort.c?ds=sidebyside diff --git a/pp_sort.c b/pp_sort.c index 3dda7cc..364a6a0 100644 --- 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 + * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + * 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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. @@ -9,8 +9,10 @@ */ /* - * ...they shuffled back towards the rear of the line. 'No, not at the - * rear!' the slave-driver shouted. 'Three files up. And stay there... + * ...they shuffled back towards the rear of the line. 'No, not at the + * rear!' the slave-driver shouted. 'Three files up. And stay there... + * + * [p.931 of _The Lord of the Rings_, VI/ii: "The Land of Shadow"] */ /* This file contains pp ("push/pop") functions that @@ -33,26 +35,18 @@ #define small xsmall #endif -static I32 sortcv(pTHX_ SV *a, SV *b); -static I32 sortcv_stacked(pTHX_ SV *a, SV *b); -static I32 sortcv_xsub(pTHX_ SV *a, SV *b); -static I32 sv_ncmp(pTHX_ SV *a, SV *b); -static I32 sv_i_ncmp(pTHX_ SV *a, SV *b); -static I32 amagic_ncmp(pTHX_ SV *a, SV *b); -static I32 amagic_i_ncmp(pTHX_ SV *a, SV *b); -static I32 amagic_cmp(pTHX_ SV *a, SV *b); -static I32 amagic_cmp_locale(pTHX_ SV *a, SV *b); - #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 . * @@ -111,7 +105,7 @@ typedef SV * gptr; /* pointers in our lists */ #define FROMTOUPTO(src, dst, lim) do *dst++ = *src++; while(src= t) p = r = t; /* too short to care about */ else { while (((cmp(aTHX_ *(p-1), *p) > 0) == sense) && - ((p -= 2) > q)); + ((p -= 2) > q)) {} if (p <= q) { /* b through r is a (long) run. ** Extend it as far as possible. @@ -225,7 +218,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) && @@ -233,17 +227,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; @@ -347,14 +342,16 @@ typedef struct { static I32 -cmp_desc(pTHX_ gptr a, gptr b) +cmp_desc(pTHX_ gptr const a, gptr const 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; @@ -364,18 +361,18 @@ 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; } if (nmemb <= SMALLSORT) aux = small; /* use stack for aux array */ - else { Newx(aux,nmemb,gptr); } /* allocate auxilliary array */ + else { Newx(aux,nmemb,gptr); } /* allocate auxiliary array */ level = 0; stackp = stack; stackp->runs = dynprep(aTHX_ base, aux, nmemb, cmp); @@ -552,7 +549,7 @@ S_mergesortsv(pTHX_ gptr *base, size_t nmemb, SVCOMPARE_t cmp, U32 flags) t = NEXT(t); /* where second run will end */ t = PINDEX(base, PNELEM(aux, t)); /* where it now ends */ FROMTOUPTO(f1, f2, t); /* copy both runs */ - NEXT(b) = p; /* paralled pointer for 1st */ + NEXT(b) = p; /* paralleled pointer for 1st */ NEXT(p) = t; /* ... and for second */ } } @@ -767,10 +764,8 @@ STATIC void /* the standard unstable (u) quicksort (qsort) */ S_qsortsvu(pTHX_ SV ** array, size_t num_elts, SVCOMPARE_t compare) { register SV * temp; - struct partition_stack_entry partition_stack[QSORT_MAX_STACK]; int next_stack_entry = 0; - int part_left; int part_right; #ifdef QSORT_ORDER_GUESS @@ -778,13 +773,15 @@ S_qsortsvu(pTHX_ SV ** array, size_t num_elts, SVCOMPARE_t compare) int swapped; #endif + PERL_ARGS_ASSERT_QSORTSVU; + /* Make sure we actually have work to do. */ if (num_elts <= 1) { return; } - /* Innoculate large partitions against quadratic behavior */ + /* Inoculate large partitions against quadratic behavior */ if (num_elts > QSORT_PLAY_SAFE) { register size_t n; register SV ** const q = array; @@ -1294,7 +1291,7 @@ S_qsortsvu(pTHX_ SV ** array, size_t num_elts, SVCOMPARE_t compare) * by the original comparison routine on the elements pointed to. * Because we don't move the elements of list1 around through * this phase, we can break ties on elements that compare equal - * using their address in the list1 array, ensuring stabilty. + * using their address in the list1 array, ensuring stability. * This leaves us with something looking like * * indir list1 @@ -1320,26 +1317,28 @@ S_qsortsvu(pTHX_ SV ** array, size_t num_elts, SVCOMPARE_t compare) static I32 -cmpindir(pTHX_ gptr a, gptr b) +cmpindir(pTHX_ gptr const a, gptr const b) { - I32 sense; + dVAR; gptr * const ap = (gptr *)a; gptr * const bp = (gptr *)b; + const I32 sense = PL_sort_RealCmp(aTHX_ *ap, *bp); - if ((sense = PL_sort_RealCmp(aTHX_ *ap, *bp)) == 0) - sense = (ap > bp) ? 1 : ((ap < bp) ? -1 : 0); - return sense; + if (sense) + return sense; + return (ap > bp) ? 1 : ((ap < bp) ? -1 : 0); } static I32 -cmpindir_desc(pTHX_ gptr a, gptr b) +cmpindir_desc(pTHX_ gptr const a, gptr const b) { - I32 sense; + dVAR; gptr * const ap = (gptr *)a; gptr * const bp = (gptr *)b; + const I32 sense = PL_sort_RealCmp(aTHX_ *ap, *bp); /* Reverse the default */ - if ((sense = PL_sort_RealCmp(aTHX_ *ap, *bp))) + if (sense) return -sense; /* But don't reverse the stability test. */ return (ap > bp) ? 1 : ((ap < bp) ? -1 : 0); @@ -1349,10 +1348,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; @@ -1370,14 +1367,16 @@ 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; for (n = nmemb; n--; ) { /* Assert A: all elements of q with index > n are already - * in place. This is vacuosly true at the start, and we + * in place. This is vacuously true at the start, and we * put element n where it belongs below (if it wasn't * already where it belonged). Assert B: we only move * elements that aren't where they belong, @@ -1414,15 +1413,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); } } @@ -1435,7 +1434,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 */ @@ -1443,38 +1443,27 @@ 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; - } + PERL_ARGS_ASSERT_SORTSV; - 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) +Sort an array, with various options. + +=cut +*/ +void +Perl_sortsv_flags(pTHX_ SV **array, size_t nmemb, SVCOMPARE_t cmp, U32 flags) { - 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; - } + PERL_ARGS_ASSERT_SORTSV_FLAGS; - sortsvp(aTHX_ array, nmemb, cmp, 1); + 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)) @@ -1486,24 +1475,33 @@ 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* nextop = PL_op->op_next; + OP* const nextop = PL_op->op_next; I32 overloading = 0; bool hasargs = FALSE; I32 is_xsub = 0; 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); RETPUSHUNDEF; } @@ -1518,22 +1516,40 @@ PP(pp_sort) stash = CopSTASH(PL_curcop); } else { - cv = sv_2cv(*++MARK, &stash, &gv, 0); + GV *autogv = NULL; + cv = sv_2cv(*++MARK, &stash, &gv, GV_ADD); + check_cv: if (cv && SvPOK(cv)) { - const char *proto = SvPV_nolen_const((SV*)cv); + const char * const proto = SvPV_nolen_const(MUTABLE_SV(cv)); if (proto && strEQ(proto, "$$")) { hasargs = TRUE; } } - if (!(cv && CvROOT(cv))) { - if (cv && CvXSUB(cv)) { - is_xsub = 1; + if (cv && CvISXSUB(cv) && CvXSUB(cv)) { + is_xsub = 1; + } + else if (!(cv && CvROOT(cv))) { + if (gv) { + goto autoload; } - else if (gv) { + else if (!CvANON(cv) && (gv = CvGV(cv))) { + if (cv != GvCV(gv)) cv = GvCV(gv); + autoload: + if (!autogv && ( + autogv = gv_autoload_pvn( + GvSTASH(gv), GvNAME(gv), GvNAMELEN(gv), + GvNAMEUTF8(gv) ? SVf_UTF8 : 0 + ) + )) { + cv = GvCVu(autogv); + goto check_cv; + } + else { 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"); @@ -1542,18 +1558,12 @@ PP(pp_sort) if (is_xsub) PL_sortcop = (OP*)cv; - else { + else PL_sortcop = CvSTART(cv); - SAVEVPTR(CvROOT(cv)->op_ppaddr); - CvROOT(cv)->op_ppaddr = PL_ppaddr[OP_NULL]; - - SAVECOMPPAD(); - PAD_SET_CUR_NOSAVE(CvPADLIST(cv), 1); - } } } else { - PL_sortcop = Nullop; + PL_sortcop = NULL; stash = CopSTASH(PL_curcop); } @@ -1563,17 +1573,22 @@ PP(pp_sort) if (priv & OPpSORT_INPLACE) { assert( MARK+1 == SP && *SP && SvTYPE(*SP) == SVt_PVAV); (void)POPMARK; /* remove mark associated with ex-OP_AASSIGN */ - av = (AV*)(*SP); + av = MUTABLE_AV((*SP)); max = AvFILL(av) + 1; if (SvMAGICAL(av)) { MEXTEND(SP, max); - p2 = SP; for (i=0; i < max; i++) { SV **svp = av_fetch(av, i, FALSE); - *SP++ = (svp) ? *svp : Nullsv; + *SP++ = (svp) ? *svp : NULL; } + SP--; + p1 = p2 = SP - (max-1); } else { + if (SvREADONLY(av)) + Perl_croak_no_modify(aTHX); + else + SvREADONLY_on(av); p1 = p2 = AvARRAY(av); sorting_av = 1; } @@ -1583,10 +1598,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 */ @@ -1596,33 +1607,23 @@ PP(pp_sort) if (!PL_sortcop) { if (priv & OPpSORT_NUMERIC) { if (priv & OPpSORT_INTEGER) { - if (!SvIOK(*p1)) { - if (SvAMAGIC(*p1)) - overloading = 1; - else - (void)sv_2iv(*p1); - } + if (!SvIOK(*p1)) + (void)sv_2iv_flags(*p1, SV_GMAGIC|SV_SKIP_OVERLOAD); } else { - if (!SvNSIOK(*p1)) { - if (SvAMAGIC(*p1)) - overloading = 1; - else - (void)sv_2nv(*p1); - } + if (!SvNSIOK(*p1)) + (void)sv_2nv_flags(*p1, SV_GMAGIC|SV_SKIP_OVERLOAD); if (all_SIVs && !SvSIOK(*p1)) all_SIVs = 0; } } else { - if (!SvPOK(*p1)) { - if (SvAMAGIC(*p1)) - overloading = 1; - else - (void)sv_2pv_flags(*p1, 0, - SV_GMAGIC|SV_CONST_RETURN); - } + if (!SvPOK(*p1)) + (void)sv_2pv_flags(*p1, 0, + SV_GMAGIC|SV_CONST_RETURN|SV_SKIP_OVERLOAD); } + if (SvAMAGIC(*p1)) + overloading = 1; } p1++; } @@ -1645,13 +1646,12 @@ PP(pp_sort) CATCH_SET(TRUE); PUSHSTACKi(PERLSI_SORT); if (!hasargs && !is_xsub) { - if (PL_sortstash != stash || !PL_firstgv || !PL_secondgv) { - SAVESPTR(PL_firstgv); - SAVESPTR(PL_secondgv); - PL_firstgv = gv_fetchpv("a", TRUE, SVt_PV); - PL_secondgv = gv_fetchpv("b", TRUE, SVt_PV); - PL_sortstash = stash; - } + SAVESPTR(PL_firstgv); + SAVESPTR(PL_secondgv); + SAVESPTR(PL_sortstash); + 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)); } @@ -1660,24 +1660,49 @@ PP(pp_sort) if (!(flags & OPf_SPECIAL)) { cx->cx_type = CXt_SUB; cx->blk_gimme = G_SCALAR; + /* If our comparison routine is already active (CvDEPTH is + * is not 0), then PUSHSUB does not increase the refcount, + * so we have to do it ourselves, because the LEAVESUB fur- + * ther down lowers it. */ + if (CvDEPTH(cv)) SvREFCNT_inc_simple_void_NN(cv); PUSHSUB(cx); - } - PL_sortcxix = cxstack_ix; + if (!is_xsub) { + AV* const padlist = CvPADLIST(cv); - if (hasargs && !is_xsub) { - /* This is mostly copied from pp_entersub */ - AV *av = (AV*)PAD_SVl(0); + if (++CvDEPTH(cv) >= 2) { + PERL_STACK_OVERFLOW_CHECK(); + pad_push(padlist, CvDEPTH(cv)); + } + SAVECOMPPAD(); + PAD_SET_CUR_NOSAVE(padlist, CvDEPTH(cv)); + + if (hasargs) { + /* This is mostly copied from pp_entersub */ + AV * const av = MUTABLE_AV(PAD_SVl(0)); - cx->blk_sub.savearray = GvAV(PL_defgv); - GvAV(PL_defgv) = (AV*)SvREFCNT_inc(av); - CX_CURPAD_SAVE(cx->blk_sub); - cx->blk_sub.argarray = av; + cx->blk_sub.savearray = GvAV(PL_defgv); + GvAV(PL_defgv) = MUTABLE_AV(SvREFCNT_inc_simple(av)); + CX_CURPAD_SAVE(cx->blk_sub); + cx->blk_sub.argarray = av; + } + + } } + cx->cx_type |= CXp_MULTICALL; start = p1 - max; sortsvp(aTHX_ start, max, - is_xsub ? sortcv_xsub : hasargs ? sortcv_stacked : sortcv); + (is_xsub ? S_sortcv_xsub : hasargs ? S_sortcv_stacked : S_sortcv), + sort_flags); + if (!(flags & OPf_SPECIAL)) { + SV *sv; + /* Reset cx, in case the context stack has been + reallocated. */ + cx = &cxstack[cxstack_ix]; + POPSUB(cx, sv); + LEAVESUB(sv); + } POPBLOCK(cx,PL_curpm); PL_stack_sp = newsp; POPSTACK; @@ -1689,26 +1714,29 @@ PP(pp_sort) sortsvp(aTHX_ start, max, (priv & OPpSORT_NUMERIC) ? ( ( ( priv & OPpSORT_INTEGER) || all_SIVs) - ? ( overloading ? amagic_i_ncmp : sv_i_ncmp) - : ( overloading ? amagic_ncmp : sv_ncmp ) ) + ? ( overloading ? S_amagic_i_ncmp : S_sv_i_ncmp) + : ( overloading ? S_amagic_ncmp : S_sv_ncmp ) ) : ( IN_LOCALE_RUNTIME ? ( overloading - ? amagic_cmp_locale - : sv_cmp_locale_static) - : ( overloading ? 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 *tmp = *start; + SV * const tmp = *start; *start++ = *q; *q-- = tmp; } } } - if (av && !sorting_av) { + if (sorting_av) + SvREADONLY_off(av); + else if (av && !sorting_av) { /* simulate pp_aassign of tied AV */ - SV** const base = ORIGMARK+1; + SV** const base = MARK+1; for (i=0; i < max; i++) { base[i] = newSVsv(base[i]); } @@ -1729,48 +1757,72 @@ PP(pp_sort) } static I32 -sortcv(pTHX_ SV *a, SV *b) +S_sortcv(pTHX_ SV *const a, SV *const b) { dVAR; const I32 oldsaveix = PL_savestack_ix; const I32 oldscopeix = PL_scopestack_ix; I32 result; + PMOP * const pm = PL_curpm; + OP * const sortop = PL_op; + COP * const cop = PL_curcop; + SV **pad; + + PERL_ARGS_ASSERT_SORTCV; + GvSV(PL_firstgv) = a; GvSV(PL_secondgv) = b; PL_stack_sp = PL_stack_base; PL_op = PL_sortcop; CALLRUNOPS(aTHX); - if (PL_stack_sp != PL_stack_base + 1) - Perl_croak(aTHX_ "Sort subroutine didn't return single value"); - if (!SvNIOKp(*PL_stack_sp)) - Perl_croak(aTHX_ "Sort subroutine didn't return a numeric value"); - result = SvIV(*PL_stack_sp); + PL_op = sortop; + PL_curcop = cop; + pad = PL_curpad; PL_curpad = 0; + if (PL_stack_sp != PL_stack_base + 1) { + assert(PL_stack_sp == PL_stack_base); + result = SvIV(&PL_sv_undef); + } + else result = SvIV(*PL_stack_sp); + PL_curpad = pad; while (PL_scopestack_ix > oldscopeix) { LEAVE; } leave_scope(oldsaveix); + PL_curpm = pm; return result; } static I32 -sortcv_stacked(pTHX_ SV *a, SV *b) +S_sortcv_stacked(pTHX_ SV *const a, SV *const b) { dVAR; const I32 oldsaveix = PL_savestack_ix; const I32 oldscopeix = PL_scopestack_ix; I32 result; AV * const av = GvAV(PL_defgv); + PMOP * const pm = PL_curpm; + OP * const sortop = PL_op; + COP * const cop = PL_curcop; + SV **pad; + + PERL_ARGS_ASSERT_SORTCV_STACKED; + if (AvREAL(av)) { + av_clear(av); + AvREAL_off(av); + AvREIFY_on(av); + } if (AvMAX(av) < 1) { - SV** ary = AvALLOC(av); + 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; + AvALLOC(av) = ary; } } AvFILLp(av) = 1; @@ -1780,26 +1832,34 @@ sortcv_stacked(pTHX_ SV *a, SV *b) PL_stack_sp = PL_stack_base; PL_op = PL_sortcop; CALLRUNOPS(aTHX); - if (PL_stack_sp != PL_stack_base + 1) - Perl_croak(aTHX_ "Sort subroutine didn't return single value"); - if (!SvNIOKp(*PL_stack_sp)) - Perl_croak(aTHX_ "Sort subroutine didn't return a numeric value"); - result = SvIV(*PL_stack_sp); + PL_op = sortop; + PL_curcop = cop; + pad = PL_curpad; PL_curpad = 0; + if (PL_stack_sp != PL_stack_base + 1) { + assert(PL_stack_sp == PL_stack_base); + result = SvIV(&PL_sv_undef); + } + else result = SvIV(*PL_stack_sp); + PL_curpad = pad; while (PL_scopestack_ix > oldscopeix) { LEAVE; } leave_scope(oldsaveix); + PL_curpm = pm; return result; } static I32 -sortcv_xsub(pTHX_ SV *a, SV *b) +S_sortcv_xsub(pTHX_ SV *const a, SV *const b) { dVAR; dSP; const I32 oldsaveix = PL_savestack_ix; const I32 oldscopeix = PL_scopestack_ix; - CV * const cv=(CV*)PL_sortcop; + CV * const cv=MUTABLE_CV(PL_sortcop); I32 result; + PMOP * const pm = PL_curpm; + + PERL_ARGS_ASSERT_SORTCV_XSUB; SP = PL_stack_base; PUSHMARK(SP); @@ -1810,117 +1870,132 @@ sortcv_xsub(pTHX_ SV *a, SV *b) (void)(*CvXSUB(cv))(aTHX_ cv); if (PL_stack_sp != PL_stack_base + 1) Perl_croak(aTHX_ "Sort subroutine didn't return single value"); - if (!SvNIOKp(*PL_stack_sp)) - Perl_croak(aTHX_ "Sort subroutine didn't return a numeric value"); result = SvIV(*PL_stack_sp); while (PL_scopestack_ix > oldscopeix) { LEAVE; } leave_scope(oldsaveix); + PL_curpm = pm; return result; } static I32 -sv_ncmp(pTHX_ SV *a, SV *b) +S_sv_ncmp(pTHX_ SV *const a, SV *const b) { const NV nv1 = SvNSIV(a); const NV nv2 = SvNSIV(b); + + PERL_ARGS_ASSERT_SV_NCMP; + +#if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan) + if (Perl_isnan(nv1) || Perl_isnan(nv2)) { +#else + if (nv1 != nv1 || nv2 != nv2) { +#endif + if (ckWARN(WARN_UNINITIALIZED)) report_uninit(NULL); + return 0; + } return nv1 < nv2 ? -1 : nv1 > nv2 ? 1 : 0; } static I32 -sv_i_ncmp(pTHX_ SV *a, SV *b) +S_sv_i_ncmp(pTHX_ SV *const a, SV *const b) { const IV iv1 = SvIV(a); const IV iv2 = SvIV(b); + + PERL_ARGS_ASSERT_SV_I_NCMP; + return iv1 < iv2 ? -1 : iv1 > iv2 ? 1 : 0; } #define tryCALL_AMAGICbin(left,right,meth) \ - (PL_amagic_generation && (SvAMAGIC(left)||SvAMAGIC(right))) \ - ? amagic_call(left, right, CAT2(meth,_amg), 0) \ - : Nullsv; + (SvAMAGIC(left)||SvAMAGIC(right)) \ + ? amagic_call(left, right, meth, 0) \ + : NULL; + +#define SORT_NORMAL_RETURN_VALUE(val) (((val) > 0) ? 1 : ((val) ? -1 : 0)) static I32 -amagic_ncmp(pTHX_ register SV *a, register SV *b) +S_amagic_ncmp(pTHX_ register SV *const a, register SV *const b) { - SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp); + dVAR; + SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp_amg); + + PERL_ARGS_ASSERT_AMAGIC_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 sv_ncmp(aTHX_ a, b); + return S_sv_ncmp(aTHX_ a, b); } static I32 -amagic_i_ncmp(pTHX_ register SV *a, register SV *b) +S_amagic_i_ncmp(pTHX_ register SV *const a, register SV *const b) { - SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp); + dVAR; + SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp_amg); + + PERL_ARGS_ASSERT_AMAGIC_I_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 sv_i_ncmp(aTHX_ a, b); + return S_sv_i_ncmp(aTHX_ a, b); } static I32 -amagic_cmp(pTHX_ register SV *str1, register SV *str2) +S_amagic_cmp(pTHX_ register SV *const str1, register SV *const str2) { - SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp); + dVAR; + SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp_amg); + + PERL_ARGS_ASSERT_AMAGIC_CMP; + 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); } static I32 -amagic_cmp_locale(pTHX_ register SV *str1, register SV *str2) +S_amagic_cmp_locale(pTHX_ register SV *const str1, register SV *const str2) { - SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp); + dVAR; + SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp_amg); + + PERL_ARGS_ASSERT_AMAGIC_CMP_LOCALE; + 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);