use std::fmt;
use std::marker;
use std::mem;
use std::ops::{Index, IndexMut};
pub struct Stride<'a, A: 'a> {
begin: *const A,
offset: isize,
end: isize,
stride: isize,
life: marker::PhantomData<&'a A>,
}
impl<'a, A> Copy for Stride<'a, A> {}
unsafe impl<'a, A> Send for Stride<'a, A> where A: Sync {}
unsafe impl<'a, A> Sync for Stride<'a, A> where A: Sync {}
pub struct StrideMut<'a, A: 'a> {
begin: *mut A,
offset: isize,
end: isize,
stride: isize,
life: marker::PhantomData<&'a mut A>,
}
unsafe impl<'a, A> Send for StrideMut<'a, A> where A: Send {}
unsafe impl<'a, A> Sync for StrideMut<'a, A> where A: Sync {}
impl<'a, A> Stride<'a, A> {
pub unsafe fn from_ptr_len(begin: *const A, nelem: usize, stride: isize) -> Stride<'a, A>
{
Stride {
begin: begin,
offset: 0,
end: stride * nelem as isize,
stride: stride,
life: marker::PhantomData,
}
}
}
impl<'a, A> StrideMut<'a, A>
{
pub unsafe fn from_ptr_len(begin: *mut A, nelem: usize, stride: isize) -> StrideMut<'a, A>
{
StrideMut {
begin: begin,
offset: 0,
end: stride * nelem as isize,
stride: stride,
life: marker::PhantomData,
}
}
}
fn div_rem(x: usize, d: usize) -> (usize, usize) {
(x / d, x % d)
}
macro_rules! stride_impl {
(struct $name:ident -> $slice:ty, $getptr:ident, $ptr:ty, $elem:ty) => {
impl<'a, A> $name<'a, A>
{
#[inline]
pub fn from_slice(xs: $slice, step: isize) -> $name<'a, A>
{
assert!(mem::size_of::<A>() != 0);
let ustep = if step < 0 { -step } else { step } as usize;
let nelem = if ustep <= 1 {
xs.len()
} else {
let (d, r) = div_rem(xs.len(), ustep);
d + if r > 0 { 1 } else { 0 }
};
let mut begin = xs. $getptr ();
unsafe {
if step > 0 {
$name::from_ptr_len(begin, nelem, step)
} else {
if nelem != 0 {
begin = begin.offset(xs.len() as isize - 1)
}
$name::from_ptr_len(begin, nelem, step)
}
}
}
#[inline]
pub fn from_stride(mut it: $name<'a, A>, mut step: isize) -> $name<'a, A>
{
assert!(step != 0);
if step < 0 {
it.swap_ends();
step = -step;
}
let len = (it.end - it.offset) / it.stride;
let newstride = it.stride * step;
let (d, r) = div_rem(len as usize, step as usize);
let len = d + if r > 0 { 1 } else { 0 };
unsafe {
$name::from_ptr_len(it.begin, len, newstride)
}
}
#[inline]
pub fn swap_ends(&mut self) {
let len = (self.end - self.offset) / self.stride;
if len > 0 {
unsafe {
let endptr = self.begin.offset((len - 1) * self.stride);
*self = $name::from_ptr_len(endptr, len as usize, -self.stride);
}
}
}
#[inline]
pub fn len(&self) -> usize {
((self.end - self.offset) / self.stride) as usize
}
#[inline]
pub fn get<'b>(&'b self, i: usize) -> Option<&'b A> {
if i >= self.len() {
None
} else {
unsafe {
let ptr = self.begin.offset(self.offset + self.stride * (i as isize));
Some(mem::transmute(ptr))
}
}
}
}
impl<'a, A> Iterator for $name<'a, A>
{
type Item = $elem;
#[inline]
fn next(&mut self) -> Option<$elem>
{
if self.offset == self.end {
None
} else {
unsafe {
let elt: $elem =
mem::transmute(self.begin.offset(self.offset));
self.offset += self.stride;
Some(elt)
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl<'a, A> DoubleEndedIterator for $name<'a, A>
{
#[inline]
fn next_back(&mut self) -> Option<$elem>
{
if self.offset == self.end {
None
} else {
unsafe {
self.end -= self.stride;
let elt = mem::transmute(self.begin.offset(self.end));
Some(elt)
}
}
}
}
impl<'a, A> ExactSizeIterator for $name<'a, A> { }
impl<'a, A> Index<usize> for $name<'a, A>
{
type Output = A;
fn index<'b>(&'b self, i: usize) -> &'b A
{
assert!(i < self.len());
unsafe {
let ptr = self.begin.offset(self.offset + self.stride * (i as isize));
mem::transmute(ptr)
}
}
}
impl<'a, A> fmt::Debug for $name<'a, A>
where A: fmt::Debug
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
try!(write!(f, "["));
for i in 0..self.len() {
if i != 0 {
try!(write!(f, ", "));
}
try!(write!(f, "{:?}", (*self)[i]));
}
write!(f, "]")
}
}
}
}
stride_impl!{struct Stride -> &'a [A], as_ptr, *const A, &'a A}
stride_impl!{struct StrideMut -> &'a mut [A], as_mut_ptr, *mut A, &'a mut A}
impl<'a, A> Clone for Stride<'a, A> {
fn clone(&self) -> Stride<'a, A> {
*self
}
}
impl<'a, A> StrideMut<'a, A> {
pub fn get_mut<'b>(&'b mut self, i: usize) -> Option<&'b mut A> {
if i >= self.len() {
None
} else {
unsafe {
let ptr = self.begin.offset(self.offset + self.stride * (i as isize));
Some(&mut *ptr)
}
}
}
}
impl<'a, A> IndexMut<usize> for StrideMut<'a, A> {
fn index_mut<'b>(&'b mut self, i: usize) -> &'b mut A {
assert!(i < self.len());
unsafe {
let ptr = self.begin.offset(self.offset + self.stride * (i as isize));
&mut *ptr
}
}
}