mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
add difference
This commit is contained in:
parent
02db8f1a05
commit
39c4353554
5 changed files with 131 additions and 84 deletions
|
@ -683,6 +683,31 @@ pub fn dictIntersection(dict1: RocDict, dict2: RocDict, alignment: Alignment, ke
|
|||
}
|
||||
}
|
||||
|
||||
pub fn dictDifference(dict1: RocDict, dict2: RocDict, alignment: Alignment, key_width: usize, value_width: usize, hash_fn: HashFn, is_eq: EqFn, dec_key: Inc, dec_value: Inc, output: *RocDict) callconv(.C) void {
|
||||
output.* = dict1.makeUnique(std.heap.c_allocator, alignment, key_width, value_width);
|
||||
|
||||
var i: usize = 0;
|
||||
const size = dict1.capacity();
|
||||
while (i < size) : (i += 1) {
|
||||
switch (output.getSlot(i, key_width, value_width)) {
|
||||
Slot.Filled => {
|
||||
const key = dict1.getKey(i, alignment, key_width, value_width);
|
||||
|
||||
switch (dict2.findIndex(alignment, key, key_width, value_width, hash_fn, is_eq)) {
|
||||
MaybeIndex.not_found => {
|
||||
// keep this key/value
|
||||
continue;
|
||||
},
|
||||
MaybeIndex.index => |_| {
|
||||
dictRemove(output.*, alignment, key, key_width, value_width, hash_fn, is_eq, dec_key, dec_value, output);
|
||||
},
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decref(
|
||||
allocator: *Allocator,
|
||||
alignment: Alignment,
|
||||
|
|
|
@ -18,7 +18,7 @@ comptime {
|
|||
exportDictFn(dict.dictValues, "values");
|
||||
exportDictFn(dict.dictUnion, "union");
|
||||
exportDictFn(dict.dictIntersection, "intersection");
|
||||
// exportDictFn(dict.dictValues, "values");
|
||||
exportDictFn(dict.dictDifference, "difference");
|
||||
|
||||
exportDictFn(hash.wyhash, "hash");
|
||||
exportDictFn(hash.wyhash_rocstr, "hash_str");
|
||||
|
|
|
@ -5,7 +5,6 @@ use crate::pattern::Pattern;
|
|||
use roc_collections::all::{MutMap, SendMap};
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::operator::CalledVia;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Located, Region};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
|
@ -2169,21 +2168,17 @@ fn dict_dict_dict(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def
|
|||
|
||||
/// Dict.union : Dict k v, Dict k v -> Dict k v
|
||||
fn dict_union(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
dict_dict_dict(Symbol::DICT_UNION, LowLevel::DictUnion, var_store)
|
||||
dict_dict_dict(symbol, LowLevel::DictUnion, var_store)
|
||||
}
|
||||
|
||||
/// Dict.difference : Dict k v, Dict k v -> Dict k v
|
||||
fn dict_difference(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
dict_dict_dict(Symbol::DICT_DIFFERENCE, LowLevel::DictDifference, var_store)
|
||||
dict_dict_dict(symbol, LowLevel::DictDifference, var_store)
|
||||
}
|
||||
|
||||
/// Dict.intersection : Dict k v, Dict k v -> Dict k v
|
||||
fn dict_intersection(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
dict_dict_dict(
|
||||
Symbol::DICT_INTERSECTION,
|
||||
LowLevel::DictIntersection,
|
||||
var_store,
|
||||
)
|
||||
dict_dict_dict(symbol, LowLevel::DictIntersection, var_store)
|
||||
}
|
||||
|
||||
/// Num.rem : Int, Int -> Result Int [ DivByZero ]*
|
||||
|
|
|
@ -570,80 +570,6 @@ pub fn dict_union<'a, 'ctx, 'env>(
|
|||
env.builder.build_load(output_ptr, "load_output_ptr")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_intersection<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict1: BasicValueEnum<'ctx>,
|
||||
dict2: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let zig_dict_type = env.module.get_struct_type("dict.RocDict").unwrap();
|
||||
|
||||
let dict1_ptr = builder.build_alloca(zig_dict_type, "dict_ptr");
|
||||
let dict2_ptr = builder.build_alloca(zig_dict_type, "dict_ptr");
|
||||
|
||||
env.builder.build_store(
|
||||
dict1_ptr,
|
||||
struct_to_zig_dict(env, dict1.into_struct_value()),
|
||||
);
|
||||
|
||||
env.builder.build_store(
|
||||
dict2_ptr,
|
||||
struct_to_zig_dict(env, dict2.into_struct_value()),
|
||||
);
|
||||
|
||||
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_int(value_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, 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);
|
||||
let dec_value_fn = build_rc_wrapper(env, layout_ids, value_layout, Mode::Dec);
|
||||
|
||||
let output_ptr = builder.build_alloca(zig_dict_type, "output_ptr");
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
dict1_ptr.into(),
|
||||
dict2_ptr.into(),
|
||||
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(),
|
||||
dec_value_fn.as_global_value().as_pointer_value().into(),
|
||||
output_ptr.into(),
|
||||
],
|
||||
&bitcode::DICT_INTERSECTION,
|
||||
);
|
||||
|
||||
let output_ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
output_ptr,
|
||||
convert::dict(env.context, env.ptr_bytes).ptr_type(AddressSpace::Generic),
|
||||
"to_roc_dict",
|
||||
)
|
||||
.into_pointer_value();
|
||||
|
||||
env.builder.build_load(output_ptr, "load_output_ptr")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_difference<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
@ -652,6 +578,47 @@ pub fn dict_difference<'a, 'ctx, 'env>(
|
|||
dict2: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
dict_intersect_or_difference(
|
||||
env,
|
||||
layout_ids,
|
||||
dict1,
|
||||
dict2,
|
||||
key_layout,
|
||||
value_layout,
|
||||
&bitcode::DICT_DIFFERENCE,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_intersection<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict1: BasicValueEnum<'ctx>,
|
||||
dict2: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
dict_intersect_or_difference(
|
||||
env,
|
||||
layout_ids,
|
||||
dict1,
|
||||
dict2,
|
||||
key_layout,
|
||||
value_layout,
|
||||
&bitcode::DICT_INTERSECTION,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn dict_intersect_or_difference<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict1: BasicValueEnum<'ctx>,
|
||||
dict2: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
op: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
|
@ -703,7 +670,7 @@ pub fn dict_difference<'a, 'ctx, 'env>(
|
|||
dec_value_fn.as_global_value().as_pointer_value().into(),
|
||||
output_ptr.into(),
|
||||
],
|
||||
&bitcode::DICT_DIFFERENCE,
|
||||
op,
|
||||
);
|
||||
|
||||
let output_ptr = env
|
||||
|
|
|
@ -437,4 +437,64 @@ mod gen_dict {
|
|||
&[i64]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn difference() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
dict1 : Dict I64 {}
|
||||
dict1 =
|
||||
Dict.empty
|
||||
|> Dict.insert 1 {}
|
||||
|> Dict.insert 2 {}
|
||||
|> Dict.insert 3 {}
|
||||
|> Dict.insert 4 {}
|
||||
|> Dict.insert 5 {}
|
||||
|
||||
dict2 : Dict I64 {}
|
||||
dict2 =
|
||||
Dict.empty
|
||||
|> Dict.insert 0 {}
|
||||
|> Dict.insert 2 {}
|
||||
|> Dict.insert 4 {}
|
||||
|
||||
Dict.difference dict1 dict2
|
||||
|> Dict.len
|
||||
"#
|
||||
),
|
||||
3,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn difference_prefer_first() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
dict1 : Dict I64 I64
|
||||
dict1 =
|
||||
Dict.empty
|
||||
|> Dict.insert 1 1
|
||||
|> Dict.insert 2 2
|
||||
|> Dict.insert 3 3
|
||||
|> Dict.insert 4 4
|
||||
|> Dict.insert 5 5
|
||||
|
||||
dict2 : Dict I64 I64
|
||||
dict2 =
|
||||
Dict.empty
|
||||
|> Dict.insert 0 100
|
||||
|> Dict.insert 2 200
|
||||
|> Dict.insert 4 300
|
||||
|
||||
Dict.difference dict1 dict2
|
||||
|> Dict.values
|
||||
"#
|
||||
),
|
||||
&[5, 3, 1],
|
||||
&[i64]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue