mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-13 09:22:22 -07:00
241 lines
5.7 KiB
Odin
241 lines
5.7 KiB
Odin
package slice
|
|
|
|
Ordering :: enum {
|
|
Less = -1,
|
|
Equal = 0,
|
|
Greater = +1,
|
|
}
|
|
|
|
@(require_results)
|
|
cmp :: proc(a, b: $E) -> Ordering where ORD(E) {
|
|
switch {
|
|
case a < b:
|
|
return .Less
|
|
case a > b:
|
|
return .Greater
|
|
}
|
|
return .Equal
|
|
}
|
|
|
|
@(require_results)
|
|
cmp_proc :: proc($E: typeid) -> (proc(E, E) -> Ordering) where ORD(E) {
|
|
return proc(a, b: E) -> Ordering {
|
|
switch {
|
|
case a < b:
|
|
return .Less
|
|
case a > b:
|
|
return .Greater
|
|
}
|
|
return .Equal
|
|
}
|
|
}
|
|
|
|
// sort sorts a slice
|
|
// This sort is not guaranteed to be stable
|
|
sort :: proc(data: $T/[]$E) where ORD(E) {
|
|
when size_of(E) != 0 {
|
|
if n := len(data); n > 1 {
|
|
_quick_sort_general(data, 0, n, _max_depth(n), struct{}{}, .Ordered)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
sort_by_indices :: proc{ sort_by_indices_allocate, _sort_by_indices}
|
|
|
|
sort_by_indices_allocate :: proc(data: $T/[]$E, indices: []int, allocator := context.allocator) -> (sorted: T) {
|
|
assert(len(data) == len(indices))
|
|
sorted = make(T, len(data), allocator)
|
|
for v, i in indices {
|
|
sorted[i] = data[v]
|
|
}
|
|
return
|
|
}
|
|
|
|
_sort_by_indices :: proc(data, sorted: $T/[]$E, indices: []int) {
|
|
assert(len(data) == len(indices))
|
|
assert(len(data) == len(sorted))
|
|
for v, i in indices {
|
|
sorted[i] = data[v]
|
|
}
|
|
}
|
|
|
|
sort_by_indices_overwrite :: proc(data: $T/[]$E, indices: []int) {
|
|
assert(len(data) == len(indices))
|
|
temp := make([]E, len(data), context.allocator)
|
|
defer delete(temp)
|
|
for v, i in indices {
|
|
temp[i] = data[v]
|
|
}
|
|
swap_with_slice(data, temp)
|
|
}
|
|
|
|
// sort sorts a slice and returns a slice of the original indices
|
|
// This sort is not guaranteed to be stable
|
|
sort_with_indices :: proc(data: $T/[]$E, allocator := context.allocator) -> (indices: []int) where ORD(E) {
|
|
indices = make([]int, len(data), allocator)
|
|
when size_of(E) != 0 {
|
|
if n := len(data); n > 1 {
|
|
for _, idx in indices {
|
|
indices[idx] = idx
|
|
}
|
|
_quick_sort_general_with_indices(data, indices, 0, n, _max_depth(n), struct{}{}, .Ordered)
|
|
}
|
|
return indices
|
|
}
|
|
return indices
|
|
}
|
|
|
|
// sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j"
|
|
// This sort is not guaranteed to be stable
|
|
sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
|
|
when size_of(E) != 0 {
|
|
if n := len(data); n > 1 {
|
|
_quick_sort_general(data, 0, n, _max_depth(n), less, .Less)
|
|
}
|
|
}
|
|
}
|
|
|
|
// sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j"
|
|
// This sort is not guaranteed to be stable
|
|
sort_by_with_indices :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool, allocator := context.allocator) -> (indices : []int) {
|
|
indices = make([]int, len(data), allocator)
|
|
when size_of(E) != 0 {
|
|
if n := len(data); n > 1 {
|
|
for _, idx in indices {
|
|
indices[idx] = idx
|
|
}
|
|
_quick_sort_general_with_indices(data, indices, 0, n, _max_depth(n), less, .Less)
|
|
return indices
|
|
}
|
|
}
|
|
return indices
|
|
}
|
|
|
|
sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) {
|
|
when size_of(E) != 0 {
|
|
if n := len(data); n > 1 {
|
|
_quick_sort_general(data, 0, n, _max_depth(n), cmp, .Cmp)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
}
|
|
|
|
@(require_results)
|
|
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] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
@(require_results)
|
|
is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool {
|
|
for i := len(array)-1; i > 0; i -= 1 {
|
|
if less(array[i], array[i-1]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
is_sorted_by_cmp :: is_sorted_cmp
|
|
|
|
@(require_results)
|
|
is_sorted_cmp :: proc(array: $T/[]$E, cmp: proc(i, j: E) -> Ordering) -> bool {
|
|
for i := len(array)-1; i > 0; i -= 1 {
|
|
if cmp(array[i], array[i-1]) == .Less {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
|
|
|
|
reverse_sort :: proc(data: $T/[]$E) where ORD(E) {
|
|
sort_by(data, proc(i, j: E) -> bool {
|
|
return j < i
|
|
})
|
|
}
|
|
|
|
|
|
reverse_sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
|
|
context._internal = rawptr(less)
|
|
sort_by(data, proc(i, j: E) -> bool {
|
|
k := (proc(i, j: E) -> bool)(context._internal)
|
|
return k(j, i)
|
|
})
|
|
}
|
|
|
|
reverse_sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) {
|
|
context._internal = rawptr(cmp)
|
|
sort_by_cmp(data, proc(i, j: E) -> Ordering {
|
|
k := (proc(i, j: E) -> Ordering)(context._internal)
|
|
return k(j, i)
|
|
})
|
|
}
|
|
|
|
|
|
// TODO(bill): Should `sort_by_key` exist or is `sort_by` more than enough?
|
|
sort_by_key :: proc(data: $T/[]$E, key: proc(E) -> $K) where ORD(K) {
|
|
context._internal = rawptr(key)
|
|
sort_by(data, proc(i, j: E) -> bool {
|
|
k := (proc(E) -> K)(context._internal)
|
|
return k(i) < k(j)
|
|
})
|
|
}
|
|
|
|
reverse_sort_by_key :: proc(data: $T/[]$E, key: proc(E) -> $K) where ORD(K) {
|
|
context._internal = rawptr(key)
|
|
sort_by(data, proc(i, j: E) -> bool {
|
|
k := (proc(E) -> K)(context._internal)
|
|
return k(j) < k(i)
|
|
})
|
|
}
|
|
|
|
@(require_results)
|
|
is_sorted_by_key :: proc(array: $T/[]$E, key: proc(E) -> $K) -> bool where ORD(K) {
|
|
for i := len(array)-1; i > 0; i -= 1 {
|
|
if key(array[i]) < key(array[i-1]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
@(private, require_results)
|
|
_max_depth :: proc(n: int) -> (depth: int) { // 2*ceil(log2(n+1))
|
|
for i := n; i > 0; i >>= 1 {
|
|
depth += 1
|
|
}
|
|
return depth * 2
|
|
}
|