use std::slice;
use imp_prelude::*;
use dimension::{self, stride_offset};
use error::ShapeError;
use NdIndex;
use arraytraits::array_out_of_bounds;
use StrideShape;
use {
ElementsBase,
ElementsBaseMut,
Iter,
IterMut,
Baseiter,
};
use iter::{self, AxisIter, AxisIterMut};
fn is_aligned<T>(ptr: *const T) -> bool {
(ptr as usize) % ::std::mem::align_of::<T>() == 0
}
impl<'a, A, D> ArrayView<'a, A, D>
where D: Dimension,
{
pub fn from_shape<Sh>(shape: Sh, xs: &'a [A])
-> Result<Self, ShapeError>
where Sh: Into<StrideShape<D>>,
{
Self::from_shape_impl(shape.into(), xs)
}
fn from_shape_impl(shape: StrideShape<D>, xs: &'a [A]) -> Result<Self, ShapeError> {
let dim = shape.dim;
let strides = shape.strides;
if shape.custom {
dimension::can_index_slice(xs, &dim, &strides)?;
} else {
dimension::can_index_slice_not_custom::<A, _>(xs, &dim)?;
}
unsafe { Ok(Self::new_(xs.as_ptr(), dim, strides)) }
}
pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *const A) -> Self
where Sh: Into<StrideShape<D>>
{
let shape = shape.into();
let dim = shape.dim;
let strides = shape.strides;
if cfg!(debug_assertions) {
assert!(!ptr.is_null(), "The pointer must be non-null.");
assert!(is_aligned(ptr), "The pointer must be aligned.");
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
}
ArrayView::new_(ptr, dim, strides)
}
pub fn reborrow<'b>(self) -> ArrayView<'b, A, D>
where 'a: 'b
{
unsafe {
ArrayView::new_(self.as_ptr(), self.dim, self.strides)
}
}
pub fn split_at(self, axis: Axis, index: Ix)
-> (Self, Self)
{
assert!(index <= self.len_of(axis));
let left_ptr = self.ptr;
let right_ptr = if index == self.len_of(axis) {
self.ptr
} else {
let offset = stride_offset(index, self.strides.axis(axis));
unsafe {
self.ptr.offset(offset)
}
};
let mut dim_left = self.dim.clone();
dim_left.set_axis(axis, index);
let left = unsafe {
Self::new_(left_ptr, dim_left, self.strides.clone())
};
let mut dim_right = self.dim;
let right_len = dim_right.axis(axis) - index;
dim_right.set_axis(axis, right_len);
let right = unsafe {
Self::new_(right_ptr, dim_right, self.strides)
};
(left, right)
}
pub fn into_slice(&self) -> Option<&'a [A]> {
if self.is_standard_layout() {
unsafe {
Some(slice::from_raw_parts(self.ptr, self.len()))
}
} else {
None
}
}
}
pub trait IndexLonger<I> {
type Output;
fn index(self, index: I) -> Self::Output;
fn get(self, index: I) -> Option<Self::Output>;
unsafe fn uget(self, index: I) -> Self::Output;
}
impl<'a, 'b, I, A, D> IndexLonger<I> for &'b ArrayView<'a, A, D>
where I: NdIndex<D>,
D: Dimension,
{
type Output = &'a A;
fn index(self, index: I) -> &'a A
{
debug_bounds_check!(self, index);
unsafe {
&*self.get_ptr(index).unwrap_or_else(|| array_out_of_bounds())
}
}
fn get(self, index: I) -> Option<&'a A>
{
unsafe {
self.get_ptr(index).map(|ptr| &*ptr)
}
}
unsafe fn uget(self, index: I) -> &'a A
{
debug_bounds_check!(self, index);
&*self.as_ptr().offset(index.index_unchecked(&self.strides))
}
}
impl<'a, A, D> ArrayViewMut<'a, A, D>
where D: Dimension,
{
pub fn from_shape<Sh>(shape: Sh, xs: &'a mut [A])
-> Result<Self, ShapeError>
where Sh: Into<StrideShape<D>>,
{
Self::from_shape_impl(shape.into(), xs)
}
fn from_shape_impl(shape: StrideShape<D>, xs: &'a mut [A]) -> Result<Self, ShapeError> {
let dim = shape.dim;
let strides = shape.strides;
if shape.custom {
dimension::can_index_slice(xs, &dim, &strides)?;
} else {
dimension::can_index_slice_not_custom::<A, _>(xs, &dim)?;
}
unsafe { Ok(Self::new_(xs.as_mut_ptr(), dim, strides)) }
}
pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *mut A) -> Self
where Sh: Into<StrideShape<D>>
{
let shape = shape.into();
let dim = shape.dim;
let strides = shape.strides;
if cfg!(debug_assertions) {
assert!(!ptr.is_null(), "The pointer must be non-null.");
assert!(is_aligned(ptr), "The pointer must be aligned.");
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
}
ArrayViewMut::new_(ptr, dim, strides)
}
pub fn reborrow<'b>(mut self) -> ArrayViewMut<'b, A, D>
where 'a: 'b
{
unsafe {
ArrayViewMut::new_(self.as_mut_ptr(), self.dim, self.strides)
}
}
pub fn split_at(self, axis: Axis, index: Ix)
-> (Self, Self)
{
assert!(index <= self.len_of(axis));
let left_ptr = self.ptr;
let right_ptr = if index == self.len_of(axis) {
self.ptr
} else {
let offset = stride_offset(index, self.strides.axis(axis));
unsafe {
self.ptr.offset(offset)
}
};
let mut dim_left = self.dim.clone();
dim_left.set_axis(axis, index);
let left = unsafe {
Self::new_(left_ptr, dim_left, self.strides.clone())
};
let mut dim_right = self.dim;
let right_len = dim_right.axis(axis) - index;
dim_right.set_axis(axis, right_len);
let right = unsafe {
Self::new_(right_ptr, dim_right, self.strides)
};
(left, right)
}
pub fn into_slice(self) -> Option<&'a mut [A]> {
self.into_slice_().ok()
}
}
impl<'a, I, A, D> IndexLonger<I> for ArrayViewMut<'a, A, D>
where I: NdIndex<D>,
D: Dimension,
{
type Output = &'a mut A;
fn index(mut self, index: I) -> &'a mut A {
debug_bounds_check!(self, index);
unsafe {
match self.get_ptr_mut(index) {
Some(ptr) => &mut *ptr,
None => array_out_of_bounds(),
}
}
}
fn get(mut self, index: I) -> Option<&'a mut A> {
debug_bounds_check!(self, index);
unsafe {
match self.get_ptr_mut(index) {
Some(ptr) => Some(&mut *ptr),
None => None,
}
}
}
unsafe fn uget(mut self, index: I) -> &'a mut A {
debug_bounds_check!(self, index);
&mut *self.as_mut_ptr().offset(index.index_unchecked(&self.strides))
}
}
impl<'a, A, D> ArrayView<'a, A, D>
where D: Dimension,
{
#[inline(always)]
pub(crate) unsafe fn new_(ptr: *const A, dim: D, strides: D) -> Self {
ArrayView {
data: ViewRepr::new(),
ptr: ptr as *mut A,
dim: dim,
strides: strides,
}
}
#[inline]
pub(crate) fn into_base_iter(self) -> Baseiter<A, D> {
unsafe {
Baseiter::new(self.ptr, self.dim, self.strides)
}
}
#[inline]
pub(crate) fn into_elements_base(self) -> ElementsBase<'a, A, D> {
ElementsBase::new(self)
}
pub(crate) fn into_iter_(self) -> Iter<'a, A, D> {
Iter::new(self)
}
#[doc(hidden)] #[deprecated(note="This method will be replaced.")]
pub fn into_outer_iter(self) -> iter::AxisIter<'a, A, D::Smaller>
where D: RemoveAxis,
{
AxisIter::new(self, Axis(0))
}
}
impl<'a, A, D> ArrayViewMut<'a, A, D>
where D: Dimension,
{
#[inline(always)]
pub(crate) unsafe fn new_(ptr: *mut A, dim: D, strides: D) -> Self {
if cfg!(debug_assertions) {
assert!(!ptr.is_null(), "The pointer must be non-null.");
assert!(is_aligned(ptr), "The pointer must be aligned.");
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
}
ArrayViewMut {
data: ViewRepr::new(),
ptr: ptr,
dim: dim,
strides: strides,
}
}
pub(crate) fn into_view(self) -> ArrayView<'a, A, D> {
unsafe {
ArrayView::new_(self.ptr, self.dim, self.strides)
}
}
#[inline]
pub(crate) fn into_base_iter(self) -> Baseiter<A, D> {
unsafe {
Baseiter::new(self.ptr, self.dim, self.strides)
}
}
#[inline]
pub(crate) fn into_elements_base(self) -> ElementsBaseMut<'a, A, D> {
ElementsBaseMut::new(self)
}
pub(crate) fn into_slice_(self) -> Result<&'a mut [A], Self> {
if self.is_standard_layout() {
unsafe {
Ok(slice::from_raw_parts_mut(self.ptr, self.len()))
}
} else {
Err(self)
}
}
pub(crate) fn into_iter_(self) -> IterMut<'a, A, D> {
IterMut::new(self)
}
#[doc(hidden)] #[deprecated(note="This method will be replaced.")]
pub fn into_outer_iter(self) -> iter::AxisIterMut<'a, A, D::Smaller>
where D: RemoveAxis,
{
AxisIterMut::new(self, Axis(0))
}
}