mech_set/operations/
cartesian_product.rs

1
2use crate::*;
3
4use indexmap::set::IndexSet;
5use mech_core::set::MechSet;
6
7// CartesianProduct ------------------------------------------------------------------------
8
9#[derive(Debug)]
10struct SetCartesianProductFxn {
11  lhs: Ref<MechSet>,
12  rhs: Ref<MechSet>,
13  out: Ref<MechSet>,
14}
15impl MechFunctionFactory for SetCartesianProductFxn {
16  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
17    match args {
18      FunctionArgs::Binary(out, arg1, arg2) => {
19        let lhs: Ref<MechSet> = unsafe { arg1.as_unchecked() }.clone();
20        let rhs: Ref<MechSet> = unsafe { arg2.as_unchecked() }.clone();
21        let out: Ref<MechSet> = unsafe { out.as_unchecked() }.clone();
22        Ok(Box::new(SetCartesianProductFxn {lhs, rhs, out }))
23      },
24      _ => Err(MechError2::new(IncorrectNumberOfArguments { expected: 2, found: args.len() }, None).with_compiler_loc()),
25    }
26  }    
27}
28impl MechFunctionImpl for SetCartesianProductFxn {
29  fn solve(&self) {
30    unsafe {
31      // Get mutable reference to the output set
32      let out_ptr: &mut MechSet = &mut *(self.out.as_mut_ptr());
33
34      // Get references to lhs and rhs sets
35      let lhs_ptr: &MechSet = &*(self.lhs.as_ptr());
36      let rhs_ptr: &MechSet = &*(self.rhs.as_ptr());
37
38      // Clear the output set first (optional, depending on semantics)
39      out_ptr.set.clear();
40
41      // Cartesian product lhs and rhs sets into output
42      for elem1 in lhs_ptr.set.clone()
43      {
44        for elem2 in rhs_ptr.set.clone()
45        {
46          out_ptr.set.insert(Value::Tuple(Ref::new(MechTuple{elements: vec![Box::new(elem1.clone()), Box::new(elem2)]})));
47        }
48      }
49
50      // Update metadata
51      out_ptr.num_elements = out_ptr.set.len();
52      out_ptr.kind = if out_ptr.set.len() > 0 {
53        out_ptr.set.iter().next().unwrap().kind()
54      } else {
55        ValueKind::Empty
56      };
57    }
58  }
59  fn out(&self) -> Value { Value::Set(self.out.clone()) }
60  fn to_string(&self) -> String { format!("{:#?}", self) }
61}
62#[cfg(feature = "compiler")]
63impl MechFunctionCompiler for SetCartesianProductFxn {
64  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
65    let name = format!("SetCartesianProductFxn");
66    compile_binop!(name, self.out, self.lhs, self.rhs, ctx, FeatureFlag::Custom(hash_str("set/cartesian-product")) );
67  }
68}
69register_descriptor! {
70  FunctionDescriptor {
71    name: "SetCartesianProductFxn",
72    ptr: SetCartesianProductFxn::new,
73  }
74}
75
76fn set_cartesian_product_fxn(lhs: Value, rhs: Value) -> MResult<Box<dyn MechFunction>> {
77  match (lhs, rhs) {
78    (Value::Set(lhs), Value::Set(rhs)) => {
79      Ok(Box::new(SetCartesianProductFxn { lhs: lhs.clone(), rhs: rhs.clone(), out: Ref::new(MechSet::new(ValueKind::Tuple(vec![lhs.borrow().kind.clone(), rhs.borrow().kind.clone()]), lhs.borrow().num_elements * rhs.borrow().num_elements)) }))
80    },
81    x => Err(MechError2::new(
82      UnhandledFunctionArgumentKind2 { arg: (x.0.kind(), x.1.kind()), fxn_name: "set/cartesian-product".to_string() },
83      None
84    ).with_compiler_loc()),
85  }
86}
87
88pub struct SetCartesianProduct {}
89impl NativeFunctionCompiler for SetCartesianProduct {
90  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
91    if arguments.len() != 2 {
92      return Err(MechError2::new(IncorrectNumberOfArguments { expected: 2, found: arguments.len() }, None).with_compiler_loc());
93    }
94    let lhs = arguments[0].clone();
95    let rhs = arguments[1].clone();
96    match set_cartesian_product_fxn(lhs.clone(),rhs.clone()) {
97      Ok(fxn) => Ok(fxn),
98      Err(x) => {
99        match (lhs,rhs) {
100          (Value::MutableReference(lhs),Value::MutableReference(rhs)) => { set_cartesian_product_fxn(lhs.borrow().clone(),rhs.borrow().clone()) },
101          (lhs,Value::MutableReference(rhs)) => { set_cartesian_product_fxn(lhs.clone(),rhs.borrow().clone()) },
102          (Value::MutableReference(lhs),rhs) => { set_cartesian_product_fxn(lhs.borrow().clone(),rhs.clone()) },
103          x => Err(MechError2::new(
104            UnhandledFunctionArgumentKind2 { arg: (x.0.kind(), x.1.kind()), fxn_name: "set/cartesian-product".to_string() },
105            None
106          ).with_compiler_loc()),
107        }
108      }
109    }
110  }
111}
112
113register_descriptor! {
114  FunctionCompilerDescriptor {
115    name: "set/cartesian-product",
116    ptr: &SetCartesianProduct{},
117  }
118}