diff -cr perl5.004_56.dist/global.sym perl5.004_56/global.sym *** perl5.004_56.dist/global.sym Wed Dec 10 04:35:45 1997 --- perl5.004_56/global.sym Fri Jan 23 18:39:50 1998 *************** *** 991,999 **** --- 991,1001 ---- sv_insert sv_isa sv_isobject + sv_i_ncmp sv_len sv_magic sv_mortalcopy + sv_ncmp sv_newmortal sv_newref sv_peek diff -cr perl5.004_56.dist/op.c perl5.004_56/op.c *** perl5.004_56.dist/op.c Thu Dec 11 09:43:00 1997 --- perl5.004_56/op.c Fri Jan 23 18:56:40 1998 *************** *** 41,46 **** --- 41,47 ---- static PADOFFSET pad_findlex _((char* name, PADOFFSET newoff, U32 seq, CV* startcv, I32 cx_ix)); static OP *newDEFSVOP _((void)); + static void simplify_sort _((OP *o)); static char* gv_ename(GV *gv) *************** *** 4475,4484 **** --- 4476,4573 ---- else kid->op_next = k; o->op_flags |= OPf_SPECIAL; + + if (o->op_type == OP_SORT) + simplify_sort(o); } } return o; + } + + void + simplify_sort(OP *o) + { + I32 descending; + I32 numeric; + I32 use_int = 0; + OP *kid; + OP *ss; + SV *tmpsv; + SV *cura = sv_2mortal(newSVpvf("%s::a", + HvNAME(curstash ? curstash : defstash))); + SV *curb = sv_2mortal(newSVpvf("%s::b", + HvNAME(curstash ? curstash : defstash))); + + kid = cLISTOPo->op_first->op_sibling; + kid = kUNOP->op_first; + kid = kUNOP->op_first; + + /* see if we can use a faster version */ + ss = kid->op_next; + + /* look for gvsv(curpkg::[ab])... */ + if (ss->op_type != OP_GVSV) + return; + else { + tmpsv = sv_2mortal(NEWSV(0,0)); + gv_fullname3(tmpsv, ((GVOP *)ss)->op_gv, Nullch); + + if (strEQ(SvPVX(tmpsv), SvPVX(cura))) + descending = 0; + else if (strEQ(SvPVX(tmpsv), SvPVX(curb))) + descending = 1; + else + return; + } + + /* ...now look for the other... */ + ss = ss->op_next; + if (ss->op_type != OP_GVSV) + return; + else { + gv_fullname3(tmpsv, ((GVOP *)ss)->op_gv, Nullch); + + if (strEQ(SvPVX(tmpsv), SvPVX(cura))) + if (!descending) + return; + else if (strEQ(SvPVX(tmpsv), SvPVX(curb))) + if (descending) + return; + else + return; + } + + /* ...check the comparison... */ + ss = ss->op_next; + switch (ss->op_type) { + case OP_NCMP: + case OP_I_NCMP: + numeric = 1; + if (ss->op_type == OP_I_NCMP) + use_int++; + break; + case OP_SCMP: + numeric = 0; + break; + default: + return; + } + + /* ...and finally terminating with OP_SCOPE ==> DONE */ + ss = ss->op_next; + if (ss->op_type != OP_SCOPE || ss->op_next) + return; + + /* success! */ + if (numeric) + o->op_private |= OPpNUMERIC; + if (descending) + o->op_private |= OPpDESCENDING; + if (use_int && numeric) + o->op_private |= OPpINTEGER; + + o->op_flags &= ~(OPf_STACKED | OPf_SPECIAL); } OP * diff -cr perl5.004_56.dist/op.h perl5.004_56/op.h *** perl5.004_56.dist/op.h Thu Dec 11 04:40:11 1997 --- perl5.004_56/op.h Fri Jan 23 11:03:11 1998 *************** *** 132,137 **** --- 132,142 ---- /* Private for OP_SORT, OP_PRTF, OP_SPRINTF, string cmp'n, and case changers */ #define OPpLOCALE 64 /* Use locale */ + /* Private for OP_SORT */ + #define OPpNUMERIC 8 /* numeric comparison */ + #define OPpDESCENDING 16 /* descending order */ + #define OPpINTEGER 32 /* use integer */ + /* Private for OP_THREADSV */ #define OPpDONE_SVREF 64 /* Been through newSVREF once */ diff -cr perl5.004_56.dist/pp_ctl.c perl5.004_56/pp_ctl.c *** perl5.004_56.dist/pp_ctl.c Thu Nov 27 09:12:20 1997 --- perl5.004_56/pp_ctl.c Fri Jan 23 16:14:07 1998 *************** *** 36,41 **** --- 36,47 ---- static int sortcv _((const void *, const void *)); static int sortcmp _((const void *, const void *)); static int sortcmp_locale _((const void *, const void *)); + static int sortncmp _((const void *, const void *)); + static int dsortcmp _((const void *, const void *)); + static int dsortncmp _((const void *, const void *)); + static int sort_i_ncmp _((const void *, const void *)); + static int dsort_i_ncmp _((const void *, const void *)); + static int dsortcmp_locale _((const void *, const void *)); static OP *doeval _((int gimme, OP** startop)); static I32 sortcxix; *************** *** 750,758 **** } else { if (max > 1) { MEXTEND(SP, 20); /* Can't afford stack realloc on signal. */ ! qsort((char*)(ORIGMARK+1), max, sizeof(SV*), ! (op->op_private & OPpLOCALE) ? sortcmp_locale : sortcmp); } } stack_sp = ORIGMARK + max; --- 756,791 ---- } else { if (max > 1) { + int cmp_ix; + static int (*cmps[]) _((const void *, const void *)) = { + sortcmp, /* 0 */ + sortncmp, /* 1 */ + dsortcmp, /* 2 */ + dsortncmp, /* 3 */ + 0, /* 4 */ + sort_i_ncmp, /* 5 */ + 0, /* 6 */ + dsort_i_ncmp, /* 7 */ + sortcmp_locale, /* 8 */ + sortncmp, /* 9 */ + dsortcmp_locale, /* 10 */ + dsortncmp, /* 11 */ + 0, /* 12 */ + sort_i_ncmp, /* 13 */ + 0, /* 14 */ + dsort_i_ncmp, /* 15 */ + }; + + /* ever get the feeling you wish you were an engineer? */ + cmp_ix = (op->op_private & + (OPpLOCALE|OPpINTEGER|OPpDESCENDING|OPpNUMERIC)) + >> 3; + + if (!cmps[cmp_ix]) + croak("panic: sort"); + MEXTEND(SP, 20); /* Can't afford stack realloc on signal. */ ! qsort((char*)(ORIGMARK+1), max, sizeof(SV*), cmps[cmp_ix]); } } stack_sp = ORIGMARK + max; *************** *** 1259,1264 **** --- 1292,1333 ---- sortcmp_locale(const void *a, const void *b) { return sv_cmp_locale(*(SV * const *)a, *(SV * const *)b); + } + + static int + sortncmp(const void *a, const void *b) + { + return sv_ncmp(*(SV * const *)a, *(SV * const *)b); + } + + static int + dsortcmp(const void *a, const void *b) + { + return sv_cmp(*(SV * const *)b, *(SV * const *)a); + } + + static int + dsortncmp(const void *a, const void *b) + { + return sv_ncmp(*(SV * const *)b, *(SV * const *)a); + } + + static int + sort_i_ncmp(const void *a, const void *b) + { + return sv_i_ncmp(*(SV * const *)a, *(SV * const *)b); + } + + static int + dsort_i_ncmp(const void *a, const void *b) + { + return sv_i_ncmp(*(SV * const *)b, *(SV * const *)a); + } + + static int + dsortcmp_locale(const void *a, const void *b) + { + return sv_cmp_locale(*(SV * const *)b, *(SV * const *) a); } PP(pp_reset) diff -cr perl5.004_56.dist/proto.h perl5.004_56/proto.h *** perl5.004_56.dist/proto.h Wed Dec 17 08:16:35 1997 --- perl5.004_56/proto.h Fri Jan 23 13:51:43 1998 *************** *** 514,522 **** --- 514,524 ---- void sv_insert _((SV* bigsv, STRLEN offset, STRLEN len, char* little, STRLEN littlelen)); int sv_isa _((SV* sv, char* name)); int sv_isobject _((SV* sv)); + I32 sv_i_ncmp _((SV* sv1, SV* sv2)); STRLEN sv_len _((SV* sv)); void sv_magic _((SV* sv, SV* obj, int how, char* name, I32 namlen)); SV* sv_mortalcopy _((SV* oldsv)); + I32 sv_ncmp _((SV* sv1, SV* sv2)); SV* sv_newmortal _((void)); SV* sv_newref _((SV* sv)); char* sv_peek _((SV* sv)); diff -cr perl5.004_56.dist/sv.c perl5.004_56/sv.c *** perl5.004_56.dist/sv.c Wed Dec 10 05:11:05 1997 --- perl5.004_56/sv.c Fri Jan 23 13:49:42 1998 *************** *** 2881,2886 **** --- 2881,2916 ---- } I32 + sv_ncmp(register SV *a, register SV *b) + { + double n1 = a ? SvNV(a) : 0.0; + double n2 = b ? SvNV(b) : 0.0; + + if (n1 == n2) + return 0; + else if (n1 < n2) + return -1; + else if (n1 > n2) + return 1; + else + return 0; + } + + I32 + sv_i_ncmp(register SV *a, register SV *b) + { + I32 i1 = a ? SvIV(a) : 0; + I32 i2 = b ? SvIV(b) : 0; + + if (i1 == i2) + return 0; + else if (i1 < i2) + return -1; + else + return 1; + } + + I32 sv_cmp_locale(register SV *sv1, register SV *sv2) { #ifdef USE_LOCALE_COLLATE diff -cr perl5.004_56.dist/t/op/sort.t perl5.004_56/t/op/sort.t *** perl5.004_56.dist/t/op/sort.t Thu Nov 27 09:13:09 1997 --- perl5.004_56/t/op/sort.t Fri Jan 23 18:53:19 1998 *************** *** 2,8 **** # $RCSfile: sort.t,v $$Revision: 4.1 $$Date: 92/08/07 18:28:24 $ ! print "1..21\n"; sub backwards { $a lt $b ? 1 : $a gt $b ? -1 : 0 } --- 2,8 ---- # $RCSfile: sort.t,v $$Revision: 4.1 $$Date: 92/08/07 18:28:24 $ ! print "1..29\n"; sub backwards { $a lt $b ? 1 : $a gt $b ? -1 : 0 } *************** *** 102,104 **** --- 102,146 ---- my @result = sort 'one', 'two'; CODE print $@ ? "not ok 21\n# $@" : "ok 21\n"; + + ## exercise sort builtins... ($a <=> $b already tested) + + @a = ( 5, 19, 1996, 255, 90 ); + @b = sort { $b <=> $a } @a; + print ("@b" eq '1996 255 90 19 5' ? "ok 22\n" : "not ok 22\n"); + print "# x = '@b'\n"; + + $x = join('', sort { $a cmp $b } @harry); + print ($x eq 'AbelCaincatdogx' ? "ok 23\n" : "not ok 23\n"); + print "# x = '$x'\n"; + + $x = join('', sort { $b cmp $a } @harry); + print ($x eq 'xdogcatCainAbel' ? "ok 24\n" : "not ok 24\n"); + print "# x = '$x'\n"; + + { + use integer; + + @b = sort { $a <=> $b } @a; + print ("@b" eq '5 19 90 255 1996' ? "ok 25\n" : "not ok 25\n"); + print "# x = '@b'\n"; + + @b = sort { $b <=> $a } @a; + print ("@b" eq '1996 255 90 19 5' ? "ok 26\n" : "not ok 26\n"); + print "# x = '@b'\n"; + + $x = join('', sort { $a cmp $b } @harry); + print ($x eq 'AbelCaincatdogx' ? "ok 27\n" : "not ok 27\n"); + print "# x = '$x'\n"; + + $x = join('', sort { $b cmp $a } @harry); + print ($x eq 'xdogcatCainAbel' ? "ok 28\n" : "not ok 28\n"); + print "# x = '$x'\n"; + } + + # test sorting in non-main package + package Foo; + @a = ( 5, 19, 1996, 255, 90 ); + @b = sort { $b <=> $a } @a; + print ("@b" eq '1996 255 90 19 5' ? "ok 29\n" : "not ok 29\n"); + print "# x = '@b'\n";