STATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj_t binop_less_result) { MP_STACK_CHECK(); while (head < tail) { mp_obj_t *h = head - 1; mp_obj_t *t = tail; mp_obj_t v = key_fn == MP_OBJ_NULL ? tail[0] : mp_call_function_1(key_fn, tail[0]); // get pivot using key_fn for (;;) { do ++h; while (h < t && mp_binary_op(MP_BINARY_OP_LESS, key_fn == MP_OBJ_NULL ? h[0] : mp_call_function_1(key_fn, h[0]), v) == binop_less_result); do --t; while (h < t && mp_binary_op(MP_BINARY_OP_LESS, v, key_fn == MP_OBJ_NULL ? t[0] : mp_call_function_1(key_fn, t[0])) == binop_less_result); if (h >= t) break; mp_obj_t x = h[0]; h[0] = t[0]; t[0] = x; } mp_obj_t x = h[0]; h[0] = tail[0]; tail[0] = x; // do the smaller recursive call first, to keep stack within O(log(N)) if (t - head < tail - h - 1) { mp_quicksort(head, t, key_fn, binop_less_result); head = h + 1; } else { mp_quicksort(h + 1, tail, key_fn, binop_less_result); tail = t; } } }
static mp_obj_t list_sort(mp_obj_t self_in, mp_obj_t key_fn) { assert(MP_OBJ_IS_TYPE(self_in, &list_type)); mp_obj_list_t *self = self_in; if (self->len > 1) { mp_quicksort(self->items, self->items + self->len - 1, key_fn); } return mp_const_none; // return None, as per CPython }
mp_obj_t mp_obj_list_sort(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) { assert(n_args >= 1); assert(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); if (n_args > 1) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "list.sort takes no positional arguments")); } mp_obj_list_t *self = args[0]; if (self->len > 1) { mp_map_elem_t *keyfun = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_key), MP_MAP_LOOKUP); mp_map_elem_t *reverse = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), MP_MAP_LOOKUP); mp_quicksort(self->items, self->items + self->len - 1, keyfun ? keyfun->value : NULL, reverse && reverse->value ? mp_obj_is_true(reverse->value) : false); } return mp_const_none; // return None, as per CPython }
// TODO make this conform to CPython's definition of sort static void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn) { while (head < tail) { mp_obj_t *h = head - 1; mp_obj_t *t = tail; mp_obj_t v = rt_call_function_1(key_fn, tail[0]); // get pivot using key_fn for (;;) { do ++h; while (rt_compare_op(RT_COMPARE_OP_LESS, rt_call_function_1(key_fn, h[0]), v) == mp_const_true); do --t; while (h < t && rt_compare_op(RT_COMPARE_OP_LESS, v, rt_call_function_1(key_fn, t[0])) == mp_const_true); if (h >= t) break; mp_obj_t x = h[0]; h[0] = t[0]; t[0] = x; } mp_obj_t x = h[0]; h[0] = tail[0]; tail[0] = x; mp_quicksort(head, t, key_fn); head = h + 1; } }
// TODO make this conform to CPython's definition of sort STATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, bool reversed) { int op = reversed ? MP_BINARY_OP_MORE : MP_BINARY_OP_LESS; while (head < tail) { mp_obj_t *h = head - 1; mp_obj_t *t = tail; mp_obj_t v = key_fn == NULL ? tail[0] : mp_call_function_1(key_fn, tail[0]); // get pivot using key_fn for (;;) { do ++h; while (mp_binary_op(op, key_fn == NULL ? h[0] : mp_call_function_1(key_fn, h[0]), v) == mp_const_true); do --t; while (h < t && mp_binary_op(op, v, key_fn == NULL ? t[0] : mp_call_function_1(key_fn, t[0])) == mp_const_true); if (h >= t) break; mp_obj_t x = h[0]; h[0] = t[0]; t[0] = x; } mp_obj_t x = h[0]; h[0] = tail[0]; tail[0] = x; mp_quicksort(head, t, key_fn, reversed); head = h + 1; } }