From fa0c85c4324a6d41c925d7937d2ca2e2c3ab486f Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 29 May 2018 07:28:46 +0100 Subject: [PATCH 1/7] Added `to_vec_mapped_mut`. --- src/iterators/mod.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 4ed5d99be..d0c8194b6 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -718,7 +718,7 @@ macro_rules! outer_iter_split_at_impl { { assert!(index <= self.iter.len); let right_ptr = if index != self.iter.len { - unsafe { self.iter.offset(index) } + unsafe { self.iter.offset(index) } } else { self.iter.ptr @@ -1219,3 +1219,27 @@ pub fn to_vec_mapped(iter: I, mut f: F) -> Vec debug_assert_eq!(size, result.len()); result } + +/// Like Iterator::collect, but only for trusted length iterators +pub fn to_vec_mapped_mut(iter: I, mut f: F) -> Vec + where I: TrustedIterator + ExactSizeIterator, + F: FnMut(&mut I::Item) -> B, +{ + // Use an `unsafe` block to do this efficiently. + // We know that iter will produce exactly .size() elements, + // and the loop can vectorize if it's clean (without branch to grow the vector). + let (size, _) = iter.size_hint(); + let mut result = Vec::with_capacity(size); + let mut out_ptr = result.as_mut_ptr(); + let mut len = 0; + iter.fold((), |(), elt| { + unsafe { + ptr::write(out_ptr, f(&mut elt)); + len += 1; + result.set_len(len); + out_ptr = out_ptr.offset(1); + } + }); + debug_assert_eq!(size, result.len()); + result +} From 3de28af6f6b3af54dbbbe3b40054feda22b16390 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 29 May 2018 07:59:40 +0100 Subject: [PATCH 2/7] Removed useless . Implemented TrustedIterator for IterMut and slice::IterMut --- src/iterators/mod.rs | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index d0c8194b6..c16e9f432 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1180,9 +1180,11 @@ use indexes::IndicesIterF; unsafe impl TrustedIterator for Linspace { } unsafe impl<'a, A, D> TrustedIterator for Iter<'a, A, D> { } +unsafe impl<'a, A, D> TrustedIterator for IterMut<'a, A, D> { } unsafe impl TrustedIterator for std::iter::Map where I: TrustedIterator { } unsafe impl<'a, A> TrustedIterator for slice::Iter<'a, A> { } +unsafe impl<'a, A> TrustedIterator for slice::IterMut<'a, A> { } unsafe impl TrustedIterator for ::std::ops::Range { } // FIXME: These indices iter are dubious -- size needs to be checked up front. unsafe impl TrustedIterator for IndicesIter where D: Dimension { } @@ -1219,27 +1221,3 @@ pub fn to_vec_mapped(iter: I, mut f: F) -> Vec debug_assert_eq!(size, result.len()); result } - -/// Like Iterator::collect, but only for trusted length iterators -pub fn to_vec_mapped_mut(iter: I, mut f: F) -> Vec - where I: TrustedIterator + ExactSizeIterator, - F: FnMut(&mut I::Item) -> B, -{ - // Use an `unsafe` block to do this efficiently. - // We know that iter will produce exactly .size() elements, - // and the loop can vectorize if it's clean (without branch to grow the vector). - let (size, _) = iter.size_hint(); - let mut result = Vec::with_capacity(size); - let mut out_ptr = result.as_mut_ptr(); - let mut len = 0; - iter.fold((), |(), elt| { - unsafe { - ptr::write(out_ptr, f(&mut elt)); - len += 1; - result.set_len(len); - out_ptr = out_ptr.offset(1); - } - }); - debug_assert_eq!(size, result.len()); - result -} From 85a83d1fb5de16bf44ab5184e401524efc47d5ec Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Tue, 29 May 2018 08:00:21 +0100 Subject: [PATCH 3/7] Implemented map_mut and map_axis_mut --- src/impl_methods.rs | 64 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 42666a894..72509eff3 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -892,7 +892,7 @@ impl ArrayBase where S: Data, D: Dimension /// **Panics** if any dimension of `chunk_size` is zero
/// (**Panics** if `D` is `IxDyn` and `chunk_size` does not match the /// number of array axes.) - pub fn exact_chunks(&self, chunk_size: E) -> ExactChunks + pub fn exact_chunks(&self, chunk_size: E) -> ExactChunks where E: IntoDimension, { exact_chunks_of(self.view(), chunk_size) @@ -930,7 +930,7 @@ impl ArrayBase where S: Data, D: Dimension /// [6, 6, 7, 7, 8, 8, 0], /// [6, 6, 7, 7, 8, 8, 0]])); /// ``` - pub fn exact_chunks_mut(&mut self, chunk_size: E) -> ExactChunksMut + pub fn exact_chunks_mut(&mut self, chunk_size: E) -> ExactChunksMut where E: IntoDimension, S: DataMut { @@ -941,13 +941,13 @@ impl ArrayBase where S: Data, D: Dimension /// /// The windows are all distinct overlapping views of size `window_size` /// that fit into the array's shape. - /// + /// /// Will yield over no elements if window size is larger /// than the actual array size of any dimension. /// /// The produced element is an `ArrayView` with exactly the dimension /// `window_size`. - /// + /// /// **Panics** if any dimension of `window_size` is zero.
/// (**Panics** if `D` is `IxDyn` and `window_size` does not match the /// number of array axes.) @@ -1694,6 +1694,34 @@ impl ArrayBase where S: Data, D: Dimension } } + /// Call `f` on a mutable reference of each element and create a new array + /// with the new values. + /// + /// Elements are visited in arbitrary order. + /// + /// Return an array with the same shape as `self`. + pub fn map_mut<'a, B, F>(&'a mut self, f: F) -> Array + where F: FnMut(&mut A) -> B, + A: 'a, + S: DataMut + { + let dim = self.dim.clone(); + let strides = self.strides.clone(); + if self.is_contiguous() { + let slc = self.as_slice_memory_order_mut().unwrap(); + let v = ::iterators::to_vec_mapped(slc.iter_mut(), f); + unsafe { + ArrayBase::from_shape_vec_unchecked( + dim.strides(strides), v) + } + } else { + let v = ::iterators::to_vec_mapped(self.iter_mut(), f); + unsafe { + ArrayBase::from_shape_vec_unchecked(dim, v) + } + } + } + /// Call `f` by **v**alue on each element and create a new array /// with the new values. /// @@ -1819,4 +1847,32 @@ impl ArrayBase where S: Data, D: Dimension } }) } + + /// Reduce the values along an axis into just one value, producing a new + /// array with one less dimension. + /// 1-dimensional lanes are passed as mutable references to the reducer, + /// allowing for side-effects. + /// + /// Elements are visited in arbitrary order. + /// + /// Return the result as an `Array`. + /// + /// **Panics** if `axis` is out of bounds. + pub fn map_axis_mut<'a, B, F>(&'a mut self, axis: Axis, mut mapping: F) + -> Array + where D: RemoveAxis, + F: FnMut(ArrayViewMut1<'a, A>) -> B, + A: 'a + Clone, + S: DataMut, + { + let view_len = self.len_of(axis); + let view_stride = self.strides.axis(axis); + // use the 0th subview as a map to each 1d array view extended from + // the 0th element. + self.subview_mut(axis, 0).map_mut(|first_elt: &mut A| { + unsafe { + mapping(ArrayViewMut::new_(first_elt, Ix1(view_len), Ix1(view_stride))) + } + }) + } } From e4075bbd1cdc626b64d1f0400e76860a74911f88 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 13 Jun 2018 22:30:11 +0100 Subject: [PATCH 4/7] Moved strides clone call inside the happy if branch. --- src/impl_methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 72509eff3..64f9349ae 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -1706,8 +1706,8 @@ impl ArrayBase where S: Data, D: Dimension S: DataMut { let dim = self.dim.clone(); - let strides = self.strides.clone(); if self.is_contiguous() { + let strides = self.strides.clone(); let slc = self.as_slice_memory_order_mut().unwrap(); let v = ::iterators::to_vec_mapped(slc.iter_mut(), f); unsafe { From b35a51b22738f92dfe8a2432c6fb6bd5d739f46b Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 13 Jun 2018 22:32:57 +0100 Subject: [PATCH 5/7] Emulating lifetime parameters usage in `map`. --- src/impl_methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 64f9349ae..55a845183 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -1701,7 +1701,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// Return an array with the same shape as `self`. pub fn map_mut<'a, B, F>(&'a mut self, f: F) -> Array - where F: FnMut(&mut A) -> B, + where F: FnMut(&'a mut A) -> B, A: 'a, S: DataMut { From 153b1f2e1d2885a8e9a7833aca94611760afdfb9 Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 13 Jun 2018 22:34:01 +0100 Subject: [PATCH 6/7] Removing unneeded Clone bound on A in map_axis_mut. --- src/impl_methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 55a845183..625e0ca6f 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -1862,7 +1862,7 @@ impl ArrayBase where S: Data, D: Dimension -> Array where D: RemoveAxis, F: FnMut(ArrayViewMut1<'a, A>) -> B, - A: 'a + Clone, + A: 'a, S: DataMut, { let view_len = self.len_of(axis); From 2bf5cc9fa07f189e13d1ec69a5f0d366053d88bf Mon Sep 17 00:00:00 2001 From: LukeMathWalker Date: Wed, 13 Jun 2018 22:37:20 +0100 Subject: [PATCH 7/7] Restoring whitespaces --- src/impl_methods.rs | 8 ++++---- src/iterators/mod.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 625e0ca6f..6e3eeaf58 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -892,7 +892,7 @@ impl ArrayBase where S: Data, D: Dimension /// **Panics** if any dimension of `chunk_size` is zero
/// (**Panics** if `D` is `IxDyn` and `chunk_size` does not match the /// number of array axes.) - pub fn exact_chunks(&self, chunk_size: E) -> ExactChunks + pub fn exact_chunks(&self, chunk_size: E) -> ExactChunks where E: IntoDimension, { exact_chunks_of(self.view(), chunk_size) @@ -930,7 +930,7 @@ impl ArrayBase where S: Data, D: Dimension /// [6, 6, 7, 7, 8, 8, 0], /// [6, 6, 7, 7, 8, 8, 0]])); /// ``` - pub fn exact_chunks_mut(&mut self, chunk_size: E) -> ExactChunksMut + pub fn exact_chunks_mut(&mut self, chunk_size: E) -> ExactChunksMut where E: IntoDimension, S: DataMut { @@ -941,13 +941,13 @@ impl ArrayBase where S: Data, D: Dimension /// /// The windows are all distinct overlapping views of size `window_size` /// that fit into the array's shape. - /// + /// /// Will yield over no elements if window size is larger /// than the actual array size of any dimension. /// /// The produced element is an `ArrayView` with exactly the dimension /// `window_size`. - /// + /// /// **Panics** if any dimension of `window_size` is zero.
/// (**Panics** if `D` is `IxDyn` and `window_size` does not match the /// number of array axes.) diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index c16e9f432..984cc2179 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -718,7 +718,7 @@ macro_rules! outer_iter_split_at_impl { { assert!(index <= self.iter.len); let right_ptr = if index != self.iter.len { - unsafe { self.iter.offset(index) } + unsafe { self.iter.offset(index) } } else { self.iter.ptr