Skip to content
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ matrixmultiply = { version = "0.1.13" }
version = "0.9"
optional = true

[dev-dependencies]
defmac = "0.1"

[features]
blas = ["blas-sys"]

Expand Down
28 changes: 22 additions & 6 deletions src/aliases.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
//! Type aliases for common array sizes
//!

use ::{Ix, Array, ArrayView, ArrayViewMut, RcArray};
use ::{
Ix,
Array,
ArrayView,
ArrayViewMut,
RcArray,
IxDynImpl,
};
use ::dimension::Dim;
use dimension::DimPrivate;

Expand Down Expand Up @@ -38,6 +45,13 @@ pub fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 {
Dim::new([i0, i1, i2, i3, i4, i5])
}

/// Create a dynamic-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn IxDyn(ix: &[Ix]) -> IxDyn {
Dim(ix)
}

/// zero-dimensionial
pub type Ix0 = Dim<[Ix; 0]>;
/// one-dimensional
Expand All @@ -54,16 +68,18 @@ pub type Ix5 = Dim<[Ix; 5]>;
pub type Ix6 = Dim<[Ix; 6]>;
/// dynamic-dimensional
///
/// `Vec<Ix>` and `&[usize]` implement `IntoDimension` to produce `IxDyn`;
/// use them to create arrays with a dynamic number of axes.
/// You can use the `IxDyn` function to create a dimension for an array with
/// dynamic number of dimensions. (`Vec<Ix>` and `&[usize]` also implement
/// `IntoDimension` to produce `IxDyn`).
///
/// ```
/// use ndarray::ArrayD;
/// use ndarray::IxDyn;
///
/// // Create a 5 × 6 × 3 × 4 array using the dynamic dimension type
/// let mut a = ArrayD::<f64>::zeros(vec![5, 6, 3, 4]);
/// let mut a = ArrayD::<f64>::zeros(IxDyn(&[5, 6, 3, 4]));
/// // Create a 1 × 3 × 4 array using the dynamic dimension type
/// let mut b = ArrayD::<f64>::zeros(vec![1, 3, 4]);
/// let mut b = ArrayD::<f64>::zeros(IxDyn(&[1, 3, 4]));
///
/// // We can use broadcasting to add arrays of compatible shapes together:
/// a += &b;
Expand All @@ -78,7 +94,7 @@ pub type Ix6 = Dim<[Ix; 6]>;
/// // the same type `Array<f64, IxDyn>` a.k.a `ArrayD<f64>`:
/// let arrays = vec![a, b];
/// ```
pub type IxDyn = Dim<Vec<Ix>>;
pub type IxDyn = Dim<IxDynImpl>;

/// zero-dimensional array
pub type Array0<A> = Array<A, Ix0>;
Expand Down
8 changes: 5 additions & 3 deletions src/arraytraits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,9 +304,11 @@ impl<'a, A: 'a, D, T> AsArray<'a, A, D> for T
///
/// The array is created with dimension `D::default()`, which results
/// in for example dimensions `0` and `(0, 0)` with zero elements for the
/// one-dimensional and two-dimensional cases respectively, while for example
/// the zero dimensional case uses `()` (or `Vec::new()`) which
/// results in an array with one element.
/// one-dimensional and two-dimensional cases respectively.
///
/// The default dimension for `IxDyn` is `IxDyn(&[0])` (array has zero
/// elements). And the default for the dimension `()` is `()` (array has
/// one element).
///
/// Since arrays cannot grow, the intention is to use the default value as
/// placeholder.
Expand Down
10 changes: 8 additions & 2 deletions src/dimension/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use std::ops::{Index, IndexMut};
use libnum::Zero;

use {Ix, Ix1, IxDyn, Dimension, Dim};
use {Ix, Ix1, IxDyn, Dimension, Dim, IxDynImpl};
use super::DimPrivate;

/// $m: macro callback
Expand Down Expand Up @@ -56,12 +56,18 @@ impl<D> IntoDimension for D where D: Dimension {
fn into_dimension(self) -> Self { self }
}

impl IntoDimension for Vec<usize> {
impl IntoDimension for IxDynImpl {
type Dim = IxDyn;
#[inline(always)]
fn into_dimension(self) -> Self::Dim { Dim::new(self) }
}

impl IntoDimension for Vec<Ix> {
type Dim = IxDyn;
#[inline(always)]
fn into_dimension(self) -> Self::Dim { Dim::new(IxDynImpl::from(self)) }
}

pub trait Convert {
type To;
fn convert(self) -> Self::To;
Expand Down
18 changes: 9 additions & 9 deletions src/dimension/dimension_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign};

use itertools::{enumerate, zip};

use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, IxDyn, Dim, Si};
use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, IxDyn, Dim, Si, IxDynImpl};
use IntoDimension;
use RemoveAxis;
use {ArrayView1, ArrayViewMut1};
Expand Down Expand Up @@ -53,7 +53,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
/// - For `Ix1`: `[Si; 1]`
/// - For `Ix2`: `[Si; 2]`
/// - and so on..
/// - For `Vec<Ix>`: `[Si]`
/// - For `IxDyn: `[Si]`
///
/// The easiest way to create a `&SliceArg` is using the macro
/// [`s![]`](macro.s!.html).
Expand All @@ -63,7 +63,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
/// - For `Ix1`: `usize`,
/// - For `Ix2`: `(usize, usize)`
/// - and so on..
/// - For `Vec<Ix>`: `Vec<usize>`,
/// - For `IxDyn: `IxDyn`
type Pattern: IntoDimension<Dim=Self>;
// Next smaller dimension (if it exists)
#[doc(hidden)]
Expand Down Expand Up @@ -734,7 +734,7 @@ large_dim!(4, Ix4, Ix, Ix, Ix, Ix);
large_dim!(5, Ix5, Ix, Ix, Ix, Ix, Ix);
large_dim!(6, Ix6, Ix, Ix, Ix, Ix, Ix, Ix);

/// Vec<Ix> is a "dynamic" index, pretty hard to use when indexing,
/// IxDyn is a "dynamic" index, pretty hard to use when indexing,
/// and memory wasteful, but it allows an arbitrary and dynamic number of axes.
unsafe impl Dimension for IxDyn
{
Expand All @@ -761,17 +761,17 @@ unsafe impl Dimension for IxDyn
}
}

impl<J> Index<J> for Dim<Vec<usize>>
where Vec<usize>: Index<J>,
impl<J> Index<J> for Dim<IxDynImpl>
where IxDynImpl: Index<J>,
{
type Output = <Vec<usize> as Index<J>>::Output;
type Output = <IxDynImpl as Index<J>>::Output;
fn index(&self, index: J) -> &Self::Output {
&self.ix()[index]
}
}

impl<J> IndexMut<J> for Dim<Vec<usize>>
where Vec<usize>: IndexMut<J>,
impl<J> IndexMut<J> for Dim<IxDynImpl>
where IxDynImpl: IndexMut<J>,
{
fn index_mut(&mut self, index: J) -> &mut Self::Output {
&mut self.ixm()[index]
Expand Down
211 changes: 211 additions & 0 deletions src/dimension/dynindeximpl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@

use std::ops::{
Index,
IndexMut,
Deref,
DerefMut,
};
use imp_prelude::*;
use dimension::DimPrivate;

const CAP: usize = 4;

/// T is usize or isize
#[derive(Debug)]
enum IxDynRepr<T> {
Inline(u32, [T; CAP]),
Alloc(Box<[T]>),
}

impl<T> Deref for IxDynRepr<T> {
type Target = [T];
fn deref(&self) -> &[T] {
match *self {
IxDynRepr::Inline(len, ref ar) => {
unsafe {
ar.get_unchecked(..len as usize)
}
}
IxDynRepr::Alloc(ref ar) => &*ar,
}
}
}

impl<T> DerefMut for IxDynRepr<T> {
fn deref_mut(&mut self) -> &mut [T] {
match *self {
IxDynRepr::Inline(len, ref mut ar) => {
unsafe {
ar.get_unchecked_mut(..len as usize)
}
}
IxDynRepr::Alloc(ref mut ar) => &mut *ar,
}
}
}

/// The default is equivalent to `Self::from(&[0])`.
impl Default for IxDynRepr<Ix> {
fn default() -> Self {
Self::copy_from(&[0])
}
}


use ::libnum::Zero;

impl<T: Copy + Zero> IxDynRepr<T> {
pub fn copy_from(x: &[T]) -> Self {
if x.len() <= CAP {
let mut arr = [T::zero(); CAP];
for i in 0..x.len() {
arr[i] = x[i];
}
IxDynRepr::Inline(x.len() as _, arr)
} else {
Self::from(x)
}
}
}

impl<T: Copy + Zero> IxDynRepr<T> {
// make an Inline or Alloc version as appropriate
fn from_vec_auto(v: Vec<T>) -> Self {
if v.len() <= CAP {
Self::copy_from(&v)
} else {
Self::from_vec(v)
}
}
}

impl<T: Copy> IxDynRepr<T> {
fn from_vec(v: Vec<T>) -> Self {
IxDynRepr::Alloc(v.into_boxed_slice())
}

fn from(x: &[T]) -> Self {
Self::from_vec(x.to_vec())
}
}

impl<T: Copy> Clone for IxDynRepr<T> {
fn clone(&self) -> Self {
match *self {
IxDynRepr::Inline(len, arr) => {
IxDynRepr::Inline(len, arr)
}
_ => Self::from(&self[..])
}
}
}

impl<T: Eq> Eq for IxDynRepr<T> { }

impl<T: PartialEq> PartialEq for IxDynRepr<T> {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(&IxDynRepr::Inline(slen, ref sarr), &IxDynRepr::Inline(rlen, ref rarr)) => {
slen == rlen &&
(0..CAP as usize).filter(|&i| i < slen as usize)
.all(|i| sarr[i] == rarr[i])
}
_ => self[..] == rhs[..]
}
}
}

/// Dynamic dimension or index type.
///
/// Use `IxDyn` directly. This type implements a dynamic number of
/// dimensions or indices. Short dimensions are stored inline and don't need
/// any dynamic memory allocation.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct IxDynImpl(IxDynRepr<Ix>);
unsafe impl Send for IxDynImpl {}
unsafe impl Sync for IxDynImpl {}

impl IxDynImpl {
fn remove(&self, i: usize) -> Self {
IxDynImpl(match self.0 {
IxDynRepr::Inline(0, _) => IxDynRepr::Inline(0, [0; CAP]),
IxDynRepr::Inline(1, _) => IxDynRepr::Inline(0, [0; CAP]),
IxDynRepr::Inline(2, ref arr) => {
let mut out = [0; CAP];
out[0] = arr[1 - i];
IxDynRepr::Inline(1, out)
}
ref ixdyn => {
let len = ixdyn.len();
let mut result = IxDynRepr::copy_from(&ixdyn[..len - 1]);
for j in i..len - 1 {
result[j] = ixdyn[j + 1]
}
result
}
})
}
}

impl<'a> From<&'a [Ix]> for IxDynImpl {
#[inline]
fn from(ix: &'a [Ix]) -> Self {
IxDynImpl(IxDynRepr::copy_from(ix))
}
}

impl From<Vec<Ix>> for IxDynImpl {
#[inline]
fn from(ix: Vec<Ix>) -> Self {
IxDynImpl(IxDynRepr::from_vec_auto(ix))
}
}

impl<J> Index<J> for IxDynImpl
where [Ix]: Index<J>,
{
type Output = <[Ix] as Index<J>>::Output;
fn index(&self, index: J) -> &Self::Output {
&self.0[index]
}
}

impl<J> IndexMut<J> for IxDynImpl
where [Ix]: IndexMut<J>,
{
fn index_mut(&mut self, index: J) -> &mut Self::Output {
&mut self.0[index]
}
}

impl Deref for IxDynImpl {
type Target = [Ix];
#[inline]
fn deref(&self) -> &[Ix] {
&self.0
}
}

impl DerefMut for IxDynImpl {
#[inline]
fn deref_mut(&mut self) -> &mut [Ix] {
&mut self.0
}
}

impl<'a> IntoIterator for &'a IxDynImpl {
type Item = &'a Ix;
type IntoIter = <&'a [Ix] as IntoIterator>::IntoIter;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self[..].into_iter()
}
}

impl RemoveAxis for Dim<IxDynImpl> {
type Smaller = Self;
fn remove_axis(&self, axis: Axis) -> Self {
debug_assert!(axis.index() < self.ndim());
Dim::new(self.ix().remove(axis.index()))
}
}
Loading