Skip to content

Commit

Permalink
Merge pull request #761 from dictu-lang/feature/sort
Browse files Browse the repository at this point in the history
Fix Sorting
  • Loading branch information
Jason2605 authored Dec 8, 2024
2 parents bce42e8 + 2563076 commit ecdba28
Show file tree
Hide file tree
Showing 7 changed files with 2,063 additions and 89 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macOS-latest, macOS-13, macOS-12]
os: [macOS-latest, macOS-15, macOS-13]

steps:
- uses: actions/checkout@v3
Expand Down
4 changes: 4 additions & 0 deletions ops/checkTests.du
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ const ignored = {
'read.txt',
'read2.txt',
],
'lists': [
'sorted.txt',
'unsorted.txt',
],
'strings': [
'test',
],
Expand Down
105 changes: 17 additions & 88 deletions src/vm/datatypes/lists/lists.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,91 +309,6 @@ static Value copyListDeep(DictuVM *vm, int argCount, Value *args) {
return OBJ_VAL(list);
}


int compareString(ObjString *operandOne, ObjString *operandTwo) {
return strcmp(operandOne->chars, operandTwo->chars);
}

static int partitionStringList(ObjList *arr, int start, int end) {
int pivot_index = (int) floor(start + end) / 2;

ObjString *pivot = AS_STRING(arr->values.values[pivot_index]);

int i = start - 1;
int j = end + 1;

for (;;) {
do {
i = i + 1;
} while (compareString(AS_STRING(arr->values.values[i]), pivot) < 0);

do {
j = j - 1;
} while (compareString(AS_STRING(arr->values.values[j]), pivot) > 0);

if (i >= j) {
return j;
}

// Swap arr[i] with arr[j]
Value temp = arr->values.values[i];

arr->values.values[i] = arr->values.values[j];
arr->values.values[j] = temp;
}
}


static int partitionNumberList(ObjList *arr, int start, int end) {
int pivot_index = (int) floor(start + end) / 2;

double pivot = AS_NUMBER(arr->values.values[pivot_index]);

int i = start - 1;
int j = end + 1;

for (;;) {
do {
i = i + 1;
} while (AS_NUMBER(arr->values.values[i]) < pivot);

do {
j = j - 1;
} while (AS_NUMBER(arr->values.values[j]) > pivot);

if (i >= j) {
return j;
}

// Swap arr[i] with arr[j]
Value temp = arr->values.values[i];

arr->values.values[i] = arr->values.values[j];
arr->values.values[j] = temp;
}
}

// Implementation of Quick Sort using the Hoare
// Partition scheme.
// Best Case O(n log n)
// Worst Case O(n^2) (If the list is already sorted.)
static void quickSort(ObjList *arr, int start, int end, int (*partition)(ObjList *, int, int)) {
while (start < end) {
int part = partition(arr, start, end);

// Recurse for the smaller halve.
if (part - start < end - part) {
quickSort(arr, start, part, partition);

start = start + 1;
} else {
quickSort(arr, part + 1, end, partition);

end = end - 1;
}
}
}

bool isNumberList(ObjList *list) {
for (int i = 0; i < list->values.count; i++) {
if (!IS_NUMBER(list->values.values[i])) {
Expand All @@ -412,6 +327,20 @@ bool isStringList(ObjList *list) {
return true;
}

int compareNumbers(const void* a, const void* b) {
Value aVal = *(Value *)a;
Value bVal = *(Value *)b;

return AS_NUMBER(aVal) - AS_NUMBER(bVal);
}

int compareString(const void* a, const void* b) {
Value aVal = *(Value *)a;
Value bVal = *(Value *)b;

return utf8cmp(AS_CSTRING(aVal), AS_CSTRING(bVal));
}

static Value sortList(DictuVM *vm, int argCount, Value *args) {
if (argCount != 0) {
runtimeError(vm, "sort() takes no arguments (%d given)", argCount);
Expand All @@ -421,17 +350,17 @@ static Value sortList(DictuVM *vm, int argCount, Value *args) {
ObjList *list = AS_LIST(args[0]);

if (isNumberList(list)) {
quickSort(list, 0, list->values.count - 1, &partitionNumberList);
qsort(list->values.values, list->values.count, sizeof(*list->values.values), compareNumbers);
return NIL_VAL;
}

if (isStringList(list)) {
quickSort(list, 0, list->values.count - 1, &partitionStringList);
qsort(list->values.values, list->values.count, sizeof(*list->values.values), compareString);
return NIL_VAL;
}

runtimeError(vm,
"sort() takes lists with either numbers or string (other types and heterotypic lists are not supported)");
"sort() takes lists with either numbers or string (other types and heterogeneous lists are not supported)");
return EMPTY_VAL;
}

Expand Down
1 change: 1 addition & 0 deletions src/vm/datatypes/lists/lists.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "../copy.h"
#include "../../util.h"
#include "../../utf8.h"

void declareListMethods(DictuVM *vm);

Expand Down
40 changes: 40 additions & 0 deletions tests/lists/sort.du
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,46 @@ class TestListSort < UnitTest {
z.sort();
this.assertEquals(z, ["abc", "abc", "cde", "cde"]);
}

testStringLargeSort() {
var contents;
with("tests/lists/unsorted.txt", "r") {
contents = file.read();
}

const listContents = contents.split("\n");
listContents.sort();

with("tests/lists/sorted.txt", "r") {
var line;
var index = 0;
// When you reach the end of the file, nil is returned
while((line = file.readLine()) != nil) {
this.assertEquals(listContents[index], line);
index += 1;
}
}
}

testNumberLargeSort() {
var contents;
with("tests/lists/unsorted.txt", "r") {
contents = file.read();
}

const listContents = contents.split("\n");
listContents.sort();

with("tests/lists/sorted.txt", "r") {
var line;
var index = 0;
// When you reach the end of the file, nil is returned
while((line = file.readLine()) != nil) {
this.assertEquals(listContents[index].toNumber().unwrap(), line.toNumber().unwrap());
index += 1;
}
}
}
}

TestListSort().run();
Loading

0 comments on commit ecdba28

Please sign in to comment.