mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +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 {
|
pub fn listRange(width: utils.IntWidth, low: Opaque, high: Opaque) callconv(.C) RocList {
|
||||||
return switch (width) {
|
return switch (width) {
|
||||||
.U8 => helper1(u8, low, high),
|
.U8 => helper1(u8, low, high),
|
||||||
|
|
|
@ -39,6 +39,7 @@ comptime {
|
||||||
exportListFn(list.listSortWith, "sort_with");
|
exportListFn(list.listSortWith, "sort_with");
|
||||||
exportListFn(list.listConcat, "concat");
|
exportListFn(list.listConcat, "concat");
|
||||||
exportListFn(list.listDrop, "drop");
|
exportListFn(list.listDrop, "drop");
|
||||||
|
exportListFn(list.listDropAt, "drop_at");
|
||||||
exportListFn(list.listSet, "set");
|
exportListFn(list.listSet, "set");
|
||||||
exportListFn(list.listSetInPlace, "set_in_place");
|
exportListFn(list.listSetInPlace, "set_in_place");
|
||||||
exportListFn(list.listSwap, "swap");
|
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
|
## If the given index is outside the bounds of the list, returns the original
|
||||||
## list unmodified.
|
## 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
|
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.
|
## 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.
|
## 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].
|
## 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.
|
## 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_APPEND: &str = "roc_builtins.list.append";
|
||||||
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
|
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
|
||||||
pub const LIST_DROP: &str = "roc_builtins.list.drop";
|
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_SWAP: &str = "roc_builtins.list.swap";
|
||||||
pub const LIST_SINGLE: &str = "roc_builtins.list.single";
|
pub const LIST_SINGLE: &str = "roc_builtins.list.single";
|
||||||
pub const LIST_JOIN: &str = "roc_builtins.list.join";
|
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))),
|
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
|
// swap : List elem, Nat, Nat -> List elem
|
||||||
add_top_level_function_type!(
|
add_top_level_function_type!(
|
||||||
Symbol::LIST_SWAP,
|
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_MAP2 => list_map2,
|
||||||
LIST_MAP3 => list_map3,
|
LIST_MAP3 => list_map3,
|
||||||
LIST_DROP => list_drop,
|
LIST_DROP => list_drop,
|
||||||
|
LIST_DROP_AT => list_drop_at,
|
||||||
LIST_SWAP => list_swap,
|
LIST_SWAP => list_swap,
|
||||||
LIST_MAP_WITH_INDEX => list_map_with_index,
|
LIST_MAP_WITH_INDEX => list_map_with_index,
|
||||||
LIST_KEEP_IF => list_keep_if,
|
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
|
/// List.append : List elem, elem -> List elem
|
||||||
fn list_append(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn list_append(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let list_var = var_store.fresh();
|
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_hash::generic_hash;
|
||||||
use crate::llvm::build_list::{
|
use crate::llvm::build_list::{
|
||||||
self, allocate_list, empty_list, empty_polymorphic_list, list_append, list_concat,
|
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_contains, list_drop, list_drop_at, list_get_unsafe, list_join, list_keep_errs,
|
||||||
list_keep_oks, list_len, list_map, list_map2, list_map3, list_map_with_index, list_prepend,
|
list_keep_if, list_keep_oks, list_len, list_map, list_map2, list_map3, list_map_with_index,
|
||||||
list_range, list_repeat, list_reverse, list_set, list_single, list_sort_with, list_swap,
|
list_prepend, list_range, list_repeat, list_reverse, list_set, list_single, list_sort_with,
|
||||||
|
list_swap,
|
||||||
};
|
};
|
||||||
use crate::llvm::build_str::{
|
use crate::llvm::build_str::{
|
||||||
empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int,
|
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),
|
_ => 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 => {
|
ListPrepend => {
|
||||||
// List.prepend : List elem, elem -> List elem
|
// List.prepend : List elem, elem -> List elem
|
||||||
debug_assert_eq!(args.len(), 2);
|
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>(
|
pub fn list_drop<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
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
|
/// List.set : List elem, Nat, elem -> List elem
|
||||||
pub fn list_set<'a, 'ctx, 'env>(
|
pub fn list_set<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
|
|
@ -41,6 +41,7 @@ pub enum LowLevel {
|
||||||
ListKeepErrs,
|
ListKeepErrs,
|
||||||
ListSortWith,
|
ListSortWith,
|
||||||
ListDrop,
|
ListDrop,
|
||||||
|
ListDropAt,
|
||||||
ListSwap,
|
ListSwap,
|
||||||
DictSize,
|
DictSize,
|
||||||
DictEmpty,
|
DictEmpty,
|
||||||
|
@ -116,13 +117,13 @@ impl LowLevel {
|
||||||
StrConcat | StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt
|
StrConcat | StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt
|
||||||
| StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8
|
| StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8
|
||||||
| StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | ListLen | ListGetUnsafe
|
| StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | ListLen | ListGetUnsafe
|
||||||
| ListSet | ListDrop | ListSingle | ListRepeat | ListReverse | ListConcat
|
| ListSet | ListDrop | ListDropAt | ListSingle | ListRepeat | ListReverse
|
||||||
| ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListSwap
|
| ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange
|
||||||
| DictSize | DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe
|
| ListSwap | DictSize | DictEmpty | DictInsert | DictRemove | DictContains
|
||||||
| DictKeys | DictValues | DictUnion | DictIntersection | DictDifference
|
| DictGetUnsafe | DictKeys | DictValues | DictUnion | DictIntersection
|
||||||
| SetFromList | NumAdd | NumAddWrap | NumAddChecked | NumSub | NumSubWrap
|
| DictDifference | SetFromList | NumAdd | NumAddWrap | NumAddChecked | NumSub
|
||||||
| NumSubChecked | NumMul | NumMulWrap | NumMulChecked | NumGt | NumGte | NumLt
|
| NumSubWrap | NumSubChecked | NumMul | NumMulWrap | NumMulChecked | NumGt | NumGte
|
||||||
| NumLte | NumCompare | NumDivUnchecked | NumRemUnchecked | NumIsMultipleOf
|
| NumLt | NumLte | NumCompare | NumDivUnchecked | NumRemUnchecked | NumIsMultipleOf
|
||||||
| NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked | NumRound
|
| NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked | NumRound
|
||||||
| NumToFloat | NumPow | NumCeiling | NumPowInt | NumFloor | NumIsFinite | NumAtan
|
| NumToFloat | NumPow | NumCeiling | NumPowInt | NumFloor | NumIsFinite | NumAtan
|
||||||
| NumAcos | NumAsin | NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy
|
| NumAcos | NumAsin | NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy
|
||||||
|
|
|
@ -964,6 +964,7 @@ define_builtins! {
|
||||||
31 LIST_SORT_WITH: "sortWith"
|
31 LIST_SORT_WITH: "sortWith"
|
||||||
32 LIST_DROP: "drop"
|
32 LIST_DROP: "drop"
|
||||||
33 LIST_SWAP: "swap"
|
33 LIST_SWAP: "swap"
|
||||||
|
34 LIST_DROP_AT: "dropAt"
|
||||||
}
|
}
|
||||||
5 RESULT: "Result" => {
|
5 RESULT: "Result" => {
|
||||||
0 RESULT_RESULT: "Result" imported // the Result.Result type alias
|
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
|
// List.append should own its first argument
|
||||||
ListAppend => arena.alloc_slice_copy(&[owned, owned]),
|
ListAppend => arena.alloc_slice_copy(&[owned, owned]),
|
||||||
ListDrop => arena.alloc_slice_copy(&[owned, irrelevant]),
|
ListDrop => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||||
|
ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||||
ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||||
|
|
||||||
Eq | NotEq => arena.alloc_slice_copy(&[borrowed, borrowed]),
|
Eq | NotEq => arena.alloc_slice_copy(&[borrowed, borrowed]),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue