X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/ea726b52599b52cf534201a46ec3455418c9eb8e..838f2281125c4e0f98e5d741f9058f09c8242d33:/pp_sort.c?ds=sidebyside diff --git a/pp_sort.c b/pp_sort.c index d06a953..364a6a0 100644 --- a/pp_sort.c +++ b/pp_sort.c @@ -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 @@ -103,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. @@ -370,7 +372,7 @@ S_mergesortsv(pTHX_ gptr *base, size_t nmemb, SVCOMPARE_t cmp, U32 flags) } 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); @@ -547,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 */ } } @@ -779,7 +781,7 @@ S_qsortsvu(pTHX_ SV ** array, size_t num_elts, SVCOMPARE_t compare) 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; @@ -1289,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 @@ -1374,7 +1376,7 @@ S_qsortsv(pTHX_ gptr *list1, size_t nmemb, SVCOMPARE_t cmp, U32 flags) 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, @@ -1514,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 * const 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 && CvISXSUB(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, NULL); DIE(aTHX_ "Undefined sort subroutine \"%"SVf"\" called", SVfARG(tmpstr)); + } } else { DIE(aTHX_ "Undefined subroutine in sort"); @@ -1553,7 +1573,7 @@ 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); @@ -1566,7 +1586,7 @@ PP(pp_sort) } else { if (SvREADONLY(av)) - Perl_croak(aTHX_ PL_no_modify); + Perl_croak_no_modify(aTHX); else SvREADONLY_on(av); p1 = p2 = AvARRAY(av); @@ -1587,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++; } @@ -1650,6 +1660,11 @@ 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); if (!is_xsub) { AV* const padlist = CvPADLIST(cv); @@ -1663,10 +1678,10 @@ PP(pp_sort) if (hasargs) { /* This is mostly copied from pp_entersub */ - AV * const av = (AV*)PAD_SVl(0); + AV * const av = MUTABLE_AV(PAD_SVl(0)); cx->blk_sub.savearray = GvAV(PL_defgv); - GvAV(PL_defgv) = (AV*)SvREFCNT_inc_simple(av); + GvAV(PL_defgv) = MUTABLE_AV(SvREFCNT_inc_simple(av)); CX_CURPAD_SAVE(cx->blk_sub); cx->blk_sub.argarray = av; } @@ -1681,9 +1696,12 @@ PP(pp_sort) sort_flags); if (!(flags & OPf_SPECIAL)) { - LEAVESUB(cv); - if (!is_xsub) - CvDEPTH(cv)--; + 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; @@ -1745,6 +1763,10 @@ S_sortcv(pTHX_ SV *const a, SV *const b) 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; @@ -1753,15 +1775,20 @@ S_sortcv(pTHX_ SV *const a, SV *const 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; } @@ -1773,11 +1800,20 @@ S_sortcv_stacked(pTHX_ SV *const a, SV *const b) 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); AvARRAY(av) = ary; @@ -1786,6 +1822,7 @@ S_sortcv_stacked(pTHX_ SV *const a, SV *const b) AvMAX(av) = 1; Renew(ary,2,SV*); AvARRAY(av) = ary; + AvALLOC(av) = ary; } } AvFILLp(av) = 1; @@ -1795,15 +1832,20 @@ S_sortcv_stacked(pTHX_ SV *const a, SV *const 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; } @@ -1815,6 +1857,7 @@ S_sortcv_xsub(pTHX_ SV *const a, SV *const b) const I32 oldscopeix = PL_scopestack_ix; CV * const cv=MUTABLE_CV(PL_sortcop); I32 result; + PMOP * const pm = PL_curpm; PERL_ARGS_ASSERT_SORTCV_XSUB; @@ -1827,13 +1870,12 @@ S_sortcv_xsub(pTHX_ SV *const a, SV *const 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; } @@ -1846,6 +1888,14 @@ S_sv_ncmp(pTHX_ SV *const a, SV *const 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; } @@ -1861,8 +1911,8 @@ S_sv_i_ncmp(pTHX_ SV *const a, SV *const b) } #define tryCALL_AMAGICbin(left,right,meth) \ - (PL_amagic_generation && (SvAMAGIC(left)||SvAMAGIC(right))) \ - ? amagic_call(left, right, CAT2(meth,_amg), 0) \ + (SvAMAGIC(left)||SvAMAGIC(right)) \ + ? amagic_call(left, right, meth, 0) \ : NULL; #define SORT_NORMAL_RETURN_VALUE(val) (((val) > 0) ? 1 : ((val) ? -1 : 0)) @@ -1871,7 +1921,7 @@ static I32 S_amagic_ncmp(pTHX_ register SV *const a, register SV *const b) { dVAR; - SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp); + SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp_amg); PERL_ARGS_ASSERT_AMAGIC_NCMP; @@ -1892,7 +1942,7 @@ static I32 S_amagic_i_ncmp(pTHX_ register SV *const a, register SV *const b) { dVAR; - SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp); + SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp_amg); PERL_ARGS_ASSERT_AMAGIC_I_NCMP; @@ -1913,7 +1963,7 @@ static I32 S_amagic_cmp(pTHX_ register SV *const str1, register SV *const str2) { dVAR; - SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp); + SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp_amg); PERL_ARGS_ASSERT_AMAGIC_CMP; @@ -1934,7 +1984,7 @@ static I32 S_amagic_cmp_locale(pTHX_ register SV *const str1, register SV *const str2) { dVAR; - SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp); + SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp_amg); PERL_ARGS_ASSERT_AMAGIC_CMP_LOCALE;