@@ -277,10 +277,20 @@ static mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) {
277277 return ret ;
278278}
279279
280+ // "head" is actually the *exclusive lower bound* of the range to sort. That is,
281+ // the first element to be sorted is `head[1]`, not `head[0]`. Similarly `tail`
282+ // is an *inclusive upper bound* of the range to sort. That is, the final
283+ // element to sort is `tail[0]`, not `tail[-1]`.
284+ //
285+ // The pivot element is always chosen as `tail[0]`.
286+ //
287+ // These unusual choices allows structuring the partitioning
288+ // process as a do/while loop, which generates smaller code than the equivalent
289+ // code with usual C bounds & a while or for loop.
280290static void mp_quicksort (mp_obj_t * head , mp_obj_t * tail , mp_obj_t key_fn , mp_obj_t binop_less_result ) {
281291 mp_cstack_check ();
282- while (head < tail ) {
283- mp_obj_t * h = head - 1 ;
292+ while (tail - head > 1 ) { // So long as at least 2 elements remain
293+ mp_obj_t * h = head ;
284294 mp_obj_t * t = tail ;
285295 mp_obj_t v = key_fn == MP_OBJ_NULL ? tail [0 ] : mp_call_function_1 (key_fn , tail [0 ]); // get pivot using key_fn
286296 for (;;) {
@@ -291,19 +301,21 @@ static void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj
291301 if (h >= t ) {
292302 break ;
293303 }
304+ // A pair of objects must be swapped to the other side of the partition
294305 mp_obj_t x = h [0 ];
295306 h [0 ] = t [0 ];
296307 t [0 ] = x ;
297308 }
309+ // Place the pivot element in the proper position
298310 mp_obj_t x = h [0 ];
299311 h [0 ] = tail [0 ];
300312 tail [0 ] = x ;
301313 // do the smaller recursive call first, to keep stack within O(log(N))
302- if (t - head < tail - h - 1 ) {
314+ if (t - head < tail - h ) {
303315 mp_quicksort (head , t , key_fn , binop_less_result );
304- head = h + 1 ;
316+ head = h ;
305317 } else {
306- mp_quicksort (h + 1 , tail , key_fn , binop_less_result );
318+ mp_quicksort (h , tail , key_fn , binop_less_result );
307319 tail = t ;
308320 }
309321 }
@@ -327,7 +339,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
327339 mp_obj_list_t * self = MP_OBJ_TO_PTR (pos_args [0 ]);
328340
329341 if (self -> len > 1 ) {
330- mp_quicksort (self -> items , self -> items + self -> len - 1 ,
342+ mp_quicksort (self -> items - 1 , self -> items + self -> len - 1 ,
331343 args .key .u_obj == mp_const_none ? MP_OBJ_NULL : args .key .u_obj ,
332344 args .reverse .u_bool ? mp_const_false : mp_const_true );
333345 }
0 commit comments