diff --git a/src/data_traits.rs b/src/data_traits.rs
index 137de0bc4..f4df024c6 100644
--- a/src/data_traits.rs
+++ b/src/data_traits.rs
@@ -414,9 +414,7 @@ unsafe impl DataOwned for OwnedArcRepr {
}
}
-unsafe impl<'a, A> RawData for CowRepr<'a, A>
- where A: Clone
-{
+unsafe impl<'a, A> RawData for CowRepr<'a, A> {
type Elem = A;
fn _data_slice(&self) -> Option<&[A]> {
match self {
@@ -435,7 +433,16 @@ unsafe impl<'a, A> RawDataMut for CowRepr<'a, A>
where Self: Sized,
D: Dimension
{
- array.ensure_is_owned();
+ match array.data {
+ CowRepr::View(_) => {
+ let owned = array.to_owned();
+ array.data = CowRepr::Owned(owned.data);
+ array.ptr = owned.ptr;
+ array.dim = owned.dim;
+ array.strides = owned.strides;
+ }
+ CowRepr::Owned(_) => {}
+ }
}
#[inline]
@@ -445,7 +452,7 @@ unsafe impl<'a, A> RawDataMut for CowRepr<'a, A>
}
unsafe impl<'a, A> RawDataClone for CowRepr<'a, A>
- where A: Copy
+ where A: Clone
{
unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) -> (Self, *mut Self::Elem) {
match self {
@@ -462,36 +469,44 @@ unsafe impl<'a, A> RawDataClone for CowRepr<'a, A>
#[doc(hidden)]
unsafe fn clone_from_with_ptr(&mut self, other: &Self, ptr: *mut Self::Elem) -> *mut Self::Elem {
- match self {
- CowRepr::View(view) => {
- match other {
- CowRepr::View(other_view) => view.clone_from_with_ptr(other_view, ptr),
- CowRepr::Owned(_) => panic!("Cannot copy `CowRepr::View` from `CowRepr::Temp`"),
- }
+ match (&mut *self, other) {
+ (CowRepr::View(self_), CowRepr::View(other)) => {
+ self_.clone_from_with_ptr(other, ptr)
},
- CowRepr::Owned(data) => {
- match other {
- CowRepr::View(_) => panic!("Cannot copy `CowRepr::Temp` from `CowRepr::View`"),
- CowRepr::Owned(other_data) => data.clone_from_with_ptr(other_data, ptr),
- }
+ (CowRepr::Owned(self_), CowRepr::Owned(other)) => {
+ self_.clone_from_with_ptr(other, ptr)
},
+ (_, CowRepr::Owned(other)) => {
+ let (cloned, ptr) = other.clone_with_ptr(ptr);
+ *self = CowRepr::Owned(cloned);
+ ptr
+ },
+ (_, CowRepr::View(other)) => {
+ let (cloned, ptr) = other.clone_with_ptr(ptr);
+ *self = CowRepr::View(cloned);
+ ptr
+ }
}
}
}
-unsafe impl<'a, A> Data for CowRepr<'a, A>
- where A: Clone
-{
+unsafe impl<'a, A> Data for CowRepr<'a, A> {
#[inline]
fn into_owned(self_: ArrayBase, D>) -> ArrayBase, D>
where
A: Clone,
D: Dimension,
{
- if self_.data.is_view() {
- ViewRepr::into_owned(self_.into_view_array().unwrap())
- } else {
- OwnedRepr::into_owned(self_.into_owned_array().unwrap())
+ match self_.data {
+ CowRepr::View(_) => self_.to_owned(),
+ CowRepr::Owned(data) => ArrayBase {
+ data,
+ ptr: self_.ptr,
+ dim: self_.dim,
+ strides: self_.strides,
+ },
}
}
}
+
+unsafe impl<'a, A> DataMut for CowRepr<'a, A> where A: Clone {}
diff --git a/src/impl_cow.rs b/src/impl_cow.rs
new file mode 100644
index 000000000..47b2af574
--- /dev/null
+++ b/src/impl_cow.rs
@@ -0,0 +1,55 @@
+// Copyright 2019 ndarray developers.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use crate::imp_prelude::*;
+
+/// Methods specific to `ArrayCow`.
+///
+/// ***See also all methods for [`ArrayBase`]***
+///
+/// [`ArrayBase`]: struct.ArrayBase.html
+impl<'a, A, D> ArrayCow<'a, A, D>
+where
+ D: Dimension,
+{
+ pub fn is_view(&self) -> bool {
+ self.data.is_view()
+ }
+
+ pub fn is_owned(&self) -> bool {
+ self.data.is_owned()
+ }
+}
+
+impl<'a, A, D> From> for ArrayCow<'a, A, D>
+where
+ D: Dimension,
+{
+ fn from(view: ArrayView<'a, A, D>) -> ArrayCow<'a, A, D> {
+ ArrayBase {
+ data: CowRepr::View(view.data),
+ ptr: view.ptr,
+ dim: view.dim,
+ strides: view.strides,
+ }
+ }
+}
+
+impl<'a, A, D> From> for ArrayCow<'a, A, D>
+where
+ D: Dimension,
+{
+ fn from(array: Array) -> ArrayCow<'a, A, D> {
+ ArrayBase {
+ data: CowRepr::Owned(array.data),
+ ptr: array.ptr,
+ dim: array.dim,
+ strides: array.strides,
+ }
+ }
+}
diff --git a/src/impl_methods.rs b/src/impl_methods.rs
index 4dd85bf58..a8a4ecea6 100644
--- a/src/impl_methods.rs
+++ b/src/impl_methods.rs
@@ -1230,14 +1230,14 @@ where
A: Clone
{
if self.is_standard_layout() {
- ArrayCow::from_view_array(self.view())
+ ArrayCow::from(self.view())
} else {
- let v = self.iter().map(|x| x.clone()).collect::>();
+ let v = self.iter().cloned().collect::>();
let owned_array: Array = unsafe {
// Safe because we use shape and content of existing array here.
- ArrayBase::from_shape_vec_unchecked(self.dim(), v)
+ ArrayBase::from_shape_vec_unchecked(self.raw_dim(), v)
};
- ArrayCow::from_owned_array(owned_array)
+ ArrayCow::from(owned_array)
}
}
diff --git a/src/lib.rs b/src/lib.rs
index a85307c7b..a96c3d63b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -205,6 +205,7 @@ mod imp_prelude {
DataShared,
RawViewRepr,
ViewRepr,
+ CowRepr,
Ix, Ixs,
};
pub use crate::dimension::DimensionExt;
@@ -1230,6 +1231,20 @@ pub type ArcArray = ArrayBase, D>;
/// and so on.
pub type Array = ArrayBase, D>;
+/// An array with copy-on-write behavior.
+///
+/// An `ArrayCow` represents either a uniquely owned array or a view of an
+/// array. The `'a` corresponds to the lifetime of the view variant.
+///
+/// Array views have all the methods of an array (see [`ArrayBase`][ab]).
+///
+/// See also [`ArcArray`](type.ArcArray.html), which also provides
+/// copy-on-write behavior but has a reference-counted pointer to the data
+/// instead of either a view or a uniquely owned copy.
+///
+/// [ab]: struct.ArrayBase.html
+pub type ArrayCow<'a, A, D> = ArrayBase, D>;
+
/// A read-only array view.
///
/// An array view represents an array or a part of it, created from
@@ -1374,16 +1389,12 @@ impl ViewRepr {
}
}
-pub enum CowRepr<'a, A>
- where A: Clone
-{
+pub enum CowRepr<'a, A> {
View(ViewRepr<&'a A>),
Owned(OwnedRepr),
}
-impl<'a, A> CowRepr<'a, A>
- where A: Clone
-{
+impl<'a, A> CowRepr<'a, A> {
pub fn is_view(&self) -> bool {
match self {
CowRepr::View(_) => true,
@@ -1396,8 +1407,6 @@ impl<'a, A> CowRepr<'a, A>
}
}
-pub type ArrayCow<'a, A, D> = ArrayBase, D>;
-
mod impl_clone;
mod impl_constructors;
@@ -1496,69 +1505,6 @@ impl ArrayBase
}
}
-impl<'a, A, D> ArrayCow<'a, A, D>
- where A: Clone,
- D: Dimension
-{
- fn from_view_array(array: ArrayView<'a, A, D>) -> ArrayCow<'a, A, D> {
- ArrayBase {
- data: CowRepr::View(array.data),
- ptr: array.ptr,
- dim: array.dim,
- strides: array.strides,
- }
- }
-
- fn from_owned_array(array: Array) -> ArrayCow<'a, A, D> {
- ArrayBase {
- data: CowRepr::Owned(array.data),
- ptr: array.ptr,
- dim: array.dim,
- strides: array.strides,
- }
- }
-
- fn into_view_array(self) -> Option> {
- match self.data {
- CowRepr::View(view) => Some(ArrayBase {
- data: view,
- ptr: self.ptr,
- dim: self.dim,
- strides: self.strides,
- }),
- CowRepr::Owned(_) => None,
- }
- }
-
- fn into_owned_array(self) -> Option> {
- match self.data {
- CowRepr::View(_) => None,
- CowRepr::Owned(data) => Some(ArrayBase {
- data,
- ptr: self.ptr,
- dim: self.dim,
- strides: self.strides,
- })
- }
- }
-
- fn ensure_is_owned(&mut self) {
- if self.data.is_view() {
- let mut copied_data: Vec = self.iter().map(|x| x.clone()).collect();
- self.ptr = copied_data.as_mut_ptr();
- self.data = CowRepr::Owned(OwnedRepr(copied_data));
- }
- }
-
- pub fn is_view(&self) -> bool {
- self.data.is_view()
- }
-
- pub fn is_owned(&self) -> bool {
- self.data.is_owned()
- }
-}
-
// parallel methods
#[cfg(feature="rayon")]
@@ -1581,6 +1527,9 @@ mod impl_views;
// Array raw view methods
mod impl_raw_views;
+// Copy-on-write array methods
+mod impl_cow;
+
/// A contiguous array shape of n dimensions.
///
/// Either c- or f- memory ordered (*c* a.k.a *row major* is the default).
diff --git a/src/prelude.rs b/src/prelude.rs
index 80c98e34c..25ab3ae65 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -25,6 +25,7 @@ pub use crate::{
Array,
ArcArray,
RcArray,
+ ArrayCow,
ArrayView,
ArrayViewMut,
RawArrayView,