@@ -3,8 +3,8 @@ use std::cell::{Cell, RefCell};
33use super :: objbool;
44use super :: objint;
55use super :: objsequence:: {
6- get_elements, get_item, get_mut_elements, seq_equal, seq_ge, seq_gt, seq_le, seq_lt , seq_mul ,
7- PySliceableSequence ,
6+ get_elements, get_elements_cell , get_item, get_mut_elements, seq_equal, seq_ge, seq_gt, seq_le,
7+ seq_lt , seq_mul , PySliceableSequence ,
88} ;
99use super :: objstr;
1010use super :: objtype;
@@ -334,12 +334,99 @@ fn list_reverse(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
334334 Ok ( vm. get_none ( ) )
335335}
336336
337+ fn quicksort (
338+ vm : & mut VirtualMachine ,
339+ keys : & mut [ PyObjectRef ] ,
340+ values : & mut [ PyObjectRef ] ,
341+ ) -> PyResult < ( ) > {
342+ let len = values. len ( ) ;
343+ if len >= 2 {
344+ let pivot = partition ( vm, keys, values) ?;
345+ quicksort ( vm, & mut keys[ 0 ..pivot] , & mut values[ 0 ..pivot] ) ?;
346+ quicksort ( vm, & mut keys[ pivot + 1 ..len] , & mut values[ pivot + 1 ..len] ) ?;
347+ }
348+ Ok ( ( ) )
349+ }
350+
351+ fn partition (
352+ vm : & mut VirtualMachine ,
353+ keys : & mut [ PyObjectRef ] ,
354+ values : & mut [ PyObjectRef ] ,
355+ ) -> PyResult < usize > {
356+ let len = values. len ( ) ;
357+ let pivot = len / 2 ;
358+
359+ values. swap ( pivot, len - 1 ) ;
360+ keys. swap ( pivot, len - 1 ) ;
361+
362+ let mut store_idx = 0 ;
363+ for i in 0 ..len - 1 {
364+ let result = vm. _lt ( keys[ i] . clone ( ) , keys[ len - 1 ] . clone ( ) ) ?;
365+ let boolval = objbool:: boolval ( vm, result) ?;
366+ if boolval {
367+ values. swap ( i, store_idx) ;
368+ keys. swap ( i, store_idx) ;
369+ store_idx += 1 ;
370+ }
371+ }
372+
373+ values. swap ( store_idx, len - 1 ) ;
374+ keys. swap ( store_idx, len - 1 ) ;
375+ Ok ( store_idx)
376+ }
377+
378+ fn do_sort (
379+ vm : & mut VirtualMachine ,
380+ values : & mut Vec < PyObjectRef > ,
381+ key_func : Option < PyObjectRef > ,
382+ reverse : bool ,
383+ ) -> PyResult < ( ) > {
384+ // build a list of keys. If no keyfunc is provided, it's a copy of the list.
385+ let mut keys: Vec < PyObjectRef > = vec ! [ ] ;
386+ for x in values. iter ( ) {
387+ keys. push ( match & key_func {
388+ None => x. clone ( ) ,
389+ Some ( ref func) => vm. invoke (
390+ ( * func) . clone ( ) ,
391+ PyFuncArgs {
392+ args : vec ! [ x. clone( ) ] ,
393+ kwargs : vec ! [ ] ,
394+ } ,
395+ ) ?,
396+ } ) ;
397+ }
398+
399+ quicksort ( vm, & mut keys, values) ?;
400+
401+ if reverse {
402+ values. reverse ( ) ;
403+ }
404+
405+ Ok ( ( ) )
406+ }
407+
337408fn list_sort ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
338409 arg_check ! ( vm, args, required = [ ( list, Some ( vm. ctx. list_type( ) ) ) ] ) ;
339- let mut _elements = get_mut_elements ( list) ;
340- unimplemented ! ( "TODO: figure out how to invoke `sort_by` on a Vec" ) ;
341- // elements.sort_by();
342- // Ok(vm.get_none())
410+ let key_func = args. get_optional_kwarg ( "key" ) ;
411+ let reverse = args. get_optional_kwarg ( "reverse" ) ;
412+ let reverse = match reverse {
413+ None => false ,
414+ Some ( val) => objbool:: boolval ( vm, val) ?,
415+ } ;
416+
417+ let elements_cell = get_elements_cell ( list) ;
418+ // replace list contents with [] for duration of sort.
419+ // this prevents keyfunc from messing with the list and makes it easy to
420+ // check if it tries to append elements to it.
421+ let mut elements = elements_cell. replace ( vec ! [ ] ) ;
422+ do_sort ( vm, & mut elements, key_func, reverse) ?;
423+ let temp_elements = elements_cell. replace ( elements) ;
424+
425+ if !temp_elements. is_empty ( ) {
426+ return Err ( vm. new_value_error ( "list modified during sort" . to_string ( ) ) ) ;
427+ }
428+
429+ Ok ( vm. get_none ( ) )
343430}
344431
345432fn list_contains ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
0 commit comments