This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #30661] autoload sort subs
[perl5.git] / pp_sort.c
index aa1fe80..8dacd74 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, 2006, 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
@@ -103,7 +105,7 @@ typedef SV * gptr;          /* pointers in our lists */
 #define FROMTOUPTO(src, dst, lim) do *dst++ = *src++; while(src<lim)
 
 
-/* Runs are identified by a pointer in the auxilliary list.
+/* Runs are identified by a pointer in the auxiliary list.
 ** The pointer is at the start of the list,
 ** and it points to the start of the next list.
 ** NEXT is used as an lvalue, too.
@@ -204,7 +206,7 @@ dynprep(pTHX_ gptr *list1, gptr *list2, size_t nmemb, const SVCOMPARE_t cmp)
            if (r >= 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.
@@ -340,7 +342,7 @@ 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);
@@ -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 */
            }
        }
@@ -762,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
@@ -773,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;
@@ -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
@@ -1315,7 +1317,7 @@ 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)
 {
     dVAR;
     gptr * const ap = (gptr *)a;
@@ -1328,7 +1330,7 @@ cmpindir(pTHX_ gptr a, gptr b)
 }
 
 static I32
-cmpindir_desc(pTHX_ gptr a, gptr b)
+cmpindir_desc(pTHX_ gptr const a, gptr const b)
 {
     dVAR;
     gptr * const ap = (gptr *)a;
@@ -1365,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 & SORTf_DESC) != 0 ? 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,
@@ -1413,11 +1417,11 @@ S_qsortsv(pTHX_ gptr *list1, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
         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);
     }
 }
 
@@ -1439,6 +1443,8 @@ flexible routine.
 void
 Perl_sortsv(pTHX_ SV **array, size_t nmemb, SVCOMPARE_t cmp)
 {
+    PERL_ARGS_ASSERT_SORTSV;
+
     sortsv_flags(array, nmemb, cmp, 0);
 }
 
@@ -1452,6 +1458,8 @@ Sort an array, with various options.
 void
 Perl_sortsv_flags(pTHX_ SV **array, size_t nmemb, SVCOMPARE_t cmp, U32 flags)
 {
+    PERL_ARGS_ASSERT_SORTSV_FLAGS;
+
     if (flags & SORTf_QSORT)
        S_qsortsv(aTHX_ array, nmemb, cmp, flags);
     else
@@ -1508,9 +1516,11 @@ 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;
                }
@@ -1520,10 +1530,26 @@ PP(pp_sort)
                    is_xsub = 1;
                }
                else 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",
-                       tmpstr);
+                       SVfARG(tmpstr));
+                 }
                }
                else {
                    DIE(aTHX_ "Undefined subroutine in sort");
@@ -1547,19 +1573,20 @@ 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 : NULL;
            }
+           SP--;
+           p1 = p2 = SP - (max-1);
        }
        else {
            if (SvREADONLY(av))
-               Perl_croak(aTHX_ PL_no_modify);
+               Perl_croak_no_modify(aTHX);
            else
                SvREADONLY_on(av);
            p1 = p2 = AvARRAY(av);
@@ -1580,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++;
        }
@@ -1643,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);
@@ -1656,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;
                    }
@@ -1674,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;
@@ -1693,9 +1718,9 @@ 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) != 0) {
@@ -1711,7 +1736,7 @@ PP(pp_sort)
        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]);
        }
@@ -1732,12 +1757,16 @@ PP(pp_sort)
 }
 
 static I32
-S_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;
+    PERL_ARGS_ASSERT_SORTCV;
+
     GvSV(PL_firstgv) = a;
     GvSV(PL_secondgv) = b;
     PL_stack_sp = PL_stack_base;
@@ -1745,35 +1774,43 @@ S_sortcv(pTHX_ SV *a, SV *b)
     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);
     while (PL_scopestack_ix > oldscopeix) {
        LEAVE;
     }
     leave_scope(oldsaveix);
+    PL_curpm = pm;
     return result;
 }
 
 static I32
-S_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;
+
+    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;
@@ -1785,24 +1822,26 @@ S_sortcv_stacked(pTHX_ SV *a, SV *b)
     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);
     while (PL_scopestack_ix > oldscopeix) {
        LEAVE;
     }
     leave_scope(oldsaveix);
+    PL_curpm = pm;
     return result;
 }
 
 static I32
-S_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);
@@ -1813,121 +1852,124 @@ S_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
-S_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;
+
     return nv1 < nv2 ? -1 : nv1 > nv2 ? 1 : 0;
 }
 
 static I32
-S_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) \
+    (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
-S_amagic_ncmp(pTHX_ register SV *a, register SV *b)
+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;
+
     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);
 }
 
 static I32
-S_amagic_i_ncmp(pTHX_ register SV *a, register SV *b)
+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;
+
     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);
 }
 
 static I32
-S_amagic_cmp(pTHX_ register SV *str1, register SV *str2)
+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;
+
     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
-S_amagic_cmp_locale(pTHX_ register SV *str1, register SV *str2)
+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;
+
     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);