58
58
type Item = A ;
59
59
type Dim = D ;
60
60
fn into_pyarray < ' py > ( self , py : Python < ' py > ) -> & ' py PyArray < Self :: Item , Self :: Dim > {
61
- let strides = NpyStrides :: from_array ( & self ) ;
61
+ let strides = self . npy_strides ( ) ;
62
62
let dim = self . raw_dim ( ) ;
63
63
let boxed = self . into_raw_vec ( ) . into_boxed_slice ( ) ;
64
64
unsafe { PyArray :: from_boxed_slice ( py, dim, strides. as_ptr ( ) , boxed) }
@@ -102,11 +102,68 @@ where
102
102
type Dim = D ;
103
103
fn to_pyarray < ' py > ( & self , py : Python < ' py > ) -> & ' py PyArray < Self :: Item , Self :: Dim > {
104
104
let len = self . len ( ) ;
105
- let strides = NpyStrides :: from_array ( self ) ;
106
- unsafe {
107
- let array = PyArray :: new_ ( py, self . raw_dim ( ) , strides. as_ptr ( ) , 0 ) ;
108
- array. copy_ptr ( self . as_ptr ( ) , len) ;
109
- array
105
+ if let Some ( order) = self . order ( ) {
106
+ // if the array is contiguous, copy it by `copy_ptr`.
107
+ let strides = self . npy_strides ( ) ;
108
+ unsafe {
109
+ let array = PyArray :: new_ ( py, self . raw_dim ( ) , strides. as_ptr ( ) , order. to_flag ( ) ) ;
110
+ array. copy_ptr ( self . as_ptr ( ) , len) ;
111
+ array
112
+ }
113
+ } else {
114
+ // if the array is not contiguous, copy all elements by `ArrayBase::iter`.
115
+ let dim = self . raw_dim ( ) ;
116
+ let strides = NpyStrides :: from_dim ( & dim, mem:: size_of :: < A > ( ) ) ;
117
+ unsafe {
118
+ let array = PyArray :: < A , _ > :: new_ ( py, dim, strides. as_ptr ( ) , 0 ) ;
119
+ let data_ptr = array. data ( ) ;
120
+ for ( i, item) in self . iter ( ) . enumerate ( ) {
121
+ data_ptr. offset ( i as isize ) . write ( * item) ;
122
+ }
123
+ array
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ enum Order {
130
+ Standard ,
131
+ Fortran ,
132
+ }
133
+
134
+ impl Order {
135
+ fn to_flag ( & self ) -> c_int {
136
+ match self {
137
+ Order :: Standard => 0 ,
138
+ Order :: Fortran => 1 ,
139
+ }
140
+ }
141
+ }
142
+
143
+ trait ArrayExt {
144
+ fn npy_strides ( & self ) -> NpyStrides ;
145
+ fn order ( & self ) -> Option < Order > ;
146
+ }
147
+
148
+ impl < A , S , D > ArrayExt for ArrayBase < S , D >
149
+ where
150
+ S : Data < Elem = A > ,
151
+ D : Dimension ,
152
+ {
153
+ fn npy_strides ( & self ) -> NpyStrides {
154
+ NpyStrides :: new (
155
+ self . strides ( ) . into_iter ( ) . map ( |& x| x as npyffi:: npy_intp ) ,
156
+ mem:: size_of :: < A > ( ) ,
157
+ )
158
+ }
159
+
160
+ fn order ( & self ) -> Option < Order > {
161
+ if self . is_standard_layout ( ) {
162
+ Some ( Order :: Standard )
163
+ } else if self . ndim ( ) > 1 && self . raw_view ( ) . reversed_axes ( ) . is_standard_layout ( ) {
164
+ Some ( Order :: Fortran )
165
+ } else {
166
+ None
110
167
}
111
168
}
112
169
}
@@ -124,31 +181,26 @@ impl NpyStrides {
124
181
NpyStrides :: Long ( inner) => inner. as_ptr ( ) ,
125
182
}
126
183
}
127
-
128
- fn from_array < A , S , D > ( array : & ArrayBase < S , D > ) -> Self
129
- where
130
- S : Data < Elem = A > ,
131
- D : Dimension ,
132
- A : TypeNum ,
133
- {
134
- Self :: from_strides ( array . strides ( ) , mem :: size_of :: < A > ( ) )
184
+ fn from_dim < D : Dimension > ( dim : & D , type_size : usize ) -> Self {
185
+ Self :: new (
186
+ dim . default_strides ( )
187
+ . slice ( )
188
+ . into_iter ( )
189
+ . map ( | & x| x as npyffi :: npy_intp ) ,
190
+ type_size ,
191
+ )
135
192
}
136
- fn from_strides ( strides : & [ isize ] , type_size : usize ) -> Self {
193
+ fn new ( strides : impl ExactSizeIterator < Item = npyffi :: npy_intp > , type_size : usize ) -> Self {
137
194
let len = strides. len ( ) ;
138
195
let type_size = type_size as npyffi:: npy_intp ;
139
196
if len <= 8 {
140
197
let mut res = [ 0 ; 8 ] ;
141
- for i in 0 ..len {
142
- res[ i] = strides [ i ] as npyffi :: npy_intp * type_size;
198
+ for ( i , s ) in strides . enumerate ( ) {
199
+ res[ i] = s * type_size;
143
200
}
144
201
NpyStrides :: Short ( res)
145
202
} else {
146
- NpyStrides :: Long (
147
- strides
148
- . into_iter ( )
149
- . map ( |& n| n as npyffi:: npy_intp * type_size)
150
- . collect ( ) ,
151
- )
203
+ NpyStrides :: Long ( strides. map ( |n| n as npyffi:: npy_intp * type_size) . collect ( ) )
152
204
}
153
205
}
154
206
}
0 commit comments