Skip to content

Commit 4941aba

Browse files
committed
ixdyn: Implement short-dimension optimization for IxDyn
This means that low-dimensional IxDyn are stored inline and don't need an allocation for creation and cloning.
1 parent 013dcb1 commit 4941aba

File tree

8 files changed

+217
-17
lines changed

8 files changed

+217
-17
lines changed

src/aliases.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
//! Type aliases for common array sizes
22
//!
33
4-
use ::{Ix, Array, ArrayView, ArrayViewMut, RcArray};
4+
use ::{
5+
Ix,
6+
Array,
7+
ArrayView,
8+
ArrayViewMut,
9+
RcArray,
10+
IxDynImpl,
11+
};
512
use ::dimension::Dim;
613
use dimension::DimPrivate;
714

@@ -78,7 +85,7 @@ pub type Ix6 = Dim<[Ix; 6]>;
7885
/// // the same type `Array<f64, IxDyn>` a.k.a `ArrayD<f64>`:
7986
/// let arrays = vec![a, b];
8087
/// ```
81-
pub type IxDyn = Dim<Vec<Ix>>;
88+
pub type IxDyn = Dim<IxDynImpl>;
8289

8390
/// zero-dimensional array
8491
pub type Array0<A> = Array<A, Ix0>;

src/dimension/conversion.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use std::ops::{Index, IndexMut};
1212
use libnum::Zero;
1313

14-
use {Ix, Ix1, IxDyn, Dimension, Dim};
14+
use {Ix, Ix1, IxDyn, Dimension, Dim, IxDynImpl};
1515
use super::DimPrivate;
1616

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

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

65+
impl IntoDimension for Vec<Ix> {
66+
type Dim = IxDyn;
67+
#[inline(always)]
68+
fn into_dimension(self) -> Self::Dim { Dim::new(IxDynImpl::from(self)) }
69+
}
70+
6571
pub trait Convert {
6672
type To;
6773
fn convert(self) -> Self::To;

src/dimension/dimension_trait.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign};
1313

1414
use itertools::{enumerate, zip};
1515

16-
use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, IxDyn, Dim, Si};
16+
use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, IxDyn, Dim, Si, IxDynImpl};
1717
use IntoDimension;
1818
use RemoveAxis;
1919
use {ArrayView1, ArrayViewMut1};
@@ -53,7 +53,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
5353
/// - For `Ix1`: `[Si; 1]`
5454
/// - For `Ix2`: `[Si; 2]`
5555
/// - and so on..
56-
/// - For `Vec<Ix>`: `[Si]`
56+
/// - For `IxDyn: `[Si]`
5757
///
5858
/// The easiest way to create a `&SliceArg` is using the macro
5959
/// [`s![]`](macro.s!.html).
@@ -63,7 +63,7 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
6363
/// - For `Ix1`: `usize`,
6464
/// - For `Ix2`: `(usize, usize)`
6565
/// - and so on..
66-
/// - For `Vec<Ix>`: `Vec<usize>`,
66+
/// - For `IxDyn: `IxDyn`
6767
type Pattern: IntoDimension<Dim=Self>;
6868
// Next smaller dimension (if it exists)
6969
#[doc(hidden)]
@@ -734,7 +734,7 @@ large_dim!(4, Ix4, Ix, Ix, Ix, Ix);
734734
large_dim!(5, Ix5, Ix, Ix, Ix, Ix, Ix);
735735
large_dim!(6, Ix6, Ix, Ix, Ix, Ix, Ix, Ix);
736736

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

764-
impl<J> Index<J> for Dim<Vec<usize>>
765-
where Vec<usize>: Index<J>,
764+
impl<J> Index<J> for Dim<IxDynImpl>
765+
where IxDynImpl: Index<J>,
766766
{
767-
type Output = <Vec<usize> as Index<J>>::Output;
767+
type Output = <IxDynImpl as Index<J>>::Output;
768768
fn index(&self, index: J) -> &Self::Output {
769769
&self.ix()[index]
770770
}
771771
}
772772

773-
impl<J> IndexMut<J> for Dim<Vec<usize>>
774-
where Vec<usize>: IndexMut<J>,
773+
impl<J> IndexMut<J> for Dim<IxDynImpl>
774+
where IxDynImpl: IndexMut<J>,
775775
{
776776
fn index_mut(&mut self, index: J) -> &mut Self::Output {
777777
&mut self.ixm()[index]

src/dimension/dynindeximpl.rs

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
2+
use std::ops::{
3+
Index,
4+
IndexMut,
5+
Deref,
6+
DerefMut,
7+
};
8+
use imp_prelude::*;
9+
10+
const CAP: usize = 4;
11+
12+
/// T is usize or isize
13+
#[derive(Debug)]
14+
enum IxDynRepr<T> {
15+
Inline(u32, [T; CAP]),
16+
Alloc(Box<[T]>),
17+
}
18+
19+
impl<T> Deref for IxDynRepr<T> {
20+
type Target = [T];
21+
fn deref(&self) -> &[T] {
22+
match *self {
23+
IxDynRepr::Inline(len, ref ar) => {
24+
unsafe {
25+
ar.get_unchecked(..len as usize)
26+
}
27+
}
28+
IxDynRepr::Alloc(ref ar) => &*ar,
29+
}
30+
}
31+
}
32+
33+
impl<T> DerefMut for IxDynRepr<T> {
34+
fn deref_mut(&mut self) -> &mut [T] {
35+
match *self {
36+
IxDynRepr::Inline(len, ref mut ar) => {
37+
unsafe {
38+
ar.get_unchecked_mut(..len as usize)
39+
}
40+
}
41+
IxDynRepr::Alloc(ref mut ar) => &mut *ar,
42+
}
43+
}
44+
}
45+
46+
impl Default for IxDynRepr<Ix> {
47+
fn default() -> Self {
48+
Self::copy_from(&[0])
49+
}
50+
}
51+
52+
53+
use ::libnum::Zero;
54+
55+
impl<T: Copy + Zero> IxDynRepr<T> {
56+
pub fn copy_from(x: &[T]) -> Self {
57+
if x.len() <= CAP {
58+
let mut arr = [T::zero(); CAP];
59+
for i in 0..x.len() {
60+
arr[i] = x[i];
61+
}
62+
IxDynRepr::Inline(x.len() as _, arr)
63+
} else {
64+
Self::from(x)
65+
}
66+
}
67+
}
68+
69+
impl<T: Copy + Zero> IxDynRepr<T> {
70+
// make an Inline or Alloc version as appropriate
71+
fn from_vec_auto(v: Vec<T>) -> Self {
72+
if v.len() <= CAP {
73+
Self::copy_from(&v)
74+
} else {
75+
Self::from_vec(v)
76+
}
77+
}
78+
}
79+
80+
impl<T: Copy> IxDynRepr<T> {
81+
fn from_vec(v: Vec<T>) -> Self {
82+
IxDynRepr::Alloc(v.into_boxed_slice())
83+
}
84+
85+
fn from(x: &[T]) -> Self {
86+
Self::from_vec(x.to_vec())
87+
}
88+
}
89+
90+
impl<T: Copy> Clone for IxDynRepr<T> {
91+
fn clone(&self) -> Self {
92+
match *self {
93+
IxDynRepr::Inline(len, arr) => {
94+
IxDynRepr::Inline(len, arr)
95+
}
96+
_ => Self::from(&self[..])
97+
}
98+
}
99+
}
100+
101+
impl<T: Eq> Eq for IxDynRepr<T> { }
102+
103+
impl<T: PartialEq> PartialEq for IxDynRepr<T> {
104+
fn eq(&self, rhs: &Self) -> bool {
105+
match (self, rhs) {
106+
(&IxDynRepr::Inline(slen, ref sarr), &IxDynRepr::Inline(rlen, ref rarr)) => {
107+
slen == rlen &&
108+
(0..CAP as usize).filter(|&i| i < slen as usize)
109+
.all(|i| sarr[i] == rarr[i])
110+
}
111+
_ => self[..] == rhs[..]
112+
}
113+
}
114+
}
115+
116+
#[derive(Debug, Clone, PartialEq, Eq, Default)]
117+
pub struct IxDynImpl(IxDynRepr<Ix>);
118+
unsafe impl Send for IxDynImpl {}
119+
unsafe impl Sync for IxDynImpl {}
120+
121+
impl IxDynImpl {
122+
pub fn remove(&mut self, i: usize) {
123+
unimplemented!()
124+
}
125+
}
126+
127+
impl<'a> From<&'a [Ix]> for IxDynImpl {
128+
#[inline]
129+
fn from(ix: &'a [Ix]) -> Self {
130+
IxDynImpl(IxDynRepr::copy_from(ix))
131+
}
132+
}
133+
134+
impl From<Vec<Ix>> for IxDynImpl {
135+
#[inline]
136+
fn from(ix: Vec<Ix>) -> Self {
137+
IxDynImpl(IxDynRepr::from_vec_auto(ix))
138+
}
139+
}
140+
141+
impl<J> Index<J> for IxDynImpl
142+
where [Ix]: Index<J>,
143+
{
144+
type Output = <[Ix] as Index<J>>::Output;
145+
fn index(&self, index: J) -> &Self::Output {
146+
&self.0[index]
147+
}
148+
}
149+
150+
impl<J> IndexMut<J> for IxDynImpl
151+
where [Ix]: IndexMut<J>,
152+
{
153+
fn index_mut(&mut self, index: J) -> &mut Self::Output {
154+
&mut self.0[index]
155+
}
156+
}
157+
158+
impl Deref for IxDynImpl {
159+
type Target = [Ix];
160+
#[inline]
161+
fn deref(&self) -> &[Ix] {
162+
&self.0
163+
}
164+
}
165+
166+
impl DerefMut for IxDynImpl {
167+
#[inline]
168+
fn deref_mut(&mut self) -> &mut [Ix] {
169+
&mut self.0
170+
}
171+
}
172+
173+
impl<'a> IntoIterator for &'a IxDynImpl {
174+
type Item = &'a Ix;
175+
type IntoIter = <&'a [Ix] as IntoIterator>::IntoIter;
176+
#[inline]
177+
fn into_iter(self) -> Self::IntoIter {
178+
self[..].into_iter()
179+
}
180+
}

src/dimension/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ pub use self::dimension_trait::Dimension;
1717
pub use self::ndindex::NdIndex;
1818
pub use self::remove_axis::RemoveAxis;
1919
pub use self::axes::{axes_of, Axes, AxisDescription};
20+
pub use self::dynindeximpl::IxDynImpl;
2021

2122
#[macro_use] mod macros;
2223
mod axis;
2324
mod conversion;
2425
pub mod dim;
2526
mod dimension_trait;
27+
mod dynindeximpl;
2628
mod ndindex;
2729
mod remove_axis;
2830
mod axes;

src/dimension/ndindex.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ use std::fmt::Debug;
44
use itertools::zip;
55

66
use {Ix, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, Dimension, IntoDimension};
7+
use {
8+
IxDynImpl,
9+
};
710
use super::{stride_offset, stride_offset_checked};
811
use super::DimPrivate;
912

@@ -194,9 +197,9 @@ ndindex_with_array!{
194197
}
195198

196199
impl<'a> IntoDimension for &'a [Ix] {
197-
type Dim = Dim<Vec<Ix>>;
200+
type Dim = IxDyn;
198201
fn into_dimension(self) -> Self::Dim {
199-
Dim(self.to_vec())
202+
Dim(IxDynImpl::from(self))
200203
}
201204
}
202205

@@ -209,7 +212,7 @@ unsafe impl<'a> NdIndex<IxDyn> for &'a [Ix] {
209212
}
210213
}
211214

212-
unsafe impl NdIndex<IxDyn> for Vec<Ix> {
215+
unsafe impl NdIndex<IxDyn> for IxDynImpl {
213216
fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option<isize> {
214217
stride_offset_checked(dim.ix(), strides.ix(), self)
215218
}

src/dimension/remove_axis.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99

1010
use {Ix, Ix0, Ix1, Dimension, Dim, Axis};
11+
use IxDyn;
1112
use super::DimPrivate;
1213

1314
/// Array shape with a next smaller dimension.
@@ -66,7 +67,7 @@ macro_rules! impl_remove_axis_array(
6667
impl_remove_axis_array!(3, 4, 5, 6);
6768

6869

69-
impl RemoveAxis for Dim<Vec<Ix>> {
70+
impl RemoveAxis for IxDyn {
7071
type Smaller = Self;
7172
fn remove_axis(&self, axis: Axis) -> Self {
7273
let mut res = self.clone();

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub use dimension::{
9494
pub use dimension::dim::*;
9595

9696
pub use dimension::NdIndex;
97+
pub use dimension::IxDynImpl;
9798
pub use indexes::Indices;
9899
pub use indexes::{indices, indices_of};
99100
pub use error::{ShapeError, ErrorKind};

0 commit comments

Comments
 (0)