mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
add Set.fromList
This commit is contained in:
parent
581628f461
commit
49ca8f3e86
10 changed files with 166 additions and 35 deletions
|
@ -712,6 +712,26 @@ pub fn dictDifference(dict1: RocDict, dict2: RocDict, alignment: Alignment, key_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setFromList(list: RocList, alignment: Alignment, key_width: usize, value_width: usize, hash_fn: HashFn, is_eq: EqFn, dec_key: Dec, output: *RocDict) callconv(.C) void {
|
||||||
|
output.* = RocDict.empty();
|
||||||
|
|
||||||
|
var ptr = @ptrCast([*]u8, list.bytes);
|
||||||
|
|
||||||
|
const dec_value = doNothing;
|
||||||
|
const value = null;
|
||||||
|
|
||||||
|
const size = list.length;
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < size) : (i += 1) {
|
||||||
|
const key = ptr + i * key_width;
|
||||||
|
dictInsert(output.*, alignment, key, key_width, value, value_width, hash_fn, is_eq, dec_key, dec_value, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: decref checks for the empty case
|
||||||
|
const data_bytes = size * key_width;
|
||||||
|
decref(std.heap.c_allocator, alignment, list.bytes, data_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
const StepperCaller = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
|
const StepperCaller = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
|
||||||
pub fn dictWalk(dict: RocDict, stepper: Opaque, stepper_caller: StepperCaller, accum: Opaque, alignment: Alignment, key_width: usize, value_width: usize, accum_width: usize, output: Opaque) callconv(.C) void {
|
pub fn dictWalk(dict: RocDict, stepper: Opaque, stepper_caller: StepperCaller, accum: Opaque, alignment: Alignment, key_width: usize, value_width: usize, accum_width: usize, output: Opaque) callconv(.C) void {
|
||||||
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
|
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
|
||||||
|
@ -740,6 +760,10 @@ fn decref(
|
||||||
bytes_or_null: ?[*]u8,
|
bytes_or_null: ?[*]u8,
|
||||||
data_bytes: usize,
|
data_bytes: usize,
|
||||||
) void {
|
) void {
|
||||||
|
if (data_bytes == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var bytes = bytes_or_null orelse return;
|
var bytes = bytes_or_null orelse return;
|
||||||
|
|
||||||
const usizes: [*]usize = @ptrCast([*]usize, @alignCast(8, bytes));
|
const usizes: [*]usize = @ptrCast([*]usize, @alignCast(8, bytes));
|
||||||
|
|
|
@ -21,6 +21,8 @@ comptime {
|
||||||
exportDictFn(dict.dictDifference, "difference");
|
exportDictFn(dict.dictDifference, "difference");
|
||||||
exportDictFn(dict.dictWalk, "walk");
|
exportDictFn(dict.dictWalk, "walk");
|
||||||
|
|
||||||
|
exportDictFn(dict.setFromList, "set_from_list");
|
||||||
|
|
||||||
exportDictFn(hash.wyhash, "hash");
|
exportDictFn(hash.wyhash, "hash");
|
||||||
exportDictFn(hash.wyhash_rocstr, "hash_str");
|
exportDictFn(hash.wyhash_rocstr, "hash_str");
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,3 +51,5 @@ pub const DICT_UNION: &str = "roc_builtins.dict.union";
|
||||||
pub const DICT_DIFFERENCE: &str = "roc_builtins.dict.difference";
|
pub const DICT_DIFFERENCE: &str = "roc_builtins.dict.difference";
|
||||||
pub const DICT_INTERSECTION: &str = "roc_builtins.dict.intersection";
|
pub const DICT_INTERSECTION: &str = "roc_builtins.dict.intersection";
|
||||||
pub const DICT_WALK: &str = "roc_builtins.dict.walk";
|
pub const DICT_WALK: &str = "roc_builtins.dict.walk";
|
||||||
|
|
||||||
|
pub const SET_FROM_LIST: &str = "roc_builtins.dict.set_from_list";
|
||||||
|
|
|
@ -2240,8 +2240,8 @@ fn set_to_list(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set.fromList : List k -> Set k
|
/// Set.fromList : List k -> Set k
|
||||||
fn set_from_list(_symbol: Symbol, _var_store: &mut VarStore) -> Def {
|
fn set_from_list(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
todo!()
|
lowlevel_1(symbol, LowLevel::SetFromList, var_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set.insert : Set k, k -> Set k
|
/// Set.insert : Set k, k -> Set k
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::llvm::build_dict::{
|
use crate::llvm::build_dict::{
|
||||||
dict_contains, dict_difference, dict_empty, dict_get, dict_insert, dict_intersection,
|
dict_contains, dict_difference, dict_empty, dict_get, dict_insert, dict_intersection,
|
||||||
dict_keys, dict_len, dict_remove, dict_union, dict_values, dict_walk,
|
dict_keys, dict_len, dict_remove, dict_union, dict_values, dict_walk, set_from_list,
|
||||||
};
|
};
|
||||||
use crate::llvm::build_hash::generic_hash;
|
use crate::llvm::build_hash::generic_hash;
|
||||||
use crate::llvm::build_list::{
|
use crate::llvm::build_list::{
|
||||||
|
@ -4095,7 +4095,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
match dict_layout {
|
match dict_layout {
|
||||||
Layout::Builtin(Builtin::EmptyDict) => {
|
Layout::Builtin(Builtin::EmptyDict) => {
|
||||||
// no elements, so `key` is not in here
|
// no elements, so `key` is not in here
|
||||||
panic!("key type unknown")
|
empty_list(env)
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
|
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
|
||||||
dict_keys(env, layout_ids, dict, key_layout, value_layout)
|
dict_keys(env, layout_ids, dict, key_layout, value_layout)
|
||||||
|
@ -4111,7 +4111,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
match dict_layout {
|
match dict_layout {
|
||||||
Layout::Builtin(Builtin::EmptyDict) => {
|
Layout::Builtin(Builtin::EmptyDict) => {
|
||||||
// no elements, so `key` is not in here
|
// no elements, so `key` is not in here
|
||||||
panic!("key type unknown")
|
empty_list(env)
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
|
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
|
||||||
dict_values(env, layout_ids, dict, key_layout, value_layout)
|
dict_values(env, layout_ids, dict, key_layout, value_layout)
|
||||||
|
@ -4196,6 +4196,19 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
_ => unreachable!("invalid dict layout"),
|
_ => unreachable!("invalid dict layout"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SetFromList => {
|
||||||
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
|
||||||
|
match list_layout {
|
||||||
|
Layout::Builtin(Builtin::EmptyList) => dict_empty(env, scope),
|
||||||
|
Layout::Builtin(Builtin::List(_, key_layout)) => {
|
||||||
|
set_from_list(env, layout_ids, list, key_layout)
|
||||||
|
}
|
||||||
|
_ => unreachable!("invalid dict layout"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -811,6 +811,68 @@ pub fn dict_values<'a, 'ctx, 'env>(
|
||||||
env.builder.build_load(list_ptr, "load_keys_list")
|
env.builder.build_load(list_ptr, "load_keys_list")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn set_from_list<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
|
list: BasicValueEnum<'ctx>,
|
||||||
|
key_layout: &Layout<'a>,
|
||||||
|
) -> BasicValueEnum<'ctx> {
|
||||||
|
let builder = env.builder;
|
||||||
|
|
||||||
|
let zig_dict_type = env.module.get_struct_type("dict.RocDict").unwrap();
|
||||||
|
|
||||||
|
let list_alloca = builder.build_alloca(list.get_type(), "list_alloca");
|
||||||
|
let list_ptr = env.builder.build_bitcast(
|
||||||
|
list_alloca,
|
||||||
|
env.context.i128_type().ptr_type(AddressSpace::Generic),
|
||||||
|
"to_zig_list",
|
||||||
|
);
|
||||||
|
|
||||||
|
env.builder.build_store(list_alloca, list);
|
||||||
|
|
||||||
|
let key_width = env
|
||||||
|
.ptr_int()
|
||||||
|
.const_int(key_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||||
|
|
||||||
|
let value_width = env.ptr_int().const_zero();
|
||||||
|
|
||||||
|
let result_alloca =
|
||||||
|
builder.build_alloca(convert::dict(env.context, env.ptr_bytes), "result_alloca");
|
||||||
|
let result_ptr = builder.build_bitcast(
|
||||||
|
result_alloca,
|
||||||
|
zig_dict_type.ptr_type(AddressSpace::Generic),
|
||||||
|
"to_zig_dict",
|
||||||
|
);
|
||||||
|
|
||||||
|
let alignment =
|
||||||
|
Alignment::from_key_value_layout(key_layout, &Layout::Struct(&[]), env.ptr_bytes);
|
||||||
|
let alignment_iv = env.context.i8_type().const_int(alignment as u64, false);
|
||||||
|
|
||||||
|
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||||
|
let eq_fn = build_eq_wrapper(env, layout_ids, key_layout);
|
||||||
|
|
||||||
|
let dec_key_fn = build_rc_wrapper(env, layout_ids, key_layout, Mode::Dec);
|
||||||
|
|
||||||
|
call_void_bitcode_fn(
|
||||||
|
env,
|
||||||
|
&[
|
||||||
|
env.builder
|
||||||
|
.build_load(list_ptr.into_pointer_value(), "as_i128"),
|
||||||
|
alignment_iv.into(),
|
||||||
|
key_width.into(),
|
||||||
|
value_width.into(),
|
||||||
|
hash_fn.as_global_value().as_pointer_value().into(),
|
||||||
|
eq_fn.as_global_value().as_pointer_value().into(),
|
||||||
|
dec_key_fn.as_global_value().as_pointer_value().into(),
|
||||||
|
result_ptr.into(),
|
||||||
|
],
|
||||||
|
&bitcode::SET_FROM_LIST,
|
||||||
|
);
|
||||||
|
|
||||||
|
env.builder.build_load(result_alloca, "load_result")
|
||||||
|
}
|
||||||
|
|
||||||
fn build_hash_wrapper<'a, 'ctx, 'env>(
|
fn build_hash_wrapper<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
|
|
|
@ -283,6 +283,10 @@ pub fn dict(ctx: &Context, ptr_bytes: u32) -> StructType<'_> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dict_ptr(ctx: &Context, ptr_bytes: u32) -> PointerType<'_> {
|
||||||
|
dict(ctx, ptr_bytes).ptr_type(AddressSpace::Generic)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ptr_int(ctx: &Context, ptr_bytes: u32) -> IntType<'_> {
|
pub fn ptr_int(ctx: &Context, ptr_bytes: u32) -> IntType<'_> {
|
||||||
match ptr_bytes {
|
match ptr_bytes {
|
||||||
1 => ctx.i8_type(),
|
1 => ctx.i8_type(),
|
||||||
|
|
|
@ -113,14 +113,11 @@ mod gen_set {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
fromList : List a -> Set a
|
|
||||||
fromList = \list -> List.walk list (\x, a -> Set.insert a x) Set.empty
|
|
||||||
|
|
||||||
set1 : Set I64
|
set1 : Set I64
|
||||||
set1 = fromList [1,2]
|
set1 = Set.fromList [1,2]
|
||||||
|
|
||||||
set2 : Set I64
|
set2 : Set I64
|
||||||
set2 = fromList [1,3,4]
|
set2 = Set.fromList [1,3,4]
|
||||||
|
|
||||||
Set.union set1 set2
|
Set.union set1 set2
|
||||||
|> Set.toList
|
|> Set.toList
|
||||||
|
@ -136,14 +133,11 @@ mod gen_set {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
fromList : List a -> Set a
|
|
||||||
fromList = \list -> List.walk list (\x, a -> Set.insert a x) Set.empty
|
|
||||||
|
|
||||||
set1 : Set I64
|
set1 : Set I64
|
||||||
set1 = fromList [1,2]
|
set1 = Set.fromList [1,2]
|
||||||
|
|
||||||
set2 : Set I64
|
set2 : Set I64
|
||||||
set2 = fromList [1,3,4]
|
set2 = Set.fromList [1,3,4]
|
||||||
|
|
||||||
Set.difference set1 set2
|
Set.difference set1 set2
|
||||||
|> Set.toList
|
|> Set.toList
|
||||||
|
@ -159,14 +153,11 @@ mod gen_set {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
fromList : List a -> Set a
|
|
||||||
fromList = \list -> List.walk list (\x, a -> Set.insert a x) Set.empty
|
|
||||||
|
|
||||||
set1 : Set I64
|
set1 : Set I64
|
||||||
set1 = fromList [1,2]
|
set1 = Set.fromList [1,2]
|
||||||
|
|
||||||
set2 : Set I64
|
set2 : Set I64
|
||||||
set2 = fromList [1,3,4]
|
set2 = Set.fromList [1,3,4]
|
||||||
|
|
||||||
Set.intersection set1 set2
|
Set.intersection set1 set2
|
||||||
|> Set.toList
|
|> Set.toList
|
||||||
|
@ -182,11 +173,7 @@ mod gen_set {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
fromList : List a -> Set a
|
Set.walk (Set.fromList [1,2,3]) (\x, y -> x + y) 0
|
||||||
fromList = \list -> List.walk list (\x, a -> Set.insert a x) Set.empty
|
|
||||||
|
|
||||||
|
|
||||||
Set.walk (fromList [1,2,3]) (\x, y -> x + y) 0
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
6,
|
6,
|
||||||
|
@ -199,11 +186,7 @@ mod gen_set {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
fromList : List a -> Set a
|
Set.contains (Set.fromList [1,3,4]) 4
|
||||||
fromList = \list -> List.walk list (\x, a -> Set.insert a x) Set.empty
|
|
||||||
|
|
||||||
|
|
||||||
Set.contains (fromList [1,3,4]) 4
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
|
@ -213,15 +196,53 @@ mod gen_set {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
fromList : List a -> Set a
|
Set.contains (Set.fromList [1,3,4]) 2
|
||||||
fromList = \list -> List.walk list (\x, a -> Set.insert a x) Set.empty
|
|
||||||
|
|
||||||
|
|
||||||
Set.contains (fromList [1,3,4]) 2
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
false,
|
false,
|
||||||
bool
|
bool
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_list() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
[1,2,2,3,1,4]
|
||||||
|
|> Set.fromList
|
||||||
|
|> Set.toList
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
&[4, 2, 3, 1],
|
||||||
|
&[i64]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
[]
|
||||||
|
|> Set.fromList
|
||||||
|
|> Set.toList
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
&[],
|
||||||
|
&[i64]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
empty : List I64
|
||||||
|
empty = []
|
||||||
|
|
||||||
|
empty
|
||||||
|
|> Set.fromList
|
||||||
|
|> Set.toList
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
&[],
|
||||||
|
&[i64]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ pub enum LowLevel {
|
||||||
DictIntersection,
|
DictIntersection,
|
||||||
DictDifference,
|
DictDifference,
|
||||||
DictWalk,
|
DictWalk,
|
||||||
|
SetFromList,
|
||||||
NumAdd,
|
NumAdd,
|
||||||
NumAddWrap,
|
NumAddWrap,
|
||||||
NumAddChecked,
|
NumAddChecked,
|
||||||
|
|
|
@ -615,5 +615,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
|
|
||||||
// borrow function argument so we don't have to worry about RC of the closure
|
// borrow function argument so we don't have to worry about RC of the closure
|
||||||
DictWalk => arena.alloc_slice_copy(&[owned, borrowed, owned]),
|
DictWalk => arena.alloc_slice_copy(&[owned, borrowed, owned]),
|
||||||
|
|
||||||
|
SetFromList => arena.alloc_slice_copy(&[owned]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue