Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CowArray feature #632

Merged
merged 12 commits into from May 30, 2019
104 changes: 103 additions & 1 deletion src/data_traits.rs
Expand Up @@ -11,7 +11,9 @@
use std::mem::{self, size_of};
use std::sync::Arc;

use crate::{ArrayBase, Dimension, OwnedArcRepr, OwnedRcRepr, OwnedRepr, RawViewRepr, ViewRepr};
use crate::{
ArrayBase, CowRepr, Dimension, OwnedArcRepr, OwnedRcRepr, OwnedRepr, RawViewRepr, ViewRepr,
};

/// Array representation trait.
///
Expand Down Expand Up @@ -423,3 +425,103 @@ unsafe impl<A> DataOwned for OwnedArcRepr<A> {
self
}
}

unsafe impl<'a, A> RawData for CowRepr<'a, A> {
type Elem = A;
fn _data_slice(&self) -> Option<&[A]> {
match self {
CowRepr::View(view) => view._data_slice(),
CowRepr::Owned(data) => data._data_slice(),
}
}
private_impl! {}
}

unsafe impl<'a, A> RawDataMut for CowRepr<'a, A>
where
A: Clone,
{
#[inline]
fn try_ensure_unique<D>(array: &mut ArrayBase<Self, D>)
where
Self: Sized,
D: Dimension,
{
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]
fn try_is_unique(&mut self) -> Option<bool> {
Some(self.is_owned())
}
}

unsafe impl<'a, A> RawDataClone for CowRepr<'a, A>
where
A: Clone,
{
unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) -> (Self, *mut Self::Elem) {
match self {
CowRepr::View(view) => {
let (new_view, ptr) = view.clone_with_ptr(ptr);
(CowRepr::View(new_view), ptr)
}
CowRepr::Owned(data) => {
let (new_data, ptr) = data.clone_with_ptr(ptr);
(CowRepr::Owned(new_data), ptr)
}
}
}

#[doc(hidden)]
unsafe fn clone_from_with_ptr(
&mut self,
other: &Self,
ptr: *mut Self::Elem,
) -> *mut Self::Elem {
match (&mut *self, other) {
(CowRepr::View(self_), CowRepr::View(other)) => self_.clone_from_with_ptr(other, 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> {
#[inline]
fn into_owned<D>(self_: ArrayBase<CowRepr<'a, A>, D>) -> ArrayBase<OwnedRepr<Self::Elem>, D>
where
A: Clone,
D: Dimension,
{
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 {}
9 changes: 6 additions & 3 deletions src/doc/ndarray_for_numpy_users/mod.rs
Expand Up @@ -72,9 +72,11 @@
//! In `ndarray`, all arrays are instances of [`ArrayBase`][ArrayBase], but
//! `ArrayBase` is generic over the ownership of the data. [`Array`][Array]
//! owns its data; [`ArrayView`][ArrayView] is a view;
//! [`ArrayViewMut`][ArrayViewMut] is a mutable view; and
//! [`ArcArray`][ArcArray] has a reference-counted pointer to its data (with
//! copy-on-write mutation). Arrays and views follow Rust's aliasing rules.
//! [`ArrayViewMut`][ArrayViewMut] is a mutable view; [`CowArray`][CowArray]
//! either owns its data or is a view (with copy-on-write mutation of the view
//! variant); and [`ArcArray`][ArcArray] has a reference-counted pointer to its
//! data (with copy-on-write mutation). Arrays and views follow Rust's aliasing
//! rules.
//!
//! </td>
//! </tr>
Expand Down Expand Up @@ -572,6 +574,7 @@
//! [.cols()]: ../../struct.ArrayBase.html#method.cols
//! [.column()]: ../../struct.ArrayBase.html#method.column
//! [.column_mut()]: ../../struct.ArrayBase.html#method.column_mut
//! [CowArray]: ../../type.CowArray.html
//! [::default()]: ../../struct.ArrayBase.html#method.default
//! [.diag()]: ../../struct.ArrayBase.html#method.diag
//! [.dim()]: ../../struct.ArrayBase.html#method.dim
Expand Down
57 changes: 57 additions & 0 deletions src/impl_cow.rs
@@ -0,0 +1,57 @@
// Copyright 2019 ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::imp_prelude::*;

/// Methods specific to `CowArray`.
///
/// ***See also all methods for [`ArrayBase`]***
///
/// [`ArrayBase`]: struct.ArrayBase.html
impl<'a, A, D> CowArray<'a, A, D>
where
D: Dimension,
{
/// Returns `true` iff the array is the view (borrowed) variant.
pub fn is_view(&self) -> bool {
self.data.is_view()
}

/// Returns `true` iff the array is the owned variant.
pub fn is_owned(&self) -> bool {
self.data.is_owned()
}
}

impl<'a, A, D> From<ArrayView<'a, A, D>> for CowArray<'a, A, D>
where
D: Dimension,
{
fn from(view: ArrayView<'a, A, D>) -> CowArray<'a, A, D> {
ArrayBase {
data: CowRepr::View(view.data),
ptr: view.ptr,
dim: view.dim,
strides: view.strides,
}
}
}

impl<'a, A, D> From<Array<A, D>> for CowArray<'a, A, D>
where
D: Dimension,
{
fn from(array: Array<A, D>) -> CowArray<'a, A, D> {
ArrayBase {
data: CowRepr::Owned(array.data),
ptr: array.ptr,
dim: array.dim,
strides: array.strides,
}
}
}