ndstruct/
utils.rs

1use cl_aux::ArrayWrapper;
2
3#[cfg(feature = "rayon")]
4/// Parallel iterator for Rayon implementation. This is mostly an internal detail.
5#[derive(Debug)]
6pub struct ParallelIteratorWrapper<I>(pub(crate) I);
7
8#[cfg(feature = "rayon")]
9/// Parallel producer for Rayon implementation. This is mostly an internal detail.
10#[derive(Debug)]
11pub struct ParallelProducerWrapper<I>(pub(crate) I);
12
13#[inline]
14pub(crate) fn are_in_ascending_order<'slice, T, U>(
15  slice: &'slice [T],
16  cb: impl Fn(&'slice T, &'slice T) -> [&'slice U; 2],
17) -> bool
18where
19  T: 'slice,
20  U: PartialOrd + 'slice,
21{
22  windows2(slice).all(|x| {
23    let [a, b] = cb(x[0], x[1]);
24    a <= b
25  })
26}
27
28#[inline]
29pub(crate) fn are_in_upper_bound<T>(slice: &[T], upper_bound: &T) -> bool
30where
31  T: PartialOrd,
32{
33  slice.iter().all(|x| x < upper_bound)
34}
35
36#[inline]
37pub(crate) fn has_duplicates<T>(slice: &[T]) -> bool
38where
39  T: PartialEq,
40{
41  for (a_idx, a) in slice.iter().enumerate() {
42    for b in slice.iter().skip(a_idx.saturating_add(1)) {
43      if a == b {
44        return true;
45      }
46    }
47  }
48  false
49}
50
51#[inline]
52pub(crate) fn max_nnz<const D: usize>(dims: &[usize; D]) -> usize {
53  if dims == &ArrayWrapper::default().0 {
54    return 0;
55  }
56  if let Some(first) = dims.first().copied() {
57    if D == 1 {
58      return first;
59    }
60
61    let mut product: usize = 1;
62    for dim in dims.iter().copied().filter(|dim| dim != &0) {
63      product = product.saturating_mul(dim);
64    }
65    return product;
66  }
67  0
68}
69
70#[cfg(feature = "rand")]
71#[inline]
72pub(crate) fn valid_random_dims<R, const D: usize>(rng: &mut R, upper_bound: usize) -> [usize; D]
73where
74  R: rand::Rng,
75{
76  let dims = ArrayWrapper::default().0;
77  if D == 0 {
78    return dims;
79  }
80  let cut_point = rng.random_range(0..D);
81  let mut array = dims;
82  let iter = if let Some(r) = array.get_mut(cut_point..) {
83    r.iter_mut()
84  } else {
85    return dims;
86  };
87  match upper_bound {
88    0 => {}
89    1 => iter.for_each(|dim| *dim = 1),
90    _ => iter.for_each(|dim| *dim = rng.random_range(1..upper_bound)),
91  }
92  dims
93}
94
95#[inline]
96pub(crate) fn windows2<T>(slice: &[T]) -> impl Iterator<Item = [&T; 2]> {
97  slice.windows(2).filter_map(|value| Some([value.first()?, value.get(1)?]))
98}