Skip to content

Commit c4cbeda

Browse files
committed
Extend min builtin function to support key and default.
1 parent 99af466 commit c4cbeda

File tree

2 files changed

+43
-11
lines changed

2 files changed

+43
-11
lines changed
File renamed without changes.

vm/src/builtins.rs

+43-11
Original file line numberDiff line numberDiff line change
@@ -447,8 +447,6 @@ fn builtin_map(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
447447
}
448448

449449
fn builtin_max(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
450-
// arg_check!(vm, args, required = [(x, None), (y, None)]);
451-
452450
let candidates = if args.args.len() > 1 {
453451
args.args.clone()
454452
} else if args.args.len() == 1 {
@@ -502,19 +500,53 @@ fn builtin_max(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
502500
// builtin_memoryview
503501

504502
fn builtin_min(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
505-
arg_check!(
506-
vm,
507-
args,
508-
required = [(x, Some(vm.ctx.int_type())), (y, Some(vm.ctx.int_type()))]
509-
);
503+
let candidates = if args.args.len() > 1 {
504+
args.args.clone()
505+
} else if args.args.len() == 1 {
506+
vm.extract_elements(&args.args[0])?
507+
} else {
508+
// zero arguments means type error:
509+
return Err(vm.new_type_error("Expected 1 or more arguments".to_string()));
510+
};
510511

511-
let order = vm.call_method(x, "__gt__", vec![y.clone()])?;
512+
if candidates.len() == 0 {
513+
let default = args.get_optional_kwarg("default");
514+
if default.is_none() {
515+
return Err(vm.new_value_error("min() arg is an empty sequence".to_string()));
516+
} else {
517+
return Ok(default.unwrap());
518+
}
519+
}
512520

513-
if objbool::get_value(&order) {
514-
Ok(y.clone())
521+
let key_func = args.get_optional_kwarg("key");
522+
523+
let mut candidates_iter = candidates.into_iter();
524+
let mut x = candidates_iter.next().unwrap();
525+
// TODO: this key function looks pretty duplicate. Maybe we can create
526+
// a local function?
527+
let mut x_key = if let Some(f) = &key_func {
528+
let args = PyFuncArgs::new(vec![x.clone()], vec![]);
529+
vm.invoke(f.clone(), args)?
515530
} else {
516-
Ok(x.clone())
531+
x.clone()
532+
};
533+
534+
for y in candidates_iter {
535+
let y_key = if let Some(f) = &key_func {
536+
let args = PyFuncArgs::new(vec![y.clone()], vec![]);
537+
vm.invoke(f.clone(), args)?
538+
} else {
539+
y.clone()
540+
};
541+
let order = vm.call_method(&x_key, "__gt__", vec![y_key.clone()])?;
542+
543+
if objbool::get_value(&order) {
544+
x = y.clone();
545+
x_key = y_key;
546+
}
517547
}
548+
549+
Ok(x)
518550
}
519551

520552
fn builtin_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {

0 commit comments

Comments
 (0)