Implement List.find

`List.find : List elem, (elem -> Bool) -> Result elem [ NotFound ]*`
behaves as follows:

```
>>> List.find [1, 2, 3] (\n -> n > 2)
Ok 2
>>> List.find [1, 2, 3] (\n -> n > 4)
Err NotFound
```

We implement this as builtin in two phases. First, we call out to a
pure-llvm-lowlevel `ListFindUnsafe` that returns a record indicating
whether a satisfying element was found, and the value of that element
(the value is all null bytes if the element wasn't found). Then, we lift
that record to a `Result` via a standard construction of the can AST.

Closes #1909
This commit is contained in:
ayazhafiz 2021-11-07 20:56:46 -05:00
parent 35df58c18f
commit f65b174ab5
16 changed files with 417 additions and 8 deletions

View file

@ -1333,3 +1333,39 @@ inline fn listSetImmutable(
//return list;
return new_bytes;
}
pub fn listFindUnsafe(
list: RocList,
caller: Caller1,
data: Opaque,
inc_n_data: IncN,
data_is_owned: bool,
alignment: u32,
element_width: usize,
inc: Inc,
dec: Dec,
) callconv(.C) extern struct { value: Opaque, found: bool } {
if (list.bytes) |source_ptr| {
const size = list.len();
if (data_is_owned) {
inc_n_data(data, size);
}
var i: usize = 0;
while (i < size) : (i += 1) {
var theOne = false;
const element = source_ptr + (i * element_width);
inc(element);
caller(data, element, @ptrCast(?[*]u8, &theOne));
if (theOne) {
return .{ .value = element, .found = true };
} else {
dec(element);
}
}
return .{ .value = null, .found = false };
} else {
return .{ .value = null, .found = false };
}
}

View file

@ -52,6 +52,7 @@ comptime {
exportListFn(list.listSetInPlace, "set_in_place");
exportListFn(list.listSwap, "swap");
exportListFn(list.listAny, "any");
exportListFn(list.listFindUnsafe, "find_unsafe");
}
// Dict Module