mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
move List.join to zig
This commit is contained in:
parent
1691b96197
commit
42d065af45
4 changed files with 60 additions and 157 deletions
|
@ -816,3 +816,32 @@ fn swapElements(source_ptr: [*]u8, element_width: usize, index_1: usize, index_2
|
||||||
|
|
||||||
return swap(element_width, element_at_i, element_at_j);
|
return swap(element_width, element_at_i, element_at_j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn listJoin(list_of_lists: RocList, alignment: usize, element_width: usize) callconv(.C) RocList {
|
||||||
|
var total_length: usize = 0;
|
||||||
|
|
||||||
|
const size = list_of_lists.len();
|
||||||
|
const slice_of_lists = @ptrCast([*]RocList, @alignCast(@alignOf(RocList), list_of_lists.bytes));
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < list_of_lists.len()) : (i += 1) {
|
||||||
|
total_length += slice_of_lists[i].len();
|
||||||
|
}
|
||||||
|
|
||||||
|
const output = RocList.allocate(std.heap.c_allocator, alignment, total_length, element_width);
|
||||||
|
|
||||||
|
if (output.bytes) |target| {
|
||||||
|
var elements_copied: usize = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < list_of_lists.len()) : (i += 1) {
|
||||||
|
const list = slice_of_lists[i];
|
||||||
|
if (list.bytes) |source| {
|
||||||
|
@memcpy(target + elements_copied * element_width, source, list.len() * element_width);
|
||||||
|
elements_copied += list.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ comptime {
|
||||||
exportListFn(list.listContains, "contains");
|
exportListFn(list.listContains, "contains");
|
||||||
exportListFn(list.listRepeat, "repeat");
|
exportListFn(list.listRepeat, "repeat");
|
||||||
exportListFn(list.listAppend, "append");
|
exportListFn(list.listAppend, "append");
|
||||||
|
exportListFn(list.listJoin, "join");
|
||||||
exportListFn(list.listRange, "range");
|
exportListFn(list.listRange, "range");
|
||||||
exportListFn(list.listReverse, "reverse");
|
exportListFn(list.listReverse, "reverse");
|
||||||
exportListFn(list.listSortWith, "sort_with");
|
exportListFn(list.listSortWith, "sort_with");
|
||||||
|
|
|
@ -75,6 +75,7 @@ pub const LIST_WALK_BACKWARDS: &str = "roc_builtins.list.walk_backwards";
|
||||||
pub const LIST_CONTAINS: &str = "roc_builtins.list.contains";
|
pub const LIST_CONTAINS: &str = "roc_builtins.list.contains";
|
||||||
pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";
|
pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";
|
||||||
pub const LIST_APPEND: &str = "roc_builtins.list.append";
|
pub const LIST_APPEND: &str = "roc_builtins.list.append";
|
||||||
|
pub const LIST_JOIN: &str = "roc_builtins.list.join";
|
||||||
pub const LIST_RANGE: &str = "roc_builtins.list.range";
|
pub const LIST_RANGE: &str = "roc_builtins.list.range";
|
||||||
pub const LIST_REVERSE: &str = "roc_builtins.list.reverse";
|
pub const LIST_REVERSE: &str = "roc_builtins.list.reverse";
|
||||||
pub const LIST_SORT_WITH: &str = "roc_builtins.list.sort_with";
|
pub const LIST_SORT_WITH: &str = "roc_builtins.list.sort_with";
|
||||||
|
|
|
@ -161,174 +161,46 @@ pub fn list_prepend<'a, 'ctx, 'env>(
|
||||||
/// List.join : List (List elem) -> List elem
|
/// List.join : List (List elem) -> List elem
|
||||||
pub fn list_join<'a, 'ctx, 'env>(
|
pub fn list_join<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
inplace: InPlace,
|
_inplace: InPlace,
|
||||||
parent: FunctionValue<'ctx>,
|
_parent: FunctionValue<'ctx>,
|
||||||
outer_list: BasicValueEnum<'ctx>,
|
outer_list: BasicValueEnum<'ctx>,
|
||||||
outer_list_layout: &Layout<'a>,
|
outer_list_layout: &Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
// List.join is implemented as follows:
|
|
||||||
// 1. loop over every list to sum the list lengths
|
|
||||||
// 2. using the sum of all the list lengths, allocate an output list of
|
|
||||||
// that size.
|
|
||||||
// 3. loop over every list, for every list, loop over every element
|
|
||||||
// putting it into the output list
|
|
||||||
|
|
||||||
match outer_list_layout {
|
match outer_list_layout {
|
||||||
// If the input list is empty, or if it is a list of empty lists
|
|
||||||
// then simply return an empty list
|
|
||||||
Layout::Builtin(Builtin::EmptyList)
|
Layout::Builtin(Builtin::EmptyList)
|
||||||
| Layout::Builtin(Builtin::List(_, Layout::Builtin(Builtin::EmptyList))) => empty_list(env),
|
| Layout::Builtin(Builtin::List(_, Layout::Builtin(Builtin::EmptyList))) => {
|
||||||
Layout::Builtin(Builtin::List(_, Layout::Builtin(Builtin::List(_, elem_layout)))) => {
|
// If the input list is empty, or if it is a list of empty lists
|
||||||
let inner_list_layout =
|
// then simply return an empty list
|
||||||
Layout::Builtin(Builtin::List(MemoryMode::Refcounted, elem_layout));
|
empty_list(env)
|
||||||
|
}
|
||||||
|
Layout::Builtin(Builtin::List(_, Layout::Builtin(Builtin::List(_, element_layout)))) => {
|
||||||
|
let list_i128 = complex_bitcast(
|
||||||
|
env.builder,
|
||||||
|
outer_list,
|
||||||
|
env.context.i128_type().into(),
|
||||||
|
"to_i128",
|
||||||
|
);
|
||||||
|
|
||||||
let builder = env.builder;
|
let element_width = env
|
||||||
let ctx = env.context;
|
.ptr_int()
|
||||||
|
.const_int(element_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||||
|
|
||||||
let elem_type = basic_type_from_layout(env, elem_layout);
|
let alignment = element_layout.alignment_bytes(env.ptr_bytes);
|
||||||
let elem_ptr_type = get_ptr_type(&elem_type, AddressSpace::Generic);
|
let alignment_iv = env.ptr_int().const_int(alignment as u64, false);
|
||||||
|
|
||||||
let inner_list_type = basic_type_from_layout(env, &inner_list_layout);
|
let output = call_bitcode_fn(
|
||||||
|
|
||||||
let outer_list_wrapper = outer_list.into_struct_value();
|
|
||||||
let outer_list_len = list_len(builder, outer_list_wrapper);
|
|
||||||
let outer_list_ptr = {
|
|
||||||
let elem_ptr_type = get_ptr_type(&inner_list_type, AddressSpace::Generic);
|
|
||||||
|
|
||||||
load_list_ptr(builder, outer_list_wrapper, elem_ptr_type)
|
|
||||||
};
|
|
||||||
|
|
||||||
// outer_list_len > 0
|
|
||||||
// We do this check to avoid allocating memory. If the input
|
|
||||||
// list is empty, then we can just return an empty list.
|
|
||||||
let comparison = list_is_not_empty(env, outer_list_len);
|
|
||||||
|
|
||||||
let build_then = || {
|
|
||||||
let list_len_sum_name = "#listslengthsum";
|
|
||||||
let list_len_sum_alloca = builder.build_alloca(ctx.i64_type(), list_len_sum_name);
|
|
||||||
|
|
||||||
builder.build_store(list_len_sum_alloca, ctx.i64_type().const_int(0, false));
|
|
||||||
|
|
||||||
// List Sum Loop
|
|
||||||
let sum_loop = |_, inner_list: BasicValueEnum<'ctx>| {
|
|
||||||
let inner_list_len = list_len(builder, inner_list.into_struct_value());
|
|
||||||
|
|
||||||
let next_list_sum = builder.build_int_add(
|
|
||||||
builder
|
|
||||||
.build_load(list_len_sum_alloca, list_len_sum_name)
|
|
||||||
.into_int_value(),
|
|
||||||
inner_list_len,
|
|
||||||
"nextlistsum",
|
|
||||||
);
|
|
||||||
|
|
||||||
builder.build_store(list_len_sum_alloca, next_list_sum);
|
|
||||||
};
|
|
||||||
|
|
||||||
incrementing_elem_loop(
|
|
||||||
builder,
|
|
||||||
ctx,
|
|
||||||
parent,
|
|
||||||
outer_list_ptr,
|
|
||||||
outer_list_len,
|
|
||||||
"#sum_index",
|
|
||||||
sum_loop,
|
|
||||||
);
|
|
||||||
|
|
||||||
let final_list_sum = builder
|
|
||||||
.build_load(list_len_sum_alloca, list_len_sum_name)
|
|
||||||
.into_int_value();
|
|
||||||
|
|
||||||
let final_list_ptr = allocate_list(env, inplace, elem_layout, final_list_sum);
|
|
||||||
|
|
||||||
let dest_elem_ptr_alloca = builder.build_alloca(elem_ptr_type, "dest_elem");
|
|
||||||
|
|
||||||
builder.build_store(dest_elem_ptr_alloca, final_list_ptr);
|
|
||||||
|
|
||||||
// Inner List Loop
|
|
||||||
let inner_list_loop = |_, inner_list: BasicValueEnum<'ctx>| {
|
|
||||||
let inner_list_wrapper = inner_list.into_struct_value();
|
|
||||||
|
|
||||||
let inner_list_len = list_len(builder, inner_list_wrapper);
|
|
||||||
|
|
||||||
// inner_list_len > 0
|
|
||||||
let inner_list_comparison = list_is_not_empty(env, inner_list_len);
|
|
||||||
|
|
||||||
let inner_list_non_empty_block =
|
|
||||||
ctx.append_basic_block(parent, "inner_list_non_empty");
|
|
||||||
let after_inner_list_non_empty_block =
|
|
||||||
ctx.append_basic_block(parent, "branchcont");
|
|
||||||
|
|
||||||
builder.build_conditional_branch(
|
|
||||||
inner_list_comparison,
|
|
||||||
inner_list_non_empty_block,
|
|
||||||
after_inner_list_non_empty_block,
|
|
||||||
);
|
|
||||||
builder.position_at_end(inner_list_non_empty_block);
|
|
||||||
|
|
||||||
let inner_list_ptr = load_list_ptr(builder, inner_list_wrapper, elem_ptr_type);
|
|
||||||
|
|
||||||
// Element Inserting Loop
|
|
||||||
let inner_elem_loop = |_, src_elem| {
|
|
||||||
// TODO clone src_elem
|
|
||||||
|
|
||||||
let curr_dest_elem_ptr = builder
|
|
||||||
.build_load(dest_elem_ptr_alloca, "load_dest_elem_ptr")
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
builder.build_store(curr_dest_elem_ptr, src_elem);
|
|
||||||
|
|
||||||
let inc_dest_elem_ptr = BasicValueEnum::PointerValue(unsafe {
|
|
||||||
builder.build_in_bounds_gep(
|
|
||||||
curr_dest_elem_ptr,
|
|
||||||
&[env.ptr_int().const_int(1_u64, false)],
|
|
||||||
"increment_dest_elem",
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.build_store(dest_elem_ptr_alloca, inc_dest_elem_ptr);
|
|
||||||
};
|
|
||||||
|
|
||||||
incrementing_elem_loop(
|
|
||||||
builder,
|
|
||||||
ctx,
|
|
||||||
parent,
|
|
||||||
inner_list_ptr,
|
|
||||||
inner_list_len,
|
|
||||||
"#inner_index",
|
|
||||||
inner_elem_loop,
|
|
||||||
);
|
|
||||||
|
|
||||||
builder.build_unconditional_branch(after_inner_list_non_empty_block);
|
|
||||||
builder.position_at_end(after_inner_list_non_empty_block);
|
|
||||||
};
|
|
||||||
|
|
||||||
incrementing_elem_loop(
|
|
||||||
builder,
|
|
||||||
ctx,
|
|
||||||
parent,
|
|
||||||
outer_list_ptr,
|
|
||||||
outer_list_len,
|
|
||||||
"#inner_list_index",
|
|
||||||
inner_list_loop,
|
|
||||||
);
|
|
||||||
|
|
||||||
store_list(env, final_list_ptr, final_list_sum)
|
|
||||||
};
|
|
||||||
|
|
||||||
let build_else = || empty_list(env);
|
|
||||||
|
|
||||||
let struct_type = super::convert::zig_list_type(env);
|
|
||||||
|
|
||||||
build_basic_phi2(
|
|
||||||
env,
|
env,
|
||||||
parent,
|
&[list_i128, alignment_iv.into(), element_width.into()],
|
||||||
comparison,
|
&bitcode::LIST_JOIN,
|
||||||
build_then,
|
);
|
||||||
build_else,
|
|
||||||
BasicTypeEnum::StructType(struct_type),
|
complex_bitcast(
|
||||||
|
env.builder,
|
||||||
|
output,
|
||||||
|
super::convert::zig_list_type(env).into(),
|
||||||
|
"from_i128",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!("Invalid List layout for List.join {:?}", outer_list_layout);
|
unreachable!("Invalid List layout for List.join {:?}", outer_list_layout);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue