use std::cmp::Ordering;
use std::fmt::{self, Formatter, Debug};
use std::intrinsics::move_val_init;
use std::iter::{self, order, FromIterator, AdditiveIterator};
use std::mem;
use std::num::ToPrimitive;
use std::option;
use std::slice;
use std::vec;
use iobuf::Iobuf;
use BufSpan::{Empty, One, Many};
use SpanIter::{Opt, Lot};
use SpanMoveIter::{MoveOpt, MoveLot};
pub enum BufSpan<Buf> {
Empty,
One (Buf),
Many(Vec<Buf>),
}
impl<Buf: Iobuf> Clone for BufSpan<Buf> {
#[inline]
fn clone(&self) -> BufSpan<Buf> {
match *self {
Empty => Empty,
One(ref b) => One ((*b).clone()),
Many(ref v) => Many((*v).clone()),
}
}
}
impl<Buf: Iobuf> Debug for BufSpan<Buf> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let mut first_time = true;
for b in self.iter() {
if !first_time {
try!(write!(f, "\n"));
} else {
first_time = false;
}
try!(b.fmt(f));
}
Ok(())
}
}
impl<Buf: Iobuf> FromIterator<Buf> for BufSpan<Buf> {
#[inline]
fn from_iter<I: Iterator<Item=Buf>>(iterator: I) -> BufSpan<Buf> {
let mut ret = BufSpan::new();
ret.extend(iterator);
ret
}
}
impl<Buf: Iobuf> Extend<Buf> for BufSpan<Buf> {
#[inline]
fn extend<I: Iterator<Item=Buf>>(&mut self, mut iterator: I) {
for x in iterator {
self.push(x);
}
}
}
impl<Buf: Iobuf> BufSpan<Buf> {
#[inline]
pub fn new() -> BufSpan<Buf> {
BufSpan::Empty
}
#[inline]
pub fn from_buf(b: Buf) -> BufSpan<Buf> {
if b.is_empty() { Empty } else { One(b) }
}
#[inline]
pub fn is_empty(&self) -> bool {
match *self {
Empty => true,
_ => false,
}
}
#[inline]
fn try_to_extend(&mut self, b: Buf) -> Option<Buf> {
if b.len() == 0 { return None; }
if self.is_empty() {
unsafe {
move_val_init(self, One(b));
return None;
}
}
match *self {
Empty => unreachable!(),
One(ref mut b0) => {
match b0.extend_with(&b) {
Ok (()) => return None,
Err(()) => return Some(b),
}
}
Many(_) => return Some(b),
}
}
#[inline(always)]
pub fn push(&mut self, b: Buf) {
match self.try_to_extend(b) {
None => {},
Some(b) => self.slow_push(b),
}
}
#[cold]
fn slow_push(&mut self, b: Buf) {
match *self {
Empty => unreachable!(),
One(_) => {},
Many(ref mut v) => unsafe {
let last_pos = v.len() - 1;
match v.get_unchecked_mut(last_pos).extend_with(&b) {
Ok (()) => {},
Err(()) => v.push(b),
}
return;
}
}
let this = mem::replace(self, Empty);
unsafe {
move_val_init(self,
match this {
One(b0) => {
let mut v = Vec::with_capacity(2);
v.push(b0);
v.push(b);
Many(v)
},
_ => unreachable!(),
})
}
}
#[inline]
pub fn iter<'a>(&'a self) -> SpanIter<'a, Buf> {
match *self {
Empty => Opt(None.into_iter()),
One (ref b) => Opt(Some(b).into_iter()),
Many(ref v) => Lot(v.as_slice().iter()),
}
}
#[inline]
pub fn into_iter(self) -> SpanMoveIter<Buf> {
match self {
Empty => MoveOpt(None.into_iter()),
One (b) => MoveOpt(Some(b).into_iter()),
Many(v) => MoveLot(v.into_iter()),
}
}
#[inline]
pub fn iter_bytes<'a>(&'a self) -> ByteIter<'a, Buf> {
#[inline]
fn iter_buf_<B: Iobuf>(buf: &B) -> slice::Iter<u8> {
unsafe { buf.as_window_slice().iter() }
}
#[inline]
fn deref_u8_(x: &u8) -> u8 { *x }
let iter_buf : fn(&Buf) -> slice::Iter<u8> = iter_buf_;
let deref_u8 : fn(&u8) -> u8 = deref_u8_;
self.iter().flat_map(iter_buf).map(deref_u8)
}
#[inline]
pub fn byte_equal<Buf2: Iobuf>(&self, other: &BufSpan<Buf2>) -> bool {
self.count_bytes_cmp(other.count_bytes() as usize) == Ordering::Equal
&& self.iter_bytes().zip(other.iter_bytes()).all(|(a, b)| a == b)
}
#[inline]
pub fn byte_equal_slice(&self, other: &[u8]) -> bool {
self.count_bytes_cmp(other.len()) == Ordering::Equal
&& self.iter_bytes().zip(other.iter()).all(|(a, &b)| a == b)
}
#[inline]
pub fn count_bytes(&self) -> u32 {
match *self {
Empty => 0,
One (ref b) => b.len(),
Many(ref v) => v.iter().map(|b| b.len()).sum(),
}
}
#[inline]
pub fn count_bytes_cmp(&self, other: usize) -> Ordering {
let mut other =
match other.to_u32() {
None => return Ordering::Less,
Some(other) => other,
};
match *self {
Empty => 0.cmp(&other),
One (ref b) => b.len().cmp(&other),
Many(ref v) => {
for b in v.iter() {
let len = b.len();
if len > other { return Ordering::Greater }
other -= len;
}
if other == 0 { Ordering::Equal }
else { Ordering::Less }
}
}
}
#[inline]
pub fn append(&mut self, other: BufSpan<Buf>) {
if self.is_empty() {
*self = other;
} else {
self.extend(other.into_iter())
}
}
#[inline]
pub fn starts_with(&self, other: &[u8]) -> bool {
if self.count_bytes_cmp(other.len()) == Ordering::Less { return false }
self.iter_bytes().zip(other.iter()).all(|(a, b)| a == *b)
}
#[inline]
pub fn ends_with(&self, other: &[u8]) -> bool {
if self.count_bytes_cmp(other.len()) == Ordering::Less { return false }
self.iter_bytes().rev().zip(other.iter().rev()).all(|(a, b)| a == *b)
}
}
impl<Buf: Iobuf> PartialEq for BufSpan<Buf> {
fn eq(&self, other: &BufSpan<Buf>) -> bool {
self.byte_equal(other)
}
}
impl<Buf: Iobuf> Eq for BufSpan<Buf> {}
impl<Buf: Iobuf> PartialOrd for BufSpan<Buf> {
fn partial_cmp(&self, other: &BufSpan<Buf>) -> Option<Ordering> {
order::partial_cmp(self.iter_bytes(), other.iter_bytes())
}
}
impl<Buf: Iobuf> Ord for BufSpan<Buf> {
fn cmp(&self, other: &BufSpan<Buf>) -> Ordering {
order::cmp(self.iter_bytes(), other.iter_bytes())
}
}
pub type ByteIter<'a, Buf> =
iter::Map<&'a u8, u8,
iter::FlatMap<&'a Buf, &'a u8,
SpanIter<'a, Buf>,
slice::Iter<'a, u8>,
fn(&Buf) -> slice::Iter<u8>>,
fn(&u8) -> u8>;
pub enum SpanIter<'a, Buf: 'a> {
Opt(option::IntoIter<&'a Buf>),
Lot(slice::Iter<'a, Buf>),
}
impl<'a, Buf: Iobuf> Iterator for SpanIter<'a, Buf> {
type Item = &'a Buf;
#[inline(always)]
fn next(&mut self) -> Option<&'a Buf> {
match *self {
Opt(ref mut iter) => iter.next(),
Lot(ref mut iter) => iter.next(),
}
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
match *self {
Opt(ref iter) => iter.size_hint(),
Lot(ref iter) => iter.size_hint(),
}
}
}
impl<'a, Buf: Iobuf> DoubleEndedIterator for SpanIter<'a, Buf> {
#[inline(always)]
fn next_back(&mut self) -> Option<&'a Buf> {
match *self {
Opt(ref mut iter) => iter.next_back(),
Lot(ref mut iter) => iter.next_back(),
}
}
}
impl<'a, Buf: Iobuf> ExactSizeIterator for SpanIter<'a, Buf> {}
pub enum SpanMoveIter<Buf> {
MoveOpt(option::IntoIter<Buf>),
MoveLot(vec::IntoIter<Buf>),
}
impl<Buf: Iobuf> Iterator for SpanMoveIter<Buf> {
type Item = Buf;
#[inline(always)]
fn next(&mut self) -> Option<Buf> {
match *self {
MoveOpt(ref mut iter) => iter.next(),
MoveLot(ref mut iter) => iter.next(),
}
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
match *self {
MoveOpt(ref iter) => iter.size_hint(),
MoveLot(ref iter) => iter.size_hint(),
}
}
}
impl<Buf: Iobuf> DoubleEndedIterator for SpanMoveIter<Buf> {
#[inline(always)]
fn next_back(&mut self) -> Option<Buf> {
match *self {
MoveOpt(ref mut iter) => iter.next_back(),
MoveLot(ref mut iter) => iter.next_back(),
}
}
}
impl<Buf: Iobuf> ExactSizeIterator for SpanMoveIter<Buf> {}
#[cfg(test)]
mod bench {
use test::{black_box, Bencher};
use super::super::iobuf::Iobuf;
use super::super::impls::{ROIobuf, RWIobuf};
use super::BufSpan;
use std::iter::range;
#[bench]
fn create_roiobuf(b: &mut Bencher) {
b.iter(|| {
let buf = ROIobuf::from_str_copy("hello, world!");
black_box(buf);
})
}
#[bench]
fn test_none_to_one(b: &mut Bencher) {
b.iter(|| {
let mut buf = BufSpan::new();
buf.push(ROIobuf::from_str_copy("hello, world!"));
black_box(buf);
})
}
#[bench]
fn test_none_to_one_with_copy(b: &mut Bencher) {
b.iter(|| {
let mut buf = BufSpan::new();
let to_push = ROIobuf::from_str_copy("hello, world!");
buf.push(to_push);
black_box(buf);
})
}
#[bench]
fn test_none_to_many(b: &mut Bencher) {
b.iter(|| {
let mut buf = BufSpan::new();
buf.push(ROIobuf::from_str_copy("hello "));
buf.push(ROIobuf::from_str_copy("world!"));
black_box(buf);
})
}
#[bench]
fn extend_1k_iobuf_0(b: &mut Bencher) {
b.iter(|| {
let source = RWIobuf::new(1024);
let mut i = 0u32;
for _ in range(0u32, 1000) {
unsafe { source.unsafe_poke_be(i, b'a'); }
i += 1;
}
let mut source = source.read_only();
let mut dst = BufSpan::new();
for _ in range(0u32, 1000) {
unsafe {
let (start, end) = source.unsafe_split_at(1);
dst.push(start);
source = end;
}
}
black_box(dst);
})
}
#[bench]
fn extend_1k_iobuf_1(b: &mut Bencher) {
b.iter(|| {
let source = RWIobuf::new(1024);
let mut i = 0u32;
for _ in range(0u32, 1000) {
unsafe { source.unsafe_poke_be(i, b'a'); }
i += 1;
}
let mut source = source.read_only();
let mut dst = BufSpan::new();
for _ in range(0u32, 1000) {
unsafe {
let start = source.unsafe_split_start_at(1);
dst.push(start);
}
}
black_box(dst);
})
}
#[bench]
fn extend_1k_iobuf_2(b: &mut Bencher) {
let source = RWIobuf::new(1024);
let mut i = 0u32;
for _ in range(0u32, 500) {
unsafe { source.unsafe_poke_be(i, b'a'); }
i += 1;
}
i = 500;
for _ in range(500u32, 1000) {
unsafe { source.unsafe_poke_be(i, b'b'); }
i += 1;
}
b.iter(|| {
let mut source = source.read_only();
let mut dst_a = BufSpan::new();
let mut dst_b = BufSpan::new();
let mut other = BufSpan::new();
for _ in range(0u32, 1000) {
unsafe {
let first_letter = source.unsafe_split_start_at(1);
match first_letter.unsafe_peek_be(0) {
b'a' => dst_a.push(first_letter),
b'b' => dst_b.push(first_letter),
_ => other.push(first_letter),
}
}
}
black_box((dst_a, dst_b, other));
})
}
#[bench]
fn extend_1k_iobuf_3(b: &mut Bencher) {
let source = RWIobuf::new(1024);
let mut i = 0u32;
for _ in range(0u32, 500) {
unsafe { source.unsafe_poke_be(i, b'a'); }
i += 1;
}
let mut i = 500;
for _ in range(500u32, 1000) {
unsafe { source.unsafe_poke_be(i, b'b'); }
i += 1;
}
b.iter(|| {
let mut source = source.read_only();
let mut dst_a = BufSpan::new();
let mut dst_b = BufSpan::new();
let mut other = BufSpan::new();
for _ in range(0u32, 1000) {
unsafe {
let first_letter = source.unsafe_split_start_at(1);
let to_push = match first_letter.unsafe_peek_be(0) {
b'a' => &mut dst_a,
b'b' => &mut dst_b,
_ => &mut other,
};
to_push.push(first_letter);
}
}
black_box((dst_a, dst_b, other));
})
}
#[bench]
fn clone_and_drop(b: &mut Bencher) {
let patient_zero = RWIobuf::new(1024);
b.iter(|| {
let clone = patient_zero.clone();
black_box(clone);
})
}
}