1use std::marker::PhantomData;
2
3use super::Baseiter;
4use crate::imp_prelude::*;
5use crate::IntoDimension;
6use crate::Layout;
7use crate::NdProducer;
8use crate::Slice;
9
10pub struct Windows<'a, A, D>
15{
16 base: RawArrayView<A, D>,
17 life: PhantomData<&'a A>,
18 window: D,
19 strides: D,
20}
21
22impl<'a, A, D: Dimension> Windows<'a, A, D>
23{
24 pub(crate) fn new<E>(a: ArrayView<'a, A, D>, window_size: E) -> Self
25 where E: IntoDimension<Dim = D>
26 {
27 let window = window_size.into_dimension();
28 let ndim = window.ndim();
29
30 let mut unit_stride = D::zeros(ndim);
31 unit_stride.slice_mut().fill(1);
32
33 Windows::new_with_stride(a, window, unit_stride)
34 }
35
36 pub(crate) fn new_with_stride<E>(a: ArrayView<'a, A, D>, window_size: E, axis_strides: E) -> Self
37 where E: IntoDimension<Dim = D>
38 {
39 let window = window_size.into_dimension();
40
41 let strides = axis_strides.into_dimension();
42 let window_strides = a.strides.clone();
43
44 let base = build_base(a, window.clone(), strides);
45 Windows {
46 base: base.into_raw_view(),
47 life: PhantomData,
48 window,
49 strides: window_strides,
50 }
51 }
52}
53
54impl_ndproducer! {
55 ['a, A, D: Dimension]
56 [Clone => 'a, A, D: Clone ]
57 Windows {
58 base,
59 life,
60 window,
61 strides,
62 }
63 Windows<'a, A, D> {
64 type Item = ArrayView<'a, A, D>;
65 type Dim = D;
66
67 unsafe fn item(&self, ptr) {
68 ArrayView::new_(ptr, self.window.clone(),
69 self.strides.clone())
70 }
71 }
72}
73
74impl<'a, A, D> IntoIterator for Windows<'a, A, D>
75where
76 D: Dimension,
77 A: 'a,
78{
79 type Item = <Self::IntoIter as Iterator>::Item;
80 type IntoIter = WindowsIter<'a, A, D>;
81 fn into_iter(self) -> Self::IntoIter
82 {
83 WindowsIter {
84 iter: self.base.into_base_iter(),
85 life: self.life,
86 window: self.window,
87 strides: self.strides,
88 }
89 }
90}
91
92pub struct WindowsIter<'a, A, D>
97{
98 iter: Baseiter<A, D>,
99 life: PhantomData<&'a A>,
100 window: D,
101 strides: D,
102}
103
104impl_iterator! {
105 ['a, A, D: Dimension]
106 [Clone => 'a, A, D: Clone]
107 WindowsIter {
108 iter,
109 life,
110 window,
111 strides,
112 }
113 WindowsIter<'a, A, D> {
114 type Item = ArrayView<'a, A, D>;
115
116 fn item(&mut self, ptr) {
117 unsafe {
118 ArrayView::new(
119 ptr,
120 self.window.clone(),
121 self.strides.clone())
122 }
123 }
124 }
125}
126
127send_sync_read_only!(Windows);
128send_sync_read_only!(WindowsIter);
129
130pub struct AxisWindows<'a, A, D>
135{
136 base: ArrayView<'a, A, D>,
137 axis_idx: usize,
138 window: D,
139 strides: D,
140}
141
142impl<'a, A, D: Dimension> AxisWindows<'a, A, D>
143{
144 pub(crate) fn new(a: ArrayView<'a, A, D>, axis: Axis, window_size: usize) -> Self
145 {
146 let window_strides = a.strides.clone();
147 let axis_idx = axis.index();
148
149 let mut window = a.raw_dim();
150 window[axis_idx] = window_size;
151
152 let ndim = window.ndim();
153 let mut unit_stride = D::zeros(ndim);
154 unit_stride.slice_mut().fill(1);
155
156 let base = build_base(a, window.clone(), unit_stride);
157 AxisWindows {
158 base,
159 axis_idx,
160 window,
161 strides: window_strides,
162 }
163 }
164}
165
166impl<'a, A, D: Dimension> NdProducer for AxisWindows<'a, A, D>
167{
168 type Item = ArrayView<'a, A, D>;
169 type Dim = Ix1;
170 type Ptr = *mut A;
171 type Stride = isize;
172
173 fn raw_dim(&self) -> Ix1
174 {
175 Ix1(self.base.raw_dim()[self.axis_idx])
176 }
177
178 fn layout(&self) -> Layout
179 {
180 self.base.layout()
181 }
182
183 fn as_ptr(&self) -> *mut A
184 {
185 self.base.as_ptr() as *mut _
186 }
187
188 fn contiguous_stride(&self) -> isize
189 {
190 self.base.contiguous_stride()
191 }
192
193 unsafe fn as_ref(&self, ptr: *mut A) -> Self::Item
194 {
195 ArrayView::new_(ptr, self.window.clone(), self.strides.clone())
196 }
197
198 unsafe fn uget_ptr(&self, i: &Self::Dim) -> *mut A
199 {
200 let mut d = D::zeros(self.base.ndim());
201 d[self.axis_idx] = i[0];
202 self.base.uget_ptr(&d)
203 }
204
205 fn stride_of(&self, axis: Axis) -> isize
206 {
207 assert_eq!(axis, Axis(0));
208 self.base.stride_of(Axis(self.axis_idx))
209 }
210
211 fn split_at(self, axis: Axis, index: usize) -> (Self, Self)
212 {
213 assert_eq!(axis, Axis(0));
214 let (a, b) = self.base.split_at(Axis(self.axis_idx), index);
215 (
216 AxisWindows {
217 base: a,
218 axis_idx: self.axis_idx,
219 window: self.window.clone(),
220 strides: self.strides.clone(),
221 },
222 AxisWindows {
223 base: b,
224 axis_idx: self.axis_idx,
225 window: self.window,
226 strides: self.strides,
227 },
228 )
229 }
230
231 private_impl!{}
232}
233
234impl<'a, A, D> IntoIterator for AxisWindows<'a, A, D>
235where
236 D: Dimension,
237 A: 'a,
238{
239 type Item = <Self::IntoIter as Iterator>::Item;
240 type IntoIter = WindowsIter<'a, A, D>;
241 fn into_iter(self) -> Self::IntoIter
242 {
243 WindowsIter {
244 iter: self.base.into_base_iter(),
245 life: PhantomData,
246 window: self.window,
247 strides: self.strides,
248 }
249 }
250}
251
252fn build_base<A, D>(a: ArrayView<A, D>, window: D, strides: D) -> ArrayView<A, D>
254where D: Dimension
255{
256 ndassert!(
257 a.ndim() == window.ndim(),
258 concat!(
259 "Window dimension {} does not match array dimension {} ",
260 "(with array of shape {:?})"
261 ),
262 window.ndim(),
263 a.ndim(),
264 a.shape()
265 );
266
267 ndassert!(
268 a.ndim() == strides.ndim(),
269 concat!(
270 "Stride dimension {} does not match array dimension {} ",
271 "(with array of shape {:?})"
272 ),
273 strides.ndim(),
274 a.ndim(),
275 a.shape()
276 );
277
278 let mut base = a;
279 base.slice_each_axis_inplace(|ax_desc| {
280 let len = ax_desc.len;
281 let wsz = window[ax_desc.axis.index()];
282 let stride = strides[ax_desc.axis.index()];
283
284 if len < wsz {
285 Slice::new(0, Some(0), 1)
286 } else {
287 Slice::new(0, Some((len - wsz + 1) as isize), stride as isize)
288 }
289 });
290 base
291}