call ListReplace and generate struct afterwards

This commit is contained in:
Brendan Hansknecht 2022-02-24 22:33:12 -08:00
parent dc59ba97c2
commit aff962809b
2 changed files with 40 additions and 17 deletions

View file

@ -1257,12 +1257,12 @@ pub fn listConcat(list_a: RocList, list_b: RocList, alignment: u32, element_widt
} }
pub fn listReplaceInPlace( pub fn listReplaceInPlace(
list: RocList list: RocList,
index: usize, index: usize,
element: Opaque, element: Opaque,
element_width: usize, element_width: usize,
out_element: ?[*]u8, out_element: ?[*]u8,
) callconv(.C) extern RocList { ) callconv(.C) RocList {
// INVARIANT: bounds checking happens on the roc side // INVARIANT: bounds checking happens on the roc side
// //
// at the time of writing, the function is implemented roughly as // at the time of writing, the function is implemented roughly as
@ -1273,7 +1273,7 @@ pub fn listReplaceInPlace(
} }
pub fn listReplace( pub fn listReplace(
list: RocList list: RocList,
alignment: u32, alignment: u32,
index: usize, index: usize,
element: Opaque, element: Opaque,
@ -1286,16 +1286,16 @@ pub fn listReplace(
// `if inBounds then LowLevelListReplace input index item else input` // `if inBounds then LowLevelListReplace input index item else input`
// so we don't do a bounds check here. Hence, the list is also non-empty, // so we don't do a bounds check here. Hence, the list is also non-empty,
// because inserting into an empty list is always out of bounds // because inserting into an empty list is always out of bounds
listReplaceInPlaceHelp(list.makeUnique(alignment, element_width), index, element, element_width, out_element); return listReplaceInPlaceHelp(list.makeUnique(alignment, element_width), index, element, element_width, out_element);
} }
inline fn listReplaceInPlaceHelp( inline fn listReplaceInPlaceHelp(
list: RocList list: RocList,
index: usize, index: usize,
element: Opaque, element: Opaque,
element_width: usize, element_width: usize,
out_element: ?[*]u8, out_element: ?[*]u8,
) extern struct RocList { ) RocList {
// the element we will replace // the element we will replace
var element_at_index = (list.bytes orelse undefined) + (index * element_width); var element_at_index = (list.bytes orelse undefined) + (index * element_width);

View file

@ -301,41 +301,64 @@ pub fn list_replace_unsafe<'a, 'ctx, 'env>(
element_layout: &Layout<'a>, element_layout: &Layout<'a>,
update_mode: UpdateMode, update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
// TODO: This or elsewhere needs to deal with building the record that gets returned. let element_type = basic_type_from_layout(env, &element_layout);
let (length, bytes) = load_list( let element_ptr = env
env.builder, .builder
list.into_struct_value(), .build_alloca(element_type, "output_element_as_opaque");
env.context.i8_type().ptr_type(AddressSpace::Generic),
);
// Assume the bounds have already been checked earlier // Assume the bounds have already been checked earlier
// (e.g. by List.replace or List.set, which wrap List.#replaceUnsafe) // (e.g. by List.replace or List.set, which wrap List.#replaceUnsafe)
let new_bytes = match update_mode { let new_list = match update_mode {
UpdateMode::InPlace => call_bitcode_fn( UpdateMode::InPlace => call_bitcode_fn(
env, env,
&[ &[
bytes.into(), list.into(),
index.into(), index.into(),
pass_element_as_opaque(env, element, *element_layout), pass_element_as_opaque(env, element, *element_layout),
layout_width(env, element_layout), layout_width(env, element_layout),
pass_as_opaque(env, element_ptr),
], ],
bitcode::LIST_REPLACE_IN_PLACE, bitcode::LIST_REPLACE_IN_PLACE,
), ),
UpdateMode::Immutable => call_bitcode_fn( UpdateMode::Immutable => call_bitcode_fn(
env, env,
&[ &[
bytes.into(), list.into(),
length.into(),
env.alignment_intvalue(element_layout), env.alignment_intvalue(element_layout),
index.into(), index.into(),
pass_element_as_opaque(env, element, *element_layout), pass_element_as_opaque(env, element, *element_layout),
layout_width(env, element_layout), layout_width(env, element_layout),
pass_as_opaque(env, element_ptr),
], ],
bitcode::LIST_REPLACE, bitcode::LIST_REPLACE,
), ),
}; };
store_list(env, new_bytes.into_pointer_value(), length) // Load the element and returned list into a struct.
let old_element = env.builder.build_load(element_ptr, "load_element");
let result = env
.context
.struct_type(
// TODO: does the order need to be decided by the size of the element type.
&[
super::convert::zig_list_type(env).into(),
element_type.into(),
],
false,
)
.const_zero();
let result = env
.builder
.build_insert_value(result, old_element, 0, "insert_value")
.unwrap();
env.builder
.build_insert_value(result, new_list, 1, "insert_list")
.unwrap()
.into_struct_value()
.into()
} }
/// List.set : List elem, Nat, elem -> List elem /// List.set : List elem, Nat, elem -> List elem