diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 426829a22..5fecc76b1 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -305,21 +305,21 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) - } scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U)->V, allocator := context.allocator) -> []V { - if len(s) == 0 { return {} } + if len(s) == 0 { return {} } - res := make([]V, len(s), allocator) - p := as_ptr(s) - q := as_ptr(res) - r := initializer + res := make([]V, len(s), allocator) + p := as_ptr(s) + q := as_ptr(res) + r := initializer - for l := len(s); l > 0; l -= 1 { - r = f(r, p[0]) - q[0] = r - p = p[1:] - q = q[1:] - } + for l := len(s); l > 0; l -= 1 { + r = f(r, p[0]) + q[0] = r + p = p[1:] + q = q[1:] + } - return res + return res } diff --git a/core/slice/sort.odin b/core/slice/sort.odin index 24bce79af..8a2dec039 100644 --- a/core/slice/sort.odin +++ b/core/slice/sort.odin @@ -56,6 +56,32 @@ sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) { } } +// stable_sort sorts a slice +stable_sort :: proc(data: $T/[]$E) where ORD(E) { + when size_of(E) != 0 { + if n := len(data); n > 1 { + _stable_sort_general(data, struct{}{}, .Ordered) + } + } +} + +// stable_sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j" +stable_sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) { + when size_of(E) != 0 { + if n := len(data); n > 1 { + _stable_sort_general(data, less, .Less) + } + } +} + +stable_sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) { + when size_of(E) != 0 { + if n := len(data); n > 1 { + _stable_sort_general(data, cmp, .Cmp) + } + } +} + is_sorted :: proc(array: $T/[]$E) -> bool where ORD(E) { for i := len(array)-1; i > 0; i -= 1 { if array[i] < array[i-1] { diff --git a/core/slice/sort_private.odin b/core/slice/sort_private.odin index 3b990c1e7..05e4d5eed 100644 --- a/core/slice/sort_private.odin +++ b/core/slice/sort_private.odin @@ -175,3 +175,26 @@ _quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND insertion_sort(data, a, b, call) } } + + +// merge sort +_stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check { + less :: #force_inline proc(a, b: $E, call: $P) -> bool { + when KIND == .Ordered { + return a < b + } else when KIND == .Less { + return call(a, b) + } else when KIND == .Cmp { + return call(a, b) == .Less + } else { + #panic("unhandled Sort_Kind") + } + } + + n := len(data) + for i in 1.. 0 && less(data[j], data[j-1], call); j -= 1 { + swap(data, j, j-1) + } + } +}