123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- 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
- }
|