int duk_bi_array_prototype_sort(duk_context *ctx) { unsigned int len; len = duk__push_this_obj_len_u32(ctx); /* stack[0] = compareFn * stack[1] = ToObject(this) * stack[2] = ToUint32(length) */ duk__array_qsort(ctx, 0, len - 1); DUK_ASSERT_TOP(ctx, 3); duk_pop(ctx); return 1; /* return ToObject(this) */ }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) { duk_uint32_t len; /* XXX: len >= 0x80000000 won't work below because a signed type * is needed by qsort. */ len = duk__push_this_obj_len_u32_limited(ctx); /* stack[0] = compareFn * stack[1] = ToObject(this) * stack[2] = ToUint32(length) */ if (len > 0) { /* avoid degenerate cases, so that (len - 1) won't underflow */ duk__array_qsort(ctx, (duk_int_t) 0, (duk_int_t) (len - 1)); } DUK_ASSERT_TOP(ctx, 3); duk_pop(ctx); return 1; /* return ToObject(this) */ }
DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) { duk_hthread *thr = (duk_hthread *) ctx; duk_int_t p, l, r; /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */ DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T", (long) lo, (long) hi, (duk_tval *) duk_get_tval(ctx, 1))); DUK_ASSERT_TOP(ctx, 3); /* In some cases it may be that lo > hi, or hi < 0; these * degenerate cases happen e.g. for empty arrays, and in * recursion leaves. */ /* trivial cases */ if (hi - lo < 1) { DUK_DDD(DUK_DDDPRINT("degenerate case, return immediately")); return; } DUK_ASSERT(hi > lo); DUK_ASSERT(hi - lo + 1 >= 2); /* randomized pivot selection */ p = lo + (duk_util_tinyrandom_get_bits(thr, 30) % (hi - lo + 1)); /* rnd in [lo,hi] */ DUK_ASSERT(p >= lo && p <= hi); DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", (long) lo, (long) hi, (long) p)); /* move pivot out of the way */ duk__array_sort_swap(ctx, p, lo); p = lo; DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(ctx, 1))); l = lo + 1; r = hi; for (;;) { /* find elements to swap */ for (;;) { DUK_DDD(DUK_DDDPRINT("left scan: l=%ld, r=%ld, p=%ld", (long) l, (long) r, (long) p)); if (l >= hi) { break; } if (duk__array_sort_compare(ctx, l, p) >= 0) { /* !(l < p) */ break; } l++; } for (;;) { DUK_DDD(DUK_DDDPRINT("right scan: l=%ld, r=%ld, p=%ld", (long) l, (long) r, (long) p)); if (r <= lo) { break; } if (duk__array_sort_compare(ctx, p, r) >= 0) { /* !(p < r) */ break; } r--; } if (l >= r) { goto done; } DUK_ASSERT(l < r); DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r)); duk__array_sort_swap(ctx, l, r); DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(ctx, 1))); l++; r--; } done: /* Note that 'l' and 'r' may cross, i.e. r < l */ DUK_ASSERT(l >= lo && l <= hi); DUK_ASSERT(r >= lo && r <= hi); /* XXX: there's no explicit recursion bound here now. For the average * qsort recursion depth O(log n) that's not really necessary: e.g. for * 2**32 recursion depth would be about 32 which is OK. However, qsort * worst case recursion depth is O(n) which may be a problem. */ /* move pivot to its final place */ DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(ctx, 1))); duk__array_sort_swap(ctx, lo, r); #if defined(DUK_USE_DDDPRINT) duk__debuglog_qsort_state(ctx, lo, hi, r); #endif DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(ctx, 1))); duk__array_qsort(ctx, lo, r - 1); duk__array_qsort(ctx, r + 1, hi); }