diff --git a/src/arrayformat.rs b/src/arrayformat.rs
index aeab4f8a9..55e1b1466 100644
--- a/src/arrayformat.rs
+++ b/src/arrayformat.rs
@@ -1,9 +1,15 @@
use std::fmt;
use super::{Array, Dimension};
+use super::{
+ ArrayBase,
+ Data,
+};
-fn format_array(view: &Array, f: &mut fmt::Formatter,
- mut format: F) -> fmt::Result where
- F: FnMut(&mut fmt::Formatter, &A) -> fmt::Result,
+fn format_array(view: &ArrayBase, f: &mut fmt::Formatter,
+ mut format: F) -> fmt::Result
+ where F: FnMut(&mut fmt::Formatter, &A) -> fmt::Result,
+ D: Dimension,
+ S: Data,
{
let ndim = view.dim.slice().len();
/* private nowadays
@@ -80,7 +86,8 @@ impl<'a, A: fmt::Display, D: Dimension> fmt::Display for Array
}
}
-impl<'a, A: fmt::Debug, D: Dimension> fmt::Debug for Array
+impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase
+ where S: Data,
{
/// Format the array using `Debug` and apply the formatting parameters used
/// to each element.
diff --git a/src/arraytraits.rs b/src/arraytraits.rs
index 0d18b2721..d1c6ebd4b 100644
--- a/src/arraytraits.rs
+++ b/src/arraytraits.rs
@@ -9,46 +9,63 @@ use std::ops::{
IndexMut,
};
-use super::{Array, Dimension, Ix, Elements, ElementsMut};
+use super::{
+ Array, Dimension, Ix, Elements, ElementsMut,
+ ArrayBase,
+ ArrayView,
+ ArrayViewMut,
+ Data,
+ DataMut,
+};
-impl<'a, A, D: Dimension> Index for Array
+/// Access the element at **index**.
+///
+/// **Panics** if index is out of bounds.
+impl Index for ArrayBase
+ where D: Dimension,
+ S: Data,
{
- type Output = A;
+ type Output = S::Elem;
#[inline]
- /// Access the element at **index**.
- ///
- /// **Panics** if index is out of bounds.
- fn index(&self, index: D) -> &A {
- self.at(index).expect("Array::index: out of bounds")
+ fn index(&self, index: D) -> &S::Elem {
+ self.get(index).expect("Array::index: out of bounds")
}
}
-impl<'a, A: Clone, D: Dimension> IndexMut for Array
+/// Access the element at **index** mutably.
+///
+/// **Panics** if index is out of bounds.
+impl IndexMut for ArrayBase
+ where D: Dimension,
+ S: DataMut,
{
#[inline]
- /// Access the element at **index** mutably.
- ///
- /// **Panics** if index is out of bounds.
- fn index_mut(&mut self, index: D) -> &mut A {
- self.at_mut(index).expect("Array::index_mut: out of bounds")
+ fn index_mut(&mut self, index: D) -> &mut S::Elem {
+ self.get_mut(index).expect("Array::index_mut: out of bounds")
}
}
-impl
-PartialEq for Array
+impl PartialEq> for ArrayBase
+ where D: Dimension,
+ S: Data,
+ S2: Data,
+ S::Elem: PartialEq,
{
/// Return `true` if the array shapes and all elements of `self` and
/// `other` are equal. Return `false` otherwise.
- fn eq(&self, other: &Array) -> bool
+ fn eq(&self, other: &ArrayBase) -> bool
{
self.shape() == other.shape() &&
self.iter().zip(other.iter()).all(|(a, b)| a == b)
}
}
-impl
-Eq for Array {}
+impl Eq for ArrayBase
+ where D: Dimension,
+ S: Data,
+ S::Elem: Eq,
+{ }
impl FromIterator for Array
{
@@ -58,24 +75,24 @@ impl FromIterator for Array
}
}
-impl<'a, A, D> IntoIterator for &'a Array where
- D: Dimension,
+impl<'a, S, D> IntoIterator for &'a ArrayBase
+ where D: Dimension,
+ S: Data,
{
- type Item = &'a A;
- type IntoIter = Elements<'a, A, D>;
+ type Item = &'a S::Elem;
+ type IntoIter = Elements<'a, S::Elem, D>;
- fn into_iter(self) -> Self::IntoIter
- {
+ fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
-impl<'a, A, D> IntoIterator for &'a mut Array where
- A: Clone,
- D: Dimension,
+impl<'a, S, D> IntoIterator for &'a mut ArrayBase
+ where D: Dimension,
+ S: DataMut,
{
- type Item = &'a mut A;
- type IntoIter = ElementsMut<'a, A, D>;
+ type Item = &'a mut S::Elem;
+ type IntoIter = ElementsMut<'a, S::Elem, D>;
fn into_iter(self) -> Self::IntoIter
{
@@ -83,10 +100,34 @@ impl<'a, A, D> IntoIterator for &'a mut Array where
}
}
-impl
-hash::Hash for Array
+impl<'a, A, D> IntoIterator for ArrayView<'a, A, D>
+ where D: Dimension,
{
- fn hash(&self, state: &mut S)
+ type Item = &'a A;
+ type IntoIter = Elements<'a, A, D>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.into_iter_()
+ }
+}
+
+impl<'a, A, D> IntoIterator for ArrayViewMut<'a, A, D>
+ where D: Dimension,
+{
+ type Item = &'a mut A;
+ type IntoIter = ElementsMut<'a, A, D>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.into_iter_()
+ }
+}
+
+impl<'a, S, D> hash::Hash for ArrayBase
+ where D: Dimension,
+ S: Data,
+ S::Elem: hash::Hash,
+{
+ fn hash(&self, state: &mut H)
{
self.shape().hash(state);
for elt in self.iter() {
@@ -95,6 +136,22 @@ hash::Hash for Array
}
}
+// NOTE: ArrayBase keeps an internal raw pointer that always
+// points into the storage. This is Sync & Send as long as we
+// follow the usual inherited mutability rules, as we do with
+// Vec, &[] and &mut []
+
+/// `ArrayBase` is `Sync` when the storage type is.
+unsafe impl Sync for ArrayBase
+ where S: Sync + Data, D: Sync
+{ }
+
+/// `ArrayBase` is `Send` when the storage type is.
+unsafe impl Send for ArrayBase
+ where S: Send + Data, D: Send
+{ }
+
+
#[cfg(feature = "rustc-serialize")]
// Use version number so we can add a packed format later.
static ARRAY_FORMAT_VERSION: u8 = 1u8;
diff --git a/src/lib.rs b/src/lib.rs
index 24438951c..7c42d6214 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,8 +1,19 @@
#![crate_name="ndarray"]
#![crate_type="dylib"]
-//! The **ndarray** crate provides the [**Array**](./struct.Array.html) type, an
-//! n-dimensional container similar to numpy's ndarray.
+//! The `ndarray` crate provides an n-dimensional container similar to numpy's ndarray.
+//!
+//! - [`ArrayBase`](struct.ArrayBase.html)
+//! The n-dimensional array type itself, parameterized by data storage.
+//! - `Array`
+//! Array where the data is reference counted and copy on write, it
+//! can act as both an owner as the data as well as a lightweight view.
+//! - `OwnedArray`
+//! Array where the data is owned uniquely.
+//! - `ArrayView`
+//! A lightweight array view.
+//! - `ArrayViewMut`
+//! A lightweight read-write array view.
//!
//! ## Crate Summary and Status
//!
@@ -10,6 +21,7 @@
//! - `Array` is clone on write, so it can be both a view or an owner of the
//! data.
//! - Striding and broadcasting is fully implemented
+//! - Focus is on being a generic n-dimensional container
//! - Due to iterators, arithmetic operations, matrix multiplication etc
//! are not very well optimized, this is not a serious crate for numerics
//! or linear algebra. `Array` is a good container.
@@ -69,7 +81,7 @@ pub type Ix = u32;
/// Array index type (signed)
pub type Ixs = i32;
-/// The **Array** type is an *N-dimensional array*.
+/// The `Array` type is an *N-dimensional array*.
///
/// A reference counted array with copy-on-write mutability.
///
@@ -84,7 +96,7 @@ pub type Ixs = i32;
/// values.
///
/// Calling a method for mutating elements, for example
-/// [*at_mut()*](#method.at_mut), [*iadd()*](#method.iadd) or
+/// [*get_mut()*](#method.get_mut), [*iadd()*](#method.iadd) or
/// [*iter_mut()*](#method.iter_mut) will break sharing and require a clone of
/// the data (if it is not uniquely held).
///
@@ -95,7 +107,7 @@ pub type Ixs = i32;
///
/// ## Indexing
///
-/// Arrays use **u32** for indexing, represented by the types **Ix** and **Ixs**
+/// Arrays use `u32` for indexing, represented by the types `Ix` and `Ixs`
/// (signed).
///
/// ## Broadcasting
@@ -103,7 +115,7 @@ pub type Ixs = i32;
/// Arrays support limited *broadcasting*, where arithmetic operations with
/// array operands of different sizes can be carried out by repeating the
/// elements of the smaller dimension array. See
-/// [*.broadcast_iter()*](#method.broadcast_iter) for a more detailed
+/// [`.broadcast()`](#method.broadcast) for a more detailed
/// description.
///
/// ```
@@ -121,49 +133,193 @@ pub type Ixs = i32;
/// );
/// ```
///
-pub struct Array {
- // FIXME: Unsafecell around vec needed?
+pub struct ArrayBase where S: Data {
/// Rc data when used as view, Uniquely held data when being mutated
- data: Rc>,
+ data: S,
/// A pointer into the buffer held by data, may point anywhere
/// in its range.
- ptr: *mut A,
+ ptr: *mut S::Elem,
/// The size of each axis
dim: D,
- /// The element count stride per axis. To be parsed as **isize**.
+ /// The element count stride per axis. To be parsed as `isize`.
strides: D,
}
-impl Clone for Array
+/// Array's inner representation.
+pub unsafe trait Data {
+ type Elem;
+ fn slice(&self) -> &[Self::Elem];
+}
+
+/// Array's writable inner representation.
+pub unsafe trait DataMut : Data {
+ fn slice_mut(&mut self) -> &mut [Self::Elem];
+ fn ensure_unique(&mut ArrayBase)
+ where Self: Sized, D: Dimension
+ {
+ }
+}
+
+/// Clone an Array's storage.
+pub unsafe trait DataClone : Data {
+ /// Unsafe because, `ptr` must point inside the current storage.
+ unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) -> (Self, *mut Self::Elem);
+}
+
+unsafe impl Data for Rc> {
+ type Elem = A;
+ fn slice(&self) -> &[A] { self }
+}
+
+// NOTE: Copy on write
+unsafe impl DataMut for Rc> where A: Clone {
+ fn slice_mut(&mut self) -> &mut [A] { &mut Rc::make_mut(self)[..] }
+
+ fn ensure_unique(self_: &mut ArrayBase)
+ where Self: Sized, D: Dimension
+ {
+ if Rc::get_mut(&mut self_.data).is_some() {
+ return
+ }
+ if self_.dim.size() <= self_.data.len() / 2 {
+ unsafe {
+ *self_ = Array::from_vec_dim(self_.dim.clone(),
+ self_.iter().map(|x| x.clone()).collect());
+ }
+ return;
+ }
+ let our_off = (self_.ptr as isize - self_.data.as_ptr() as isize)
+ / mem::size_of::() as isize;
+ let rvec = Rc::make_mut(&mut self_.data);
+ unsafe {
+ self_.ptr = rvec.as_mut_ptr().offset(our_off);
+ }
+ }
+}
+
+unsafe impl DataClone for Rc> {
+ unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem)
+ -> (Self, *mut Self::Elem)
+ {
+ // pointer is preserved
+ (self.clone(), ptr)
+ }
+}
+
+unsafe impl Data for Vec {
+ type Elem = A;
+ fn slice(&self) -> &[A] { self }
+}
+
+unsafe impl DataMut for Vec {
+ fn slice_mut(&mut self) -> &mut [A] { self }
+}
+
+unsafe impl DataClone for Vec where A: Clone {
+ unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem)
+ -> (Self, *mut Self::Elem)
+ {
+ let mut u = self.clone();
+ let our_off = (self.as_ptr() as isize - ptr as isize)
+ / mem::size_of::() as isize;
+ let new_ptr = u.as_mut_ptr().offset(our_off);
+ (u, new_ptr)
+ }
+}
+
+unsafe impl<'a, A> Data for &'a [A] {
+ type Elem = A;
+ fn slice(&self) -> &[A] { self }
+}
+
+unsafe impl<'a, A> DataClone for &'a [A] {
+ unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem)
+ -> (Self, *mut Self::Elem)
+ {
+ (*self, ptr)
+ }
+}
+
+unsafe impl<'a, A> Data for &'a mut [A] {
+ type Elem = A;
+ fn slice(&self) -> &[A] { self }
+}
+
+unsafe impl<'a, A> DataMut for &'a mut [A] {
+ fn slice_mut(&mut self) -> &mut [A] { self }
+}
+
+/// Array representation that is a unique or shared owner of its data.
+pub unsafe trait DataOwned : Data {
+ fn new(elements: Vec) -> Self;
+ fn into_shared(self) -> Rc>;
+}
+
+/// Array representation that is a lightweight view.
+pub trait DataShared : Clone + DataClone { }
+
+impl DataShared for Rc> { }
+impl<'a, A> DataShared for &'a [A] { }
+
+unsafe impl DataOwned for Vec {
+ fn new(elements: Vec) -> Self { elements }
+ fn into_shared(self) -> Rc> { Rc::new(self) }
+}
+
+unsafe impl DataOwned for Rc> {
+ fn new(elements: Vec) -> Self { Rc::new(elements) }
+ fn into_shared(self) -> Rc> { self }
+}
+
+
+/// Array where the data is reference counted and copy on write, it
+/// can act as both an owner as the data as well as a lightweight view.
+pub type Array = ArrayBase>, D>;
+
+/// Array where the data is owned uniquely.
+pub type OwnedArray = ArrayBase, D>;
+
+/// A lightweight array view.
+pub type ArrayView<'a, A, D> = ArrayBase<&'a [A], D>;
+/// A lightweight read-write array view.
+pub type ArrayViewMut<'a, A, D> = ArrayBase<&'a mut [A], D>;
+
+impl Clone for ArrayBase
{
- fn clone(&self) -> Array {
- Array {
- data: self.data.clone(),
- ptr: self.ptr,
- dim: self.dim.clone(),
- strides: self.strides.clone(),
+ fn clone(&self) -> ArrayBase {
+ unsafe {
+ let (data, ptr) = self.data.clone_with_ptr(self.ptr);
+ ArrayBase {
+ data: data,
+ ptr: ptr,
+ dim: self.dim.clone(),
+ strides: self.strides.clone(),
+ }
}
}
}
-impl Array
+impl Copy for ArrayBase { }
+
+impl ArrayBase
+ where S: DataOwned,
{
/// Create a one-dimensional array from a vector (no allocation needed).
- pub fn from_vec(v: Vec) -> Array {
+ pub fn from_vec(v: Vec) -> Self {
unsafe {
- Array::from_vec_dim(v.len() as Ix, v)
+ Self::from_vec_dim(v.len() as Ix, v)
}
}
/// Create a one-dimensional array from an iterable.
- pub fn from_iter>(iterable: I) -> Array {
+ pub fn from_iter>(iterable: I) -> ArrayBase {
Self::from_vec(iterable.into_iter().collect())
}
}
impl Array
{
- /// Create a one-dimensional Array from interval **[begin, end)**
+ /// Create a one-dimensional Array from interval `[begin, end)`
pub fn range(begin: f32, end: f32) -> Array
{
let n = (end - begin) as usize;
@@ -174,25 +330,31 @@ impl Array
}
}
-impl Array where D: Dimension
+impl ArrayBase
+ where S: DataOwned,
+ D: Dimension,
{
- /// Construct an Array with zeros.
- pub fn zeros(dim: D) -> Array where A: Clone + libnum::Zero
+ /// Create an array from a vector (with no allocation needed).
+ ///
+ /// Unsafe because dimension is unchecked, and must be correct.
+ pub unsafe fn from_vec_dim(dim: D, mut v: Vec) -> ArrayBase
{
- Array::from_elem(dim, libnum::zero())
+ debug_assert!(dim.size() == v.len());
+ ArrayBase {
+ ptr: v.as_mut_ptr(),
+ data: DataOwned::new(v),
+ strides: dim.default_strides(),
+ dim: dim
+ }
}
- /// Construct an Array with default values, dimension `dim`.
- pub fn default(dim: D) -> Array
- where A: Default
+ /// Construct an Array with zeros.
+ pub fn zeros(dim: D) -> ArrayBase where S::Elem: Clone + libnum::Zero
{
- let v = (0..dim.size()).map(|_| A::default()).collect();
- unsafe {
- Array::from_vec_dim(dim, v)
- }
+ Self::from_elem(dim, libnum::zero())
}
- /// Construct an Array with copies of **elem**.
+ /// Construct an Array with copies of `elem`.
///
/// ```
/// use ndarray::Array;
@@ -207,28 +369,58 @@ impl Array where D: Dimension
/// [1., 1.]]])
/// );
/// ```
- pub fn from_elem(dim: D, elem: A) -> Array where A: Clone
+ pub fn from_elem(dim: D, elem: S::Elem) -> ArrayBase where S::Elem: Clone
{
let v = std::iter::repeat(elem).take(dim.size()).collect();
unsafe {
- Array::from_vec_dim(dim, v)
+ Self::from_vec_dim(dim, v)
}
}
- /// Create an array from a vector (with no allocation needed).
- ///
- /// Unsafe because dimension is unchecked, and must be correct.
- pub unsafe fn from_vec_dim(dim: D, mut v: Vec) -> Array
+ /// Construct an Array with default values, dimension `dim`.
+ pub fn default(dim: D) -> ArrayBase
+ where S::Elem: Default
{
- debug_assert!(dim.size() == v.len());
- Array {
- ptr: v.as_mut_ptr(),
- data: std::rc::Rc::new(v),
- strides: dim.default_strides(),
- dim: dim
+ let v = (0..dim.size()).map(|_| ::default()).collect();
+ unsafe {
+ Self::from_vec_dim(dim, v)
}
}
+}
+
+impl<'a, A, D> ArrayView<'a, A, D>
+ where D: Dimension,
+{
+ #[inline]
+ fn into_base_iter(self) -> Baseiter<'a, A, D> {
+ unsafe {
+ Baseiter::new(self.ptr, self.dim.clone(), self.strides.clone())
+ }
+ }
+
+ fn into_iter_(self) -> Elements<'a, A, D> {
+ Elements { inner: self.into_base_iter() }
+ }
+}
+
+impl<'a, A, D> ArrayViewMut<'a, A, D>
+ where D: Dimension,
+{
+ #[inline]
+ fn into_base_iter(self) -> Baseiter<'a, A, D> {
+ unsafe {
+ Baseiter::new(self.ptr, self.dim.clone(), self.strides.clone())
+ }
+ }
+
+ fn into_iter_(self) -> ElementsMut<'a, A, D> {
+ ElementsMut { inner: self.into_base_iter() }
+ }
+}
+
+impl ArrayBase where S: Data, D: Dimension
+{
/// Return the total number of elements in the Array.
pub fn len(&self) -> usize
{
@@ -245,31 +437,91 @@ impl Array where D: Dimension
self.dim.slice()
}
- /// Return **true** if the array data is laid out in
+ /// Return `true` if the array data is laid out in
/// contiguous “C order” where the last index is the most rapidly
/// varying.
///
- /// Return **false** otherwise, i.e the array is possibly not
+ /// Return `false` otherwise, i.e the array is possibly not
/// contiguous in memory, it has custom strides, etc.
pub fn is_standard_layout(&self) -> bool
{
self.strides == self.dim.default_strides()
}
+ /// Return a read-only view of the array
+ pub fn view(&self) -> ArrayView {
+ ArrayView {
+ ptr: self.ptr,
+ dim: self.dim.clone(),
+ strides: self.strides.clone(),
+ data: self.raw_data(),
+ }
+ }
+
+ /// Return a read-write view of the array
+ pub fn view_mut(&mut self) -> ArrayViewMut
+ where S: DataMut,
+ {
+ self.ensure_unique();
+ ArrayViewMut {
+ ptr: self.ptr,
+ dim: self.dim.clone(),
+ strides: self.strides.clone(),
+ data: self.data.slice_mut(),
+ }
+ }
+
+ /// Return an uniquely owned copy of the array or view
+ pub fn to_owned(&self) -> OwnedArray
+ where A: Clone
+ {
+ // FIXME: Use standard layout / more efficient copy?
+ let data = self.iter().cloned().collect();
+ unsafe {
+ ArrayBase::from_vec_dim(self.dim.clone(), data)
+ }
+ }
+
+ /// Return a shared ownership (copy on write) array.
+ pub fn to_shared(&self) -> Array
+ where A: Clone
+ {
+ // FIXME: Avoid copying if it's already an Array.
+ // FIXME: Use standard layout / more efficient copy?
+ let data = self.iter().cloned().collect();
+ unsafe {
+ ArrayBase::from_vec_dim(self.dim.clone(), data)
+ }
+ }
+
+ /// Return a shared ownership (copy on write) array.
+ pub fn into_shared(self) -> Array
+ where S: DataOwned,
+ {
+ let data = self.data.into_shared();
+ ArrayBase {
+ data: data,
+ ptr: self.ptr,
+ dim: self.dim,
+ strides: self.strides,
+ }
+ }
+
/// Return a slice of the array's backing data in memory order.
///
/// **Note:** Data memory order may not correspond to the index order
/// of the array. Neither is the raw data slice is restricted to just the
/// Array's view.
- pub fn raw_data<'a>(&'a self) -> &'a [A]
+ pub fn raw_data(&self) -> &[A]
{
- &self.data
+ self.data.slice()
}
/// Return a sliced array.
///
- /// **Panics** if **indexes** does not match the number of array axes.
- pub fn slice(&self, indexes: &[Si]) -> Array
+ /// **Panics** if `indexes` does not match the number of array axes.
+ pub fn slice(&self, indexes: &[Si]) -> Self
+ where S: DataShared
{
let mut arr = self.clone();
arr.islice(indexes);
@@ -278,7 +530,7 @@ impl Array where D: Dimension
/// Slice the array's view in place.
///
- /// **Panics** if **indexes** does not match the number of array axes.
+ /// **Panics** if `indexes` does not match the number of array axes.
pub fn islice(&mut self, indexes: &[Si])
{
let offset = Dimension::do_slices(&mut self.dim, &mut self.strides, indexes);
@@ -289,8 +541,8 @@ impl Array where D: Dimension
/// Return an iterator over a sliced view.
///
- /// **Panics** if **indexes** does not match the number of array axes.
- pub fn slice_iter<'a>(&'a self, indexes: &[Si]) -> Elements<'a, A, D>
+ /// **Panics** if `indexes` does not match the number of array axes.
+ pub fn slice_iter(&self, indexes: &[Si]) -> Elements
{
let mut it = self.iter();
let offset = Dimension::do_slices(&mut it.inner.dim, &mut it.inner.strides, indexes);
@@ -300,22 +552,46 @@ impl Array where D: Dimension
it
}
- /// Return a reference to the element at **index**, or return **None**
+ /// Return a reference to the element at `index`, or return `None`
/// if the index is out of bounds.
- pub fn at<'a>(&'a self, index: D) -> Option<&'a A> {
+ pub fn get(&self, index: D) -> Option<&A> {
self.dim.stride_offset_checked(&self.strides, &index)
.map(|offset| unsafe {
&*self.ptr.offset(offset)
})
}
+ /// ***Deprecated: use .get(i)***
+ pub fn at(&self, index: D) -> Option<&A> {
+ self.get(index)
+ }
+
+ /// Return a mutable reference to the element at `index`, or return `None`
+ /// if the index is out of bounds.
+ pub fn get_mut(&mut self, index: D) -> Option<&mut A>
+ where S: DataMut,
+ {
+ self.ensure_unique();
+ self.dim.stride_offset_checked(&self.strides, &index)
+ .map(|offset| unsafe {
+ &mut *self.ptr.offset(offset)
+ })
+ }
+
+ /// ***Deprecated: use .get_mut(i)***
+ pub fn at_mut(&mut self, index: D) -> Option<&mut A>
+ where S: DataMut,
+ {
+ self.get_mut(index)
+ }
+
/// Perform *unchecked* array indexing.
///
- /// Return a reference to the element at **index**.
+ /// Return a reference to the element at `index`.
///
/// **Note:** only unchecked for non-debug builds of ndarray.
#[inline]
- pub unsafe fn uchk_at<'a>(&'a self, index: D) -> &'a A {
+ pub unsafe fn uchk_at(&self, index: D) -> &A {
debug_assert!(self.dim.stride_offset_checked(&self.strides, &index).is_some());
let off = Dimension::stride_offset(&index, &self.strides);
&*self.ptr.offset(off)
@@ -323,13 +599,15 @@ impl Array where D: Dimension
/// Perform *unchecked* array indexing.
///
- /// Return a mutable reference to the element at **index**.
+ /// Return a mutable reference to the element at `index`.
///
/// **Note:** Only unchecked for non-debug builds of ndarray.
/// **Note:** The array must be uniquely held when mutating it.
#[inline]
- pub unsafe fn uchk_at_mut(&mut self, index: D) -> &mut A {
- debug_assert!(Rc::get_mut(&mut self.data).is_some());
+ pub unsafe fn uchk_at_mut(&mut self, index: D) -> &mut A
+ where S: DataMut
+ {
+ //debug_assert!(Rc::get_mut(&mut self.data).is_some());
debug_assert!(self.dim.stride_offset_checked(&self.strides, &index).is_some());
let off = Dimension::stride_offset(&index, &self.strides);
&mut *self.ptr.offset(off)
@@ -346,24 +624,24 @@ impl Array where D: Dimension
/// Return an iterator of references to the elements of the array.
///
- /// Iterator element type is **&'a A**.
- pub fn iter<'a>(&'a self) -> Elements<'a, A, D>
+ /// Iterator element type is `&A`.
+ pub fn iter(&self) -> Elements
{
Elements { inner: self.base_iter() }
}
/// Return an iterator of references to the elements of the array.
///
- /// Iterator element type is **(D, &'a A)**.
- pub fn indexed_iter<'a>(&'a self) -> Indexed>
+ /// Iterator element type is `(D, &A)`.
+ pub fn indexed_iter(&self) -> Indexed>
{
self.iter().indexed()
}
- /// Collapse dimension **axis** into length one,
- /// and select the subview of **index** along that axis.
+ /// Collapse dimension `axis` into length one,
+ /// and select the subview of `index` along that axis.
///
- /// **Panics** if **index** is past the length of the axis.
+ /// **Panics** if `index` is past the length of the axis.
pub fn isubview(&mut self, axis: usize, index: Ix)
{
dimension::do_sub(&mut self.dim, &mut self.ptr, &self.strides, axis, index)
@@ -372,9 +650,9 @@ impl Array where D: Dimension
/// Act like a larger size and/or shape array by *broadcasting*
/// into a larger shape, if possible.
///
- /// Return **None** if shapes can not be broadcast together.
+ /// Return `None` if shapes can not be broadcast together.
///
- /// ## Background
+ /// ***Background***
///
/// * Two axes are compatible if they are equal, or one of them is 1.
/// * In this instance, only the axes of the smaller side (self) can be 1.
@@ -385,23 +663,23 @@ impl Array where D: Dimension
/// because its axes are either equal or 1 (or missing);
/// while (2, 2) can *not* be broadcast into (2, 4).
///
- /// The implementation creates an iterator with strides set to 0 for the
+ /// The implementation creates a view with strides set to zero for the
/// axes that are to be repeated.
///
- /// See broadcasting documentation for Numpy for more information.
+ /// The broadcasting documentation for Numpy has more information.
///
/// ```
/// use ndarray::arr1;
///
/// assert!(
- /// arr1(&[1., 0.]).broadcast_iter((10, 2)).unwrap().count()
- /// == 20
+ /// arr1(&[1., 0.]).broadcast((10, 2)).unwrap().dim()
+ /// == (10, 2)
/// );
/// ```
- pub fn broadcast_iter<'a, E: Dimension>(&'a self, dim: E)
- -> Option>
+ pub fn broadcast(&self, dim: E)
+ -> Option>
{
- /// Return new stride when trying to grow **from** into shape **to**
+ /// Return new stride when trying to grow `from` into shape `to`
///
/// Broadcasting works by returning a "fake stride" where elements
/// to repeat are in axes with 0 stride, so that several indexes point
@@ -443,22 +721,33 @@ impl Array where D: Dimension
Some(new_stride)
}
+ // Note: zero strides are safe precisely because we return an read-only view
let broadcast_strides =
match upcast(&dim, &self.dim, &self.strides) {
Some(st) => st,
None => return None,
};
- Some(Elements {
- inner:
- unsafe {
- Baseiter::new(self.ptr, dim, broadcast_strides)
- }
+ Some(ArrayView {
+ data: self.raw_data(),
+ ptr: self.ptr,
+ dim: dim,
+ strides: broadcast_strides,
})
}
+ /// Act like a larger size and/or shape array by *broadcasting*
+ /// into a larger shape, if possible.
+ ///
+ /// Return `None` if shapes can not be broadcast together.
+ pub fn broadcast_iter(&self, dim: E)
+ -> Option>
+ {
+ self.broadcast(dim).map(|v| v.into_iter_())
+ }
+
#[inline(never)]
- fn broadcast_iter_unwrap<'a, E: Dimension>(&'a self, dim: E)
- -> Elements<'a, A, E>
+ fn broadcast_iter_unwrap(&self, dim: E)
+ -> Elements
{
match self.broadcast_iter(dim.clone()) {
Some(it) => it,
@@ -467,7 +756,7 @@ impl Array where D: Dimension
}
}
- /// Swap axes **ax** and **bx**.
+ /// Swap axes `ax` and `bx`.
///
/// **Panics** if the axes are out of bounds.
///
@@ -501,7 +790,7 @@ impl Array where D: Dimension
///
/// The diagonal is simply the sequence indexed by *(0, 0, .., 0)*,
/// *(1, 1, ..., 1)* etc as long as all axes have elements.
- pub fn diag_iter<'a>(&'a self) -> Elements<'a, A, Ix>
+ pub fn diag_iter(&self) -> Elements
{
let (len, stride) = self.diag_params();
unsafe {
@@ -512,9 +801,11 @@ impl Array where D: Dimension
}
/// Return the diagonal as a one-dimensional array.
- pub fn diag(&self) -> Array {
+ pub fn diag(&self) -> ArrayBase
+ where S: DataShared,
+ {
let (len, stride) = self.diag_params();
- Array {
+ ArrayBase {
data: self.data.clone(),
ptr: self.ptr,
dim: len,
@@ -522,7 +813,7 @@ impl Array where D: Dimension
}
}
- /// Apply **f** elementwise and return a new array with
+ /// Apply `f` elementwise and return a new array with
/// the results.
///
/// Return an array with the same shape as *self*.
@@ -537,22 +828,23 @@ impl Array where D: Dimension
/// == arr2(&[[0, 1], [1, 2]])
/// );
/// ```
- pub fn map<'a, B, F>(&'a self, mut f: F) -> Array where
- F: FnMut(&'a A) -> B
+ pub fn map<'a, B, F>(&'a self, mut f: F) -> OwnedArray
+ where F: FnMut(&'a A) -> B,
+ A: 'a,
{
- let mut res = Vec::::with_capacity(self.dim.size());
+ let mut res = Vec::with_capacity(self.dim.size());
for elt in self.iter() {
res.push(f(elt))
}
unsafe {
- Array::from_vec_dim(self.dim.clone(), res)
+ ArrayBase::from_vec_dim(self.dim.clone(), res)
}
}
- /// Select the subview **index** along **axis** and return an
+ /// Select the subview `index` along `axis` and return an
/// array with that axis removed.
///
- /// **Panics** if **index** is past the length of the axis.
+ /// **Panics** if `index` is past the length of the axis.
///
/// ```
/// use ndarray::{arr1, arr2};
@@ -565,14 +857,15 @@ impl Array where D: Dimension
/// a.subview(1, 1) == arr1(&[2., 4.])
/// );
/// ```
- pub fn subview(&self, axis: usize, index: Ix) -> Array::Smaller> where
- D: RemoveAxis
+ pub fn subview(&self, axis: usize, index: Ix) -> ArrayBase::Smaller>
+ where D: RemoveAxis,
+ S: DataShared,
{
let mut res = self.clone();
res.isubview(axis, index);
// don't use reshape -- we always know it will fit the size,
// and we can use remove_axis on the strides as well
- Array{
+ ArrayBase {
data: res.data,
ptr: res.ptr,
dim: res.dim.remove_axis(axis),
@@ -583,41 +876,17 @@ impl Array where D: Dimension
/// Make the array unshared.
///
/// This method is mostly only useful with unsafe code.
- pub fn ensure_unique(&mut self) where A: Clone
+ fn ensure_unique(&mut self)
+ where S: DataMut
{
- if Rc::get_mut(&mut self.data).is_some() {
- return
- }
- if self.dim.size() <= self.data.len() / 2 {
- unsafe {
- *self = Array::from_vec_dim(self.dim.clone(),
- self.iter().map(|x| x.clone()).collect());
- }
- return;
- }
- let our_off = (self.ptr as isize - self.data.as_ptr() as isize)
- / mem::size_of::() as isize;
- let rvec = Rc::make_mut(&mut self.data);
- unsafe {
- self.ptr = rvec.as_mut_ptr().offset(our_off);
- }
- }
-
- /// Return a mutable reference to the element at **index**, or return **None**
- /// if the index is out of bounds.
- pub fn at_mut<'a>(&'a mut self, index: D) -> Option<&'a mut A> where A: Clone
- {
- self.ensure_unique();
- self.dim.stride_offset_checked(&self.strides, &index)
- .map(|offset| unsafe {
- &mut *self.ptr.offset(offset)
- })
+ S::ensure_unique(self);
}
/// Return an iterator of mutable references to the elements of the array.
///
- /// Iterator element type is **&'a mut A**.
- pub fn iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, D> where A: Clone
+ /// Iterator element type is `&mut A`.
+ pub fn iter_mut(&mut self) -> ElementsMut
+ where S: DataMut,
{
self.ensure_unique();
ElementsMut { inner: self.base_iter() }
@@ -625,19 +894,32 @@ impl Array where D: Dimension
/// Return an iterator of indexes and mutable references to the elements of the array.
///
- /// Iterator element type is **(D, &'a mut A)**.
- pub fn indexed_iter_mut<'a>(&'a mut self) -> Indexed> where A: Clone
+ /// Iterator element type is `(D, &mut A)`.
+ pub fn indexed_iter_mut(&mut self) -> Indexed>
+ where S: DataMut,
{
self.iter_mut().indexed()
}
+ /// Return a sliced read-write view of the array.
+ ///
+ /// **Panics** if `indexes` does not match the number of array axes.
+ pub fn slice_mut(&mut self, indexes: &[Si]) -> ArrayViewMut
+ where S: DataMut
+ {
+ let mut arr = self.view_mut();
+ arr.islice(indexes);
+ arr
+ }
+
/// Return an iterator of mutable references into the sliced view
/// of the array.
///
- /// Iterator element type is **&'a mut A**.
+ /// Iterator element type is `&mut A`.
///
- /// **Panics** if **indexes** does not match the number of array axes.
- pub fn slice_iter_mut<'a>(&'a mut self, indexes: &[Si]) -> ElementsMut<'a, A, D> where A: Clone
+ /// **Panics** if `indexes` does not match the number of array axes.
+ pub fn slice_iter_mut(&mut self, indexes: &[Si]) -> ElementsMut
+ where S: DataMut,
{
let mut it = self.iter_mut();
let offset = Dimension::do_slices(&mut it.inner.dim, &mut it.inner.strides, indexes);
@@ -647,14 +929,47 @@ impl Array where D: Dimension
it
}
- /// Select the subview **index** along **axis** and return an iterator
+ /// Select the subview `index` along `axis` and return a read-write view.
+ ///
+ /// **Panics** if `axis` or `index` is out of bounds.
+ ///
+ /// ```
+ /// use ndarray::{arr2, aview2};
+ ///
+ /// let mut a = arr2(&[[1., 2.],
+ /// [3., 4.]]);
+ ///
+ /// a.subview_mut(1, 1).iadd_scalar(&10.);
+ ///
+ /// assert!(
+ /// a == aview2(&[[1., 12.],
+ /// [3., 14.]])
+ /// );
+ /// ```
+ pub fn subview_mut(&mut self, axis: usize, index: Ix)
+ -> ArrayViewMut
+ where S: DataMut,
+ D: RemoveAxis,
+ {
+ let mut res = self.view_mut();
+ res.isubview(axis, index);
+ ArrayBase {
+ data: res.data,
+ ptr: res.ptr,
+ dim: res.dim.remove_axis(axis),
+ strides: res.strides.remove_axis(axis),
+ }
+ }
+
+ /// Select the subview `index` along `axis` and return an iterator
/// of the subview.
///
- /// Iterator element type is **&'a mut A**.
+ /// Iterator element type is `&mut A`.
///
- /// **Panics** if **axis** or **index** is out of bounds.
- pub fn sub_iter_mut<'a>(&'a mut self, axis: usize, index: Ix)
- -> ElementsMut<'a, A, D> where A: Clone
+ /// **Panics** if `axis` or `index` is out of bounds.
+ pub fn sub_iter_mut(&mut self, axis: usize, index: Ix)
+ -> ElementsMut
+ where S: DataMut,
{
let mut it = self.iter_mut();
dimension::do_sub(&mut it.inner.dim, &mut it.inner.ptr, &it.inner.strides, axis, index);
@@ -662,7 +977,8 @@ impl Array where D: Dimension
}
/// Return an iterator over the diagonal elements of the array.
- pub fn diag_iter_mut<'a>(&'a mut self) -> ElementsMut<'a, A, Ix> where A: Clone
+ pub fn diag_iter_mut(&mut self) -> ElementsMut
+ where S: DataMut,
{
self.ensure_unique();
let (len, stride) = self.diag_params();
@@ -681,15 +997,15 @@ impl Array where D: Dimension
///
/// **Note:** The data is uniquely held and nonaliased
/// while it is mutably borrowed.
- pub fn raw_data_mut<'a>(&'a mut self) -> &'a mut [A]
- where A: Clone
+ pub fn raw_data_mut(&mut self) -> &mut [A]
+ where S: DataMut,
{
self.ensure_unique();
- &mut Rc::make_mut(&mut self.data)[..]
+ self.data.slice_mut()
}
- /// Transform the array into **shape**; any other shape
+ /// Transform the array into `shape`; any other shape
/// with the same number of elements is accepted.
///
/// **Panics** if sizes are incompatible.
@@ -703,7 +1019,8 @@ impl Array where D: Dimension
/// [3., 4.]])
/// );
/// ```
- pub fn reshape(&self, shape: E) -> Array where A: Clone
+ pub fn reshape(&self, shape: E) -> ArrayBase
+ where S: DataShared + DataOwned, A: Clone,
{
if shape.size() != self.dim.size() {
panic!("Incompatible sizes in reshape, attempted from: {:?}, to: {:?}",
@@ -712,7 +1029,7 @@ impl Array where D: Dimension
// Check if contiguous, if not => copy all, else just adapt strides
if self.is_standard_layout() {
let cl = self.clone();
- Array{
+ ArrayBase {
data: cl.data,
ptr: cl.ptr,
strides: shape.default_strides(),
@@ -721,40 +1038,44 @@ impl Array where D: Dimension
} else {
let v = self.iter().map(|x| x.clone()).collect::>();
unsafe {
- Array::from_vec_dim(shape, v)
+ ArrayBase::from_vec_dim(shape, v)
}
}
}
- /// Perform an elementwise assigment to **self** from **other**.
+ /// Perform an elementwise assigment to `self` from `rhs`.
///
- /// If their shapes disagree, **other** is broadcast to the shape of **self**.
+ /// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
///
/// **Panics** if broadcasting isn't possible.
- pub fn assign(&mut self, other: &Array) where A: Clone
+ pub fn assign(&mut self, rhs: &ArrayBase)
+ where S: DataMut,
+ A: Clone,
+ S2: Data,
{
- if self.shape() == other.shape() {
- for (x, y) in self.iter_mut().zip(other.iter()) {
+ if self.shape() == rhs.shape() {
+ for (x, y) in self.iter_mut().zip(rhs.iter()) {
*x = y.clone();
}
} else {
- let other_iter = other.broadcast_iter_unwrap(self.dim());
+ let other_iter = rhs.broadcast_iter_unwrap(self.dim());
for (x, y) in self.iter_mut().zip(other_iter) {
*x = y.clone();
}
}
}
- /// Perform an elementwise assigment to **self** from scalar **x**.
- pub fn assign_scalar(&mut self, x: &A) where A: Clone
+ /// Perform an elementwise assigment to `self` from scalar `x`.
+ pub fn assign_scalar(&mut self, x: &A)
+ where S: DataMut, A: Clone,
{
- for elt in self.raw_data_mut().iter_mut() {
+ for elt in self.iter_mut() {
*elt = x.clone();
}
}
}
-/// Return a zero-dimensional array with the element **x**.
+/// Return a zero-dimensional array with the element `x`.
pub fn arr0(x: A) -> Array
{
let mut v = Vec::with_capacity(1);
@@ -762,32 +1083,81 @@ pub fn arr0(x: A) -> Array
unsafe { Array::from_vec_dim((), v) }
}
-/// Return a one-dimensional array with elements from **xs**.
+/// Return a one-dimensional array with elements from `xs`.
pub fn arr1(xs: &[A]) -> Array
{
Array::from_vec(xs.to_vec())
}
+/// Return a zero-dimensional array view borrowing `x`.
+pub fn aview0(x: &A) -> ArrayView {
+ let data = unsafe {
+ std::slice::from_raw_parts(x, 1)
+ };
+ ArrayView {
+ data: data,
+ ptr: data.as_ptr() as *mut _,
+ dim: (),
+ strides: (),
+ }
+}
+
+/// Return a one-dimensional array view with elements borrowing `xs`.
+pub fn aview1(xs: &[A]) -> ArrayView {
+ ArrayView {
+ data: xs,
+ ptr: xs.as_ptr() as *mut _,
+ dim: xs.len() as Ix,
+ strides: 1,
+ }
+}
+
+/// Return a two-dimensional array view with elements borrowing `xs`.
+pub fn aview2>(xs: &[V]) -> ArrayView {
+ let cols = V::len();
+ let rows = xs.len();
+ let data = unsafe {
+ std::slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows)
+ };
+ let dim = (rows as Ix, cols as Ix);
+ ArrayView {
+ data: data,
+ ptr: data.as_ptr() as *mut _,
+ strides: dim.default_strides(),
+ dim: dim,
+ }
+}
+
/// Slice or fixed-size array used for array initialization
-pub unsafe trait ArrInit {
- fn as_init_slice(&self) -> &[T];
+pub unsafe trait Initializer {
+ type Elem;
+ fn as_init_slice(&self) -> &[Self::Elem];
fn is_fixed_size() -> bool { false }
}
-unsafe impl ArrInit for [T]
-{
- fn as_init_slice(&self) -> &[T]
- {
+/// Fixed-size array used for array initialization
+pub unsafe trait FixedInitializer: Initializer {
+ fn len() -> usize;
+}
+
+unsafe impl Initializer for [T] {
+ type Elem = T;
+ fn as_init_slice(&self) -> &[T] {
self
}
}
macro_rules! impl_arr_init {
(__impl $n: expr) => (
- unsafe impl ArrInit for [T; $n] {
+ unsafe impl Initializer for [T; $n] {
+ type Elem = T;
fn as_init_slice(&self) -> &[T] { self }
fn is_fixed_size() -> bool { true }
}
+
+ unsafe impl FixedInitializer for [T; $n] {
+ fn len() -> usize { $n }
+ }
);
() => ();
($n: expr, $($m:expr,)*) => (
@@ -799,7 +1169,7 @@ macro_rules! impl_arr_init {
impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,);
-/// Return a two-dimensional array with elements from **xs**.
+/// Return a two-dimensional array with elements from `xs`.
///
/// **Panics** if the slices are not all of the same length.
///
@@ -812,7 +1182,7 @@ impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,);
/// a.shape() == [2, 3]
/// );
/// ```
-pub fn arr2>(xs: &[V]) -> Array
+pub fn arr2>(xs: &[V]) -> Array
{
// FIXME: Simplify this when V is fix size array
let (m, n) = (xs.len() as Ix,
@@ -821,7 +1191,7 @@ pub fn arr2>(xs: &[V]) -> Array
let mut result = Vec::::with_capacity(dim.size());
for snd in xs.iter() {
let snd = snd.as_init_slice();
- assert!(>::is_fixed_size() || snd.len() as Ix == n);
+ assert!(::is_fixed_size() || snd.len() as Ix == n);
result.extend(snd.iter().map(|x| x.clone()))
}
unsafe {
@@ -829,7 +1199,7 @@ pub fn arr2>(xs: &[V]) -> Array
}
}
-/// Return a three-dimensional array with elements from **xs**.
+/// Return a three-dimensional array with elements from `xs`.
///
/// **Panics** if the slices are not all of the same length.
///
@@ -846,7 +1216,8 @@ pub fn arr2>(xs: &[V]) -> Array
/// a.shape() == [3, 2, 2]
/// );
/// ```
-pub fn arr3, U: ArrInit>(xs: &[V]) -> Array
+pub fn arr3, U: Initializer>(xs: &[V])
+ -> Array
{
// FIXME: Simplify this when U/V are fix size arrays
let m = xs.len() as Ix;
@@ -858,10 +1229,10 @@ pub fn arr3, U: ArrInit>(xs: &[V]) -> Array::with_capacity(dim.size());
for snd in xs.iter() {
let snd = snd.as_init_slice();
- assert!(>::is_fixed_size() || snd.len() as Ix == n);
+ assert!(::is_fixed_size() || snd.len() as Ix == n);
for thr in snd.iter() {
let thr = thr.as_init_slice();
- assert!(>::is_fixed_size() || thr.len() as Ix == o);
+ assert!(::is_fixed_size() || thr.len() as Ix == o);
result.extend(thr.iter().map(|x| x.clone()))
}
}
@@ -871,57 +1242,60 @@ pub fn arr3, U: ArrInit>(xs: &[V]) -> Array Array where
- A: Clone + Add