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