mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 11:52:19 +00:00
add first version of List.dropAt
* adds an implementation with no uniqueness/mutability
This commit is contained in:
parent
ff9866420b
commit
3baff93a97
11 changed files with 145 additions and 13 deletions
|
@ -833,6 +833,54 @@ pub fn listDrop(
|
|||
}
|
||||
}
|
||||
|
||||
// GIESCH add type inference test
|
||||
// GIESCH add unit tests
|
||||
// GIESCH do a uniqueness check, and reuse the same array if possible
|
||||
// GIESCH figure out where to specify uniqueness of output, update builtins readme
|
||||
pub fn listDropAt(
|
||||
list: RocList,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
drop_index: usize,
|
||||
dec: Dec,
|
||||
) callconv(.C) RocList {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
|
||||
if (drop_index >= size) {
|
||||
return RocList.empty();
|
||||
}
|
||||
|
||||
if (drop_index < size) {
|
||||
const element = source_ptr + drop_index * element_width;
|
||||
dec(element);
|
||||
}
|
||||
|
||||
// GIESCH is this necessary?
|
||||
if (size < 2 and drop_index == 0) {
|
||||
return RocList.empty();
|
||||
}
|
||||
|
||||
const output = RocList.allocate(alignment, (size - 1), element_width);
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
|
||||
const head_size = drop_index * element_width;
|
||||
@memcpy(target_ptr, source_ptr, head_size);
|
||||
|
||||
const tail_target = target_ptr + drop_index * element_width;
|
||||
const tail_source = source_ptr + (drop_index + 1) * element_width;
|
||||
const tail_size = (size - drop_index - 1) * element_width;
|
||||
@memcpy(tail_target, tail_source, tail_size);
|
||||
|
||||
// GIESCH what's the difference between this and Dec?
|
||||
utils.decref(list.bytes, size * element_width, alignment);
|
||||
|
||||
return output;
|
||||
} else {
|
||||
return RocList.empty();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listRange(width: utils.IntWidth, low: Opaque, high: Opaque) callconv(.C) RocList {
|
||||
return switch (width) {
|
||||
.U8 => helper1(u8, low, high),
|
||||
|
|
|
@ -39,6 +39,7 @@ comptime {
|
|||
exportListFn(list.listSortWith, "sort_with");
|
||||
exportListFn(list.listConcat, "concat");
|
||||
exportListFn(list.listDrop, "drop");
|
||||
exportListFn(list.listDropAt, "drop_at");
|
||||
exportListFn(list.listSet, "set");
|
||||
exportListFn(list.listSetInPlace, "set_in_place");
|
||||
exportListFn(list.listSwap, "swap");
|
||||
|
|
|
@ -422,15 +422,18 @@ min : List (Num a) -> Result (Num a) [ ListWasEmpty ]*
|
|||
## If the given index is outside the bounds of the list, returns the original
|
||||
## list unmodified.
|
||||
##
|
||||
## To drop the element at a given index, instead of replacing it, see [List.drop].
|
||||
## To drop the element at a given index, instead of replacing it, see [List.dropAt].
|
||||
set : List elem, Nat, elem -> List elem
|
||||
|
||||
# GIESCH figure out if we should add docs for List.drop;
|
||||
# what's the relationship with List.dropFirst, below?
|
||||
# GIESCH add docs re: uniqueness and performance
|
||||
## Drops the element at the given index from the list.
|
||||
##
|
||||
## This has no effect if the given index is outside the bounds of the list.
|
||||
##
|
||||
## To replace the element at a given index, instead of dropping it, see [List.set].
|
||||
drop : List elem, Nat -> List elem
|
||||
dropAt : List elem, Nat -> List elem
|
||||
|
||||
## Adds a new element to the end of the list.
|
||||
##
|
||||
|
|
|
@ -63,6 +63,7 @@ pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";
|
|||
pub const LIST_APPEND: &str = "roc_builtins.list.append";
|
||||
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
|
||||
pub const LIST_DROP: &str = "roc_builtins.list.drop";
|
||||
pub const LIST_DROP_AT: &str = "roc_builtins.list.drop_at";
|
||||
pub const LIST_SWAP: &str = "roc_builtins.list.swap";
|
||||
pub const LIST_SINGLE: &str = "roc_builtins.list.single";
|
||||
pub const LIST_JOIN: &str = "roc_builtins.list.join";
|
||||
|
|
|
@ -920,6 +920,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
|||
Box::new(list_type(flex(TVAR1))),
|
||||
);
|
||||
|
||||
// dropAt : List elem, Nat -> List elem
|
||||
add_top_level_function_type!(
|
||||
Symbol::LIST_DROP_AT,
|
||||
vec![list_type(flex(TVAR1)), nat_type()],
|
||||
Box::new(list_type(flex(TVAR1))),
|
||||
);
|
||||
|
||||
// swap : List elem, Nat, Nat -> List elem
|
||||
add_top_level_function_type!(
|
||||
Symbol::LIST_SWAP,
|
||||
|
|
|
@ -87,6 +87,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
LIST_MAP2 => list_map2,
|
||||
LIST_MAP3 => list_map3,
|
||||
LIST_DROP => list_drop,
|
||||
LIST_DROP_AT => list_drop_at,
|
||||
LIST_SWAP => list_swap,
|
||||
LIST_MAP_WITH_INDEX => list_map_with_index,
|
||||
LIST_KEEP_IF => list_keep_if,
|
||||
|
@ -1979,6 +1980,29 @@ fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
)
|
||||
}
|
||||
|
||||
/// List.dropAt : List elem, Nat -> List elem
|
||||
fn list_drop_at(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let list_var = var_store.fresh();
|
||||
let index_var = var_store.fresh();
|
||||
|
||||
let body = RunLowLevel {
|
||||
op: LowLevel::ListDropAt,
|
||||
args: vec![
|
||||
(list_var, Var(Symbol::ARG_1)),
|
||||
(index_var, Var(Symbol::ARG_2)),
|
||||
],
|
||||
ret_var: list_var,
|
||||
};
|
||||
|
||||
defn(
|
||||
symbol,
|
||||
vec![(list_var, Symbol::ARG_1), (index_var, Symbol::ARG_2)],
|
||||
var_store,
|
||||
body,
|
||||
list_var,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.append : List elem, elem -> List elem
|
||||
fn list_append(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let list_var = var_store.fresh();
|
||||
|
|
|
@ -9,9 +9,10 @@ use crate::llvm::build_dict::{
|
|||
use crate::llvm::build_hash::generic_hash;
|
||||
use crate::llvm::build_list::{
|
||||
self, allocate_list, empty_list, empty_polymorphic_list, list_append, list_concat,
|
||||
list_contains, list_drop, list_get_unsafe, list_join, list_keep_errs, list_keep_if,
|
||||
list_keep_oks, list_len, list_map, list_map2, list_map3, list_map_with_index, list_prepend,
|
||||
list_range, list_repeat, list_reverse, list_set, list_single, list_sort_with, list_swap,
|
||||
list_contains, list_drop, list_drop_at, list_get_unsafe, list_join, list_keep_errs,
|
||||
list_keep_if, list_keep_oks, list_len, list_map, list_map2, list_map3, list_map_with_index,
|
||||
list_prepend, list_range, list_repeat, list_reverse, list_set, list_single, list_sort_with,
|
||||
list_swap,
|
||||
};
|
||||
use crate::llvm::build_str::{
|
||||
empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int,
|
||||
|
@ -5018,6 +5019,27 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
_ => unreachable!("Invalid layout {:?} in List.drop", list_layout),
|
||||
}
|
||||
}
|
||||
ListDropAt => {
|
||||
// List.dropAt : List elem, Nat -> List elem
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
let original_wrapper = list.into_struct_value();
|
||||
|
||||
let count = load_symbol(scope, &args[1]);
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
||||
Layout::Builtin(Builtin::List(element_layout)) => list_drop_at(
|
||||
env,
|
||||
layout_ids,
|
||||
original_wrapper,
|
||||
count.into_int_value(),
|
||||
element_layout,
|
||||
),
|
||||
_ => unreachable!("Invalid layout {:?} in List.dropAt", list_layout),
|
||||
}
|
||||
}
|
||||
ListPrepend => {
|
||||
// List.prepend : List elem, elem -> List elem
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
|
|
@ -297,7 +297,7 @@ pub fn list_swap<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
|
||||
/// List.drop : List elem, Nat, Nat -> List elem
|
||||
/// List.drop : List elem, Nat -> List elem
|
||||
pub fn list_drop<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
|
@ -319,6 +319,29 @@ pub fn list_drop<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
|
||||
// GIESCH ask about how this calling/linking to compiled zig works
|
||||
/// List.dropAt : List elem, Nat -> List elem
|
||||
pub fn list_drop_at<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
original_wrapper: StructValue<'ctx>,
|
||||
count: IntValue<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
|
||||
call_bitcode_fn_returns_list(
|
||||
env,
|
||||
&[
|
||||
pass_list_cc(env, original_wrapper.into()),
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
count.into(),
|
||||
dec_element_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::LIST_DROP_AT,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.set : List elem, Nat, elem -> List elem
|
||||
pub fn list_set<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
|
|
@ -41,6 +41,7 @@ pub enum LowLevel {
|
|||
ListKeepErrs,
|
||||
ListSortWith,
|
||||
ListDrop,
|
||||
ListDropAt,
|
||||
ListSwap,
|
||||
DictSize,
|
||||
DictEmpty,
|
||||
|
@ -116,13 +117,13 @@ impl LowLevel {
|
|||
StrConcat | StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt
|
||||
| StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8
|
||||
| StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | ListLen | ListGetUnsafe
|
||||
| ListSet | ListDrop | ListSingle | ListRepeat | ListReverse | ListConcat
|
||||
| ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListSwap
|
||||
| DictSize | DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe
|
||||
| DictKeys | DictValues | DictUnion | DictIntersection | DictDifference
|
||||
| SetFromList | NumAdd | NumAddWrap | NumAddChecked | NumSub | NumSubWrap
|
||||
| NumSubChecked | NumMul | NumMulWrap | NumMulChecked | NumGt | NumGte | NumLt
|
||||
| NumLte | NumCompare | NumDivUnchecked | NumRemUnchecked | NumIsMultipleOf
|
||||
| ListSet | ListDrop | ListDropAt | ListSingle | ListRepeat | ListReverse
|
||||
| ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange
|
||||
| ListSwap | DictSize | DictEmpty | DictInsert | DictRemove | DictContains
|
||||
| DictGetUnsafe | DictKeys | DictValues | DictUnion | DictIntersection
|
||||
| DictDifference | SetFromList | NumAdd | NumAddWrap | NumAddChecked | NumSub
|
||||
| NumSubWrap | NumSubChecked | NumMul | NumMulWrap | NumMulChecked | NumGt | NumGte
|
||||
| NumLt | NumLte | NumCompare | NumDivUnchecked | NumRemUnchecked | NumIsMultipleOf
|
||||
| NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked | NumRound
|
||||
| NumToFloat | NumPow | NumCeiling | NumPowInt | NumFloor | NumIsFinite | NumAtan
|
||||
| NumAcos | NumAsin | NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy
|
||||
|
|
|
@ -964,6 +964,7 @@ define_builtins! {
|
|||
31 LIST_SORT_WITH: "sortWith"
|
||||
32 LIST_DROP: "drop"
|
||||
33 LIST_SWAP: "swap"
|
||||
34 LIST_DROP_AT: "dropAt"
|
||||
}
|
||||
5 RESULT: "Result" => {
|
||||
0 RESULT_RESULT: "Result" imported // the Result.Result type alias
|
||||
|
|
|
@ -993,6 +993,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
// List.append should own its first argument
|
||||
ListAppend => arena.alloc_slice_copy(&[owned, owned]),
|
||||
ListDrop => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||
ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||
ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||
|
||||
Eq | NotEq => arena.alloc_slice_copy(&[borrowed, borrowed]),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue