#include "EXTERN.h"
#define PERL_IN_PP_SORT_C
#include "perl.h"
#ifndef SMALLSORT
#define SMALLSORT (200)
#endif
typedef
char
* aptr;
typedef
SV * gptr;
#define APTR(P) ((aptr)(P))
#define GPTP(P) ((gptr *)(P))
#define GPPP(P) ((gptr **)(P))
#define BYTEOFF(P, Q) (APTR(Q) - APTR(P))
#define PSIZE sizeof(gptr)
#ifdef PSHIFT
#define PNELEM(P, Q) (BYTEOFF(P,Q) >> (PSHIFT))
#define PNBYTE(N) ((N) << (PSHIFT))
#define PINDEX(P, N) (GPTP(APTR(P) + PNBYTE(N)))
#else
#define PNELEM(P, Q) (GPTP(Q) - GPTP(P))
#define PNBYTE(N) ((N) * (PSIZE))
#define PINDEX(P, N) (GPTP(P) + (N))
#endif
#define POTHER(P, THIS, OTHER) GPTP(APTR(OTHER) + BYTEOFF(THIS,P))
#define FROMTOUPTO(src, dst, lim) do *dst++ = *src++; while(src<lim)
#define NEXT(P) (*GPPP(P))
#define PTHRESH (8)
#define RTHRESH (6)
PERL_STATIC_FORCE_INLINE IV __attribute__always_inline__
dynprep(pTHX_ gptr *list1, gptr *list2,
size_t
nmemb,
const
SVCOMPARE_t cmp)
{
I32 sense;
gptr *b, *p, *q, *t, *p2;
gptr *last, *r;
IV runs = 0;
b = list1;
last = PINDEX(b, nmemb);
sense = (cmp(aTHX_ *b, *(b+1)) > 0);
for
(p2 = list2; b < last; ) {
for
(p = b+2, t = p; ++p < last; t = ++p) {
if
((cmp(aTHX_ *t, *p) > 0) != sense)
break
;
}
q = b;
do
{
p = r = b + (2 * PTHRESH);
if
(r >= t) p = r = t;
else
{
while
(((cmp(aTHX_ *(p-1), *p) > 0) == sense) &&
((p -= 2) > q)) {}
if
(p <= q) {
p = q = r;
while
(((p += 2) < t) &&
((cmp(aTHX_ *(p-1), *p) > 0) == sense)) q = p;
r = p = q + 2;
}
}
if
(q > b) {
gptr *savep = p;
p = q += 2;
if
((p == t) &&
((t + 1) == last) &&
((cmp(aTHX_ *(p-1), *p) > 0) == sense))
savep = r = p = q = last;
p2 = NEXT(p2) = p2 + (p - b); ++runs;
if
(sense)
while
(b < --p) {
const
gptr c = *b;
*b++ = *p;
*p = c;
}
p = savep;
}
while
(q < p) {
p2 = NEXT(p2) = p2 + 2; ++runs;
if
(sense) {
const
gptr c = *q++;
*(q-1) = *q;
*q++ = c;
}
else
q += 2;
}
if
(((b = p) == t) && ((t+1) == last)) {
NEXT(p2) = p2 + 1; ++runs;
b++;
}
q = r;
}
while
(b < t);
sense = !sense;
}
return
runs;
}
typedef
struct
{
IV offset;
IV runs;
} off_runs;
PERL_STATIC_FORCE_INLINE
void
S_sortsv_flags_impl(pTHX_ gptr *base,
size_t
nmemb, SVCOMPARE_t cmp, U32 flags)
{
IV i, run, offset;
I32 sense, level;
gptr *f1, *f2, *t, *b, *p;
int
iwhich;
gptr *aux;
gptr *p1;
gptr small[SMALLSORT];
gptr *which[3];
off_runs stack[60], *stackp;
PERL_UNUSED_ARG(flags);
PERL_ARGS_ASSERT_SORTSV_FLAGS_IMPL;
if
(nmemb <= 1)
return
;
if
(nmemb <= SMALLSORT) aux = small;
else
{ Newx(aux,nmemb,gptr); }
level = 0;
stackp = stack;
stackp->runs = dynprep(aTHX_ base, aux, nmemb, cmp);
stackp->offset = offset = 0;
which[0] = which[2] = base;
which[1] = aux;
for
(;;) {
IV runs = stackp->runs;
if
(runs == 0) {
gptr *list1, *list2;
iwhich = level & 1;
list1 = which[iwhich];
list2 = which[++iwhich];
do
{
gptr *l1, *l2, *tp2;
offset = stackp->offset;
f1 = p1 = list1 + offset;
p = tp2 = list2 + offset;
t = NEXT(p);
f2 = l1 = POTHER(t, list2, list1);
t = NEXT(t);
l2 = POTHER(t, list2, list1);
offset = PNELEM(list2, t);
while
(f1 < l1 && f2 < l2) {
gptr *q;
if
(cmp(aTHX_ *f1, *f2) <= 0) {
q = f2; b = f1; t = l1;
sense = -1;
}
else
{
q = f1; b = f2; t = l2;
sense = 0;
}
for
(i = 1, run = 0 ;;) {
if
((p = PINDEX(b, i)) >= t) {
if
(((p = PINDEX(t, -1)) > b) &&
(cmp(aTHX_ *q, *p) <= sense))
t = p;
else
b = p;
break
;
}
else
if
(cmp(aTHX_ *q, *p) <= sense) {
t = p;
break
;
}
else
b = p;
if
(++run >= RTHRESH) i += i;
}
b++;
while
(b < t) {
p = PINDEX(b, (PNELEM(b, t) - 1) / 2);
if
(cmp(aTHX_ *q, *p) <= sense) {
t = p;
}
else
b = p + 1;
}
if
(q == f1) {
FROMTOUPTO(f2, tp2, t);
*tp2++ = *f1++;
}
else
{
FROMTOUPTO(f1, tp2, t);
*tp2++ = *f2++;
}
}
if
(f1 == l1) {
if
(f2 < l2) FROMTOUPTO(f2, tp2, l2);
}
else
FROMTOUPTO(f1, tp2, l1);
p1 = NEXT(p1) = POTHER(tp2, list2, list1);
if
(--level == 0)
goto
done;
--stackp;
t = list1; list1 = list2; list2 = t;
}
while
((runs = stackp->runs) == 0);
}
stackp->runs = 0;
while
(runs > 2) {
++level;
++stackp;
stackp->offset = offset;
runs -= stackp->runs = runs / 2;
}
iwhich = level & 1;
if
(runs == 1) {
if
(iwhich) {
f1 = b = PINDEX(base, offset);
f2 = PINDEX(aux, offset);
t = NEXT(f2);
offset = PNELEM(aux, t);
t = PINDEX(base, offset);
FROMTOUPTO(f1, f2, t);
NEXT(b) = t;
}
else
if
(level == 0)
goto
done;
}
else
{
++level;
++stackp;
stackp->offset = offset;
stackp->runs = 0;
if
(!iwhich) {
f1 = b = PINDEX(base, offset);
f2 = PINDEX(aux, offset);
t = NEXT(f2);
offset = PNELEM(aux, t);
p = PINDEX(base, offset);
t = NEXT(t);
t = PINDEX(base, PNELEM(aux, t));
FROMTOUPTO(f1, f2, t);
NEXT(b) = p;
NEXT(p) = t;
}
}
}
done:
if
(aux != small) Safefree(aux);
return
;
}
void
Perl_sortsv_flags(pTHX_ gptr *base,
size_t
nmemb, SVCOMPARE_t cmp, U32 flags)
{
PERL_ARGS_ASSERT_SORTSV_FLAGS;
sortsv_flags_impl(base, nmemb, cmp, flags);
}
static
void
sortsv_amagic_i_ncmp(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_amagic_i_ncmp, flags);
}
static
void
sortsv_amagic_i_ncmp_desc(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_amagic_i_ncmp_desc, flags);
}
static
void
sortsv_i_ncmp(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_sv_i_ncmp, flags);
}
static
void
sortsv_i_ncmp_desc(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_sv_i_ncmp_desc, flags);
}
static
void
sortsv_amagic_ncmp(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_amagic_ncmp, flags);
}
static
void
sortsv_amagic_ncmp_desc(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_amagic_ncmp_desc, flags);
}
static
void
sortsv_ncmp(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_sv_ncmp, flags);
}
static
void
sortsv_ncmp_desc(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_sv_ncmp_desc, flags);
}
static
void
sortsv_amagic_cmp(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_amagic_cmp, flags);
}
static
void
sortsv_amagic_cmp_desc(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_amagic_cmp_desc, flags);
}
static
void
sortsv_cmp(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, Perl_sv_cmp, flags);
}
static
void
sortsv_cmp_desc(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_cmp_desc, flags);
}
#ifdef USE_LOCALE_COLLATE
static
void
sortsv_amagic_cmp_locale(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_amagic_cmp_locale, flags);
}
static
void
sortsv_amagic_cmp_locale_desc(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_amagic_cmp_locale_desc, flags);
}
static
void
sortsv_cmp_locale(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, Perl_sv_cmp_locale, flags);
}
static
void
sortsv_cmp_locale_desc(pTHX_ gptr *base,
size_t
nmemb, U32 flags)
{
sortsv_flags_impl(base, nmemb, S_cmp_locale_desc, flags);
}
#endif
void
Perl_sortsv(pTHX_ SV **array,
size_t
nmemb, SVCOMPARE_t cmp)
{
PERL_ARGS_ASSERT_SORTSV;
sortsv_flags(array, nmemb, cmp, 0);
}
#define SvNSIOK(sv) ((SvFLAGS(sv) & SVf_NOK) || ((SvFLAGS(sv) & (SVf_IOK|SVf_IVisUV)) == SVf_IOK))
#define SvSIOK(sv) ((SvFLAGS(sv) & (SVf_IOK|SVf_IVisUV)) == SVf_IOK)
#define SvNSIV(sv) ( SvNOK(sv) ? SvNVX(sv) : ( SvSIOK(sv) ? SvIVX(sv) : sv_2nv(sv) ) )
PP(pp_sort)
{
dMARK; dORIGMARK;
SV **p1 = ORIGMARK+1, **p2;
SSize_t max, i;
AV* av = NULL;
GV *gv;
CV *cv = NULL;
U8 gimme = GIMME_V;
OP*
const
nextop = PL_op->op_next;
I32 overloading = 0;
bool
hasargs = FALSE;
bool
copytmps;
I32 is_xsub = 0;
const
U8 priv = PL_op->op_private;
const
U8 flags = PL_op->op_flags;
U32 sort_flags = 0;
I32 all_SIVs = 1, descending = 0;
if
((priv & OPpSORT_DESCEND) != 0)
descending = 1;
if
(gimme != G_LIST) {
rpp_popfree_to_NN(mark);
rpp_xpush_IMM(&PL_sv_undef);
return
NORMAL;
}
ENTER;
SAVEVPTR(PL_sortcop);
if
(flags & OPf_STACKED) {
if
(flags & OPf_SPECIAL) {
OP *nullop = OpSIBLING(cLISTOP->op_first);
assert
(nullop->op_type == OP_NULL);
PL_sortcop = nullop->op_next;
}
else
{
GV *autogv = NULL;
HV *stash;
SV *fn = *++MARK;
cv = sv_2cv(fn, &stash, &gv, GV_ADD);
#ifdef PERL_RC_STACK
assert
(fn != (SV*)cv || SvREFCNT(fn) > 1);
SvREFCNT_dec(fn);
#endif
*MARK = NULL;
check_cv:
if
(cv && SvPOK(cv)) {
const
char
*
const
proto = SvPV_nolen_const(MUTABLE_SV(cv));
if
(proto && strEQ(proto,
"$$"
)) {
hasargs = TRUE;
}
}
if
(cv && CvISXSUB(cv) && CvXSUB(cv)) {
is_xsub = 1;
}
else
if
(!(cv && CvROOT(cv))) {
if
(gv) {
goto
autoload;
}
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"
);
}
}
if
(is_xsub)
PL_sortcop = (OP*)cv;
else
PL_sortcop = CvSTART(cv);
}
}
else
{
PL_sortcop = NULL;
}
if
(priv & OPpSORT_INPLACE) {
assert
( MARK+1 == PL_stack_sp
&& *PL_stack_sp
&& SvTYPE(*PL_stack_sp) == SVt_PVAV);
(
void
)POPMARK;
av = MUTABLE_AV((*PL_stack_sp));
if
(SvREADONLY(av))
Perl_croak_no_modify();
max = AvFILL(av) + 1;
I32 oldmark = MARK - PL_stack_base;
rpp_extend(max);
MARK = PL_stack_base + oldmark;
if
(SvMAGICAL(av)) {
for
(i=0; i < max; i++) {
SV **svp = av_fetch(av, i, FALSE);
SV *sv;
if
(svp) {
sv = *svp;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(sv);
#endif
}
else
sv = NULL;
*++PL_stack_sp = sv;
}
}
else
{
SV **svp = AvARRAY(av);
assert
(svp || max == 0);
for
(i = 0; i < max; i++) {
SV *sv = *svp++;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void(sv);
#endif
*++PL_stack_sp = sv;
}
}
p1 = p2 = PL_stack_sp - (max-1);
assert
((SV*)av == p1[-1]);
}
else
{
p2 = MARK+1;
max = PL_stack_sp - MARK;
}
assert
(p1 == p2 || (p1+1 == p2 && !*p1));
copytmps = cBOOL(PL_sortcop);
for
(i=max; i > 0 ; i--) {
SV *sv = *p2++;
if
(sv) {
if
(copytmps && SvPADTMP(sv)) {
SV *nsv = sv_mortalcopy(sv);
#ifdef PERL_RC_STACK
SvREFCNT_dec_NN(sv);
SvREFCNT_inc_simple_void_NN(nsv);
#endif
sv = nsv;
}
SvTEMP_off(sv);
if
(!PL_sortcop) {
if
(priv & OPpSORT_NUMERIC) {
if
(priv & OPpSORT_INTEGER) {
if
(!SvIOK(sv))
(
void
)sv_2iv_flags(sv, SV_GMAGIC|SV_SKIP_OVERLOAD);
}
else
{
if
(!SvNSIOK(sv))
(
void
)sv_2nv_flags(sv, SV_GMAGIC|SV_SKIP_OVERLOAD);
if
(all_SIVs && !SvSIOK(sv))
all_SIVs = 0;
}
}
else
{
if
(!SvPOK(sv))
(
void
)sv_2pv_flags(sv, 0,
SV_GMAGIC|SV_CONST_RETURN|SV_SKIP_OVERLOAD);
}
if
(SvAMAGIC(sv))
overloading = 1;
}
*p1++ = sv;
}
else
max--;
}
if
(max > 1) {
SV **start;
if
(PL_sortcop) {
PERL_CONTEXT *cx;
const
bool
oldcatch = CATCH_GET;
I32 old_savestack_ix = PL_savestack_ix;
SAVEOP();
CATCH_SET(TRUE);
push_stackinfo(PERLSI_SORT, 1);
if
(!hasargs && !is_xsub) {
SAVEGENERICSV(PL_firstgv);
SAVEGENERICSV(PL_secondgv);
PL_firstgv = MUTABLE_GV(SvREFCNT_inc(
gv_fetchpvs(
"a"
, GV_ADD|GV_NOTQUAL, SVt_PV)
));
PL_secondgv = MUTABLE_GV(SvREFCNT_inc(
gv_fetchpvs(
"b"
, GV_ADD|GV_NOTQUAL, SVt_PV)
));
save_gp(PL_firstgv, 0);
save_gp(PL_secondgv, 0);
GvINTRO_off(PL_firstgv);
GvINTRO_off(PL_secondgv);
SAVEGENERICSV(GvSV(PL_firstgv));
SvREFCNT_inc(GvSV(PL_firstgv));
SAVEGENERICSV(GvSV(PL_secondgv));
SvREFCNT_inc(GvSV(PL_secondgv));
}
gimme = G_SCALAR;
cx = cx_pushblock(CXt_NULL, gimme, PL_stack_base, old_savestack_ix);
if
(!(flags & OPf_SPECIAL)) {
cx->cx_type = CXt_SUB|CXp_MULTICALL;
cx_pushsub(cx, cv, NULL, hasargs);
if
(!is_xsub) {
PADLIST *
const
padlist = CvPADLIST(cv);
if
(++CvDEPTH(cv) >= 2)
pad_push(padlist, CvDEPTH(cv));
PAD_SET_CUR_NOSAVE(padlist, CvDEPTH(cv));
if
(hasargs) {
AV *
const
av0 = MUTABLE_AV(PAD_SVl(0));
cx->blk_sub.savearray = GvAV(PL_defgv);
GvAV(PL_defgv) = MUTABLE_AV(SvREFCNT_inc_simple(av0));
}
}
}
start = p1 - max;
Perl_sortsv_flags(aTHX_ start, max,
(is_xsub ? S_sortcv_xsub : hasargs ? S_sortcv_stacked : S_sortcv),
sort_flags);
cx = CX_CUR();
assert
(cx->blk_oldsp == 0);
rpp_popfree_to_NN(PL_stack_base);
CX_LEAVE_SCOPE(cx);
if
(!(flags & OPf_SPECIAL)) {
assert
(CxTYPE(cx) == CXt_SUB);
cx_popsub(cx);
}
else
assert
(CxTYPE(cx) == CXt_NULL);
cx_popblock(cx);
CX_POP(cx);
pop_stackinfo();
CATCH_SET(oldcatch);
}
else
{
start = p1 - max;
if
(priv & OPpSORT_NUMERIC) {
if
((priv & OPpSORT_INTEGER) || all_SIVs) {
if
(overloading)
if
(descending)
sortsv_amagic_i_ncmp_desc(aTHX_ start, max, sort_flags);
else
sortsv_amagic_i_ncmp(aTHX_ start, max, sort_flags);
else
if
(descending)
sortsv_i_ncmp_desc(aTHX_ start, max, sort_flags);
else
sortsv_i_ncmp(aTHX_ start, max, sort_flags);
}
else
{
if
(overloading)
if
(descending)
sortsv_amagic_ncmp_desc(aTHX_ start, max, sort_flags);
else
sortsv_amagic_ncmp(aTHX_ start, max, sort_flags);
else
if
(descending)
sortsv_ncmp_desc(aTHX_ start, max, sort_flags);
else
sortsv_ncmp(aTHX_ start, max, sort_flags);
}
}
#ifdef USE_LOCALE_COLLATE
else
if
(IN_LC_RUNTIME(LC_COLLATE)) {
if
(overloading)
if
(descending)
sortsv_amagic_cmp_locale_desc(aTHX_ start, max, sort_flags);
else
sortsv_amagic_cmp_locale(aTHX_ start, max, sort_flags);
else
if
(descending)
sortsv_cmp_locale_desc(aTHX_ start, max, sort_flags);
else
sortsv_cmp_locale(aTHX_ start, max, sort_flags);
}
#endif
else
{
if
(overloading)
if
(descending)
sortsv_amagic_cmp_desc(aTHX_ start, max, sort_flags);
else
sortsv_amagic_cmp(aTHX_ start, max, sort_flags);
else
if
(descending)
sortsv_cmp_desc(aTHX_ start, max, sort_flags);
else
sortsv_cmp(aTHX_ start, max, sort_flags);
}
}
if
((priv & OPpSORT_REVERSE) != 0) {
SV **q = start+max-1;
while
(start < q) {
SV *
const
tmp = *start;
*start++ = *q;
*q-- = tmp;
}
}
}
if
(!av) {
LEAVE;
PL_stack_sp = ORIGMARK + max;
return
nextop;
}
{
SV**
const
base = MARK+2;
SSize_t max_minus_one = max - 1;
assert
(base[-1] == (SV*)av);
if
(SvMAGICAL(av)) {
for
(i = 0; i <= max_minus_one; i++) {
SV *sv = base[i];
base[i] = newSVsv(sv);
#ifdef PERL_RC_STACK
SvREFCNT_dec_NN(sv);
#endif
}
av_clear(av);
if
(max_minus_one >= 0)
av_extend(av, max_minus_one);
for
(i=0; i <= max_minus_one; i++) {
SV *
const
sv = base[i];
SV **
const
didstore = av_store(av, i, sv);
if
(SvSMAGICAL(sv))
mg_set(sv);
#ifdef PERL_RC_STACK
if
(didstore)
SvREFCNT_inc_simple_void_NN(sv);
#else
if
(!didstore)
sv_2mortal(sv);
#endif
}
}
else
{
for
(i = 0; i <= max_minus_one; i++) {
SV *sv = base[i];
assert
(sv);
#ifdef PERL_RC_STACK
if
(SvREFCNT(sv) > 2) {
base[i] = newSVsv(sv);
SvREFCNT_dec_NN(sv);
}
#else
if
(SvREFCNT(sv) > 1)
base[i] = newSVsv(sv);
else
SvREFCNT_inc_simple_void_NN(sv);
#endif
}
av_clear(av);
if
(max_minus_one >= 0) {
av_extend(av, max_minus_one);
Copy(base, AvARRAY(av), max, SV*);
}
AvFILLp(av) = max_minus_one;
AvREIFY_off(av);
AvREAL_on(av);
}
PL_stack_sp = ORIGMARK;
#ifdef PERL_RC_STACK
SvREFCNT_dec_NN(av);
#endif
LEAVE;
return
nextop;
}
}
static
I32
S_sortcv(pTHX_ SV *
const
a, SV *
const
b)
{
const
I32 oldsaveix = PL_savestack_ix;
I32 result;
PMOP *
const
pm = PL_curpm;
COP *
const
cop = PL_curcop;
SV *olda, *oldb;
PERL_ARGS_ASSERT_SORTCV;
#ifdef PERL_RC_STACK
assert
(rpp_stack_is_rc());
#endif
olda = GvSV(PL_firstgv);
GvSV(PL_firstgv) = SvREFCNT_inc_simple_NN(a);
SvREFCNT_dec(olda);
oldb = GvSV(PL_secondgv);
GvSV(PL_secondgv) = SvREFCNT_inc_simple_NN(b);
SvREFCNT_dec(oldb);
assert
(PL_stack_sp == PL_stack_base);
PL_op = PL_sortcop;
CALLRUNOPS(aTHX);
PL_curcop = cop;
assert
(PL_stack_sp > PL_stack_base || *PL_stack_base == &PL_sv_undef);
result = SvIV(*PL_stack_sp);
rpp_popfree_to_NN(PL_stack_base);
LEAVE_SCOPE(oldsaveix);
PL_curpm = pm;
return
result;
}
static
I32
S_sortcv_stacked(pTHX_ SV *
const
a, SV *
const
b)
{
const
I32 oldsaveix = PL_savestack_ix;
I32 result;
AV *
const
av = GvAV(PL_defgv);
PMOP *
const
pm = PL_curpm;
COP *
const
cop = PL_curcop;
PERL_ARGS_ASSERT_SORTCV_STACKED;
#ifdef PERL_RC_STACK
assert
(rpp_stack_is_rc());
#endif
#ifdef PERL_RC_STACK
assert
(AvREAL(av));
av_clear(av);
#else
if
(AvREAL(av)) {
av_clear(av);
AvREAL_off(av);
AvREIFY_on(av);
}
#endif
if
(AvMAX(av) < 1) {
SV **ary = AvALLOC(av);
if
(AvARRAY(av) != ary) {
AvMAX(av) += AvARRAY(av) - AvALLOC(av);
AvARRAY(av) = ary;
}
if
(AvMAX(av) < 1) {
Renew(ary,2,SV*);
AvMAX(av) = 1;
AvARRAY(av) = ary;
AvALLOC(av) = ary;
}
}
AvFILLp(av) = 1;
AvARRAY(av)[0] = a;
AvARRAY(av)[1] = b;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(a);
SvREFCNT_inc_simple_void_NN(b);
#endif
assert
(PL_stack_sp == PL_stack_base);
PL_op = PL_sortcop;
CALLRUNOPS(aTHX);
PL_curcop = cop;
assert
(PL_stack_sp > PL_stack_base || *PL_stack_base == &PL_sv_undef);
result = SvIV(*PL_stack_sp);
rpp_popfree_to_NN(PL_stack_base);
LEAVE_SCOPE(oldsaveix);
PL_curpm = pm;
return
result;
}
static
I32
S_sortcv_xsub(pTHX_ SV *
const
a, SV *
const
b)
{
const
I32 oldsaveix = PL_savestack_ix;
CV *
const
cv=MUTABLE_CV(PL_sortcop);
I32 result;
PMOP *
const
pm = PL_curpm;
PERL_ARGS_ASSERT_SORTCV_XSUB;
#ifdef PERL_RC_STACK
assert
(rpp_stack_is_rc());
#endif
assert
(PL_stack_sp == PL_stack_base);
PUSHMARK(PL_stack_sp);
rpp_xpush_2(a, b);
rpp_invoke_xs(cv);
assert
(PL_stack_sp > PL_stack_base || *PL_stack_base == &PL_sv_undef);
result = SvIV(*PL_stack_sp);
rpp_popfree_to_NN(PL_stack_base);
LEAVE_SCOPE(oldsaveix);
PL_curpm = pm;
return
result;
}
PERL_STATIC_FORCE_INLINE I32
S_sv_ncmp(pTHX_ SV *
const
a, SV *
const
b)
{
I32 cmp = do_ncmp(a, b);
PERL_ARGS_ASSERT_SV_NCMP;
if
(cmp == 2) {
if
(ckWARN(WARN_UNINITIALIZED)) report_uninit(NULL);
return
0;
}
return
cmp;
}
PERL_STATIC_FORCE_INLINE I32
S_sv_ncmp_desc(pTHX_ SV *
const
a, SV *
const
b)
{
PERL_ARGS_ASSERT_SV_NCMP_DESC;
return
-S_sv_ncmp(aTHX_ a, b);
}
PERL_STATIC_FORCE_INLINE I32
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;
}
PERL_STATIC_FORCE_INLINE I32
S_sv_i_ncmp_desc(pTHX_ SV *
const
a, SV *
const
b)
{
PERL_ARGS_ASSERT_SV_I_NCMP_DESC;
return
-S_sv_i_ncmp(aTHX_ a, b);
}
#define tryCALL_AMAGICbin(left,right,meth) \
(SvAMAGIC(left)||SvAMAGIC(right)) \
? amagic_call(left, right, meth, 0) \
: NULL;
#define SORT_NORMAL_RETURN_VALUE(val) (((val) > 0) ? 1 : ((val) ? -1 : 0))
PERL_STATIC_FORCE_INLINE I32
S_amagic_ncmp(pTHX_ SV *
const
a, SV *
const
b)
{
SV *
const
tmpsv = tryCALL_AMAGICbin(a,b,ncmp_amg);
PERL_ARGS_ASSERT_AMAGIC_NCMP;
if
(tmpsv) {
if
(SvIOK(tmpsv)) {
const
I32 i = SvIVX(tmpsv);
return
SORT_NORMAL_RETURN_VALUE(i);
}
else
{
const
NV d = SvNV(tmpsv);
return
SORT_NORMAL_RETURN_VALUE(d);
}
}
return
S_sv_ncmp(aTHX_ a, b);
}
PERL_STATIC_FORCE_INLINE I32
S_amagic_ncmp_desc(pTHX_ SV *
const
a, SV *
const
b)
{
PERL_ARGS_ASSERT_AMAGIC_NCMP_DESC;
return
-S_amagic_ncmp(aTHX_ a, b);
}
PERL_STATIC_FORCE_INLINE I32
S_amagic_i_ncmp(pTHX_ SV *
const
a, SV *
const
b)
{
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);
return
SORT_NORMAL_RETURN_VALUE(i);
}
else
{
const
NV d = SvNV(tmpsv);
return
SORT_NORMAL_RETURN_VALUE(d);
}
}
return
S_sv_i_ncmp(aTHX_ a, b);
}
PERL_STATIC_FORCE_INLINE I32
S_amagic_i_ncmp_desc(pTHX_ SV *
const
a, SV *
const
b)
{
PERL_ARGS_ASSERT_AMAGIC_I_NCMP_DESC;
return
-S_amagic_i_ncmp(aTHX_ a, b);
}
PERL_STATIC_FORCE_INLINE I32
S_amagic_cmp(pTHX_ SV *
const
str1, SV *
const
str2)
{
SV *
const
tmpsv = tryCALL_AMAGICbin(str1,str2,scmp_amg);
PERL_ARGS_ASSERT_AMAGIC_CMP;
if
(tmpsv) {
if
(SvIOK(tmpsv)) {
const
I32 i = SvIVX(tmpsv);
return
SORT_NORMAL_RETURN_VALUE(i);
}
else
{
const
NV d = SvNV(tmpsv);
return
SORT_NORMAL_RETURN_VALUE(d);
}
}
return
sv_cmp(str1, str2);
}
PERL_STATIC_FORCE_INLINE I32
S_amagic_cmp_desc(pTHX_ SV *
const
str1, SV *
const
str2)
{
PERL_ARGS_ASSERT_AMAGIC_CMP_DESC;
return
-S_amagic_cmp(aTHX_ str1, str2);
}
PERL_STATIC_FORCE_INLINE I32
S_cmp_desc(pTHX_ SV *
const
str1, SV *
const
str2)
{
PERL_ARGS_ASSERT_CMP_DESC;
return
-sv_cmp(str1, str2);
}
#ifdef USE_LOCALE_COLLATE
PERL_STATIC_FORCE_INLINE I32
S_amagic_cmp_locale(pTHX_ SV *
const
str1, SV *
const
str2)
{
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);
return
SORT_NORMAL_RETURN_VALUE(i);
}
else
{
const
NV d = SvNV(tmpsv);
return
SORT_NORMAL_RETURN_VALUE(d);
}
}
return
sv_cmp_locale(str1, str2);
}
PERL_STATIC_FORCE_INLINE I32
S_amagic_cmp_locale_desc(pTHX_ SV *
const
str1, SV *
const
str2)
{
PERL_ARGS_ASSERT_AMAGIC_CMP_LOCALE_DESC;
return
-S_amagic_cmp_locale(aTHX_ str1, str2);
}
PERL_STATIC_FORCE_INLINE I32
S_cmp_locale_desc(pTHX_ SV *
const
str1, SV *
const
str2)
{
PERL_ARGS_ASSERT_CMP_LOCALE_DESC;
return
-sv_cmp_locale(str1, str2);
}
#endif