use crate::common_simd::assets::validate_inputs;
use crate::indicators::instantaneoustrendline::{
min_data, output_length, IndicatorState, State, INPUTS_WIDTH, OPTIONS_WIDTH,
};
use crate::indicators::simd_indicators::instantaneoustrendline_simd::SimdState;
use crate::indicators::simd_indicators::road_train::{Asset, Driver, PrimeMover};
use crate::types::IndicatorError;
use std::simd::Simd;
struct ItDriver {
want_optional_outputs: (bool, bool, bool, bool),
}
impl Driver<State> for ItDriver {
fn next_run<const N: usize>(
&mut self,
inputs: Vec<Vec<&[f64]>>,
mut outputs: Vec<Vec<&mut [f64]>>,
mut states: Vec<&mut State>,
_options: Vec<Option<&()>>,
) {
let len = inputs[0][0].len();
let mut simd_state = SimdState::new(&mut states);
let (has_optional, want_trigger, want_dc, want_alpha) = self.want_optional_outputs;
let real_ptrs = crate::extract_input_ptrs!(inputs, N, real_ptrs);
let (trendline_ptrs, trigger_ptrs, dc_period_ptrs, alpha_ptrs) = crate::extract_output_ptrs!(
outputs,
N,
trendline_ptrs,
trigger_ptrs,
dc_period_ptrs,
alpha_ptrs
);
for i in 0..len {
let real = crate::extract_simd_inputs_at_index!(i, N, real @ real_ptrs);
let it = unsafe { simd_state.calc_simd_unchecked(real) };
crate::write_simd_at_indices!(N, i, trendline_ptrs => it);
if has_optional {
let trigger = Simd::splat(2.0_f64) * simd_state.it_prev - simd_state.it_prev2;
crate::store_simd_optional_outputs!(i, N,
want_trigger, trigger_ptrs => trigger,
want_dc, dc_period_ptrs => simd_state.hd.smooth_period,
want_alpha, alpha_ptrs => simd_state.alpha
);
}
}
simd_state.write_states(&mut states);
}
}
pub fn indicator_by_assets<const N: usize>(
inputs: &[&[&[f64]; INPUTS_WIDTH]; N],
options: &[f64; OPTIONS_WIDTH],
optional_outputs: Option<&[bool]>,
) -> Result<(Vec<Vec<Vec<f64>>>, Vec<IndicatorState>), IndicatorError> {
validate_inputs::<INPUTS_WIDTH>(inputs, min_data(options))?;
let mut output_buffers = Vec::with_capacity(N);
let mut road_train = PrimeMover::<N, State>::new();
let mut want_optional_outputs = (false, false, false, false);
for i in 0..N {
let len = inputs[i][0].len();
let capacity = output_length(len, options);
let mut trendline_line = crate::uninit_vec!(f64, capacity);
let (mut trigger_line, mut dc_period_line, mut alpha_line) = crate::init_optional_outputs!(
optional_outputs, &[false, false, false],
trigger_line: capacity,
dc_period_line: capacity,
alpha_line: capacity
);
let state = State::init_state(
inputs[i][0],
&mut trendline_line,
&mut trigger_line,
&mut dc_period_line,
&mut alpha_line,
);
if i == 0 {
want_optional_outputs =
crate::calc_want_flags!(trigger_line, dc_period_line, alpha_line);
}
let mut output_buffer = vec![trendline_line, trigger_line, dc_period_line, alpha_line];
let mut asset_outputs = Vec::with_capacity(output_buffer.len());
for j in 0..output_buffer.len() {
unsafe {
let buf = &mut output_buffer[j];
let buf_len = buf.len();
let start = if buf_len > 0 { 1 } else { 0 };
asset_outputs.push(std::slice::from_raw_parts_mut(
buf.as_mut_ptr().add(start),
buf_len.saturating_sub(start),
));
}
}
road_train.add_asset(Asset::new(
vec![inputs[i][0]],
asset_outputs,
i,
min_data(options),
0,
state,
None,
));
output_buffers.push(output_buffer);
}
let mut driver = ItDriver {
want_optional_outputs,
};
let final_states = road_train.drive(&mut driver);
let states = final_states.into_iter().map(IndicatorState::new).collect();
Ok((output_buffers, states))
}