@@ -9,7 +9,7 @@ use crate::common::lock::{
99use crate :: object:: { Traverse , TraverseFn } ;
1010use crate :: {
1111 AsObject , Context , Py , PyObject , PyObjectRef , PyPayload , PyRef , PyResult ,
12- builtins:: { PyFloat , PyInt , PyStr } ,
12+ builtins:: { PyFloat , PyInt , PyStr , PyTuple } ,
1313 class:: PyClassImpl ,
1414 convert:: ToPyObject ,
1515 function:: { ArgSize , Either , FuncArgs , OptionalArg , PyComparisonValue } ,
@@ -635,38 +635,100 @@ impl Representable for PyList {
635635 }
636636}
637637
638+ enum Elem {
639+ Str ,
640+ Int ,
641+ Float ,
642+ Object ( RichCompareFunc ) ,
643+ Generic ,
644+ }
645+
638646enum PreSort {
639647 Str ,
640648 Int ,
641649 Float ,
642650 Object ( RichCompareFunc ) ,
651+ Tuple ( Elem ) ,
643652 Generic ,
644653}
645654
655+ impl From < Elem > for PreSort {
656+ fn from ( e : Elem ) -> Self {
657+ match e {
658+ Elem :: Str => Self :: Str ,
659+ Elem :: Int => Self :: Int ,
660+ Elem :: Float => Self :: Float ,
661+ Elem :: Object ( f) => Self :: Object ( f) ,
662+ Elem :: Generic => Self :: Generic ,
663+ }
664+ }
665+ }
666+
667+ fn classify ( class : & Py < PyType > , vm : & VirtualMachine ) -> Elem {
668+ if class. is ( vm. ctx . types . str_type ) {
669+ Elem :: Str
670+ } else if class. is ( vm. ctx . types . int_type ) {
671+ Elem :: Int
672+ } else if class. is ( vm. ctx . types . float_type ) {
673+ Elem :: Float
674+ } else if let Some ( f) = class. slots . richcompare . load ( ) {
675+ Elem :: Object ( f)
676+ } else {
677+ Elem :: Generic
678+ }
679+ }
680+
646681fn pre_sort_check < ' a > (
647682 mut keys : impl Iterator < Item = & ' a PyObjectRef > ,
648683 vm : & VirtualMachine ,
649684) -> PreSort {
650685 let Some ( first) = keys. next ( ) else {
651686 return PreSort :: Generic ;
652687 } ;
653- let class = first. class ( ) ;
654- if !keys. all ( |o| o. class ( ) . is ( class) ) {
655- return PreSort :: Generic ;
656- }
657- if class. is ( vm. ctx . types . str_type ) {
658- PreSort :: Str
659- } else if class. is ( vm. ctx . types . int_type ) {
660- PreSort :: Int
661- } else if class. is ( vm. ctx . types . float_type ) {
662- PreSort :: Float
663- } else if let Some ( f) = class. slots . richcompare . load ( ) {
664- PreSort :: Object ( f)
688+
689+ if let Some ( t) = first
690+ . downcast_ref_if_exact :: < PyTuple > ( vm)
691+ . filter ( |t| !t. as_slice ( ) . is_empty ( ) )
692+ {
693+ pre_sort_check_tuples ( & t. as_slice ( ) [ 0 ] , keys, vm)
665694 } else {
666- PreSort :: Generic
695+ let class = first. class ( ) ;
696+ if keys. all ( |k| k. class ( ) . is ( class) ) {
697+ classify ( class, vm) . into ( )
698+ } else {
699+ PreSort :: Generic
700+ }
667701 }
668702}
669703
704+ fn pre_sort_check_tuples < ' a > (
705+ first_elem : & PyObjectRef ,
706+ keys : impl Iterator < Item = & ' a PyObjectRef > ,
707+ vm : & VirtualMachine ,
708+ ) -> PreSort {
709+ let class = first_elem. class ( ) ;
710+ let mut all_same_type = true ;
711+
712+ for k in keys {
713+ let Some ( t) = k
714+ . downcast_ref_if_exact :: < PyTuple > ( vm)
715+ . filter ( |t| !t. as_slice ( ) . is_empty ( ) )
716+ else {
717+ return PreSort :: Generic ;
718+ } ;
719+ if all_same_type && !t. as_slice ( ) [ 0 ] . class ( ) . is ( class) {
720+ all_same_type = false ;
721+ }
722+ }
723+
724+ let elem = if !all_same_type || class. is ( vm. ctx . types . tuple_type ) {
725+ Elem :: Generic
726+ } else {
727+ classify ( class, vm)
728+ } ;
729+ PreSort :: Tuple ( elem)
730+ }
731+
670732fn str_lt ( a : & PyObjectRef , b : & PyObjectRef ) -> bool {
671733 a. downcast_ref :: < PyStr > ( ) . unwrap ( ) . as_bytes ( ) < b. downcast_ref :: < PyStr > ( ) . unwrap ( ) . as_bytes ( )
672734}
@@ -704,6 +766,37 @@ fn object_lt(
704766 }
705767}
706768
769+ fn elem_lt ( elem : & Elem , a : & PyObjectRef , b : & PyObjectRef , vm : & VirtualMachine ) -> PyResult < bool > {
770+ match elem {
771+ Elem :: Str => Ok ( str_lt ( a, b) ) ,
772+ Elem :: Int => Ok ( int_lt ( a, b) ) ,
773+ Elem :: Float => Ok ( float_lt ( a, b) ) ,
774+ Elem :: Object ( f) => object_lt ( * f, a, b, vm) ,
775+ Elem :: Generic => a. rich_compare_bool ( b, PyComparisonOp :: Lt , vm) ,
776+ }
777+ }
778+
779+ fn tuple_lt ( elem : & Elem , a : & PyObjectRef , b : & PyObjectRef , vm : & VirtualMachine ) -> PyResult < bool > {
780+ let a = a. downcast_ref :: < PyTuple > ( ) . unwrap ( ) . as_slice ( ) ;
781+ let b = b. downcast_ref :: < PyTuple > ( ) . unwrap ( ) . as_slice ( ) ;
782+
783+ let mut i = 0 ;
784+ while i < a. len ( ) && i < b. len ( ) {
785+ if !a[ i] . rich_compare_bool ( & b[ i] , PyComparisonOp :: Eq , vm) ? {
786+ break ;
787+ }
788+ i += 1 ;
789+ }
790+ if i >= a. len ( ) || i >= b. len ( ) {
791+ return Ok ( a. len ( ) < b. len ( ) ) ;
792+ }
793+ if i == 0 {
794+ elem_lt ( elem, & a[ 0 ] , & b[ 0 ] , vm)
795+ } else {
796+ a[ i] . rich_compare_bool ( & b[ i] , PyComparisonOp :: Lt , vm)
797+ }
798+ }
799+
707800fn timsort_specialized < T , K > (
708801 vm : & VirtualMachine ,
709802 items : & mut [ T ] ,
@@ -747,6 +840,14 @@ where
747840 } ;
748841 object_lt ( cmp, a, b, vm)
749842 } ) ,
843+ PreSort :: Tuple ( elem) => timsort ( items, & mut |a, b| {
844+ let ( a, b) = if reverse {
845+ ( key ( b) , key ( a) )
846+ } else {
847+ ( key ( a) , key ( b) )
848+ } ;
849+ tuple_lt ( & elem, a, b, vm)
850+ } ) ,
750851 PreSort :: Generic => timsort ( items, & mut |a, b| {
751852 let ( a, b) = if reverse {
752853 ( key ( b) , key ( a) )
0 commit comments