mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
add basic quicksort support (#816)
* lib/std/sort: refactor binarysearch namespace to prepare for sorting Signed-off-by: Pierre Curto <pierre.curto@gmail.com> * std/lib/sort: add basic quicksort support Signed-off-by: Pierre Curto <pierre.curto@gmail.com> * lib/std/hash: use method first parameter inferred type Signed-off-by: Pierre Curto <pierre.curto@gmail.com> * lib/std/hash: add fnv64a support Signed-off-by: Pierre Curto <pierre.curto@gmail.com> --------- Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
@@ -8,17 +8,17 @@ struct Crc32
|
||||
uint result;
|
||||
}
|
||||
|
||||
fn void Crc32.init(Crc32* this, uint seed = 0)
|
||||
fn void Crc32.init(&this, uint seed = 0)
|
||||
{
|
||||
this.result = ~seed;
|
||||
}
|
||||
|
||||
fn void Crc32.updatec(Crc32* this, char c)
|
||||
fn void Crc32.updatec(&this, char c)
|
||||
{
|
||||
this.result = (this.result >> 8) ^ CRC32_TABLE[(this.result ^ c) & 0xFF];
|
||||
}
|
||||
|
||||
fn void Crc32.update(Crc32* this, char[] data)
|
||||
fn void Crc32.update(&this, char[] data)
|
||||
{
|
||||
uint result = this.result;
|
||||
foreach (char x : data)
|
||||
@@ -28,7 +28,7 @@ fn void Crc32.update(Crc32* this, char[] data)
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
fn uint Crc32.final(Crc32* this)
|
||||
fn uint Crc32.final(&this)
|
||||
{
|
||||
return ~this.result;
|
||||
}
|
||||
|
||||
@@ -8,17 +8,17 @@ struct Crc64
|
||||
ulong result;
|
||||
}
|
||||
|
||||
fn void Crc64.init(Crc64* this, uint seed = 0)
|
||||
fn void Crc64.init(&this, uint seed = 0)
|
||||
{
|
||||
this.result = seed;
|
||||
}
|
||||
|
||||
fn void Crc64.updatec(Crc64* this, char c)
|
||||
fn void Crc64.updatec(&this, char c)
|
||||
{
|
||||
this.result = (this.result << 8) ^ CRC64_TABLE[(char)((this.result >> 56) ^ c)];
|
||||
}
|
||||
|
||||
fn void Crc64.update(Crc64* this, char[] data)
|
||||
fn void Crc64.update(&this, char[] data)
|
||||
{
|
||||
ulong result = this.result;
|
||||
foreach (char x : data)
|
||||
@@ -28,7 +28,7 @@ fn void Crc64.update(Crc64* this, char[] data)
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
fn ulong Crc64.final(Crc64* this)
|
||||
fn ulong Crc64.final(&this)
|
||||
{
|
||||
return this.result;
|
||||
}
|
||||
|
||||
@@ -10,12 +10,12 @@ const FNV32A_MUL @private = 0x01000193;
|
||||
|
||||
macro void @update(uint &h, char x) @private => h = (h * FNV32A_MUL) ^ x;
|
||||
|
||||
fn void Fnv32a.init(Fnv32a* this)
|
||||
fn void Fnv32a.init(&this)
|
||||
{
|
||||
*this = FNV32A_START;
|
||||
}
|
||||
|
||||
fn void Fnv32a.update(Fnv32a* this, char[] data)
|
||||
fn void Fnv32a.update(&this, char[] data)
|
||||
{
|
||||
uint h = (uint)*this;
|
||||
foreach (char x : data)
|
||||
@@ -25,7 +25,7 @@ fn void Fnv32a.update(Fnv32a* this, char[] data)
|
||||
*this = (Fnv32a)h;
|
||||
}
|
||||
|
||||
macro void Fnv32a.update_char(Fnv32a* this, char c)
|
||||
macro void Fnv32a.update_char(&this, char c)
|
||||
{
|
||||
@update(*this, x);
|
||||
}
|
||||
|
||||
41
lib/std/hash/fnv64a.c3
Normal file
41
lib/std/hash/fnv64a.c3
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::hash::fnv64a;
|
||||
|
||||
def Fnv64a = distinct ulong;
|
||||
|
||||
const FNV64A_START @private = 0xcbf29ce484222325;
|
||||
const FNV64A_MUL @private = 0x00000100000001b3;
|
||||
|
||||
macro void @update(ulong &h, char x) @private => h = (h * FNV64A_MUL) ^ x;
|
||||
|
||||
fn void Fnv64a.init(&this)
|
||||
{
|
||||
*this = FNV64A_START;
|
||||
}
|
||||
|
||||
fn void Fnv64a.update(&this, char[] data)
|
||||
{
|
||||
ulong h = (ulong)*this;
|
||||
foreach (char x : data)
|
||||
{
|
||||
@update(h, x);
|
||||
}
|
||||
*this = (Fnv64a)h;
|
||||
}
|
||||
|
||||
macro void Fnv64a.update_char(&this, char c)
|
||||
{
|
||||
@update(*this, x);
|
||||
}
|
||||
|
||||
fn ulong encode(char[] data)
|
||||
{
|
||||
ulong h = FNV64A_START;
|
||||
foreach (char x : data)
|
||||
{
|
||||
@update(h, x);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
module std::sort::binarysearch;
|
||||
module std::sort;
|
||||
|
||||
/**
|
||||
* Perform a binary search over the sorted array and return the smallest index
|
||||
* in [0, array.len) where cmp(i) is true and cmp(j) is true for j in [i, array.len).
|
||||
* @require is_searchable(list) "The list must be indexable and support .len or .len()"
|
||||
* @require is_comparer(cmp, list) "Expeced a comparison function which compares values"
|
||||
* @require is_comparer(cmp, list) "Expected a comparison function which compares values"
|
||||
**/
|
||||
macro usz cmp_search(list, x, cmp)
|
||||
macro usz binarysearch_with(list, x, cmp)
|
||||
{
|
||||
usz i;
|
||||
usz len = @len_from_list(list);
|
||||
@@ -34,7 +34,7 @@ macro usz cmp_search(list, x, cmp)
|
||||
* @require is_searchable(list) "The list must be indexable and support .len or .len()"
|
||||
* @checked less(list[0], x) "The values must be comparable"
|
||||
**/
|
||||
macro usz search(list, x)
|
||||
macro usz binarysearch(list, x)
|
||||
{
|
||||
usz i;
|
||||
usz len = @len_from_list(list);
|
||||
@@ -48,24 +48,4 @@ macro usz search(list, x)
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
macro bool is_searchable(list) @local
|
||||
{
|
||||
return $checks(list[0]) && ($checks(list.len) || $checks(list.len()));
|
||||
}
|
||||
|
||||
macro usz @len_from_list(&list) @local
|
||||
{
|
||||
$if $checks(list.len()):
|
||||
return list.len();
|
||||
$else
|
||||
return list.len;
|
||||
$endif
|
||||
}
|
||||
|
||||
macro bool is_comparer(cmp, list)
|
||||
{
|
||||
return $checks(int i = cmp(list[0], list[0]))
|
||||
|| $checks(int i = cmp(&list[0], &list[0]));
|
||||
}
|
||||
}
|
||||
66
lib/std/sort/quicksort.c3
Normal file
66
lib/std/sort/quicksort.c3
Normal file
@@ -0,0 +1,66 @@
|
||||
module std::sort;
|
||||
|
||||
/**
|
||||
* @require is_searchable(list) "The list must be indexable and support .len or .len()"
|
||||
**/
|
||||
macro quicksort(list, $Type)
|
||||
{
|
||||
(($Type)(list)).sort(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require is_searchable(list) "The list must be indexable and support .len or .len()"
|
||||
* @require is_comparer(cmp, list) "Expected a comparison function which compares values"
|
||||
**/
|
||||
macro quicksort_with(list, $Type, cmp)
|
||||
{
|
||||
(($Type)(list)).sort(cmp);
|
||||
}
|
||||
|
||||
module std::sort::quicksort<Type, Comparer>;
|
||||
import std::sort;
|
||||
|
||||
def Quicksort = distinct Type[];
|
||||
|
||||
fn void Quicksort.sort(qs, Comparer cmp)
|
||||
{
|
||||
usz len = sort::@len_from_list(qs);
|
||||
qs.qsort(0, (isz)len - 1, cmp);
|
||||
}
|
||||
|
||||
fn void Quicksort.qsort(Quicksort qs, isz low, isz high, Comparer cmp) @private
|
||||
{
|
||||
if (low < high)
|
||||
{
|
||||
isz p = qs.partition(low, high, cmp);
|
||||
qs.qsort(low, p - 1, cmp);
|
||||
qs.qsort(p + 1, high, cmp);
|
||||
}
|
||||
}
|
||||
|
||||
fn isz Quicksort.partition(qs, isz low, isz high, Comparer cmp) @inline @private
|
||||
{
|
||||
Type pivot = qs[high];
|
||||
isz i = low - 1;
|
||||
for (isz j = low; j < high; j++)
|
||||
{
|
||||
$if $checks(cmp(qs[0], qs[0])):
|
||||
int res = cmp(qs[j], pivot);
|
||||
$else
|
||||
$if $checks(cmp(&qs[0], &qs[0])):
|
||||
int res = cmp(&qs[j], &pivot);
|
||||
$else
|
||||
int res;
|
||||
if (greater(qs[j], pivot)) res = 1;
|
||||
$endif
|
||||
$endif
|
||||
if (res <= 0)
|
||||
{
|
||||
i++;
|
||||
@swap(qs[i], qs[j]);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
@swap(qs[i], qs[high]);
|
||||
return i;
|
||||
}
|
||||
21
lib/std/sort/sort.c3
Normal file
21
lib/std/sort/sort.c3
Normal file
@@ -0,0 +1,21 @@
|
||||
module std::sort;
|
||||
|
||||
macro bool is_searchable(list)
|
||||
{
|
||||
return $checks(list[0]) && ($checks(list.len) || $checks(list.len()));
|
||||
}
|
||||
|
||||
macro usz @len_from_list(&list)
|
||||
{
|
||||
$if $checks(list.len()):
|
||||
return list.len();
|
||||
$else
|
||||
return list.len;
|
||||
$endif
|
||||
}
|
||||
|
||||
macro bool is_comparer(cmp, list)
|
||||
{
|
||||
return $checks(int i = cmp(list[0], list[0]))
|
||||
|| $checks(int i = cmp(&list[0], &list[0]));
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
module binarysearch_test @test;
|
||||
import std::sort::binarysearch;
|
||||
module sort_test @test;
|
||||
import std::sort;
|
||||
|
||||
struct SearchTest
|
||||
struct BinarySearchTest
|
||||
{
|
||||
int[] data;
|
||||
int x;
|
||||
int index;
|
||||
}
|
||||
|
||||
fn void search()
|
||||
fn void binarysearch()
|
||||
{
|
||||
SearchTest[] tcases = {
|
||||
BinarySearchTest[] tcases = {
|
||||
{ {}, 0, 0 },
|
||||
{ {1, 2, 3}, 1, 0 },
|
||||
{ {1, 2, 3}, 2, 1 },
|
||||
@@ -22,28 +22,17 @@ fn void search()
|
||||
|
||||
foreach (tc : tcases)
|
||||
{
|
||||
usz idx = binarysearch::search(tc.data, tc.x);
|
||||
usz idx = sort::binarysearch(tc.data, tc.x);
|
||||
assert(idx == tc.index, "%s: got %d; want %d", tc.data, idx, tc.index);
|
||||
|
||||
usz cmp_idx = binarysearch::cmp_search(tc.data, tc.x, &cmp_int);
|
||||
usz cmp_idx = sort::binarysearch_with(tc.data, tc.x, &sort::cmp_int);
|
||||
assert(cmp_idx == tc.index, "%s: got %d; want %d", tc.data, cmp_idx, tc.index);
|
||||
|
||||
usz cmp_idx2 = binarysearch::cmp_search(tc.data, tc.x, &cmp_int2);
|
||||
usz cmp_idx2 = sort::binarysearch_with(tc.data, tc.x, &sort::cmp_int2);
|
||||
assert(cmp_idx2 == tc.index, "%s: got %d; want %d", tc.data, cmp_idx2, tc.index);
|
||||
|
||||
usz cmp_idx3 = binarysearch::cmp_search(tc.data, tc.x, fn int(int a, int b) => a - b);
|
||||
usz cmp_idx3 = sort::binarysearch_with(tc.data, tc.x, fn int(int a, int b) => a - b);
|
||||
assert(cmp_idx3 == tc.index, "%s: got %d; want %d", tc.data, cmp_idx2, tc.index);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module binarysearch_test;
|
||||
|
||||
fn int cmp_int(void* x, void* y) {
|
||||
return *(int*)x - *(int*)y;
|
||||
}
|
||||
|
||||
fn int cmp_int2(int x, int y) {
|
||||
return x - y;
|
||||
}
|
||||
|
||||
}
|
||||
92
test/unit/stdlib/sort/quicksort.c3
Normal file
92
test/unit/stdlib/sort/quicksort.c3
Normal file
@@ -0,0 +1,92 @@
|
||||
module sort_test @test;
|
||||
import std::sort;
|
||||
import std::sort::quicksort;
|
||||
|
||||
def QSInt = quicksort::Quicksort<int, void*>;
|
||||
|
||||
fn void quicksort()
|
||||
{
|
||||
int[][] tcases = {
|
||||
{},
|
||||
{10, 3},
|
||||
{3, 2, 1},
|
||||
{1, 2, 3},
|
||||
{2, 1, 3},
|
||||
};
|
||||
|
||||
foreach (tc : tcases)
|
||||
{
|
||||
sort::quicksort(tc, QSInt);
|
||||
assert(sort::check_int_sort(tc));
|
||||
}
|
||||
}
|
||||
|
||||
def Cmp = fn int (void*, void*);
|
||||
def QSIntCmp = quicksort::Quicksort<int, Cmp>;
|
||||
|
||||
fn void quicksort_with()
|
||||
{
|
||||
int[][] tcases = {
|
||||
{},
|
||||
{10, 3},
|
||||
{3, 2, 1},
|
||||
{1, 2, 3},
|
||||
{2, 1, 3},
|
||||
};
|
||||
|
||||
foreach (tc : tcases)
|
||||
{
|
||||
sort::quicksort_with(tc, QSIntCmp, &sort::cmp_int);
|
||||
assert(sort::check_int_sort(tc));
|
||||
}
|
||||
}
|
||||
|
||||
def Cmp2 = fn int (int, int);
|
||||
def QSIntCmp2 = quicksort::Quicksort<int, Cmp2>;
|
||||
|
||||
fn void quicksort_with2()
|
||||
{
|
||||
int[][] tcases = {
|
||||
{},
|
||||
{10, 3},
|
||||
{3, 2, 1},
|
||||
{1, 2, 3},
|
||||
{2, 1, 3},
|
||||
};
|
||||
|
||||
foreach (tc : tcases)
|
||||
{
|
||||
sort::quicksort_with(tc, QSIntCmp2, &sort::cmp_int2);
|
||||
assert(sort::check_int_sort(tc));
|
||||
}
|
||||
}
|
||||
|
||||
fn void quicksort_with_lambda()
|
||||
{
|
||||
int[][] tcases = {
|
||||
{},
|
||||
{10, 3},
|
||||
{3, 2, 1},
|
||||
{1, 2, 3},
|
||||
{2, 1, 3},
|
||||
};
|
||||
|
||||
foreach (tc : tcases)
|
||||
{
|
||||
sort::quicksort_with(tc, QSIntCmp2, fn int(int a, int b) => a - b);
|
||||
assert(sort::check_int_sort(tc));
|
||||
}
|
||||
}
|
||||
|
||||
module std::sort;
|
||||
|
||||
fn bool check_int_sort(int[] list)
|
||||
{
|
||||
int prev = int.min;
|
||||
foreach (x : list)
|
||||
{
|
||||
if (prev > x) return false;
|
||||
prev = x;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
9
test/unit/stdlib/sort/sort.c3
Normal file
9
test/unit/stdlib/sort/sort.c3
Normal file
@@ -0,0 +1,9 @@
|
||||
module std::sort;
|
||||
|
||||
fn int cmp_int(void* x, void* y) {
|
||||
return *(int*)x - *(int*)y;
|
||||
}
|
||||
|
||||
fn int cmp_int2(int x, int y) {
|
||||
return x - y;
|
||||
}
|
||||
Reference in New Issue
Block a user