antecedent_kernels/
view.rs1use core::fmt;
8
9#[derive(Clone, Debug, Eq, PartialEq)]
11pub enum ViewError {
12 InvalidShape {
14 message: &'static str,
16 },
17 OutOfBounds {
19 index: usize,
21 len: usize,
23 },
24}
25
26impl fmt::Display for ViewError {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 match self {
29 Self::InvalidShape { message } => write!(f, "invalid view shape: {message}"),
30 Self::OutOfBounds { index, len } => {
31 write!(f, "index {index} out of bounds for length {len}")
32 }
33 }
34 }
35}
36
37impl std::error::Error for ViewError {}
38
39#[derive(Clone, Copy, Debug)]
41pub struct F64VectorView<'a> {
42 data: &'a [f64],
43 len: usize,
44 stride: usize,
45}
46
47impl<'a> F64VectorView<'a> {
48 #[must_use]
50 pub const fn contiguous(data: &'a [f64]) -> Self {
51 Self { data, len: data.len(), stride: 1 }
52 }
53
54 pub fn strided(data: &'a [f64], len: usize, stride: usize) -> Result<Self, ViewError> {
61 if len == 0 {
62 return Ok(Self { data, len: 0, stride: stride.max(1) });
63 }
64 if stride == 0 {
65 return Err(ViewError::InvalidShape { message: "stride must be non-zero" });
66 }
67 let need = (len - 1)
68 .checked_mul(stride)
69 .and_then(|v| v.checked_add(1))
70 .ok_or(ViewError::InvalidShape { message: "stride*len overflow" })?;
71 if data.len() < need {
72 return Err(ViewError::InvalidShape {
73 message: "underlying slice shorter than strided extent",
74 });
75 }
76 Ok(Self { data, len, stride })
77 }
78
79 #[must_use]
81 pub const fn len(self) -> usize {
82 self.len
83 }
84
85 #[must_use]
87 pub const fn is_empty(self) -> bool {
88 self.len == 0
89 }
90
91 #[must_use]
93 pub const fn stride(self) -> usize {
94 self.stride
95 }
96
97 #[must_use]
99 pub const fn is_contiguous(self) -> bool {
100 self.stride == 1
101 }
102
103 pub fn get(self, i: usize) -> Result<f64, ViewError> {
109 if i >= self.len {
110 return Err(ViewError::OutOfBounds { index: i, len: self.len });
111 }
112 Ok(self.data[i * self.stride])
113 }
114
115 #[inline]
121 #[must_use]
122 pub unsafe fn get_unchecked(self, i: usize) -> f64 {
123 unsafe { *self.data.get_unchecked(i * self.stride) }
125 }
126
127 #[must_use]
129 pub fn as_slice(self) -> Option<&'a [f64]> {
130 if self.is_contiguous() { Some(&self.data[..self.len]) } else { None }
131 }
132}
133
134#[derive(Clone, Copy, Debug)]
136pub struct F64MatrixView<'a> {
137 data: &'a [f64],
138 nrows: usize,
139 ncols: usize,
140 row_stride: usize,
141 col_stride: usize,
142}
143
144impl<'a> F64MatrixView<'a> {
145 pub fn column_major(data: &'a [f64], nrows: usize, ncols: usize) -> Result<Self, ViewError> {
151 let need = nrows
152 .checked_mul(ncols)
153 .ok_or(ViewError::InvalidShape { message: "nrows*ncols overflow" })?;
154 if data.len() < need {
155 return Err(ViewError::InvalidShape { message: "buffer shorter than matrix" });
156 }
157 Ok(Self { data, nrows, ncols, row_stride: 1, col_stride: nrows })
158 }
159
160 #[must_use]
162 pub const fn nrows(self) -> usize {
163 self.nrows
164 }
165
166 #[must_use]
168 pub const fn ncols(self) -> usize {
169 self.ncols
170 }
171
172 pub fn get(self, row: usize, col: usize) -> Result<f64, ViewError> {
178 if row >= self.nrows {
179 return Err(ViewError::OutOfBounds { index: row, len: self.nrows });
180 }
181 if col >= self.ncols {
182 return Err(ViewError::OutOfBounds { index: col, len: self.ncols });
183 }
184 Ok(self.data[row * self.row_stride + col * self.col_stride])
185 }
186
187 pub fn column(self, j: usize) -> Result<F64VectorView<'a>, ViewError> {
193 if j >= self.ncols {
194 return Err(ViewError::OutOfBounds { index: j, len: self.ncols });
195 }
196 let offset = j * self.col_stride;
197 F64VectorView::strided(&self.data[offset..], self.nrows, self.row_stride)
198 }
199}
200
201#[derive(Clone, Copy, Debug)]
203pub struct BitMaskView<'a> {
204 bytes: &'a [u8],
205 len: usize,
206}
207
208impl<'a> BitMaskView<'a> {
209 pub fn new(bytes: &'a [u8], len: usize) -> Result<Self, ViewError> {
215 let need = len.div_ceil(8);
216 if bytes.len() < need {
217 return Err(ViewError::InvalidShape { message: "mask buffer too short" });
218 }
219 Ok(Self { bytes, len })
220 }
221
222 #[must_use]
224 pub const fn len(self) -> usize {
225 self.len
226 }
227
228 #[must_use]
230 pub const fn is_empty(self) -> bool {
231 self.len == 0
232 }
233
234 #[must_use]
236 pub fn get(self, i: usize) -> bool {
237 if i >= self.len {
238 return false;
239 }
240 let byte = self.bytes[i / 8];
241 (byte >> (i % 8)) & 1 == 1
242 }
243}