Browse Source

Add `slice.stable_sort*` procedures

gingerBill 3 years ago
parent
commit
14a17fb36f
3 changed files with 61 additions and 12 deletions
  1. 12 12
      core/slice/slice.odin
  2. 26 0
      core/slice/sort.odin
  3. 23 0
      core/slice/sort_private.odin

+ 12 - 12
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
 }
 
 

+ 26 - 0
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] {

+ 23 - 0
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..<n {
+		for j := i; j > 0 && less(data[j], data[j-1], call); j -= 1 {
+			swap(data, j, j-1)
+		}
+	}
+}