1#![feature(step_trait)]
2use crate::*;
3use mech_core::*;
4use std::iter::Step;
5use nalgebra::{
6 base::{Matrix as naMatrix, Storage, StorageMut},
7 Dim, Scalar,
8};
9use mech_core::matrix::Matrix;
10use std::marker::PhantomData;
11
12#[derive(Debug)]
15pub struct RangeIncrementInclusiveScalar<T, MatA> {
16 pub from: Ref<T>,
17 pub step: Ref<T>,
18 pub to: Ref<T>,
19 pub out: Ref<MatA>,
20 phantom: PhantomData<T>,
21}
22impl<T, R1, C1, S1> MechFunctionFactory for RangeIncrementInclusiveScalar<T, naMatrix<T, R1, C1, S1>>
23where
24 T: Copy + Debug + Clone + Sync + Send +
25 CompileConst + ConstElem + AsValueKind +
26 PartialOrd + 'static + One + Add<Output = T>,
27 Ref<naMatrix<T, R1, C1, S1>>: ToValue,
28 naMatrix<T, R1, C1, S1>: CompileConst + ConstElem + AsNaKind,
29 R1: Dim + 'static, C1: Dim, S1: StorageMut<T, R1, C1> + Clone + Debug + 'static,
30{
31 fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
32 match args {
33 FunctionArgs::Ternary(out, from, step, to) => {
34 let from: Ref<T> = unsafe { from.as_unchecked() }.clone();
35 let step: Ref<T> = unsafe { step.as_unchecked() }.clone();
36 let to: Ref<T> = unsafe { to.as_unchecked() }.clone();
37 let out: Ref<naMatrix<T, R1, C1, S1>> = unsafe { out.as_unchecked() }.clone();
38 Ok(Box::new(Self { from, step, to, out, phantom: PhantomData::default() }))
39 },
40 _ => Err(MechError2::new(
41 IncorrectNumberOfArguments { expected: 3, found: args.len() },
42 None
43 ).with_compiler_loc()
44 ),
45 }
46 }
47}
48impl<T, R1, C1, S1> MechFunctionImpl for RangeIncrementInclusiveScalar<T, naMatrix<T, R1, C1, S1>>
49where
50 Ref<naMatrix<T, R1, C1, S1>>: ToValue,
51 T: Copy + Scalar + Clone + Debug + Sync + Send + 'static + PartialOrd + One + Add<Output = T> + 'static,
52 R1: Dim, C1: Dim, S1: StorageMut<T, R1, C1> + Clone + Debug,
53{
54 fn solve(&self) {
55 unsafe {
56 let out_ptr = self.out.as_ptr() as *mut naMatrix<T, R1, C1, S1>;
57 let mut current = *self.from.as_ptr();
58 let step = *self.step.as_ptr();
59 for i in 0..(*out_ptr).len() {
60 (&mut (*out_ptr))[i] = current;
61 current = current + step;
62 }
63 }
64 }
65 fn out(&self) -> Value { self.out.to_value() }
66 fn to_string(&self) -> String { format!("{:#?}", self) }
67}
68#[cfg(feature = "compiler")]
69impl<T, R1, C1, S1> MechFunctionCompiler for RangeIncrementInclusiveScalar<T, naMatrix<T, R1, C1, S1>>
70where
71 T: CompileConst + ConstElem + AsValueKind,
72 naMatrix<T, R1, C1, S1>: CompileConst + ConstElem + AsNaKind,
73{
74 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
75 let name = format!("RangeIncrementInclusiveScalar<{}{}>", T::as_value_kind(), naMatrix::<T, R1, C1, S1>::as_na_kind());
76 compile_ternop!(name, self.out, self.from, self.step, self.to, ctx, FeatureFlag::Builtin(FeatureKind::RangeInclusive) );
77 }
78}
79
80#[macro_export]
81macro_rules! impl_range_increment_inclusive_match_arms {
82 ($fxn:ident, $arg1:expr, $arg2:expr, $arg3:expr, $($ty:tt, $feat:tt);+ $(;)?) => {
83 paste! {
84 match ($arg1, $arg2, $arg3) {
85 $(
86 #[cfg(feature = $feat)]
87 (Value::[<$ty:camel>](from), Value::[<$ty:camel>](step), Value::[<$ty:camel>](to)) => {
88 let from_val = *from.borrow();
89 let step_val = *step.borrow();
90 let to_val = *to.borrow();
91 let diff = to_val - from_val;
92 if diff < $ty::zero() {
93 return Err(MechError2::new(
94 EmptyRangeError{},
95 None
96 ).with_compiler_loc());
97 }
98 let size = {
99 let diff = to_val as f64 - from_val as f64;
100 let step = step_val as f64;
101 if step == 0.0 {
102 return Err(MechError2::new(EmptyRangeError {}, None).with_compiler_loc());
103 }
104 if (diff > 0.0 && step > 0.0) || (diff < 0.0 && step < 0.0) {
105 (diff / step).floor() as usize + 1
106 } else if diff == 0.0 {
107 1
108 } else {
109 return Err(MechError2::new(EmptyRangeError {}, None).with_compiler_loc());
110 }
111 };
112 let mut vec = vec![from_val; size];
113 match size {
114 0 => Err(MechError2::new(
115 EmptyRangeError{},
116 None
117 ).with_compiler_loc()),
118 #[cfg(feature = "matrix1")]
119 1 => {
120 register_range!($fxn, $ty, $feat, Matrix1);
121 Ok(Box::new($fxn::<$ty,Matrix1<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(Matrix1::from_element(vec[0])), phantom: PhantomData::default()}))
122 }
123 #[cfg(all(not(feature = "matrix1"), feature = "matrixd") )]
124 1 => {
125 register_range!($fxn, $ty, $feat, DMatrix);
126 Ok(Box::new($fxn::<$ty,DMatrix<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(DMatrix::from_element(1,1,vec[0])), phantom: PhantomData::default()}))
127 }
128 #[cfg(feature = "row_vector2")]
129 2 => {
130 register_range!($fxn, $ty, $feat, RowVector2);
131 Ok(Box::new($fxn::<$ty,RowVector2<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(RowVector2::from_vec(vec)), phantom: PhantomData::default()}))
132 }
133 #[cfg(feature = "row_vector3")]
134 3 => {
135 register_range!($fxn, $ty, $feat, RowVector3);
136 Ok(Box::new($fxn::<$ty,RowVector3<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(RowVector3::from_vec(vec)), phantom: PhantomData::default()}))
137 }
138 #[cfg(feature = "row_vector4")]
139 4 => {
140 register_range!($fxn, $ty, $feat, RowVector4);
141 Ok(Box::new($fxn::<$ty,RowVector4<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(RowVector4::from_vec(vec)), phantom: PhantomData::default()}))
142 }
143 #[cfg(feature = "row_vectord")]
144 n => {
145 register_range!($fxn, $ty, $feat, RowDVector);
146 Ok(Box::new($fxn::<$ty,RowDVector<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(RowDVector::from_vec(vec)), phantom: PhantomData::default()}))
147 }
148 }
149 }
150 )+
151 (arg1,arg2,arg3) => Err(MechError2::new(
152 UnhandledFunctionArgumentKind3 {arg: (arg1.kind(),arg2.kind(), arg3.kind()), fxn_name: stringify!($fxn).to_string() },
153 None
154 ).with_compiler_loc()),
155 }
156 }
157 }
158}
159
160fn impl_range_increment_inclusive_fxn(arg1_value: Value, arg2_value: Value, arg3_value: Value) -> MResult<Box<dyn MechFunction>> {
161 impl_range_increment_inclusive_match_arms!(RangeIncrementInclusiveScalar, arg1_value, arg2_value, arg3_value,
162 f32, "f32";
163 f64, "f64";
164 i8, "i8";
165 i16, "i16";
166 i32, "i32";
167 i64, "i64";
168 i128,"i128";
169 u8, "u8";
170 u16, "u16";
171 u32, "u32";
172 u64, "u64";
173 u128,"u128";
174 )
175}
176
177pub struct RangeIncrementInclusive {}
178
179impl NativeFunctionCompiler for RangeIncrementInclusive {
180 fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
181 if arguments.len() != 3 {
182 return Err(MechError2::new(IncorrectNumberOfArguments { expected: 3, found: arguments.len() },None).with_compiler_loc());
183 }
184 let arg1 = arguments[0].clone();
185 let arg2 = arguments[1].clone();
186 let arg3 = arguments[2].clone();
187 match impl_range_increment_inclusive_fxn(arg1.clone(), arg2.clone(), arg3.clone()) {
188 Ok(fxn) => Ok(fxn),
189 Err(_) => {
190 match (arg1, arg2, arg3) {
191 (Value::MutableReference(arg1), Value::MutableReference(arg2), Value::MutableReference(arg3)) => {
192 impl_range_increment_inclusive_fxn(arg1.borrow().clone(), arg2.borrow().clone(), arg3.borrow().clone())
193 }
194 (Value::MutableReference(arg1), Value::MutableReference(arg2), arg3) => {
195 impl_range_increment_inclusive_fxn(arg1.borrow().clone(), arg2.borrow().clone(), arg3.clone())
196 }
197 (Value::MutableReference(arg1), arg2, Value::MutableReference(arg3)) => {
198 impl_range_increment_inclusive_fxn(arg1.borrow().clone(), arg2.clone(), arg3.borrow().clone())
199 }
200 (Value::MutableReference(arg1), arg2, arg3) => {
201 impl_range_increment_inclusive_fxn(arg1.borrow().clone(), arg2.clone(), arg3.clone())
202 }
203 (arg1, Value::MutableReference(arg2), Value::MutableReference(arg3)) => {
204 impl_range_increment_inclusive_fxn(arg1.clone(), arg2.borrow().clone(), arg3.borrow().clone())
205 }
206 (arg1, Value::MutableReference(arg2), arg3) => {
207 impl_range_increment_inclusive_fxn(arg1.clone(), arg2.borrow().clone(), arg3.clone())
208 }
209 (arg1, arg2, Value::MutableReference(arg3)) => {
210 impl_range_increment_inclusive_fxn(arg1.clone(), arg2.clone(), arg3.borrow().clone())
211 }
212 (arg1, arg2, arg3) => Err(MechError2::new(
213 UnhandledFunctionArgumentKind3 { arg: (arg1.kind(), arg2.kind(), arg3.kind()), fxn_name: "range/inclusive-increment".to_string() },
214 None
215 ).with_compiler_loc()),
216 }
217 }
218 }
219 }
220}
221
222register_descriptor! {
223 FunctionCompilerDescriptor {
224 name: "range/inclusive-increment",
225 ptr: &RangeIncrementInclusive{},
226 }
227}