diff --git a/src/array.c b/src/array.c index 1d3983209..53ed02038 100644 --- a/src/array.c +++ b/src/array.c @@ -2081,6 +2081,79 @@ mrb_ary_delete(mrb_state *mrb, mrb_value self) #define SMALL_ARRAY_SORT_THRESHOLD 16 +/* Check if all elements in the array are integers (fast path candidate) */ +static mrb_bool +ary_all_fixnum_p(const mrb_value *a, mrb_int n) +{ + for (mrb_int i = 0; i < n; i++) { + if (!mrb_integer_p(a[i])) return FALSE; + } + return TRUE; +} + +/* Integer-specialized heapify: no sort_cmp overhead, direct comparison */ +static void +heapify_fixnum(mrb_value *a, mrb_int index, mrb_int size) +{ + mrb_int val = mrb_integer(a[index]); + + while (1) { + mrb_int child = 2 * index + 1; + if (child >= size) break; + if (child + 1 < size && mrb_integer(a[child + 1]) > mrb_integer(a[child])) { + child++; + } + if (mrb_integer(a[child]) <= val) break; + a[index] = a[child]; + index = child; + } + SET_FIXNUM_VALUE(a[index], val); +} + +/* Integer-specialized Floyd's bottom-up heap deletion */ +static void +heap_delete_root_fixnum(mrb_value *a, mrb_int size) +{ + mrb_int last = mrb_integer(a[0]); + + mrb_int hole = 0; + mrb_int child = 1; + while (child + 1 < size) { + if (mrb_integer(a[child + 1]) > mrb_integer(a[child])) { + child++; + } + a[hole] = a[child]; + hole = child; + child = 2 * hole + 1; + } + if (child < size) { + a[hole] = a[child]; + hole = child; + } + + while (hole > 0) { + mrb_int parent = (hole - 1) / 2; + if (mrb_integer(a[parent]) >= last) break; + a[hole] = a[parent]; + hole = parent; + } + SET_FIXNUM_VALUE(a[hole], last); +} + +/* Integer-specialized insertion sort */ +static void +insertion_sort_fixnum(mrb_value *a, mrb_int size) +{ + for (mrb_int i = 1; i < size; i++) { + mrb_int key = mrb_integer(a[i]); + mrb_int j = i - 1; + while (j >= 0 && mrb_integer(a[j]) > key) { + a[j + 1] = a[j]; + j--; + } + SET_FIXNUM_VALUE(a[j + 1], key); + } +} static mrb_bool sort_cmp(mrb_state *mrb, mrb_value ary, mrb_value a_val, mrb_value b_val, mrb_value blk) @@ -2243,7 +2316,26 @@ mrb_ary_sort_bang(mrb_state *mrb, mrb_value ary) mrb_value *a = RARRAY_PTR(ary); - /* Algorithm selection based on array size */ + /* Integer fast path: no block and all elements are integers */ + if (mrb_nil_p(blk) && ary_all_fixnum_p(a, n)) { + if (n <= SMALL_ARRAY_SORT_THRESHOLD) { + insertion_sort_fixnum(a, n); + } + else { + for (mrb_int i = n / 2 - 1; i >= 0; i--) { + heapify_fixnum(a, i, n); + } + for (mrb_int i = n - 1; i > 0; i--) { + mrb_value tmp = a[0]; + a[0] = a[i]; + a[i] = tmp; + heap_delete_root_fixnum(a, i); + } + } + return ary; + } + + /* General path */ if (n <= SMALL_ARRAY_SORT_THRESHOLD) { /* Use insertion sort for small arrays */ insertion_sort(mrb, ary, a, n, blk);