Passing without bounds checks

This commit is contained in:
Joshua Hoeflich 2021-08-08 11:26:43 -05:00
parent 4231b340ee
commit b8b20a376a
3 changed files with 42 additions and 20 deletions

View File

@ -1198,30 +1198,17 @@ fn fromUtf8(arg: RocList) FromUtf8Result {
}
pub fn fromUtf8RangeC(arg: RocList, countAndStart: CountAndStart, output: *FromUtf8Result) callconv(.C) void {
output.* = @call(.{ .modifier = always_inline }, fromUtf8Range, .{arg, countAndStart});
output.* = @call(.{ .modifier = always_inline }, fromUtf8Range, .{ arg, countAndStart });
}
fn fromUtf8Range(arg: RocList, countAndStart: CountAndStart) FromUtf8Result {
const bytes = @ptrCast([*]const u8, arg.bytes)[0..arg.length];
const bytes = @ptrCast([*]const u8, arg.bytes)[countAndStart.start..countAndStart.count];
if (unicode.utf8ValidateSlice(bytes)) {
// the output will be correct. Now we need to take ownership of the input
if (arg.len() <= SMALL_STR_MAX_LENGTH) {
// turn the bytes into a small string
const string = RocStr.init(@ptrCast([*]u8, arg.bytes), arg.len());
// the output will be correct. Now we need to clone the input
const string = RocStr.init(@ptrCast([*]const u8, bytes), countAndStart.count);
// then decrement the input list
const data_bytes = arg.len();
utils.decref(arg.bytes, data_bytes, RocStr.alignment);
return FromUtf8Result{ .is_ok = true, .string = string, .byte_index = 0, .problem_code = Utf8ByteProblem.InvalidStartByte };
} else {
const byte_list = arg.makeUnique(RocStr.alignment, @sizeOf(u8));
const string = RocStr{ .str_bytes = byte_list.bytes, .str_len = byte_list.length };
return FromUtf8Result{ .is_ok = true, .string = string, .byte_index = 0, .problem_code = Utf8ByteProblem.InvalidStartByte };
}
return FromUtf8Result{ .is_ok = true, .string = string, .byte_index = 0, .problem_code = Utf8ByteProblem.InvalidStartByte };
} else {
const temp = errorToProblem(@ptrCast([*]u8, arg.bytes), arg.length);
@ -1233,7 +1220,6 @@ fn fromUtf8Range(arg: RocList, countAndStart: CountAndStart) FromUtf8Result {
}
}
fn errorToProblem(bytes: [*]u8, length: usize) struct { index: usize, problem: Utf8ByteProblem } {
var index: usize = 0;

View File

@ -1015,7 +1015,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[owned, borrowed]),
StrStartsWithCodePoint => arena.alloc_slice_copy(&[borrowed, irrelevant]),
StrFromUtf8 => arena.alloc_slice_copy(&[owned]),
StrFromUtf8Range => arena.alloc_slice_copy(&[owned, irrelevant]),
StrFromUtf8Range => arena.alloc_slice_copy(&[borrowed, irrelevant]),
StrToBytes => arena.alloc_slice_copy(&[owned]),
StrFromInt | StrFromFloat => arena.alloc_slice_copy(&[irrelevant]),
Hash => arena.alloc_slice_copy(&[borrowed, irrelevant]),

View File

@ -842,3 +842,39 @@ fn str_from_utf8_range() {
RocStr
);
}
#[test]
fn str_from_utf8_range_slice() {
assert_evals_to!(
r#"
bytes = Str.toBytes "hello"
Str.fromUtf8Range bytes { start: 1, count: 4 }
"#,
RocStr::from("ello"),
RocStr
);
}
#[test]
fn str_from_utf8_range_slice_not_end() {
assert_evals_to!(
r#"
bytes = Str.toBytes "hello"
Str.fromUtf8Range bytes { start: 1, count: 3 }
"#,
RocStr::from("ell"),
RocStr
);
}
// #[test]
// fn str_from_utf8_range_slice() {
// assert_evals_to!(
// r#"
// bytes = Str.toBytes "hello"
// Str.fromUtf8Range bytes { start: 6, count: 5 }
// "#,
// RocStr::from("ello"),
// RocStr
// );
// }