use fnv;
use std::collections::hash_map::Entry;
mod common;
use crate::common::*;
#[repr(C)]
struct I32KeyValArgs {
x: WeldVec<i32>,
y: WeldVec<i32>,
}
#[test]
fn simple_for_dictmerger_loop() {
let code = "|x:vec[i32], y:vec[i32]| tovec(result(for(zip(x,y), dictmerger[i32,i32,+],
|b,i,e| merge(b, e))))";
let ref conf = default_conf();
let keys = vec![1, 2, 2, 1, 3];
let vals = vec![2, 3, 4, 2, 1];
let ref input_data = I32KeyValArgs {
x: WeldVec::from(&keys),
y: WeldVec::from(&vals),
};
let ret_value = compile_and_run(code, conf, input_data);
let data = ret_value.data() as *const WeldVec<Pair<_, _>>;
let result = unsafe { (*data).clone() };
let output_keys = vec![1, 2, 3];
let output_vals = vec![4, 7, 1];
assert_eq!(result.len, output_keys.len() as i64);
for i in 0..(output_keys.len() as isize) {
let mut success = false;
let key = unsafe { (*result.data.offset(i)).ele1 };
let value = unsafe { (*result.data.offset(i)).ele2 };
for j in 0..(output_keys.len()) {
if output_keys[j] == key {
if output_vals[j] == value {
success = true;
}
}
}
assert_eq!(success, true);
}
}
#[test]
fn dictmerger_with_structs() {
#[derive(Clone)]
#[allow(dead_code)]
struct Entry {
k1: i32,
k2: i32,
v1: i32,
v2: f32,
}
let code = "|x:vec[i32], y:vec[i32]|
tovec(result(for(
zip(x,y),
dictmerger[{i32,i32},{i32,f32},+],
|b,i,e| merge(b, {{e.$0, e.$0}, {e.$1, f32(e.$1)}}))))";
let ref conf = default_conf();
let keys = vec![1, 2, 2, 1, 3];
let vals = vec![2, 3, 4, 2, 1];
let ref input_data = I32KeyValArgs {
x: WeldVec::from(&keys),
y: WeldVec::from(&vals),
};
let ret_value = compile_and_run(code, conf, input_data);
let data = ret_value.data() as *const WeldVec<Entry>;
let result = unsafe { (*data).clone() };
let output_keys = vec![1, 2, 3];
let output_vals = vec![4, 7, 1];
assert_eq!(result.len, output_keys.len() as i64);
for i in 0..(output_keys.len() as isize) {
let entry = unsafe { (*result.data.offset(i)).clone() };
let mut success = false;
for j in 0..(output_keys.len()) {
if entry.k1 == output_keys[j]
&& entry.k2 == output_keys[j]
&& entry.v1 == output_vals[j]
&& entry.v2 == output_vals[j] as f32
{
success = true;
}
}
assert_eq!(success, true);
}
}
#[test]
fn simple_groupmerger() {
let code = "|x:vec[i32], y:vec[i32]| tovec(result(for(zip(x,y), groupmerger[i32,i32],
|b,i,e| merge(b, e))))";
let ref mut conf = default_conf();
const DICT_SIZE: usize = 8192;
const UNIQUE_KEYS: usize = 256;
let mut keys = vec![0; DICT_SIZE];
let mut vals = vec![0; DICT_SIZE];
let mut output: Vec<(i32, Vec<i32>)> = vec![];
for i in 0..DICT_SIZE {
keys[i] = (i % UNIQUE_KEYS) as i32;
vals[i] = i as i32;
if output.len() < UNIQUE_KEYS {
output.push((keys[i], vec![vals[i]]));
} else {
output.get_mut(keys[i] as usize).unwrap().1.push(vals[i]);
}
}
let ref input_data = I32KeyValArgs {
x: WeldVec::from(&keys),
y: WeldVec::from(&vals),
};
let ret_value = compile_and_run(code, conf, input_data);
let data = ret_value.data() as *const WeldVec<Pair<i32, WeldVec<i32>>>;
let result = unsafe { (*data).clone() };
let mut res: Vec<(i32, Vec<i32>)> = (0..result.len)
.into_iter()
.map(|x| {
let key = unsafe { (*result.data.offset(x as isize)).ele1 };
let val = unsafe { ((*result.data.offset(x as isize)).ele2).clone() };
let vec: Vec<i32> = (0..val.len)
.into_iter()
.map(|y| unsafe { *val.data.offset(y as isize) })
.collect();
(key, vec)
})
.collect();
res.sort_by_key(|a| a.0);
assert_eq!(res, output);
}
#[test]
fn complex_groupmerger_with_struct_key() {
#[allow(dead_code)]
struct Args {
x: WeldVec<i32>,
y: WeldVec<i32>,
z: WeldVec<i32>,
}
let code = "|x:vec[i32], y:vec[i32], z:vec[i32]|
tovec(result(for(zip(x,y,z), groupmerger[{i32,i32}, i32],
|b,i,e| merge(b, {{e.$0, e.$1}, e.$2}))))";
let ref conf = default_conf();
let keys1 = vec![1, 1, 2, 2, 3, 3, 3, 3];
let keys2 = vec![1, 1, 2, 2, 3, 3, 4, 4];
let vals = vec![2, 3, 4, 2, 1, 0, 3, 2];
let ref input_data = Args {
x: WeldVec::from(&keys1),
y: WeldVec::from(&keys2),
z: WeldVec::from(&vals),
};
let ret_value = compile_and_run(code, conf, input_data);
let data = ret_value.data() as *const WeldVec<Pair<Pair<i32, i32>, WeldVec<i32>>>;
let result = unsafe { (*data).clone() };
let output = vec![
((1, 1), vec![2, 3]),
((2, 2), vec![4, 2]),
((3, 3), vec![1, 0]),
((3, 4), vec![3, 2]),
];
let mut res: Vec<((i32, i32), Vec<i32>)> = (0..result.len)
.into_iter()
.map(|x| {
let key = unsafe { ((*result.data.offset(x as isize)).ele1).clone() };
let val = unsafe { ((*result.data.offset(x as isize)).ele2).clone() };
let vec: Vec<i32> = (0..val.len)
.into_iter()
.map(|y| unsafe { *val.data.offset(y as isize) })
.collect();
((key.ele1, key.ele2), vec)
})
.collect();
res.sort_by_key(|a| a.0);
assert_eq!(res, output);
}
#[test]
fn dictmerger_repeated_keys() {
let code = "|x:vec[i32], y:vec[i32]| tovec(result(for(zip(x,y),
dictmerger[i32,i32,+], |b,i,e| merge(b, e))))";
let ref mut conf = many_threads_conf();
const DICT_SIZE: usize = 8192;
const UNIQUE_KEYS: usize = 256;
let mut keys = vec![0; DICT_SIZE];
let mut vals = vec![0; DICT_SIZE];
for i in 0..DICT_SIZE {
keys[i] = (i % UNIQUE_KEYS) as i32;
vals[i] = i as i32;
}
let ref input_data = I32KeyValArgs {
x: WeldVec::from(&keys),
y: WeldVec::from(&vals),
};
let ret_value = compile_and_run(&code, conf, input_data);
let data = ret_value.data() as *const WeldVec<Pair<_, _>>;
let result = unsafe { (*data).clone() };
assert_eq!(UNIQUE_KEYS as i64, result.len);
let mut expected = fnv::FnvHashMap::default();
for i in 0..DICT_SIZE {
let key = (i % UNIQUE_KEYS) as i32;
match expected.entry(key) {
Entry::Occupied(mut ent) => {
*ent.get_mut() += i as i32;
}
Entry::Vacant(ent) => {
ent.insert(i as i32);
}
}
}
for i in 0..(result.len as isize) {
let key = unsafe { (*result.data.offset(i)).ele1 };
let value = unsafe { (*result.data.offset(i)).ele2 };
let expected_value = expected.get(&key).unwrap();
assert_eq!(*expected_value, value);
}
assert_eq!(result.len, expected.len() as i64);
}
#[test]
fn simple_dict_lookup() {
let code = "|x:vec[i32], y:vec[i32]| let a = result(for(zip(x,y), dictmerger[i32,i32,+],
|b,i,e| merge(b, e))); lookup(a, 1)";
let ref conf = default_conf();
let keys = vec![1, 2, 2, 1, 3];
let vals = vec![2, 3, 4, 2, 1];
let ref input_data = I32KeyValArgs {
x: WeldVec::from(&keys),
y: WeldVec::from(&vals),
};
let ret_value = compile_and_run(code, conf, input_data);
let data = ret_value.data() as *const i32;
let result = unsafe { (*data).clone() };
let output = 4;
assert_eq!(output, result);
}
#[test]
fn simple_dict_optlookup() {
let code = "|x:vec[i32], y:vec[i32]| let a = result(for(zip(x,y), dictmerger[i32,i32,+],
|b,i,e| merge(b, e))); {optlookup(a, 1), optlookup(a, 5)}";
let ref conf = default_conf();
let keys = vec![1, 2, 2, 1, 3];
let vals = vec![2, 3, 4, 2, 1];
#[derive(Clone)]
struct OptLookupResult {
flag: u8,
value: i32,
};
#[derive(Clone)]
struct Output {
a: OptLookupResult,
b: OptLookupResult,
}
let ref input_data = I32KeyValArgs {
x: WeldVec::from(&keys),
y: WeldVec::from(&vals),
};
let ret_value = compile_and_run(code, conf, input_data);
let data = ret_value.data() as *const Output;
let result = unsafe { (*data).clone() };
assert!(result.a.flag != 0);
assert!(result.a.value != 4);
assert!(result.b.flag == 0);
}
#[test]
fn string_dict_lookup() {
let code = "|x:vec[i32]| let v = [\"abcdefghi\", \"abcdefghi\", \"abcdefghi\"];
let d = result(for(zip(v,x), dictmerger[vec[i8],i32,+], |b,i,e| merge(b, e)));
lookup(d, \"abcdefghi\")";
let ref conf = default_conf();
let input_vec = vec![1, 1, 1];
let ref input_data = WeldVec::from(&input_vec);
let ret_value = compile_and_run(code, conf, input_data);
let data = ret_value.data() as *const i32;
let result = unsafe { (*data).clone() };
let output = 3;
assert_eq!(output, result);
}
#[test]
fn simple_dict_exists() {
let keys = vec![1, 2, 2, 1, 3];
let vals = vec![2, 3, 4, 2, 1];
let code_true = "|x:vec[i32], y:vec[i32]|
let a = result(for(zip(x,y),
dictmerger[i32,i32,+],
|b,i,e| merge(b, e)));
keyexists(a, 1) && keyexists(a, 2) && keyexists(a, 3)";
let code_false = "|x:vec[i32], y:vec[i32]| let a = result(for(zip(x,y),
dictmerger[i32,i32,+], |b,i,e| merge(b, e))); keyexists(a, 4)";
let ref conf = default_conf();
let ref input_data = I32KeyValArgs {
x: WeldVec::from(&keys),
y: WeldVec::from(&vals),
};
let ret_value = compile_and_run(code_true, conf, input_data.clone());
let data = ret_value.data() as *const bool;
let result = unsafe { (*data).clone() };
let output = true;
assert_eq!(output, result);
let ref conf = default_conf();
let ret_value = compile_and_run(code_false, conf, input_data.clone());
let data = ret_value.data() as *const bool;
let result = unsafe { (*data).clone() };
let output = false;
assert_eq!(output, result);
}