mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
add List.clone
This commit is contained in:
parent
ebfcd71e8d
commit
f1ffc36efe
14 changed files with 147 additions and 4 deletions
|
@ -1173,6 +1173,16 @@ fn lowlevel_spec<'a>(
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
ListClone => {
|
||||
let list = env.symbols[&arguments[0]];
|
||||
|
||||
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||
let cell = builder.add_get_tuple_field(block, list, LIST_CELL_INDEX)?;
|
||||
|
||||
let _unit = builder.add_update(block, update_mode_var, cell)?;
|
||||
|
||||
with_new_heap_cell(builder, block, bag)
|
||||
}
|
||||
ListSwap => {
|
||||
let list = env.symbols[&arguments[0]];
|
||||
|
||||
|
|
|
@ -962,6 +962,14 @@ pub fn listIsUnique(
|
|||
return list.isEmpty() or list.isUnique();
|
||||
}
|
||||
|
||||
pub fn listClone(
|
||||
list: RocList,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
) callconv(.C) RocList {
|
||||
return list.makeUnique(alignment, element_width);
|
||||
}
|
||||
|
||||
pub fn listCapacity(
|
||||
list: RocList,
|
||||
) callconv(.C) usize {
|
||||
|
|
|
@ -75,6 +75,7 @@ comptime {
|
|||
exportListFn(list.listReplaceInPlace, "replace_in_place");
|
||||
exportListFn(list.listSwap, "swap");
|
||||
exportListFn(list.listIsUnique, "is_unique");
|
||||
exportListFn(list.listClone, "clone");
|
||||
exportListFn(list.listCapacity, "capacity");
|
||||
exportListFn(list.listAllocationPtr, "allocation_ptr");
|
||||
exportListFn(list.listReleaseExcessCapacity, "release_excess_capacity");
|
||||
|
|
|
@ -435,7 +435,8 @@ repeatHelp = \value, count, accum ->
|
|||
## ```
|
||||
reverse : List a -> List a
|
||||
reverse = \list ->
|
||||
reverseHelp list 0 (Num.subSaturated (List.len list) 1)
|
||||
end = List.len list |> Num.subSaturated 1
|
||||
reverseHelp (List.clone list) 0 end
|
||||
|
||||
reverseHelp = \list, left, right ->
|
||||
if left < right then
|
||||
|
@ -443,6 +444,9 @@ reverseHelp = \list, left, right ->
|
|||
else
|
||||
list
|
||||
|
||||
# Ensures that the list in unique (will re-use if already unique)
|
||||
clone : List a -> List a
|
||||
|
||||
## Join the given lists together into one list.
|
||||
## ```
|
||||
## expect List.join [[1], [2, 3], [], [4, 5]] == [1, 2, 3, 4, 5]
|
||||
|
|
|
@ -386,6 +386,7 @@ pub const LIST_CONCAT: &str = "roc_builtins.list.concat";
|
|||
pub const LIST_REPLACE: &str = "roc_builtins.list.replace";
|
||||
pub const LIST_REPLACE_IN_PLACE: &str = "roc_builtins.list.replace_in_place";
|
||||
pub const LIST_IS_UNIQUE: &str = "roc_builtins.list.is_unique";
|
||||
pub const LIST_CLONE: &str = "roc_builtins.list.clone";
|
||||
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
|
||||
pub const LIST_APPEND_UNSAFE: &str = "roc_builtins.list.append_unsafe";
|
||||
pub const LIST_RESERVE: &str = "roc_builtins.list.reserve";
|
||||
|
|
|
@ -142,6 +142,7 @@ map_symbol_to_lowlevel_and_arity! {
|
|||
ListWithCapacity; LIST_WITH_CAPACITY; 1,
|
||||
ListReserve; LIST_RESERVE; 2,
|
||||
ListIsUnique; LIST_IS_UNIQUE; 1,
|
||||
ListClone; LIST_CLONE; 1,
|
||||
ListAppendUnsafe; LIST_APPEND_UNSAFE; 2,
|
||||
ListPrepend; LIST_PREPEND; 2,
|
||||
ListGetUnsafe; LIST_GET_UNSAFE; 2,
|
||||
|
|
|
@ -2809,6 +2809,55 @@ impl<
|
|||
self.storage_manager.list_len(&mut self.buf, dst, list);
|
||||
}
|
||||
|
||||
fn build_list_clone(
|
||||
&mut self,
|
||||
dst: Symbol,
|
||||
input_list: Symbol,
|
||||
elem_layout: InLayout<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
) {
|
||||
// List alignment argument (u32).
|
||||
self.load_layout_alignment(ret_layout, Symbol::DEV_TMP);
|
||||
|
||||
// Load element_width argument (usize).
|
||||
self.load_layout_stack_size(elem_layout, Symbol::DEV_TMP2);
|
||||
|
||||
// Setup the return location.
|
||||
let base_offset =
|
||||
self.storage_manager
|
||||
.claim_stack_area_layout(self.layout_interner, dst, ret_layout);
|
||||
|
||||
let lowlevel_args = [
|
||||
input_list,
|
||||
// alignment
|
||||
Symbol::DEV_TMP,
|
||||
// element_width
|
||||
Symbol::DEV_TMP2,
|
||||
];
|
||||
let lowlevel_arg_layouts = [ret_layout, Layout::U32, Layout::U64];
|
||||
|
||||
self.build_fn_call(
|
||||
&Symbol::DEV_TMP3,
|
||||
bitcode::LIST_CLONE.to_string(),
|
||||
&lowlevel_args,
|
||||
&lowlevel_arg_layouts,
|
||||
&ret_layout,
|
||||
);
|
||||
self.free_symbol(&Symbol::DEV_TMP);
|
||||
self.free_symbol(&Symbol::DEV_TMP2);
|
||||
|
||||
// Copy from list to the output record.
|
||||
self.storage_manager.copy_symbol_to_stack_offset(
|
||||
self.layout_interner,
|
||||
&mut self.buf,
|
||||
base_offset,
|
||||
&Symbol::DEV_TMP3,
|
||||
&ret_layout,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP3);
|
||||
}
|
||||
|
||||
fn build_list_with_capacity(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
|
|
|
@ -1518,6 +1518,15 @@ trait Backend<'a> {
|
|||
let elem_layout = list_element_layout!(self.interner(), *ret_layout);
|
||||
self.build_list_with_capacity(sym, args[0], arg_layouts[0], elem_layout, ret_layout)
|
||||
}
|
||||
LowLevel::ListClone => {
|
||||
debug_assert_eq!(
|
||||
1,
|
||||
args.len(),
|
||||
"ListClone: expected to have exactly one argument"
|
||||
);
|
||||
let elem_layout = list_element_layout!(self.interner(), *ret_layout);
|
||||
self.build_list_clone(*sym, args[0], elem_layout, *ret_layout)
|
||||
}
|
||||
LowLevel::ListReserve => {
|
||||
debug_assert_eq!(
|
||||
2,
|
||||
|
@ -2416,6 +2425,14 @@ trait Backend<'a> {
|
|||
fn build_indirect_inc(&mut self, layout: InLayout<'a>) -> Symbol;
|
||||
fn build_indirect_dec(&mut self, layout: InLayout<'a>) -> Symbol;
|
||||
|
||||
fn build_list_clone(
|
||||
&mut self,
|
||||
dst: Symbol,
|
||||
input_list: Symbol,
|
||||
elem_layout: InLayout<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
);
|
||||
|
||||
/// build_list_with_capacity creates and returns a list with the given capacity.
|
||||
fn build_list_with_capacity(
|
||||
&mut self,
|
||||
|
|
|
@ -34,8 +34,8 @@ use crate::llvm::{
|
|||
BuilderExt, FuncBorrowSpec, RocReturn,
|
||||
},
|
||||
build_list::{
|
||||
list_append_unsafe, list_concat, list_drop_at, list_get_unsafe, list_len, list_map,
|
||||
list_map2, list_map3, list_map4, list_prepend, list_release_excess_capacity,
|
||||
layout_width, list_append_unsafe, list_concat, list_drop_at, list_get_unsafe, list_len,
|
||||
list_map, list_map2, list_map3, list_map4, list_prepend, list_release_excess_capacity,
|
||||
list_replace_unsafe, list_reserve, list_sort_with, list_sublist, list_swap,
|
||||
list_symbol_to_c_abi, list_with_capacity, pass_update_mode,
|
||||
},
|
||||
|
@ -962,6 +962,31 @@ pub(crate) fn run_low_level<'a, 'ctx>(
|
|||
bitcode::LIST_IS_UNIQUE,
|
||||
)
|
||||
}
|
||||
ListClone => {
|
||||
// List.clone : List a -> List a
|
||||
arguments_with_layouts!((list, list_layout));
|
||||
let element_layout = list_element_layout!(layout_interner, list_layout);
|
||||
|
||||
match update_mode {
|
||||
UpdateMode::Immutable => {
|
||||
//
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
&[list.into_struct_value()],
|
||||
&[
|
||||
env.alignment_intvalue(layout_interner, element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
],
|
||||
BitcodeReturns::List,
|
||||
bitcode::LIST_CLONE,
|
||||
)
|
||||
}
|
||||
UpdateMode::InPlace => {
|
||||
// we statically know the list is unique
|
||||
list
|
||||
}
|
||||
}
|
||||
}
|
||||
NumToStr => {
|
||||
// Num.toStr : Num a -> Str
|
||||
arguments_with_layouts!((num, num_layout));
|
||||
|
|
|
@ -299,6 +299,28 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
ListIsUnique => self.load_args_and_call_zig(backend, bitcode::LIST_IS_UNIQUE),
|
||||
|
||||
ListClone => {
|
||||
let input_list: Symbol = self.arguments[0];
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout_raw);
|
||||
let elem_layout = backend.layout_interner.get_repr(elem_layout);
|
||||
let (elem_width, elem_align) =
|
||||
elem_layout.stack_size_and_alignment(backend.layout_interner);
|
||||
|
||||
// Zig arguments Wasm types
|
||||
// (return pointer) i32
|
||||
// input_list: &RocList i32
|
||||
// alignment: u32 i32
|
||||
// element_width: usize i32
|
||||
|
||||
backend
|
||||
.storage
|
||||
.load_symbols(&mut backend.code_builder, &[self.ret_symbol, input_list]);
|
||||
backend.code_builder.i32_const(elem_align as i32);
|
||||
backend.code_builder.i32_const(elem_width as i32);
|
||||
|
||||
backend.call_host_fn_after_loading_args(bitcode::LIST_CLONE);
|
||||
}
|
||||
|
||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListSortWith => {
|
||||
internal_error!("HigherOrder lowlevels should not be handled here")
|
||||
}
|
||||
|
|
|
@ -50,8 +50,9 @@ pub enum LowLevel {
|
|||
ListSublist,
|
||||
ListDropAt,
|
||||
ListSwap,
|
||||
ListIsUnique,
|
||||
ListGetCapacity,
|
||||
ListIsUnique,
|
||||
ListClone,
|
||||
NumAdd,
|
||||
NumAddWrap,
|
||||
NumAddChecked,
|
||||
|
@ -291,6 +292,7 @@ map_symbol_to_lowlevel! {
|
|||
ListReserve <= LIST_RESERVE;
|
||||
ListReleaseExcessCapacity <= LIST_RELEASE_EXCESS_CAPACITY;
|
||||
ListIsUnique <= LIST_IS_UNIQUE;
|
||||
ListClone <= LIST_CLONE;
|
||||
ListAppendUnsafe <= LIST_APPEND_UNSAFE;
|
||||
ListPrepend <= LIST_PREPEND;
|
||||
ListGetUnsafe <= LIST_GET_UNSAFE, DICT_LIST_GET_UNSAFE;
|
||||
|
|
|
@ -1440,6 +1440,7 @@ define_builtins! {
|
|||
84 LIST_APPEND_IF_OK: "appendIfOk"
|
||||
85 LIST_PREPEND_IF_OK: "prependIfOk"
|
||||
86 LIST_WALK_WITH_INDEX_UNTIL: "walkWithIndexUntil"
|
||||
87 LIST_CLONE: "clone"
|
||||
}
|
||||
7 RESULT: "Result" => {
|
||||
0 RESULT_RESULT: "Result" exposed_type=true // the Result.Result type alias
|
||||
|
|
|
@ -1611,6 +1611,7 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC {
|
|||
Hash => RC::NoRc,
|
||||
|
||||
ListIsUnique => RC::Rc,
|
||||
ListClone => RC::Rc,
|
||||
|
||||
BoxExpr | UnboxExpr => {
|
||||
unreachable!("These lowlevel operations are turned into mono Expr's")
|
||||
|
|
|
@ -1366,6 +1366,7 @@ fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[Ownership] {
|
|||
Hash => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
|
||||
ListIsUnique => arena.alloc_slice_copy(&[borrowed]),
|
||||
ListClone => arena.alloc_slice_copy(&[owned]),
|
||||
|
||||
BoxExpr | UnboxExpr => {
|
||||
unreachable!("These lowlevel operations are turned into mono Expr's")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue