X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=pp_sort.c;h=7585b759405dc7a38534af4775eba933385301cd;hb=d83f0a8247ea7458731c8479d8cbf3ee1fa81243;hp=68ad610f10c007165364f744f4b77820e74e83a8;hpb=9850bf21fc4ed69d8ddb0293df59411f891c62df;p=p5sagit%2Fp5-mst-13.2.git diff --git a/pp_sort.c b/pp_sort.c index 68ad610..7585b75 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 + * 2000, 2001, 2002, 2003, 2004, 2005, 2006, 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. @@ -33,26 +33,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 . * @@ -349,12 +341,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; @@ -1322,24 +1316,26 @@ S_qsortsvu(pTHX_ SV ** array, size_t num_elts, SVCOMPARE_t compare) static I32 cmpindir(pTHX_ gptr a, gptr 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) { - 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 +1345,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; @@ -1371,7 +1365,7 @@ S_qsortsv(pTHX_ gptr *list1, size_t nmemb, SVCOMPARE_t cmp, U32 flags) /* sort, with indirection */ S_qsortsvu(aTHX_ (gptr *)indir, nmemb, - flags ? cmpindir_desc : cmpindir); + ((flags & SORTf_DESC) != 0 ? cmpindir_desc : cmpindir)); pp = indir; q = list1; @@ -1414,7 +1408,7 @@ 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) { + } else if ((flags & SORTf_DESC) != 0) { 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; @@ -1435,7 +1429,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 +1438,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) +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; - } + = ((flags & SORTf_QSORT) != 0 ? S_qsortsv : S_mergesortsv); - sortsvp(aTHX_ array, nmemb, cmp, 1); + sortsvp(aTHX_ array, nmemb, cmp, flags); } #define SvNSIOK(sv) ((SvFLAGS(sv) & SVf_NOK) || ((SvFLAGS(sv) & (SVf_IOK|SVf_IVisUV)) == SVf_IOK)) @@ -1486,24 +1466,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; } @@ -1520,18 +1509,18 @@ PP(pp_sort) else { cv = sv_2cv(*++MARK, &stash, &gv, 0); if (cv && SvPOK(cv)) { - const char *proto = SvPV_nolen_const((SV*)cv); + const char * const proto = SvPV_nolen_const((SV*)cv); if (proto && strEQ(proto, "$$")) { hasargs = TRUE; } } 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); } @@ -1547,7 +1536,7 @@ PP(pp_sort) } } else { - PL_sortcop = Nullop; + PL_sortcop = NULL; stash = CopSTASH(PL_curcop); } @@ -1564,7 +1553,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 { @@ -1581,10 +1570,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 */ @@ -1646,8 +1631,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)); @@ -1659,7 +1644,7 @@ PP(pp_sort) cx->blk_gimme = G_SCALAR; PUSHSUB(cx); if (!is_xsub) { - AV* padlist = CvPADLIST(cv); + AV* const padlist = CvPADLIST(cv); if (++CvDEPTH(cv) >= 2) { PERL_STACK_OVERFLOW_CHECK(); @@ -1670,10 +1655,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; } @@ -1684,7 +1669,8 @@ PP(pp_sort) 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)) { LEAVESUB(cv); @@ -1702,18 +1688,19 @@ 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 + ? S_amagic_cmp_locale : sv_cmp_locale_static) - : ( overloading ? amagic_cmp : sv_cmp_static))); + : ( overloading ? S_amagic_cmp : 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; } @@ -1744,7 +1731,7 @@ PP(pp_sort) } static I32 -sortcv(pTHX_ SV *a, SV *b) +S_sortcv(pTHX_ SV *a, SV *b) { dVAR; const I32 oldsaveix = PL_savestack_ix; @@ -1768,7 +1755,7 @@ sortcv(pTHX_ SV *a, SV *b) } static I32 -sortcv_stacked(pTHX_ SV *a, SV *b) +S_sortcv_stacked(pTHX_ SV *a, SV *b) { dVAR; const I32 oldsaveix = PL_savestack_ix; @@ -1808,7 +1795,7 @@ sortcv_stacked(pTHX_ SV *a, SV *b) } static I32 -sortcv_xsub(pTHX_ SV *a, SV *b) +S_sortcv_xsub(pTHX_ SV *a, SV *b) { dVAR; dSP; const I32 oldsaveix = PL_savestack_ix; @@ -1837,7 +1824,7 @@ sortcv_xsub(pTHX_ SV *a, SV *b) static I32 -sv_ncmp(pTHX_ SV *a, SV *b) +S_sv_ncmp(pTHX_ SV *a, SV *b) { const NV nv1 = SvNSIV(a); const NV nv2 = SvNSIV(b); @@ -1845,7 +1832,7 @@ sv_ncmp(pTHX_ SV *a, SV *b) } static I32 -sv_i_ncmp(pTHX_ SV *a, SV *b) +S_sv_i_ncmp(pTHX_ SV *a, SV *b) { const IV iv1 = SvIV(a); const IV iv2 = SvIV(b); @@ -1855,11 +1842,12 @@ 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; static I32 -amagic_ncmp(pTHX_ register SV *a, register SV *b) +S_amagic_ncmp(pTHX_ register SV *a, register SV *b) { + dVAR; SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp); if (tmpsv) { if (SvIOK(tmpsv)) { @@ -1875,12 +1863,13 @@ amagic_ncmp(pTHX_ register SV *a, register SV *b) return d ? -1 : 0; } } - 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 *a, register SV *b) { + dVAR; SV * const tmpsv = tryCALL_AMAGICbin(a,b,ncmp); if (tmpsv) { if (SvIOK(tmpsv)) { @@ -1896,12 +1885,13 @@ amagic_i_ncmp(pTHX_ register SV *a, register SV *b) return d ? -1 : 0; } } - 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 *str1, register SV *str2) { + dVAR; SV * const tmpsv = tryCALL_AMAGICbin(str1,str2,scmp); if (tmpsv) { if (SvIOK(tmpsv)) { @@ -1921,8 +1911,9 @@ amagic_cmp(pTHX_ register SV *str1, register SV *str2) } static I32 -amagic_cmp_locale(pTHX_ register SV *str1, register SV *str2) +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)) {