diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index 35b061baf5..93a4b50975 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -152,8 +152,64 @@ pub fn listMapWithIndex(list: RocList, transform: Opaque, caller: Caller2, align } } -pub fn listMap2(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, old_element_width: usize, new_element_width: usize) callconv(.C) RocList { - unreachable; +pub fn listMap2(list1: RocList, list2: RocList, transform: Opaque, caller: Caller2, alignment: usize, a_width: usize, b_width: usize, c_width: usize, dec_a: Dec, dec_b: Dec) callconv(.C) RocList { + const output_length = std.math.min(list1.len(), list2.len()); + + if (list1.bytes) |source_a| { + if (list2.bytes) |source_b| { + const output = RocList.allocate(std.heap.c_allocator, alignment, output_length, c_width); + const target_ptr = output.bytes orelse unreachable; + + var i: usize = 0; + while (i < output_length) : (i += 1) { + const element_a = source_a + i * a_width; + const element_b = source_b + i * b_width; + const target = target_ptr + i * c_width; + caller(transform, element_a, element_b, target); + } + + // if the lists don't have equal length, we must consume the remaining elements + // In this case we consume by (recursively) decrementing the elements + if (list1.len() > output_length) { + while (i < list1.len()) : (i += 1) { + const element_a = source_a + i * a_width; + dec_a(element_a); + } + } else if (list2.len() > output_length) { + while (i < list2.len()) : (i += 1) { + const element_b = source_b + i * b_width; + dec_b(element_b); + } + } + + utils.decref(std.heap.c_allocator, alignment, list1.bytes, list1.len() * a_width); + utils.decref(std.heap.c_allocator, alignment, list2.bytes, list2.len() * b_width); + + return output; + } else { + // consume list1 elements (we know there is at least one because the list1.bytes pointer is non-null + var i: usize = 0; + while (i < list1.len()) : (i += 1) { + const element_a = source_a + i * a_width; + dec_a(element_a); + } + utils.decref(std.heap.c_allocator, alignment, list1.bytes, list1.len() * a_width); + + return RocList.empty(); + } + } else { + // consume list2 elements (if any) + if (list2.bytes) |source_b| { + var i: usize = 0; + while (i < list2.len()) : (i += 1) { + const element_b = source_b + i * b_width; + dec_b(element_b); + } + utils.decref(std.heap.c_allocator, alignment, list2.bytes, list2.len() * b_width); + } + + return RocList.empty(); + } } pub fn listKeepIf(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, element_width: usize, inc: Inc, dec: Dec) callconv(.C) RocList {