1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum MemoryLayout {
6 C,
8 Fortran,
10 Custom,
12}
13
14impl MemoryLayout {
15 #[inline]
17 pub fn is_c_contiguous(self) -> bool {
18 self == Self::C
19 }
20
21 #[inline]
23 pub fn is_f_contiguous(self) -> bool {
24 self == Self::Fortran
25 }
26
27 #[inline]
29 pub fn is_custom(self) -> bool {
30 self == Self::Custom
31 }
32}
33
34impl core::fmt::Display for MemoryLayout {
35 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
36 match self {
37 Self::C => write!(f, "C"),
38 Self::Fortran => write!(f, "F"),
39 Self::Custom => write!(f, "Custom"),
40 }
41 }
42}
43
44#[cfg(not(feature = "no_std"))]
46pub(crate) fn detect_layout(shape: &[usize], strides: &[isize]) -> MemoryLayout {
47 if shape.is_empty() {
48 return MemoryLayout::C; }
50
51 let is_c = is_c_contiguous(shape, strides);
52 let is_f = is_f_contiguous(shape, strides);
53
54 if is_c {
55 MemoryLayout::C
56 } else if is_f {
57 MemoryLayout::Fortran
58 } else {
59 MemoryLayout::Custom
60 }
61}
62
63#[cfg(not(feature = "no_std"))]
64fn is_c_contiguous(shape: &[usize], strides: &[isize]) -> bool {
65 if shape.len() != strides.len() {
66 return false;
67 }
68 let ndim = shape.len();
69 if ndim == 0 {
70 return true;
71 }
72 let mut expected: isize = 1;
73 for i in (0..ndim).rev() {
74 if shape[i] == 0 {
75 return true; }
77 if shape[i] != 1 && strides[i] != expected {
78 return false;
79 }
80 expected = strides[i] * shape[i] as isize;
81 }
82 true
83}
84
85#[cfg(not(feature = "no_std"))]
86fn is_f_contiguous(shape: &[usize], strides: &[isize]) -> bool {
87 if shape.len() != strides.len() {
88 return false;
89 }
90 let ndim = shape.len();
91 if ndim == 0 {
92 return true;
93 }
94 let mut expected: isize = 1;
95 for i in 0..ndim {
96 if shape[i] == 0 {
97 return true; }
99 if shape[i] != 1 && strides[i] != expected {
100 return false;
101 }
102 expected = strides[i] * shape[i] as isize;
103 }
104 true
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn detect_c_contiguous() {
113 assert_eq!(detect_layout(&[3, 4], &[4, 1]), MemoryLayout::C);
115 }
116
117 #[test]
118 fn detect_f_contiguous() {
119 assert_eq!(detect_layout(&[3, 4], &[1, 3]), MemoryLayout::Fortran);
121 }
122
123 #[test]
124 fn detect_custom() {
125 assert_eq!(detect_layout(&[3, 4], &[8, 2]), MemoryLayout::Custom);
127 }
128
129 #[test]
130 fn detect_empty() {
131 assert_eq!(detect_layout(&[], &[]), MemoryLayout::C);
132 }
133
134 #[test]
135 fn display() {
136 assert_eq!(MemoryLayout::C.to_string(), "C");
137 assert_eq!(MemoryLayout::Fortran.to_string(), "F");
138 assert_eq!(MemoryLayout::Custom.to_string(), "Custom");
139 }
140}