Skip to content

Commit 3010dd4

Browse files
committed
Cache the richcompare slot for homogeneous list sorts
1 parent b92659d commit 3010dd4

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

crates/vm/src/builtins/list.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
builtins::{PyFloat, PyInt, PyStr},
1313
class::PyClassImpl,
1414
convert::ToPyObject,
15-
function::{ArgSize, FuncArgs, OptionalArg, PyComparisonValue},
15+
function::{ArgSize, Either, FuncArgs, OptionalArg, PyComparisonValue},
1616
iter::PyExactSizeIterator,
1717
protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods},
1818
recursion::ReprGuard,
@@ -21,7 +21,7 @@ use crate::{
2121
sorting::timsort,
2222
types::{
2323
AsMapping, AsSequence, Comparable, Constructor, Initializer, IterNext, Iterable,
24-
PyComparisonOp, Representable, SelfIter,
24+
PyComparisonOp, Representable, RichCompareFunc, SelfIter,
2525
},
2626
vm::VirtualMachine,
2727
};
@@ -639,6 +639,7 @@ enum PreSort {
639639
Str,
640640
Int,
641641
Float,
642+
Object(RichCompareFunc),
642643
Generic,
643644
}
644645

@@ -659,6 +660,8 @@ fn pre_sort_check<'a>(
659660
PreSort::Int
660661
} else if class.is(vm.ctx.types.float_type) {
661662
PreSort::Float
663+
} else if let Some(f) = class.slots.richcompare.load() {
664+
PreSort::Object(f)
662665
} else {
663666
PreSort::Generic
664667
}
@@ -676,6 +679,31 @@ fn float_lt(a: &PyObjectRef, b: &PyObjectRef) -> bool {
676679
a.downcast_ref::<PyFloat>().unwrap().to_f64() < b.downcast_ref::<PyFloat>().unwrap().to_f64()
677680
}
678681

682+
fn object_lt(
683+
cmp: RichCompareFunc,
684+
a: &PyObjectRef,
685+
b: &PyObjectRef,
686+
vm: &VirtualMachine,
687+
) -> PyResult<bool> {
688+
#[allow(unpredictable_function_pointer_comparisons)]
689+
if a.class().slots.richcompare.load() != Some(cmp) {
690+
return a.rich_compare_bool(b, PyComparisonOp::Lt, vm);
691+
}
692+
match cmp(a, b, PyComparisonOp::Lt, vm)? {
693+
Either::B(PyComparisonValue::Implemented(v)) => Ok(v),
694+
Either::B(PyComparisonValue::NotImplemented) => {
695+
a.rich_compare_bool(b, PyComparisonOp::Lt, vm)
696+
}
697+
Either::A(obj) => {
698+
if obj.is(&vm.ctx.not_implemented) {
699+
a.rich_compare_bool(b, PyComparisonOp::Lt, vm)
700+
} else {
701+
obj.try_to_bool(vm)
702+
}
703+
}
704+
}
705+
}
706+
679707
fn timsort_specialized<T, K>(
680708
vm: &VirtualMachine,
681709
items: &mut [T],
@@ -711,6 +739,14 @@ where
711739
};
712740
Ok(float_lt(a, b))
713741
}),
742+
PreSort::Object(cmp) => timsort(items, &mut |a, b| {
743+
let (a, b) = if reverse {
744+
(key(b), key(a))
745+
} else {
746+
(key(a), key(b))
747+
};
748+
object_lt(cmp, a, b, vm)
749+
}),
714750
PreSort::Generic => timsort(items, &mut |a, b| {
715751
let (a, b) = if reverse {
716752
(key(b), key(a))

extra_tests/snippets/builtin_list.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ class IntSub(int):
256256
assert_raises(TypeError, sorted, [1, "a"])
257257
nan = float("nan")
258258
assert repr(sorted([nan, 1.0, 2.0])) == "[nan, 1.0, 2.0]"
259+
assert sorted([b"b", b"a", b"c"]) == [b"a", b"b", b"c"]
259260

260261
lst = [3, 1, 5, 2, 4]
261262

0 commit comments

Comments
 (0)