From 002bec256adcfa1ff41ba1437dbe912ae01ee8c5 Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 1 Sep 2022 11:46:59 -0700 Subject: [PATCH 1/5] have sort_with_indices allocate. Add a couple convenience procs for using the indices result to sort other slices. --- core/slice/sort.odin | 33 +++++++++++++++++++++++---- tests/core/slice/test_core_slice.odin | 14 ++++-------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/core/slice/sort.odin b/core/slice/sort.odin index 779ba37fd..5319fbaaa 100644 --- a/core/slice/sort.odin +++ b/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) { diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 12577ab20..8caf911e8 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/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 } } -} \ No newline at end of file +} From d45661c405bfb36c0e4dd385d1f87721f3e8feba Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 1 Sep 2022 11:51:45 -0700 Subject: [PATCH 2/5] cleanup slice sorting with indices changes --- core/slice/sort.odin | 6 +++--- tests/core/slice/test_core_slice.odin | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/slice/sort.odin b/core/slice/sort.odin index 5319fbaaa..e0303a65a 100644 --- a/core/slice/sort.odin +++ b/core/slice/sort.odin @@ -60,17 +60,17 @@ sort_by_indices_overwrite :: proc(data: $T/[]$E, indices: []int) { // 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 { - 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 indices } - return nil + return indices } // sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j" diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 8caf911e8..08dc2d3ae 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -51,8 +51,11 @@ test_sort_with_indices :: proc(t: ^testing.T) { r := rand.create(seed) vals := make([]u64, test_size) - defer delete(vals) r_idx := make([]int, test_size) // Reverse index + defer { + delete(vals) + delete(r_idx) + } // Set up test values for _, i in vals { From 7a9b0731cf6e57043c46b8cf4e7b4dba0e4af7c1 Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 1 Sep 2022 12:13:15 -0700 Subject: [PATCH 3/5] add tests for sort_by_indices --- core/slice/sort.odin | 3 +- tests/core/slice/test_core_slice.odin | 65 +++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/core/slice/sort.odin b/core/slice/sort.odin index e0303a65a..01d762ad7 100644 --- a/core/slice/sort.odin +++ b/core/slice/sort.odin @@ -45,11 +45,12 @@ sort_by_indices :: proc(data: $T/[]$E, indices: []int, allocator := context.allo for v, i in indices { sorted[i] = data[v] } + return } sort_by_indices_overwrite :: proc(data: $T/[]$E, indices: []int) { assert(len(data) == len(indices)) - temp := make([]int, len(data), context.temp_allocator) + temp := make([]int, len(data), context.allocator) defer delete(temp) for v, i in indices { temp[i] = data[v] diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 08dc2d3ae..fb13364fd 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -92,3 +92,68 @@ test_sort_with_indices :: proc(t: ^testing.T) { } } } + +@test +test_sort_by_indices :: proc(t: ^testing.T) { + seed := rand.uint64() + fmt.printf("Random seed: %v\n", seed) + + // Test sizes are all prime. + test_sizes :: []int{7, 13, 347, 1031, 10111, 100003} + + for test_size in test_sizes { + fmt.printf("Sorting %v random u64 values along with index.\n", test_size) + + r := rand.create(seed) + + vals := make([]u64, test_size) + r_idx := make([]int, test_size) // Reverse index + defer { + delete(vals) + delete(r_idx) + } + + // Set up test values + for _, i in vals { + vals[i] = rand.uint64(&r) + } + + // Sort + f_idx := slice.sort_with_indices(vals) + defer delete(f_idx) + + // Verify sorted test values + rand.init(&r, seed) + + { + indices := make([]int, test_size) + for _, i in indices { + indices[i] = i + } + + sorted_indices := slice.sort_by_indices(indices, f_idx) + for v, i in sorted_indices { + idx_pass := v == f_idx[i] + expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices") + if !idx_pass { + break + } + } + } + { + indices := make([]int, test_size) + for _, i in indices { + indices[i] = i + } + + slice.sort_by_indices_overwrite(indices, f_idx) + for v, i in indices { + idx_pass := v == f_idx[i] + expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices") + if !idx_pass { + break + } + } + } + } +} From 63eec25044d1abc6665ce8409c21e6d58e6aca8a Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 1 Sep 2022 12:32:33 -0700 Subject: [PATCH 4/5] add sort_by_indices overload and test --- core/slice/sort.odin | 12 +++++++++++- tests/core/slice/test_core_slice.odin | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/core/slice/sort.odin b/core/slice/sort.odin index 01d762ad7..8020cede7 100644 --- a/core/slice/sort.odin +++ b/core/slice/sort.odin @@ -39,7 +39,9 @@ sort :: proc(data: $T/[]$E) where ORD(E) { } -sort_by_indices :: proc(data: $T/[]$E, indices: []int, allocator := context.allocator) -> (sorted: T) { +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([]int, len(data), allocator) for v, i in indices { @@ -48,6 +50,14 @@ sort_by_indices :: proc(data: $T/[]$E, indices: []int, allocator := context.allo 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([]int, len(data), context.allocator) diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index fb13364fd..8ef3af869 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -155,5 +155,21 @@ test_sort_by_indices :: proc(t: ^testing.T) { } } } + { + indices := make([]int, test_size) + swap := make([]int, test_size) + for _, i in indices { + indices[i] = i + } + + slice.sort_by_indices(indices, swap, f_idx) + for v, i in swap { + idx_pass := v == f_idx[i] + expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices") + if !idx_pass { + break + } + } + } } } From 12966301609b460076c6358efb2413286307fb7d Mon Sep 17 00:00:00 2001 From: Phil Date: Thu, 1 Sep 2022 12:34:08 -0700 Subject: [PATCH 5/5] cleanup tests --- tests/core/slice/test_core_slice.odin | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 8ef3af869..05dfb58ff 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -127,11 +127,13 @@ test_sort_by_indices :: proc(t: ^testing.T) { { indices := make([]int, test_size) + defer delete(indices) for _, i in indices { indices[i] = i } sorted_indices := slice.sort_by_indices(indices, f_idx) + defer delete(sorted_indices) for v, i in sorted_indices { idx_pass := v == f_idx[i] expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices") @@ -142,6 +144,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { } { indices := make([]int, test_size) + defer delete(indices) for _, i in indices { indices[i] = i } @@ -158,6 +161,10 @@ test_sort_by_indices :: proc(t: ^testing.T) { { indices := make([]int, test_size) swap := make([]int, test_size) + defer { + delete(indices) + delete(swap) + } for _, i in indices { indices[i] = i }