Browse Source

have sort_with_indices allocate. Add a couple convenience procs for using the indices result to sort other slices.

Phil 3 years ago
parent
commit
002bec256a
2 changed files with 32 additions and 15 deletions
  1. 28 5
      core/slice/sort.odin
  2. 4 10
      tests/core/slice/test_core_slice.odin

+ 28 - 5
core/slice/sort.odin

@@ -38,18 +38,39 @@ sort :: proc(data: $T/[]$E) where ORD(E) {
 	}
 }
 
-// sort sorts a slice
+
+sort_by_indices :: proc(data: $T/[]$E, indices: []int, allocator := context.allocator) -> (sorted: T) {
+	assert(len(data) == len(indices))
+	sorted = make([]int, len(data), allocator)
+	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([]int, len(data), context.temp_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, indices: []int) where ORD(E) {
+sort_with_indices :: proc(data: $T/[]$E, allocator := context.allocator) -> (indices: []int) where ORD(E) {
 	when size_of(E) != 0 {
 		if n := len(data); n > 1 {
-			assert(len(data) == len(indices))
+			indices = make([]int, len(data), allocator)
 			for _, idx in indices {
 				indices[idx] = idx
 			}
 			_quick_sort_general_with_indices(data, indices, 0, n, _max_depth(n), struct{}{}, .Ordered)
+			return indices
 		}
 	}
+	return nil
 }
 
 // sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j"
@@ -64,16 +85,18 @@ sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
 
 // 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, indices: []int, less: proc(i, j: E) -> bool) {
+sort_by_with_indices :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool, allocator := context.allocator) -> (indices : []int) {
 	when size_of(E) != 0 {
 		if n := len(data); n > 1 {
-			assert(len(data) == len(indices))
+			indices = make([]int, len(data), allocator)
 			for _, idx in indices {
 				indices[idx] = idx
 			}
 			_quick_sort_general_with_indices(data, indices, 0, n, _max_depth(n), less, .Less)
+			return indices
 		}
 	}
+	return nil
 }
 
 sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) {

+ 4 - 10
tests/core/slice/test_core_slice.odin

@@ -51,23 +51,17 @@ test_sort_with_indices :: proc(t: ^testing.T) {
 		r := rand.create(seed)
 
 		vals  := make([]u64, test_size)
-		f_idx := make([]int, test_size) // Forward index, will be sorted
+		defer delete(vals)
 		r_idx := make([]int, test_size) // Reverse index
 
-		defer {
-			delete(vals)
-			delete(f_idx)
-			delete(r_idx)
-		}
-
 		// Set up test values
 		for _, i in vals {
 			vals[i]     = rand.uint64(&r)
-			f_idx[i] = i
 		}
 
 		// Sort
-		slice.sort_with_indices(vals, f_idx)
+		f_idx := slice.sort_with_indices(vals)
+		defer delete(f_idx)
 
 		// Verify sorted test values
 		rand.init(&r, seed)
@@ -94,4 +88,4 @@ test_sort_with_indices :: proc(t: ^testing.T) {
 			last = v
 		}
 	}
-}
+}