1use std::sync::atomic::{AtomicU32, Ordering};
8
9extern "C" {
14 fn sesh_vec_version() -> u32;
15}
16
17static HOST_VEC_VERSION: AtomicU32 = AtomicU32::new(0);
19
20fn host_version() -> u32 {
21 let v = HOST_VEC_VERSION.load(Ordering::Relaxed);
22 if v != 0 {
23 return v;
24 }
25 let v = unsafe { sesh_vec_version() };
26 let store = if v == 0 { u32::MAX } else { v };
28 HOST_VEC_VERSION.store(store, Ordering::Relaxed);
29 v
30}
31
32#[inline]
33fn use_host_ops() -> bool {
34 host_version() > 0 && host_version() != u32::MAX
35}
36
37extern "C" {
42 fn sesh_vec_copy_host(dst: *mut f32, src: *const f32, len: u32);
43 fn sesh_vec_fill_host(dst: *mut f32, value: f32, len: u32);
44 fn sesh_vec_add_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
45 fn sesh_vec_add_scalar_host(dst: *mut f32, value: f32, len: u32);
46 fn sesh_vec_mul_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
47 fn sesh_vec_mul_scalar_host(dst: *mut f32, value: f32, len: u32);
48 fn sesh_vec_mul_add_host(dst: *mut f32, src: *const f32, gain: f32, len: u32);
49 fn sesh_vec_clamp_host(dst: *mut f32, src: *const f32, min: f32, max: f32, len: u32);
50 fn sesh_vec_ring_write_host(
51 buf: *mut f32, buf_len: u32, pos: *mut u32, src: *const f32, len: u32,
52 );
53 fn sesh_vec_ring_read_host(
54 buf: *const f32, buf_len: u32, pos: u32, dst: *mut f32, offset: u32, len: u32,
55 );
56 fn sesh_vec_delay_read_host(
57 buf: *const f32, buf_len: u32, pos: u32, dst: *mut f32, time: *const f32, len: u32,
58 );
59 fn sesh_vec_osc_host(
60 phase: *mut f32, dst: *mut f32, freq: f32, waveform: u32, sample_rate: f32, len: u32,
61 );
62 fn sesh_vec_biquad_host(
63 state: *mut f32, dst: *mut f32, src: *const f32,
64 cutoff: *const f32, q: *const f32, gain: *const f32,
65 filter_type: u32, sample_rate: f32, len: u32,
66 );
67 fn sesh_vec_envelope_host(
68 state: *mut f32, dst: *mut f32, src: *const f32,
69 attack: *const f32, release: *const f32,
70 mode: u32, sample_rate: f32, len: u32,
71 );
72 fn sesh_vec_tanh_host(dst: *mut f32, src: *const f32, drive: *const f32, len: u32);
73 fn sesh_vec_hard_clip_host(dst: *mut f32, src: *const f32, threshold: *const f32, len: u32);
74 fn sesh_vec_abs_host(dst: *mut f32, src: *const f32, len: u32);
75 fn sesh_vec_neg_host(dst: *mut f32, src: *const f32, len: u32);
76 fn sesh_vec_sqrt_host(dst: *mut f32, src: *const f32, len: u32);
77 fn sesh_vec_recip_host(dst: *mut f32, src: *const f32, len: u32);
78 fn sesh_vec_div_host(dst: *mut f32, a: *const f32, b: *const f32, len: u32);
79 fn sesh_vec_pow_host(dst: *mut f32, src: *const f32, exp: *const f32, len: u32);
80}
81
82#[repr(u32)]
88#[derive(Clone, Copy)]
89pub enum Waveform {
90 Sine = 0,
91 Triangle = 1,
92 Saw = 2,
93 Square = 3,
94}
95
96#[repr(u32)]
98#[derive(Clone, Copy)]
99pub enum FilterType {
100 Lowpass = 0,
101 Highpass = 1,
102 Bandpass = 2,
103 Notch = 3,
104 Peak = 4,
106 LowShelf = 5,
108 HighShelf = 6,
110 Allpass = 7,
112}
113
114#[repr(C)]
116pub struct BiquadState {
117 pub x1: f32,
118 pub x2: f32,
119 pub y1: f32,
120 pub y2: f32,
121}
122
123impl BiquadState {
124 pub const fn new() -> Self {
125 Self { x1: 0.0, x2: 0.0, y1: 0.0, y2: 0.0 }
126 }
127}
128
129#[repr(u32)]
131#[derive(Clone, Copy)]
132pub enum EnvelopeMode {
133 Peak = 0,
135 Rms = 1,
137}
138
139#[repr(C)]
141pub struct EnvelopeState {
142 pub current: f32,
143}
144
145impl EnvelopeState {
146 pub const fn new() -> Self {
147 Self { current: 0.0 }
148 }
149}
150
151pub fn vec_copy(dst: &mut [f32], src: &[f32]) {
157 let len = dst.len().min(src.len());
158 if use_host_ops() {
159 unsafe { sesh_vec_copy_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) }
160 } else {
161 dst[..len].copy_from_slice(&src[..len]);
162 }
163}
164
165pub fn vec_fill(dst: &mut [f32], value: f32) {
167 let len = dst.len();
168 if use_host_ops() {
169 unsafe { sesh_vec_fill_host(dst.as_mut_ptr(), value, len as u32) }
170 } else {
171 for s in dst.iter_mut() {
172 *s = value;
173 }
174 }
175}
176
177pub fn vec_add(dst: &mut [f32], a: &[f32], b: &[f32]) {
179 let len = dst.len().min(a.len()).min(b.len());
180 if use_host_ops() {
181 unsafe { sesh_vec_add_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) }
182 } else {
183 for i in 0..len {
184 dst[i] = a[i] + b[i];
185 }
186 }
187}
188
189pub fn vec_add_scalar(dst: &mut [f32], value: f32) {
191 let len = dst.len();
192 if use_host_ops() {
193 unsafe { sesh_vec_add_scalar_host(dst.as_mut_ptr(), value, len as u32) }
194 } else {
195 for s in dst.iter_mut() {
196 *s += value;
197 }
198 }
199}
200
201pub fn vec_mul(dst: &mut [f32], a: &[f32], b: &[f32]) {
203 let len = dst.len().min(a.len()).min(b.len());
204 if use_host_ops() {
205 unsafe { sesh_vec_mul_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) }
206 } else {
207 for i in 0..len {
208 dst[i] = a[i] * b[i];
209 }
210 }
211}
212
213pub fn vec_mul_scalar(dst: &mut [f32], value: f32) {
215 let len = dst.len();
216 if use_host_ops() {
217 unsafe { sesh_vec_mul_scalar_host(dst.as_mut_ptr(), value, len as u32) }
218 } else {
219 for s in dst.iter_mut() {
220 *s *= value;
221 }
222 }
223}
224
225pub fn vec_mul_add(dst: &mut [f32], src: &[f32], gain: f32) {
227 let len = dst.len().min(src.len());
228 if use_host_ops() {
229 unsafe { sesh_vec_mul_add_host(dst.as_mut_ptr(), src.as_ptr(), gain, len as u32) }
230 } else {
231 for i in 0..len {
232 dst[i] += src[i] * gain;
233 }
234 }
235}
236
237pub fn vec_clamp(dst: &mut [f32], src: &[f32], min: f32, max: f32) {
239 let len = dst.len().min(src.len());
240 if use_host_ops() {
241 unsafe { sesh_vec_clamp_host(dst.as_mut_ptr(), src.as_ptr(), min, max, len as u32) }
242 } else {
243 for i in 0..len {
244 dst[i] = src[i].clamp(min, max);
245 }
246 }
247}
248
249pub fn vec_clamp_assign(dst: &mut [f32], min: f32, max: f32) {
251 let len = dst.len();
252 if use_host_ops() {
253 unsafe { sesh_vec_clamp_host(dst.as_mut_ptr(), dst.as_ptr(), min, max, len as u32) }
254 } else {
255 for i in 0..len {
256 dst[i] = dst[i].clamp(min, max);
257 }
258 }
259}
260
261pub fn vec_ring_write(buf: &mut [f32], pos: &mut usize, src: &[f32]) {
268 let buf_len = buf.len();
269 let frames = src.len();
270 if use_host_ops() {
271 let mut pos32 = *pos as u32;
272 unsafe {
273 sesh_vec_ring_write_host(
274 buf.as_mut_ptr(), buf_len as u32, &mut pos32, src.as_ptr(), frames as u32,
275 );
276 }
277 *pos = pos32 as usize;
278 } else {
279 for i in 0..frames {
280 buf[(*pos + i) % buf_len] = src[i];
281 }
282 *pos = (*pos + frames) % buf_len;
283 }
284}
285
286pub fn vec_ring_read(buf: &[f32], pos: usize, dst: &mut [f32], offset: usize) {
288 let buf_len = buf.len();
289 let frames = dst.len();
290 if use_host_ops() {
291 unsafe {
292 sesh_vec_ring_read_host(
293 buf.as_ptr(), buf_len as u32, pos as u32,
294 dst.as_mut_ptr(), offset as u32, frames as u32,
295 );
296 }
297 } else {
298 let start = (pos + buf_len - offset) % buf_len;
299 for i in 0..frames {
300 dst[i] = buf[(start + i) % buf_len];
301 }
302 }
303}
304
305pub fn vec_delay_read(buf: &[f32], pos: usize, dst: &mut [f32], time: &[f32]) {
315 let buf_len = buf.len();
316 let frames = dst.len().min(time.len());
317 if use_host_ops() {
318 unsafe {
319 sesh_vec_delay_read_host(
320 buf.as_ptr(), buf_len as u32, pos as u32,
321 dst.as_mut_ptr(), time.as_ptr(), frames as u32,
322 );
323 }
324 } else {
325 for i in 0..frames {
326 let write_pos_at_i = (pos + buf_len - frames + i) % buf_len;
328
329 let delay_int = time[i] as usize;
330 let delay_frac = time[i] - delay_int as f32;
331
332 let idx1 = (write_pos_at_i + buf_len - delay_int) % buf_len;
333 let idx2 = (idx1 + buf_len - 1) % buf_len;
334
335 dst[i] = buf[idx1] + delay_frac * (buf[idx2] - buf[idx1]);
336 }
337 }
338}
339
340pub fn vec_osc(
346 phase: &mut f32,
347 dst: &mut [f32],
348 freq: f32,
349 waveform: Waveform,
350 sample_rate: f32,
351) {
352 let frames = dst.len();
353 if use_host_ops() {
354 unsafe {
355 sesh_vec_osc_host(
356 phase as *mut f32, dst.as_mut_ptr(),
357 freq, waveform as u32, sample_rate, frames as u32,
358 );
359 }
360 } else {
361 let phase_inc = freq / sample_rate;
362 for i in 0..frames {
363 dst[i] = match waveform {
364 Waveform::Sine => (*phase * std::f32::consts::TAU).sin(),
365 Waveform::Triangle => 4.0 * (*phase - (*phase + 0.5).floor()).abs() - 1.0,
366 Waveform::Saw => 2.0 * (*phase - (*phase + 0.5).floor()),
367 Waveform::Square => if *phase % 1.0 < 0.5 { 1.0 } else { -1.0 },
368 };
369 *phase += phase_inc;
370 if *phase >= 1.0 {
371 *phase -= 1.0;
372 }
373 }
374 }
375}
376
377pub fn vec_biquad(
386 state: &mut BiquadState,
387 dst: &mut [f32],
388 src: &[f32],
389 cutoff: &[f32],
390 q: &[f32],
391 gain: &[f32],
392 filter_type: FilterType,
393 sample_rate: f32,
394) {
395 let frames = dst.len().min(src.len()).min(cutoff.len()).min(q.len()).min(gain.len());
396 if use_host_ops() {
397 unsafe {
398 sesh_vec_biquad_host(
399 state as *mut BiquadState as *mut f32,
400 dst.as_mut_ptr(), src.as_ptr(),
401 cutoff.as_ptr(), q.as_ptr(), gain.as_ptr(),
402 filter_type as u32, sample_rate, frames as u32,
403 );
404 }
405 } else {
406 for i in 0..frames {
407 let w0 = std::f32::consts::TAU * cutoff[i] / sample_rate;
408 let cos_w0 = w0.cos();
409 let sin_w0 = w0.sin();
410 let alpha = sin_w0 / (2.0 * q[i]);
411 let a_db = gain[i];
412 let a_lin = 10.0f32.powf(a_db / 40.0);
413
414 let (b0, b1, b2, a0, a1, a2) = match filter_type {
415 FilterType::Lowpass => {
416 let b1 = 1.0 - cos_w0;
417 let b0 = b1 / 2.0;
418 (b0, b1, b0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
419 }
420 FilterType::Highpass => {
421 let b1 = -(1.0 + cos_w0);
422 let b0 = (1.0 + cos_w0) / 2.0;
423 (b0, b1, b0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
424 }
425 FilterType::Bandpass => {
426 (alpha, 0.0, -alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
427 }
428 FilterType::Notch => {
429 (1.0, -2.0 * cos_w0, 1.0, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
430 }
431 FilterType::Peak => {
432 (
433 1.0 + alpha * a_lin,
434 -2.0 * cos_w0,
435 1.0 - alpha * a_lin,
436 1.0 + alpha / a_lin,
437 -2.0 * cos_w0,
438 1.0 - alpha / a_lin,
439 )
440 }
441 FilterType::LowShelf => {
442 let two_sqrt_a_alpha = 2.0 * a_lin.sqrt() * alpha;
443 (
444 a_lin * ((a_lin + 1.0) - (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha),
445 2.0 * a_lin * ((a_lin - 1.0) - (a_lin + 1.0) * cos_w0),
446 a_lin * ((a_lin + 1.0) - (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha),
447 (a_lin + 1.0) + (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha,
448 -2.0 * ((a_lin - 1.0) + (a_lin + 1.0) * cos_w0),
449 (a_lin + 1.0) + (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha,
450 )
451 }
452 FilterType::HighShelf => {
453 let two_sqrt_a_alpha = 2.0 * a_lin.sqrt() * alpha;
454 (
455 a_lin * ((a_lin + 1.0) + (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha),
456 -2.0 * a_lin * ((a_lin - 1.0) + (a_lin + 1.0) * cos_w0),
457 a_lin * ((a_lin + 1.0) + (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha),
458 (a_lin + 1.0) - (a_lin - 1.0) * cos_w0 + two_sqrt_a_alpha,
459 2.0 * ((a_lin - 1.0) - (a_lin + 1.0) * cos_w0),
460 (a_lin + 1.0) - (a_lin - 1.0) * cos_w0 - two_sqrt_a_alpha,
461 )
462 }
463 FilterType::Allpass => {
464 (1.0 - alpha, -2.0 * cos_w0, 1.0 + alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha)
465 }
466 };
467
468 let b0 = b0 / a0;
470 let b1 = b1 / a0;
471 let b2 = b2 / a0;
472 let a1 = a1 / a0;
473 let a2 = a2 / a0;
474
475 let x0 = src[i];
476 let y0 = b0 * x0 + b1 * state.x1 + b2 * state.x2
477 - a1 * state.y1 - a2 * state.y2;
478
479 state.x2 = state.x1;
480 state.x1 = x0;
481 state.y2 = state.y1;
482 state.y1 = y0;
483
484 dst[i] = y0;
485 }
486 }
487}
488
489pub fn vec_envelope(
498 state: &mut EnvelopeState,
499 dst: &mut [f32],
500 src: &[f32],
501 attack: &[f32],
502 release: &[f32],
503 mode: EnvelopeMode,
504 sample_rate: f32,
505) {
506 let frames = dst.len().min(src.len()).min(attack.len()).min(release.len());
507 if use_host_ops() {
508 unsafe {
509 sesh_vec_envelope_host(
510 state as *mut EnvelopeState as *mut f32,
511 dst.as_mut_ptr(), src.as_ptr(),
512 attack.as_ptr(), release.as_ptr(),
513 mode as u32, sample_rate, frames as u32,
514 );
515 }
516 } else {
517 for i in 0..frames {
518 let input_level = match mode {
519 EnvelopeMode::Peak => src[i].abs(),
520 EnvelopeMode::Rms => src[i] * src[i],
521 };
522
523 let att_coeff = (-1.0 / (attack[i] * sample_rate)).exp();
524 let rel_coeff = (-1.0 / (release[i] * sample_rate)).exp();
525
526 let coeff = if input_level > state.current { att_coeff } else { rel_coeff };
527 state.current = coeff * state.current + (1.0 - coeff) * input_level;
528
529 dst[i] = match mode {
530 EnvelopeMode::Peak => state.current,
531 EnvelopeMode::Rms => state.current.sqrt(),
532 };
533 }
534 }
535}
536
537pub fn vec_tanh(dst: &mut [f32], src: &[f32], drive: &[f32]) {
543 let len = dst.len().min(src.len()).min(drive.len());
544 if use_host_ops() {
545 unsafe { sesh_vec_tanh_host(dst.as_mut_ptr(), src.as_ptr(), drive.as_ptr(), len as u32) }
546 } else {
547 for i in 0..len {
548 dst[i] = (src[i] * drive[i]).tanh();
549 }
550 }
551}
552
553pub fn vec_hard_clip(dst: &mut [f32], src: &[f32], threshold: &[f32]) {
555 let len = dst.len().min(src.len()).min(threshold.len());
556 if use_host_ops() {
557 unsafe {
558 sesh_vec_hard_clip_host(dst.as_mut_ptr(), src.as_ptr(), threshold.as_ptr(), len as u32)
559 }
560 } else {
561 for i in 0..len {
562 dst[i] = src[i].clamp(-threshold[i], threshold[i]);
563 }
564 }
565}
566
567pub fn vec_abs(dst: &mut [f32], src: &[f32]) {
573 let len = dst.len().min(src.len());
574 if use_host_ops() {
575 unsafe { sesh_vec_abs_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) }
576 } else {
577 for i in 0..len {
578 dst[i] = src[i].abs();
579 }
580 }
581}
582
583pub fn vec_neg(dst: &mut [f32], src: &[f32]) {
585 let len = dst.len().min(src.len());
586 if use_host_ops() {
587 unsafe { sesh_vec_neg_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) }
588 } else {
589 for i in 0..len {
590 dst[i] = -src[i];
591 }
592 }
593}
594
595pub fn vec_sqrt(dst: &mut [f32], src: &[f32]) {
597 let len = dst.len().min(src.len());
598 if use_host_ops() {
599 unsafe { sesh_vec_sqrt_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) }
600 } else {
601 for i in 0..len {
602 dst[i] = src[i].sqrt();
603 }
604 }
605}
606
607pub fn vec_recip(dst: &mut [f32], src: &[f32]) {
609 let len = dst.len().min(src.len());
610 if use_host_ops() {
611 unsafe { sesh_vec_recip_host(dst.as_mut_ptr(), src.as_ptr(), len as u32) }
612 } else {
613 for i in 0..len {
614 dst[i] = 1.0 / src[i];
615 }
616 }
617}
618
619pub fn vec_div(dst: &mut [f32], a: &[f32], b: &[f32]) {
621 let len = dst.len().min(a.len()).min(b.len());
622 if use_host_ops() {
623 unsafe { sesh_vec_div_host(dst.as_mut_ptr(), a.as_ptr(), b.as_ptr(), len as u32) }
624 } else {
625 for i in 0..len {
626 dst[i] = a[i] / b[i];
627 }
628 }
629}
630
631pub fn vec_pow(dst: &mut [f32], src: &[f32], exp: &[f32]) {
633 let len = dst.len().min(src.len()).min(exp.len());
634 if use_host_ops() {
635 unsafe { sesh_vec_pow_host(dst.as_mut_ptr(), src.as_ptr(), exp.as_ptr(), len as u32) }
636 } else {
637 for i in 0..len {
638 dst[i] = src[i].powf(exp[i]);
639 }
640 }
641}
642
643pub fn vec_add_assign(dst: &mut [f32], src: &[f32]) {
653 let len = dst.len().min(src.len());
654 if use_host_ops() {
655 unsafe { sesh_vec_add_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) }
656 } else {
657 for i in 0..len {
658 dst[i] += src[i];
659 }
660 }
661}
662
663pub fn vec_mul_assign(dst: &mut [f32], src: &[f32]) {
665 let len = dst.len().min(src.len());
666 if use_host_ops() {
667 unsafe { sesh_vec_mul_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) }
668 } else {
669 for i in 0..len {
670 dst[i] *= src[i];
671 }
672 }
673}
674
675pub fn vec_tanh_assign(dst: &mut [f32], drive: &[f32]) {
677 let len = dst.len().min(drive.len());
678 if use_host_ops() {
679 unsafe { sesh_vec_tanh_host(dst.as_mut_ptr(), dst.as_ptr(), drive.as_ptr(), len as u32) }
680 } else {
681 for i in 0..len {
682 dst[i] = (dst[i] * drive[i]).tanh();
683 }
684 }
685}
686
687pub fn vec_hard_clip_assign(dst: &mut [f32], threshold: &[f32]) {
689 let len = dst.len().min(threshold.len());
690 if use_host_ops() {
691 unsafe { sesh_vec_hard_clip_host(dst.as_mut_ptr(), dst.as_ptr(), threshold.as_ptr(), len as u32) }
692 } else {
693 for i in 0..len {
694 dst[i] = dst[i].clamp(-threshold[i], threshold[i]);
695 }
696 }
697}
698
699pub fn vec_abs_assign(dst: &mut [f32]) {
701 let len = dst.len();
702 if use_host_ops() {
703 unsafe { sesh_vec_abs_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) }
704 } else {
705 for i in 0..len {
706 dst[i] = dst[i].abs();
707 }
708 }
709}
710
711pub fn vec_neg_assign(dst: &mut [f32]) {
713 let len = dst.len();
714 if use_host_ops() {
715 unsafe { sesh_vec_neg_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) }
716 } else {
717 for i in 0..len {
718 dst[i] = -dst[i];
719 }
720 }
721}
722
723pub fn vec_sqrt_assign(dst: &mut [f32]) {
725 let len = dst.len();
726 if use_host_ops() {
727 unsafe { sesh_vec_sqrt_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) }
728 } else {
729 for i in 0..len {
730 dst[i] = dst[i].sqrt();
731 }
732 }
733}
734
735pub fn vec_recip_assign(dst: &mut [f32]) {
737 let len = dst.len();
738 if use_host_ops() {
739 unsafe { sesh_vec_recip_host(dst.as_mut_ptr(), dst.as_ptr(), len as u32) }
740 } else {
741 for i in 0..len {
742 dst[i] = 1.0 / dst[i];
743 }
744 }
745}
746
747pub fn vec_div_assign(dst: &mut [f32], src: &[f32]) {
749 let len = dst.len().min(src.len());
750 if use_host_ops() {
751 unsafe { sesh_vec_div_host(dst.as_mut_ptr(), dst.as_ptr(), src.as_ptr(), len as u32) }
752 } else {
753 for i in 0..len {
754 dst[i] /= src[i];
755 }
756 }
757}
758
759pub fn vec_pow_assign(dst: &mut [f32], exp: &[f32]) {
761 let len = dst.len().min(exp.len());
762 if use_host_ops() {
763 unsafe { sesh_vec_pow_host(dst.as_mut_ptr(), dst.as_ptr(), exp.as_ptr(), len as u32) }
764 } else {
765 for i in 0..len {
766 dst[i] = dst[i].powf(exp[i]);
767 }
768 }
769}