Add RocStr.eq function & simplify tests; Normalize func/var naming

This commit is contained in:
Jared Ramirez 2020-10-29 08:56:11 -07:00
parent aa0eff1645
commit c47c7f3d96

View file

@ -17,198 +17,226 @@ export fn pow_int_(base: i64, exp: i64) i64 {
// Str.split // Str.split
const RocStr = struct { const RocStr = struct {
str_bytes: [*]u8, strBytesPtrs: [*]u8,
str_len: usize, strLen: usize,
pub fn init(bytes: [*]u8, len: usize) RocStr { pub fn init(bytes: [*]u8, len: usize) RocStr {
return RocStr { return RocStr {
.str_bytes = bytes, .strBytesPtrs = bytes,
.str_len = len .strLen = len
}; };
} }
pub fn eq(self: RocStr, other: RocStr) bool {
if (self.strLen != other.strLen) {
return false;
}
var areEq: bool = true;
var index: usize = 0;
while (index < self.strLen and areEq) {
areEq = areEq and self.strBytesPtrs[index] == other.strBytesPtrs[index];
index = index + 1;
}
return areEq;
}
test "RocStr.eq: equal" {
const str1Len = 3;
var str1: [str1Len]u8 = "abc".*;
const str1Ptr: [*]u8 = &str1;
var rocStr1 = RocStr.init(str1Ptr, str1Len);
const str2Len = 3;
var str2: [str2Len]u8 = "abc".*;
const str2Ptr: [*]u8 = &str2;
var rocStr2 = RocStr.init(str2Ptr, str2Len);
expect(RocStr.eq(rocStr1, rocStr2));
}
test "RocStr.eq: not equal different length" {
const str1Len = 4;
var str1: [str1Len]u8 = "abcd".*;
const str1Ptr: [*]u8 = &str1;
var rocStr1 = RocStr.init(str1Ptr, str1Len);
const str2Len = 3;
var str2: [str2Len]u8 = "abc".*;
const str2Ptr: [*]u8 = &str2;
var rocStr2 = RocStr.init(str2Ptr, str2Len);
expect(!RocStr.eq(rocStr1, rocStr2));
}
test "RocStr.eq: not equal same length" {
const str1Len = 3;
var str1: [str1Len]u8 = "acb".*;
const str1Ptr: [*]u8 = &str1;
var rocStr1 = RocStr.init(str1Ptr, str1Len);
const str2Len = 3;
var str2: [str2Len]u8 = "abc".*;
const str2Ptr: [*]u8 = &str2;
var rocStr2 = RocStr.init(str2Ptr, str2Len);
expect(!RocStr.eq(rocStr1, rocStr2));
}
}; };
export fn str_split_in_place_( export fn str_split_in_place_(
list: [*]RocStr, array: [*]RocStr,
list_len: usize, arrayLen: usize,
str_bytes: [*]u8, strBytesPtrs: [*]u8,
str_len: usize, strLen: usize,
delimiter_bytes: [*]u8, delimiterBytes: [*]u8,
delimiter_len: usize delimiterLen: usize
) void { ) void {
var ret_list_index : usize = 0; var retArrayIndex : usize = 0;
var slice_start_index : usize = 0; var sliceStartIndex : usize = 0;
var str_index : usize = 0; var strIndex : usize = 0;
if (str_len > delimiter_len) { if (strLen > delimiterLen) {
const end_index : usize = str_len - delimiter_len; const endIndex : usize = strLen - delimiterLen;
while (str_index <= end_index) { while (strIndex <= endIndex) {
var delimiter_index : usize = 0; var delimiterIndex : usize = 0;
var matches_delimiter = true; var matchesDelimiter = true;
while (delimiter_index < delimiter_len) { while (delimiterIndex < delimiterLen) {
var delimiter_char = delimiter_bytes[delimiter_index]; var delimiterChar = delimiterBytes[delimiterIndex];
var str_char = str_bytes[str_index + delimiter_index]; var strChar = strBytesPtrs[strIndex + delimiterIndex];
if (delimiter_char != str_char) { if (delimiterChar != strChar) {
matches_delimiter = false; matchesDelimiter = false;
break; break;
} }
delimiter_index += 1; delimiterIndex += 1;
} }
if (matches_delimiter) { if (matchesDelimiter) {
list[ret_list_index] = RocStr.init(str_bytes + slice_start_index, str_index - slice_start_index); array[retArrayIndex] = RocStr.init(strBytesPtrs + sliceStartIndex, strIndex - sliceStartIndex);
slice_start_index = str_index + delimiter_len; sliceStartIndex = strIndex + delimiterLen;
ret_list_index += 1; retArrayIndex += 1;
str_index += delimiter_len; strIndex += delimiterLen;
} else { } else {
str_index += 1; strIndex += 1;
} }
} }
} }
list[ret_list_index] = RocStr.init(str_bytes + slice_start_index, str_len - slice_start_index); array[retArrayIndex] = RocStr.init(strBytesPtrs + sliceStartIndex, strLen - sliceStartIndex);
} }
test "str_split_in_place_ no delimiter" { test "str_split_in_place_: no delimiter" {
// Str.split "abc" "!" == [ "abc" ] // Str.split "abc" "!" == [ "abc" ]
var str: [3]u8 = "abc".*; var str: [3]u8 = "abc".*;
const str_ptr: [*]u8 = &str; const strPtr: [*]u8 = &str;
var delimiter: [1]u8 = "!".*; var delimiter: [1]u8 = "!".*;
const delimiter_ptr: [*]u8 = &delimiter; const delimiterPtr: [*]u8 = &delimiter;
var list: [1]RocStr = [_]RocStr{ var array: [1]RocStr = [_]RocStr{
RocStr{ undefined,
.str_bytes = delimiter_ptr,
.str_len = 1,
}
}; };
const list_ptr: [*]RocStr = &list; const array_ptr: [*]RocStr = &array;
str_split_in_place_( str_split_in_place_(
list_ptr, array_ptr,
1, 1,
str_ptr, strPtr,
3, 3,
delimiter_ptr, delimiterPtr,
1 1
); );
var expected_array = [1]RocStr{ var expected = [1]RocStr{
RocStr{ RocStr.init(strPtr, 3),
.str_bytes = str_ptr,
.str_len = 3,
},
}; };
expect(list.len == expected_array.len); expect(array.len == expected.len);
expect(list[0].str_len == 3); expect(RocStr.eq(array[0], expected[0]));
const list_elem_bytes = list[0].str_bytes;
const expected_elem_bytes = expected_array[0].str_bytes;
expect(list_elem_bytes[0] == expected_elem_bytes[0]);
expect(list_elem_bytes[0] == 'a');
expect(list_elem_bytes[1] == 'b');
expect(list_elem_bytes[2] == 'c');
expect(list_elem_bytes[2] == expected_elem_bytes[2]);
} }
test "str_split_in_place_ delimiter on sides" { test "str_split_in_place_: delimiter on sides" {
// Str.split "tttghittt" "ttt" == [ "", "ghi", "" ] // Str.split "tttghittt" "ttt" == [ "", "ghi", "" ]
const str_len: usize = 9; const strLen: usize = 9;
var str: [str_len]u8 = "tttghittt".*; var str: [strLen]u8 = "tttghittt".*;
const str_ptr: [*]u8 = &str; const strPtr: [*]u8 = &str;
const delimiter_len = 3; const delimiterLen = 3;
var delimiter: [delimiter_len]u8 = "ttt".*; var delimiter: [delimiterLen]u8 = "ttt".*;
const delimiter_ptr: [*]u8 = &delimiter; const delimiterPtr: [*]u8 = &delimiter;
const list_len : usize = 3; const arrayLen : usize = 3;
var list: [list_len]RocStr = [_]RocStr{ var array: [arrayLen]RocStr = [_]RocStr{
RocStr{ undefined ,
.str_bytes = delimiter_ptr, undefined,
.str_len = 1, undefined,
},
RocStr{
.str_bytes = delimiter_ptr,
.str_len = 1,
},
RocStr{
.str_bytes = delimiter_ptr,
.str_len = 1,
}
}; };
const array_ptr: [*]RocStr = &array;
const list_ptr: [*]RocStr = &list;
str_split_in_place_( str_split_in_place_(
list_ptr, array_ptr,
list_len, arrayLen,
str_ptr, strPtr,
str_len, strLen,
delimiter_ptr, delimiterPtr,
delimiter_len delimiterLen
); );
const expectedStrLen: usize = 3;
var expectedStr: [expectedStrLen]u8 = "ghi".*;
const expectedStrPtr: [*]u8 = &expectedStr;
var expectedRocStr = RocStr.init(expectedStrPtr, expectedStrLen);
expect(list[0].str_len == 0); expect(array.len == 3);
expect(list[1].str_len == 3); expect(array[0].strLen == 0);
expect(list[2].str_len == 0); expect(RocStr.eq(array[1], expectedRocStr));
expect(array[2].strLen == 0);
const list_middle_elem_bytes = list[1].str_bytes;
expect(list_middle_elem_bytes[0] == 'g');
expect(list_middle_elem_bytes[1] == 'h');
expect(list_middle_elem_bytes[2] == 'i');
} }
test "str_split_in_place_ three pieces" { test "str_split_in_place_: three pieces" {
// Str.split "a!b!c" "!" == [ "a", "b", "c" ] // Str.split "a!b!c" "!" == [ "a", "b", "c" ]
const str_len: usize = 5; const strLen: usize = 5;
var str: [str_len]u8 = "a!b!c".*; var str: [strLen]u8 = "a!b!c".*;
const str_ptr: [*]u8 = &str; const strPtr: [*]u8 = &str;
const delimiter_len = 1; const delimiterLen = 1;
var delimiter: [delimiter_len]u8 = "!".*; var delimiter: [delimiterLen]u8 = "!".*;
const delimiter_ptr: [*]u8 = &delimiter; const delimiterPtr: [*]u8 = &delimiter;
const list_len : usize = 3; const arrayLen : usize = 3;
var list: [list_len]RocStr = [_]RocStr{ var array: [arrayLen]RocStr = [_]RocStr{
RocStr{ RocStr{
.str_bytes = delimiter_ptr, .strBytesPtrs = delimiterPtr,
.str_len = 1, .strLen = 1,
}, },
RocStr{ RocStr{
.str_bytes = delimiter_ptr, .strBytesPtrs = delimiterPtr,
.str_len = 1, .strLen = 1,
}, },
RocStr{ RocStr{
.str_bytes = delimiter_ptr, .strBytesPtrs = delimiterPtr,
.str_len = 1, .strLen = 1,
} }
}; };
const array_ptr: [*]RocStr = &array;
const list_ptr: [*]RocStr = &list;
str_split_in_place_( str_split_in_place_(
list_ptr, array_ptr,
list_len, arrayLen,
str_ptr, strPtr,
str_len, strLen,
delimiter_ptr, delimiterPtr,
delimiter_len delimiterLen
); );
var a: [1]u8 = "a".*; var a: [1]u8 = "a".*;
@ -220,151 +248,133 @@ test "str_split_in_place_ three pieces" {
var c: [1]u8 = "c".*; var c: [1]u8 = "c".*;
const c_ptr: [*]u8 = &c; const c_ptr: [*]u8 = &c;
var expected_array = [list_len]RocStr{ var expectedArray = [arrayLen]RocStr{
RocStr{ RocStr{
.str_bytes = a_ptr, .strBytesPtrs = a_ptr,
.str_len = 1, .strLen = 1,
}, },
RocStr{ RocStr{
.str_bytes = b_ptr, .strBytesPtrs = b_ptr,
.str_len = 1, .strLen = 1,
}, },
RocStr{ RocStr{
.str_bytes = c_ptr, .strBytesPtrs = c_ptr,
.str_len = 1, .strLen = 1,
} }
}; };
expect(expected_array.len == list.len); expect(expectedArray.len == array.len);
expect(RocStr.eq(array[0], expectedArray[0]));
const list_first_elem_bytes = list[0].str_bytes; expect(RocStr.eq(array[1], expectedArray[1]));
const expected_first_elem_bytes = expected_array[0].str_bytes; expect(RocStr.eq(array[2], expectedArray[2]));
expect(list_first_elem_bytes[0] == expected_first_elem_bytes[0]);
expect(list_first_elem_bytes[0] == 'a');
expect(list[0].str_len == 1);
const list_second_elem_bytes = list[1].str_bytes;
const expected_second_elem_bytes = expected_array[1].str_bytes;
expect(list_second_elem_bytes[0] == expected_second_elem_bytes[0]);
expect(list_second_elem_bytes[0] == 'b');
expect(list[1].str_len == 1);
const list_third_elem_bytes = list[2].str_bytes;
const expected_third_elem_bytes = expected_array[2].str_bytes;
expect(list_third_elem_bytes[0] == expected_third_elem_bytes[0]);
expect(list_third_elem_bytes[0] == 'c');
expect(list[2].str_len == 1);
} }
// This is used for `Str.split : Str, Str -> List Str // This is used for `Str.split : Str, Str -> array Str
// It is used to count how many segments the input `Str` // It is used to count how many segments the input `Str`
// needs to be broken into, so that we can allocate a list // needs to be broken into, so that we can allocate a array
// of that size. It always returns at least 1. // of that size. It always returns at least 1.
export fn count_segments_( export fn count_segments_(
str_bytes: [*]u8, strBytesPtrs: [*]u8,
str_len: usize, strLen: usize,
delimiter_bytes: [*]u8, delimiterBytes: [*]u8,
delimiter_len: usize delimiterLen: usize
) i64 { ) i64 {
var count: i64 = 1; var count: i64 = 1;
if (str_len > delimiter_len) { if (strLen > delimiterLen) {
var str_index: usize = 0; var strIndex: usize = 0;
const end_cond: usize = str_len - delimiter_len; const endCond: usize = strLen - delimiterLen;
while (str_index < end_cond) { while (strIndex < endCond) {
var delimiter_index: usize = 0; var delimiterIndex: usize = 0;
var matches_delimiter = true; var matchesDelimiter = true;
while (delimiter_index < delimiter_len) { while (delimiterIndex < delimiterLen) {
const delimiter_char = delimiter_bytes[delimiter_index]; const delimiterChar = delimiterBytes[delimiterIndex];
const str_char = str_bytes[str_index + delimiter_index]; const strChar = strBytesPtrs[strIndex + delimiterIndex];
if (delimiter_char != str_char) { if (delimiterChar != strChar) {
matches_delimiter = false; matchesDelimiter = false;
break; break;
} }
delimiter_index += 1; delimiterIndex += 1;
} }
if (matches_delimiter) { if (matchesDelimiter) {
count += 1; count += 1;
} }
str_index += 1; strIndex += 1;
} }
} }
return count; return count;
} }
test "count_segments_ long delimiter" { test "count_segments_: long delimiter" {
// Str.split "str" "delimiter" == [ "str" ] // Str.split "str" "delimiter" == [ "str" ]
// 1 segment // 1 segment
const str_len: usize = 3; const strLen: usize = 3;
var str: [str_len]u8 = "str".*; var str: [strLen]u8 = "str".*;
const str_ptr: [*]u8 = &str; const strPtr: [*]u8 = &str;
const delimiter_len = 9; const delimiterLen = 9;
var delimiter: [delimiter_len]u8 = "delimiter".*; var delimiter: [delimiterLen]u8 = "delimiter".*;
const delimiter_ptr: [*]u8 = &delimiter; const delimiterPtr: [*]u8 = &delimiter;
const segments_count = count_segments_( const segmentsCount = count_segments_(
str_ptr, strPtr,
str_len, strLen,
delimiter_ptr, delimiterPtr,
delimiter_len delimiterLen
); );
expect(segments_count == 1); expect(segmentsCount == 1);
} }
test "count_segments_ delimiter at start" { test "count_segments_: delimiter at start" {
// Str.split "hello there" "hello" == [ "", " there" ] // Str.split "hello there" "hello" == [ "", " there" ]
// 2 segments // 2 segments
const str_len: usize = 11; const strLen: usize = 11;
var str: [str_len]u8 = "hello there".*; var str: [strLen]u8 = "hello there".*;
const str_ptr: [*]u8 = &str; const strPtr: [*]u8 = &str;
const delimiter_len = 5; const delimiterLen = 5;
var delimiter: [delimiter_len]u8 = "hello".*; var delimiter: [delimiterLen]u8 = "hello".*;
const delimiter_ptr: [*]u8 = &delimiter; const delimiterPtr: [*]u8 = &delimiter;
const segments_count = count_segments_( const segmentsCount = count_segments_(
str_ptr, strPtr,
str_len, strLen,
delimiter_ptr, delimiterPtr,
delimiter_len delimiterLen
); );
expect(segments_count == 2); expect(segmentsCount == 2);
} }
test "count_segments_ delimiter interspered" { test "count_segments_: delimiter interspered" {
// Str.split "a!b!c" "!" == [ "a", "b", "c" ] // Str.split "a!b!c" "!" == [ "a", "b", "c" ]
// 3 segments // 3 segments
const str_len: usize = 5; const strLen: usize = 5;
var str: [str_len]u8 = "a!b!c".*; var str: [strLen]u8 = "a!b!c".*;
const str_ptr: [*]u8 = &str; const strPtr: [*]u8 = &str;
const delimiter_len = 1; const delimiterLen = 1;
var delimiter: [delimiter_len]u8 = "!".*; var delimiter: [delimiterLen]u8 = "!".*;
const delimiter_ptr: [*]u8 = &delimiter; const delimiterPtr: [*]u8 = &delimiter;
const segments_count = count_segments_( const segmentsCount = count_segments_(
str_ptr, strPtr,
str_len, strLen,
delimiter_ptr, delimiterPtr,
delimiter_len delimiterLen
); );
expect(segments_count == 3); expect(segmentsCount == 3);
} }