From c5b2bdae112d37a6ed7ca7010752f048f08b1e27 Mon Sep 17 00:00:00 2001 From: Steve Perkins Date: Wed, 2 Nov 2016 18:10:44 -0400 Subject: [PATCH 1/4] quicksort --- std/sort.zig | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 std/sort.zig diff --git a/std/sort.zig b/std/sort.zig new file mode 100644 index 0000000000..d95ef3b2c0 --- /dev/null +++ b/std/sort.zig @@ -0,0 +1,65 @@ +const assert = @import("debug.zig").assert; +const str = @import("str.zig"); + +pub fn sort(inline T: type, array: []T) { + if (array.len > 0) { + quicksort(T, array, 0, array.len - 1); + } +} + +fn quicksort(inline T: type, array: []T, left: usize, right: usize) { + var i = left; + var j = right; + var p = (i + j) / 2; + + while (i <= j) { + while (array[i] < array[p]) { + i += 1; + } + while (array[j] > array[p]) { + j -= 1; + } + if (i <= j) { + const tmp = array[i]; + array[i] = array[j]; + array[j] = tmp; + i += 1; + if (j > 0) j -= 1; + } + } + + if (left < j) quicksort(T, array, left, j); + if (i < right) quicksort(T, array, i, right); +} + +fn testSort() { + @setFnTest(this, true); + + const u8cases = [][][]u8 { + [][]u8{"", ""}, + [][]u8{"a", "a"}, + [][]u8{"az", "az"}, + [][]u8{"za", "az"}, + [][]u8{"asdf", "adfs"}, + [][]u8{"one", "eno"}, + }; + + for (u8cases) |case| { + sort(u8, case[0]); + assert(str.eql(case[0], case[1])); + } + + const i32cases = [][][]i32 { + [][]i32{[]i32{}, []i32{}}, + [][]i32{[]i32{1}, []i32{1}}, + [][]i32{[]i32{0, 1}, []i32{0, 1}}, + [][]i32{[]i32{1, 0}, []i32{0, 1}}, + [][]i32{[]i32{1, -1, 0}, []i32{-1, 0, 1}}, + [][]i32{[]i32{2, 1, 3}, []i32{1, 2, 3}}, + }; + + for (i32cases) |case| { + sort(i32, case[0]); + assert(str.sliceEql(i32, case[0], case[1])); + } +} From e761aa2d2f0034b1b6a071c4dae5262ef96997fb Mon Sep 17 00:00:00 2001 From: Steve Perkins Date: Wed, 2 Nov 2016 18:52:00 -0400 Subject: [PATCH 2/4] sortCmp allows for a custom cmp function --- std/sort.zig | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/std/sort.zig b/std/sort.zig index d95ef3b2c0..15302e5fb0 100644 --- a/std/sort.zig +++ b/std/sort.zig @@ -1,5 +1,8 @@ const assert = @import("debug.zig").assert; const str = @import("str.zig"); +const math = @import("math.zig"); + +pub const Cmp = math.Cmp; pub fn sort(inline T: type, array: []T) { if (array.len > 0) { @@ -32,6 +35,43 @@ fn quicksort(inline T: type, array: []T, left: usize, right: usize) { if (i < right) quicksort(T, array, i, right); } +// --------------------------------------- +// sortCmp + +pub fn sortCmp(inline T: type, array: []T, inline cmp: fn(a: T, b: T)->Cmp) { + if (array.len > 0) { + quicksortCmp(T, array, 0, array.len - 1, cmp); + } +} + +fn quicksortCmp(inline T: type, array: []T, left: usize, right: usize, inline cmp: fn(a: T, b: T)->Cmp) { + var i = left; + var j = right; + var p = (i + j) / 2; + + while (i <= j) { + while (cmp(array[i], array[p]) == Cmp.Less) { + i += 1; + } + while (cmp(array[j], array[p]) == Cmp.Greater) { + j -= 1; + } + if (i <= j) { + const tmp = array[i]; + array[i] = array[j]; + array[j] = tmp; + i += 1; + if (j > 0) j -= 1; + } + } + + if (left < j) quicksortCmp(T, array, left, j, cmp); + if (i < right) quicksortCmp(T, array, i, right, cmp); +} + +// --------------------------------------- +// tests + fn testSort() { @setFnTest(this, true); @@ -63,3 +103,44 @@ fn testSort() { assert(str.sliceEql(i32, case[0], case[1])); } } + +fn testSortCmp() { + @setFnTest(this, true); + + const i32cases = [][][]i32 { + [][]i32{[]i32{}, []i32{}}, + [][]i32{[]i32{1}, []i32{1}}, + [][]i32{[]i32{0, 1}, []i32{0, 1}}, + [][]i32{[]i32{1, 0}, []i32{0, 1}}, + [][]i32{[]i32{1, -1, 0}, []i32{-1, 0, 1}}, + [][]i32{[]i32{2, 1, 3}, []i32{1, 2, 3}}, + }; + + for (i32cases) |case| { + sortCmp(i32, case[0], normalCmp); + assert(str.sliceEql(i32, case[0], case[1])); + } + + const revCases = [][][]i32 { + [][]i32{[]i32{}, []i32{}}, + [][]i32{[]i32{1}, []i32{1}}, + [][]i32{[]i32{0, 1}, []i32{1, 0}}, + [][]i32{[]i32{1, 0}, []i32{1, 0}}, + [][]i32{[]i32{1, -1, 0}, []i32{1, 0, -1}}, + [][]i32{[]i32{2, 1, 3}, []i32{3, 2, 1}}, + }; + + for (revCases) |case| { + sortCmp(i32, case[0], revCmp); + assert(str.sliceEql(i32, case[0], case[1])); + } + +} + +fn normalCmp(a: i32, b: i32) -> Cmp { + return if (a > b) Cmp.Greater else if (a < b) Cmp.Less else Cmp.Equal; +} + +fn revCmp(a: i32, b: i32) -> Cmp { + return if (a < b) Cmp.Greater else if (a > b) Cmp.Less else Cmp.Equal; +} From cf00245bf9367f9a8ce11739372b4899639cdccf Mon Sep 17 00:00:00 2001 From: Steve Perkins Date: Thu, 3 Nov 2016 04:10:33 +0000 Subject: [PATCH 3/4] sort requires compare function. Provide some handy functions for builtin comparable types. --- std/sort.zig | 93 ++++++++++++++++------------------------------------ 1 file changed, 29 insertions(+), 64 deletions(-) diff --git a/std/sort.zig b/std/sort.zig index 15302e5fb0..af65cd3a59 100644 --- a/std/sort.zig +++ b/std/sort.zig @@ -4,47 +4,13 @@ const math = @import("math.zig"); pub const Cmp = math.Cmp; -pub fn sort(inline T: type, array: []T) { +pub fn sort(inline T: type, array: []T, inline cmp: fn(a: T, b: T)->Cmp) { if (array.len > 0) { - quicksort(T, array, 0, array.len - 1); + quicksort(T, array, 0, array.len - 1, cmp); } } -fn quicksort(inline T: type, array: []T, left: usize, right: usize) { - var i = left; - var j = right; - var p = (i + j) / 2; - - while (i <= j) { - while (array[i] < array[p]) { - i += 1; - } - while (array[j] > array[p]) { - j -= 1; - } - if (i <= j) { - const tmp = array[i]; - array[i] = array[j]; - array[j] = tmp; - i += 1; - if (j > 0) j -= 1; - } - } - - if (left < j) quicksort(T, array, left, j); - if (i < right) quicksort(T, array, i, right); -} - -// --------------------------------------- -// sortCmp - -pub fn sortCmp(inline T: type, array: []T, inline cmp: fn(a: T, b: T)->Cmp) { - if (array.len > 0) { - quicksortCmp(T, array, 0, array.len - 1, cmp); - } -} - -fn quicksortCmp(inline T: type, array: []T, left: usize, right: usize, inline cmp: fn(a: T, b: T)->Cmp) { +fn quicksort(inline T: type, array: []T, left: usize, right: usize, inline cmp: fn(a: T, b: T)->Cmp) { var i = left; var j = right; var p = (i + j) / 2; @@ -65,8 +31,28 @@ fn quicksortCmp(inline T: type, array: []T, left: usize, right: usize, inline cm } } - if (left < j) quicksortCmp(T, array, left, j, cmp); - if (i < right) quicksortCmp(T, array, i, right, cmp); + if (left < j) quicksort(T, array, left, j, cmp); + if (i < right) quicksort(T, array, i, right, cmp); +} + +pub fn i32asc(a: i32, b: i32) -> Cmp { + return if (a > b) Cmp.Greater else if (a < b) Cmp.Less else Cmp.Equal; +} + +pub fn i32desc(a: i32, b: i32) -> Cmp { + return reverse(i32asc(a, b)); +} + +pub fn u8asc(a: u8, b: u8) -> Cmp { + return if (a > b) Cmp.Greater else if (a < b) Cmp.Less else Cmp.Equal; +} + +pub fn u8desc(a: u8, b: u8) -> Cmp { + return reverse(u8asc(a, b)); +} + +fn reverse(was: Cmp) -> Cmp { + return if (was == Cmp.Greater) Cmp.Less else if (was == Cmp.Less) Cmp.Greater else Cmp.Equal; } // --------------------------------------- @@ -85,7 +71,7 @@ fn testSort() { }; for (u8cases) |case| { - sort(u8, case[0]); + sort(u8, case[0], u8asc); assert(str.eql(case[0], case[1])); } @@ -99,28 +85,14 @@ fn testSort() { }; for (i32cases) |case| { - sort(i32, case[0]); + sort(i32, case[0], i32asc); assert(str.sliceEql(i32, case[0], case[1])); } } -fn testSortCmp() { +fn testSortDesc() { @setFnTest(this, true); - const i32cases = [][][]i32 { - [][]i32{[]i32{}, []i32{}}, - [][]i32{[]i32{1}, []i32{1}}, - [][]i32{[]i32{0, 1}, []i32{0, 1}}, - [][]i32{[]i32{1, 0}, []i32{0, 1}}, - [][]i32{[]i32{1, -1, 0}, []i32{-1, 0, 1}}, - [][]i32{[]i32{2, 1, 3}, []i32{1, 2, 3}}, - }; - - for (i32cases) |case| { - sortCmp(i32, case[0], normalCmp); - assert(str.sliceEql(i32, case[0], case[1])); - } - const revCases = [][][]i32 { [][]i32{[]i32{}, []i32{}}, [][]i32{[]i32{1}, []i32{1}}, @@ -131,16 +103,9 @@ fn testSortCmp() { }; for (revCases) |case| { - sortCmp(i32, case[0], revCmp); + sort(i32, case[0], i32desc); assert(str.sliceEql(i32, case[0], case[1])); } } -fn normalCmp(a: i32, b: i32) -> Cmp { - return if (a > b) Cmp.Greater else if (a < b) Cmp.Less else Cmp.Equal; -} - -fn revCmp(a: i32, b: i32) -> Cmp { - return if (a < b) Cmp.Greater else if (a > b) Cmp.Less else Cmp.Equal; -} From 4b55966a160b1fc79a666770e3d163f52331164a Mon Sep 17 00:00:00 2001 From: Steve Perkins Date: Thu, 3 Nov 2016 07:01:40 +0000 Subject: [PATCH 4/4] add sort to CMakeLists + std/index --- CMakeLists.txt | 1 + std/index.zig | 1 + 2 files changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 375a007341..e08a55002b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,6 +222,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/os.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}") +install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/str.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_libc.zig" DESTINATION "${ZIG_STD_DEST}") diff --git a/std/index.zig b/std/index.zig index 0b7333b138..95d9e80e7c 100644 --- a/std/index.zig +++ b/std/index.zig @@ -4,6 +4,7 @@ pub const os = @import("os.zig"); pub const math = @import("math.zig"); pub const str = @import("str.zig"); pub const cstr = @import("cstr.zig"); +pub const sort = @import("sort.zig"); pub const net = @import("net.zig"); pub const list = @import("list.zig"); pub const hash_map = @import("hash_map.zig");