@@ -145,6 +145,46 @@ impl<T, D> PyArray<T, D> {
145
145
self . as_ptr ( ) as _
146
146
}
147
147
148
+ #[ inline( always) ]
149
+ fn check_flag ( & self , flag : c_int ) -> bool {
150
+ unsafe { ( * self . as_array_ptr ( ) ) . flags & flag == flag }
151
+ }
152
+
153
+ /// Returns `true` if the internal data of the array is C-style contiguous
154
+ /// (default of numpy and ndarray) or Fortran-style contiguous.
155
+ ///
156
+ /// # Example
157
+ /// ```
158
+ /// # extern crate pyo3; extern crate numpy; fn main() {
159
+ /// use pyo3::types::IntoPyDict;
160
+ /// let gil = pyo3::Python::acquire_gil();
161
+ /// let py = gil.python();
162
+ /// let array = numpy::PyArray::arange(py, 0, 1, 10);
163
+ /// assert!(array.is_contiguous());
164
+ /// let locals = [("np", numpy::get_array_module(py).unwrap())].into_py_dict(py);
165
+ /// let not_contiguous: &numpy::PyArray1<f32> = py
166
+ /// .eval("np.zeros((3, 5))[::2, 4]", Some(locals), None)
167
+ /// .unwrap()
168
+ /// .downcast_ref()
169
+ /// .unwrap();
170
+ /// assert!(!not_contiguous.is_contiguous());
171
+ /// # }
172
+ /// ```
173
+ pub fn is_contiguous ( & self ) -> bool {
174
+ self . check_flag ( npyffi:: NPY_ARRAY_C_CONTIGUOUS )
175
+ | self . check_flag ( npyffi:: NPY_ARRAY_F_CONTIGUOUS )
176
+ }
177
+
178
+ /// Returns `true` if the internal data of the array is Fortran-style contiguous.
179
+ pub fn is_fotran_contiguous ( & self ) -> bool {
180
+ self . check_flag ( npyffi:: NPY_ARRAY_F_CONTIGUOUS )
181
+ }
182
+
183
+ /// Returns `true` if the internal data of the array is C-style contiguous.
184
+ pub fn is_c_contiguous ( & self ) -> bool {
185
+ self . check_flag ( npyffi:: NPY_ARRAY_C_CONTIGUOUS )
186
+ }
187
+
148
188
/// Get `Py<PyArray>` from `&PyArray`, which is the owned wrapper of PyObject.
149
189
///
150
190
/// You can use this method when you have to avoid lifetime annotation to your function args
@@ -162,7 +202,7 @@ impl<T, D> PyArray<T, D> {
162
202
/// }
163
203
/// let gil = Python::acquire_gil();
164
204
/// let array = return_py_array();
165
- /// assert_eq!(array.as_ref(gil.python()).as_slice(), &[0, 0, 0, 0, 0]);
205
+ /// assert_eq!(array.as_ref(gil.python()).as_slice().unwrap() , &[0, 0, 0, 0, 0]);
166
206
/// # }
167
207
/// ```
168
208
pub fn to_owned ( & self ) -> Py < Self > {
@@ -395,24 +435,43 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
395
435
}
396
436
397
437
/// Get the immutable view of the internal data of `PyArray`, as slice.
438
+ ///
439
+ /// Returns `ErrorKind::NotContiguous` if the internal array is not contiguous.
398
440
/// # Example
399
441
/// ```
400
442
/// # extern crate pyo3; extern crate numpy; fn main() {
401
- /// use numpy::PyArray;
443
+ /// use numpy::{PyArray, PyArray1};
444
+ /// use pyo3::types::IntoPyDict;
402
445
/// let gil = pyo3::Python::acquire_gil();
403
- /// let py_array = PyArray::arange(gil.python(), 0, 4, 1).reshape([2, 2]).unwrap();
404
- /// assert_eq!(py_array.as_slice(), &[0, 1, 2, 3]);
446
+ /// let py = gil.python();
447
+ /// let py_array = PyArray::arange(py, 0, 4, 1).reshape([2, 2]).unwrap();
448
+ /// assert_eq!(py_array.as_slice().unwrap(), &[0, 1, 2, 3]);
449
+ /// let locals = [("np", numpy::get_array_module(py).unwrap())].into_py_dict(py);
450
+ /// let not_contiguous: &PyArray1<f32> = py
451
+ /// .eval("np.zeros((3, 5))[[0, 2], [3, 4]]", Some(locals), None)
452
+ /// .unwrap()
453
+ /// .downcast_ref()
454
+ /// .unwrap();
455
+ /// assert!(not_contiguous.as_slice().is_err());
405
456
/// # }
406
457
/// ```
407
- pub fn as_slice ( & self ) -> & [ T ] {
408
- self . type_check_assert ( ) ;
409
- unsafe { :: std:: slice:: from_raw_parts ( self . data ( ) , self . len ( ) ) }
458
+ pub fn as_slice ( & self ) -> Result < & [ T ] , ErrorKind > {
459
+ self . type_check ( ) ?;
460
+ if !self . is_contiguous ( ) {
461
+ Err ( ErrorKind :: NotContiguous )
462
+ } else {
463
+ Ok ( unsafe { :: std:: slice:: from_raw_parts ( self . data ( ) , self . len ( ) ) } )
464
+ }
410
465
}
411
466
412
467
/// Get the mmutable view of the internal data of `PyArray`, as slice.
413
- pub fn as_slice_mut ( & self ) -> & mut [ T ] {
414
- self . type_check_assert ( ) ;
415
- unsafe { :: std:: slice:: from_raw_parts_mut ( self . data ( ) , self . len ( ) ) }
468
+ pub fn as_slice_mut ( & self ) -> Result < & mut [ T ] , ErrorKind > {
469
+ self . type_check ( ) ?;
470
+ if !self . is_contiguous ( ) {
471
+ Err ( ErrorKind :: NotContiguous )
472
+ } else {
473
+ Ok ( unsafe { :: std:: slice:: from_raw_parts_mut ( self . data ( ) , self . len ( ) ) } )
474
+ }
416
475
}
417
476
418
477
/// Construct PyArray from `ndarray::ArrayBase`.
@@ -614,10 +673,7 @@ impl<T: TypeNum + Clone, D: Dimension> PyArray<T, D> {
614
673
/// # }
615
674
/// ```
616
675
pub fn to_owned_array ( & self ) -> Array < T , D > {
617
- unsafe {
618
- let vec = self . as_slice ( ) . to_vec ( ) ;
619
- Array :: from_shape_vec_unchecked ( self . ndarray_shape ( ) , vec)
620
- }
676
+ self . as_array ( ) . to_owned ( )
621
677
}
622
678
}
623
679
@@ -631,7 +687,7 @@ impl<T: TypeNum> PyArray<T, Ix1> {
631
687
/// let gil = pyo3::Python::acquire_gil();
632
688
/// let array = [1, 2, 3, 4, 5];
633
689
/// let pyarray = PyArray::from_slice(gil.python(), &array);
634
- /// assert_eq!(pyarray.as_slice(), &[1, 2, 3, 4, 5]);
690
+ /// assert_eq!(pyarray.as_slice().unwrap() , &[1, 2, 3, 4, 5]);
635
691
/// # }
636
692
/// ```
637
693
pub fn from_slice < ' py > ( py : Python < ' py > , slice : & [ T ] ) -> & ' py Self {
@@ -652,7 +708,7 @@ impl<T: TypeNum> PyArray<T, Ix1> {
652
708
/// let gil = pyo3::Python::acquire_gil();
653
709
/// let vec = vec![1, 2, 3, 4, 5];
654
710
/// let pyarray = PyArray::from_vec(gil.python(), vec);
655
- /// assert_eq!(pyarray.as_slice(), &[1, 2, 3, 4, 5]);
711
+ /// assert_eq!(pyarray.as_slice().unwrap() , &[1, 2, 3, 4, 5]);
656
712
/// # }
657
713
/// ```
658
714
pub fn from_vec < ' py > ( py : Python < ' py > , vec : Vec < T > ) -> & ' py Self {
@@ -670,7 +726,7 @@ impl<T: TypeNum> PyArray<T, Ix1> {
670
726
/// let gil = pyo3::Python::acquire_gil();
671
727
/// let vec = vec![1, 2, 3, 4, 5];
672
728
/// let pyarray = PyArray::from_iter(gil.python(), vec.iter().map(|&x| x));
673
- /// assert_eq!(pyarray.as_slice(), &[1, 2, 3, 4, 5]);
729
+ /// assert_eq!(pyarray.as_slice().unwrap() , &[1, 2, 3, 4, 5]);
674
730
/// # }
675
731
/// ```
676
732
pub fn from_exact_iter ( py : Python , iter : impl ExactSizeIterator < Item = T > ) -> & Self {
@@ -697,7 +753,7 @@ impl<T: TypeNum> PyArray<T, Ix1> {
697
753
/// let gil = pyo3::Python::acquire_gil();
698
754
/// let set: BTreeSet<u32> = [4, 3, 2, 5, 1].into_iter().cloned().collect();
699
755
/// let pyarray = PyArray::from_iter(gil.python(), set);
700
- /// assert_eq!(pyarray.as_slice(), &[1, 2, 3, 4, 5]);
756
+ /// assert_eq!(pyarray.as_slice().unwrap() , &[1, 2, 3, 4, 5]);
701
757
/// # }
702
758
/// ```
703
759
pub fn from_iter ( py : Python , iter : impl IntoIterator < Item = T > ) -> & Self {
@@ -872,7 +928,7 @@ impl<T: TypeNum, D> PyArray<T, D> {
872
928
/// let pyarray_f = PyArray::arange(gil.python(), 2.0, 5.0, 1.0);
873
929
/// let pyarray_i = PyArray::<i64, _>::new(gil.python(), [3], false);
874
930
/// assert!(pyarray_f.copy_to(pyarray_i).is_ok());
875
- /// assert_eq!(pyarray_i.as_slice(), &[2, 3, 4]);
931
+ /// assert_eq!(pyarray_i.as_slice().unwrap() , &[2, 3, 4]);
876
932
/// # }
877
933
pub fn copy_to < U : TypeNum > ( & self , other : & PyArray < U , D > ) -> Result < ( ) , ErrorKind > {
878
934
let self_ptr = self . as_array_ptr ( ) ;
@@ -893,7 +949,7 @@ impl<T: TypeNum, D> PyArray<T, D> {
893
949
/// let gil = pyo3::Python::acquire_gil();
894
950
/// let pyarray_f = PyArray::arange(gil.python(), 2.0, 5.0, 1.0);
895
951
/// let pyarray_i = pyarray_f.cast::<i32>(false).unwrap();
896
- /// assert_eq!(pyarray_i.as_slice(), &[2, 3, 4]);
952
+ /// assert_eq!(pyarray_i.as_slice().unwrap() , &[2, 3, 4]);
897
953
/// # }
898
954
pub fn cast < ' py , U : TypeNum > (
899
955
& ' py self ,
@@ -980,9 +1036,9 @@ impl<T: TypeNum + AsPrimitive<f64>> PyArray<T, Ix1> {
980
1036
/// use numpy::PyArray;
981
1037
/// let gil = pyo3::Python::acquire_gil();
982
1038
/// let pyarray = PyArray::arange(gil.python(), 2.0, 4.0, 0.5);
983
- /// assert_eq!(pyarray.as_slice(), &[2.0, 2.5, 3.0, 3.5]);
1039
+ /// assert_eq!(pyarray.as_slice().unwrap() , &[2.0, 2.5, 3.0, 3.5]);
984
1040
/// let pyarray = PyArray::arange(gil.python(), -2, 4, 3);
985
- /// assert_eq!(pyarray.as_slice(), &[-2, 1]);
1041
+ /// assert_eq!(pyarray.as_slice().unwrap() , &[-2, 1]);
986
1042
/// # }
987
1043
pub fn arange < ' py > ( py : Python < ' py > , start : T , stop : T , step : T ) -> & ' py Self {
988
1044
unsafe {
0 commit comments