use std::cmp::Ordering;
use std::fmt::{self, Formatter, Debug};
use std::intrinsics::{assume, move_val_init};
use std::iter::{self, order, IntoIterator, FromIterator};
use std::mem;
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};
#[cold]
fn bytes_in_vbuf<Buf: Iobuf>(v: &[Buf]) -> usize {
v.into_iter().map(|b| b.len() as usize).sum()
}
#[test]
fn test_bytes_in_vbuf() {
use impls::ROIobuf;
let bs = [
ROIobuf::from_str("1234"),
ROIobuf::from_str("5678"),
ROIobuf::from_str("9"),
];
assert_eq!(bytes_in_vbuf(&bs), 9);
assert_eq!(bytes_in_vbuf(&bs[1..]), 5);
assert_eq!(bytes_in_vbuf(&bs[2..]), 1);
}
#[cold]
fn count_bytes_cmp_vbuf<Buf: Iobuf>(v: &[Buf], mut other: usize) -> Ordering {
for b in v {
let len = b.len() as usize;
if len > other { return Ordering::Greater }
other -= len;
}
if other == 0 { Ordering::Equal }
else { Ordering::Less }
}
#[test]
fn test_count_bytes_cmp_vbuf() {
use impls::ROIobuf;
let bs = [
ROIobuf::from_str("1234"),
ROIobuf::from_str("5678"),
ROIobuf::from_str("9"),
];
assert_eq!(count_bytes_cmp_vbuf(&bs, 0 ), Ordering::Greater);
assert_eq!(count_bytes_cmp_vbuf(&bs, 10), Ordering::Less);
assert_eq!(count_bytes_cmp_vbuf(&bs, 9 ), Ordering::Equal);
}
#[cold]
fn byte_equal_slice_vbuf<Buf: Iobuf>(v: &[Buf], mut other: &[u8]) -> bool {
if count_bytes_cmp_vbuf(v, other.len()) != Ordering::Equal {
return false;
}
unsafe {
for b in v {
let b_as_slice = b.as_window_slice();
assume(other.len() >= b_as_slice.len());
let (start, new_other) = other.split_at(b_as_slice.len());
if b_as_slice != start { return false; }
other = new_other;
}
}
true
}
#[test]
fn test_byte_equal_slice_vbuf() {
use impls::ROIobuf;
let bs = [
ROIobuf::from_str("1234"),
ROIobuf::from_str("5678"),
ROIobuf::from_str("9"),
];
assert!(byte_equal_slice_vbuf(&bs, b"123456789"));
assert!(!byte_equal_slice_vbuf(&bs, b"123456780"));
assert!(!byte_equal_slice_vbuf(&bs, b"987654321"));
assert!(!byte_equal_slice_vbuf(&bs, b"12345678"));
assert!(!byte_equal_slice_vbuf(&bs, b"23456789"));
}
#[inline]
fn byte_equal_buf_buf<Buf1: Iobuf, Buf2: Iobuf>(x: &Buf1, y: &Buf2) -> bool {
unsafe {
x.as_window_slice() == y.as_window_slice()
}
}
#[inline]
fn byte_equal_buf_vbuf<Buf1: Iobuf, Buf2: Iobuf>(x: &Buf1, y: &[Buf2]) -> bool {
unsafe { byte_equal_slice_vbuf(y, x.as_window_slice()) }
}
#[cold]
fn byte_equal_vbuf_vbuf<Buf1: Iobuf, Buf2: Iobuf>(x: &[Buf1], y: &[Buf2]) -> bool {
if count_bytes_cmp_vbuf(x, bytes_in_vbuf(y)) != Ordering::Equal {
return false;
}
unsafe {
x.into_iter().flat_map(|b| b.as_window_slice().into_iter())
.zip(y.iter().flat_map(|b| b.as_window_slice().into_iter()))
.all(|(x, y)| x == y)
}
}
#[test]
fn test_byte_equal_vbuf_vbuf() {
use impls::ROIobuf;
let b0 = [
ROIobuf::from_str("1234"),
ROIobuf::from_str("5678"),
ROIobuf::from_str("9"),
];
let b1 = [
ROIobuf::from_str("12"),
ROIobuf::from_str("34567"),
ROIobuf::from_str("89"),
];
let b2 = [
ROIobuf::from_str("123456789"),
];
let b3 = [
ROIobuf::from_str("123456780"),
];
let b4 = [
ROIobuf::from_str("11111111111111"),
];
assert!(byte_equal_vbuf_vbuf(&b0, &b1));
assert!(byte_equal_vbuf_vbuf(&b1, &b0));
assert!(byte_equal_vbuf_vbuf(&b0, &b2));
assert!(byte_equal_vbuf_vbuf(&b2, &b0));
assert!(byte_equal_vbuf_vbuf(&b1, &b2));
assert!(byte_equal_vbuf_vbuf(&b2, &b1));
assert!(!byte_equal_vbuf_vbuf(&b0, &b3));
assert!(!byte_equal_vbuf_vbuf(&b1, &b3));
assert!(!byte_equal_vbuf_vbuf(&b2, &b3));
assert!(!byte_equal_vbuf_vbuf(&b0, &b4));
assert!(!byte_equal_vbuf_vbuf(&b1, &b4));
assert!(!byte_equal_vbuf_vbuf(&b2, &b4));
assert!(!byte_equal_vbuf_vbuf(&b3, &b4));
}
#[cold]
fn starts_with_vbuf<Buf: Iobuf>(v: &[Buf], mut other: &[u8]) -> bool {
for b in v {
let b = unsafe { b.as_window_slice() };
match b.len().cmp(&other.len()) {
Ordering::Greater => return b.starts_with(other),
Ordering::Equal => return b == other,
Ordering::Less => {
let (start, new_other) = other.split_at(b.len());
if b != start { return false; }
other = new_other;
}
}
}
other.is_empty()
}
#[test]
fn test_starts_with_vbuf() {
use impls::ROIobuf;
let b0 = [
ROIobuf::from_str("1234"),
ROIobuf::from_str("5678"),
ROIobuf::from_str("9"),
];
assert!(starts_with_vbuf(&b0, b"123456789"));
assert!(starts_with_vbuf(&b0, b"12345678"));
assert!(starts_with_vbuf(&b0, b""));
assert!(starts_with_vbuf(&b0, b"12345"));
assert!(!starts_with_vbuf(&b0, b"123456780"));
assert!(!starts_with_vbuf(&b0, b"1234567890"));
assert!(!starts_with_vbuf(&b0, b"123450789"));
assert!(!starts_with_vbuf(&b0, b"2"));
}
#[cold]
fn ends_with_vbuf<Buf: Iobuf>(v: &[Buf], mut other: &[u8]) -> bool {
for b in v.into_iter().rev() {
let b = unsafe { b.as_window_slice() };
match b.len().cmp(&other.len()) {
Ordering::Greater => return b.ends_with(other),
Ordering::Equal => return b == other,
Ordering::Less => {
let (new_other, end) = other.split_at(other.len() - b.len());
if b != end { return false; }
other = new_other;
}
}
}
other.is_empty()
}
#[test]
fn test_ends_with_vbuf() {
use impls::ROIobuf;
let b0 = [
ROIobuf::from_str("1234"),
ROIobuf::from_str("5678"),
ROIobuf::from_str("9"),
];
assert!(ends_with_vbuf(&b0, b"123456789"));
assert!(ends_with_vbuf(&b0, b"23456789"));
assert!(ends_with_vbuf(&b0, b"3456789"));
assert!(ends_with_vbuf(&b0, b"456789"));
assert!(ends_with_vbuf(&b0, b"56789"));
assert!(ends_with_vbuf(&b0, b"6789"));
assert!(ends_with_vbuf(&b0, b"9"));
assert!(ends_with_vbuf(&b0, b""));
assert!(!ends_with_vbuf(&b0, b"1234567890"));
assert!(!ends_with_vbuf(&b0, b"023456789"));
assert!(!ends_with_vbuf(&b0, b"123456780"));
assert!(!ends_with_vbuf(&b0, b"123450789"));
assert!(!ends_with_vbuf(&b0, b"987654321"));
}
#[inline]
fn cmp_buf_buf<Buf: Iobuf>(bx: &Buf, by: &Buf) -> Ordering {
unsafe {
order::cmp(
bx.as_window_slice().into_iter(),
by.as_window_slice().into_iter())
}
}
#[cold]
fn cmp_buf_vec<Buf: Iobuf>(b: &Buf, v: &[Buf]) -> Ordering {
let mut b = unsafe { b.as_window_slice() };
for x in v {
let x = unsafe { x.as_window_slice() };
if b.len() >= x.len() {
let (start, new_b) = b.split_at(x.len());
match order::cmp(start.into_iter(), x.into_iter()) {
Ordering::Equal => { b = new_b; }
order => return order,
}
} else {
return order::cmp((&b).into_iter(), x.into_iter());
}
}
if b.is_empty() { Ordering::Equal } else { Ordering::Greater }
}
#[test]
fn test_cmp_buf_vec() {
use impls::ROIobuf;
let b0 = [
ROIobuf::from_str("1234"),
ROIobuf::from_str("5678"),
ROIobuf::from_str("9"),
];
assert_eq!(cmp_buf_vec(&ROIobuf::from_str("123456789"), &b0), Ordering::Equal);
assert_eq!(cmp_buf_vec(&ROIobuf::from_str("12345678"), &b0), Ordering::Less);
assert_eq!(cmp_buf_vec(&ROIobuf::from_str("1234567890"), &b0), Ordering::Greater);
assert_eq!(cmp_buf_vec(&ROIobuf::from_str("023456789"), &b0), Ordering::Less);
assert_eq!(cmp_buf_vec(&ROIobuf::from_str("223456789"), &b0), Ordering::Greater);
}
#[cold]
fn cmp_vec_vec<Buf: Iobuf>(vx: &BufSpan<Buf>, vy: &BufSpan<Buf>) -> Ordering {
order::cmp(vx.iter_bytes(), vy.iter_bytes())
}
#[derive(Clone)]
pub enum BufSpan<Buf> {
Empty,
One (Buf),
Many(Vec<Buf>),
}
impl<Buf: Iobuf> Debug for BufSpan<Buf> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let mut first_time = true;
for b in self {
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<T>(iterator: T) -> Self
where T: IntoIterator<Item=Buf> {
let mut ret = BufSpan::new();
ret.extend(iterator);
ret
}
}
impl<Buf: Iobuf> Extend<Buf> for BufSpan<Buf> {
#[inline]
fn extend<I: IntoIterator<Item=Buf>>(&mut self, iterator: I) {
for x in iterator {
self.push(x);
}
}
}
impl<Buf: Iobuf> IntoIterator for BufSpan<Buf> {
type Item = Buf;
type IntoIter = SpanMoveIter<Buf>;
#[inline]
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()),
}
}
}
impl<'a, Buf: Iobuf> IntoIterator for &'a BufSpan<Buf> {
type Item = &'a Buf;
type IntoIter = SpanIter<'a, Buf>;
#[inline]
fn into_iter(self) -> SpanIter<'a, Buf> {
match *self {
Empty => Opt(None.into_iter()),
One (ref b) => Opt(Some(b).into_iter()),
Many(ref v) => Lot(v.into_iter()),
}
}
}
impl<Buf: Iobuf> BufSpan<Buf> {
#[inline]
pub fn new() -> Self {
BufSpan::Empty
}
#[inline]
pub fn from_buf(b: Buf) -> Self {
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_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.into_iter().flat_map(iter_buf).map(deref_u8)
}
#[inline]
pub fn byte_equal<Buf2: Iobuf>(&self, other: &BufSpan<Buf2>) -> bool {
match (self, other) {
(&Empty , &Empty ) => true,
(&Empty , _ ) => false,
( _ , &Empty ) => false,
(&One (ref x), &One (ref y)) => byte_equal_buf_buf(x, y),
(&One (ref x), &Many(ref y)) => byte_equal_buf_vbuf(x, y),
(&Many(ref x), &One (ref y)) => byte_equal_buf_vbuf(y, x),
(&Many(ref x), &Many(ref y)) => byte_equal_vbuf_vbuf(x, y),
}
}
#[inline]
pub fn byte_equal_slice(&self, other: &[u8]) -> bool {
match *self {
Empty => other.is_empty(),
One (ref b) => unsafe { b.as_window_slice() == other },
Many(ref v) => byte_equal_slice_vbuf(v, other),
}
}
#[inline]
pub fn count_bytes(&self) -> usize {
match *self {
Empty => 0,
One (ref b) => b.len() as usize,
Many(ref v) => bytes_in_vbuf(v),
}
}
#[inline]
pub fn count_bytes_cmp(&self, other: usize) -> Ordering {
match *self {
Empty => 0.cmp(&other),
One (ref b) => (b.len() as usize).cmp(&other),
Many(ref v) => count_bytes_cmp_vbuf(v, other),
}
}
#[inline]
pub fn append(&mut self, other: Self) {
if self.is_empty() {
unsafe { move_val_init(self, other) }
} else {
self.extend(other.into_iter())
}
}
#[inline]
pub fn starts_with(&self, other: &[u8]) -> bool {
match *self {
Empty => other.is_empty(),
One(ref b) => unsafe { b.as_window_slice().starts_with(other) },
Many(ref v) => starts_with_vbuf(v, other),
}
}
#[inline]
pub fn ends_with(&self, other: &[u8]) -> bool {
match *self {
Empty => other.is_empty(),
One (ref b) => unsafe { b.as_window_slice().ends_with(other) },
Many(ref v) => ends_with_vbuf(v, other),
}
}
}
impl<Buf: Iobuf> PartialEq for BufSpan<Buf> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.byte_equal(other)
}
}
impl<Buf: Iobuf> Eq for BufSpan<Buf> {}
impl<Buf: Iobuf> PartialOrd for BufSpan<Buf> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<Buf: Iobuf> Ord for BufSpan<Buf> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(&Empty, &Empty) => Ordering::Equal,
(&Empty, _ ) => Ordering::Less,
( _ , &Empty) => Ordering::Greater,
(&One (ref bx), &One (ref by)) => cmp_buf_buf(bx, by),
(&One (ref bx), &Many(ref vy)) => cmp_buf_vec(bx, vy),
(&Many(ref vx), &One (ref by)) => cmp_buf_vec(by, vx).reverse(),
(&Many( _ ), &Many( _ )) => cmp_vec_vec(self, other),
}
}
}
pub type ByteIter<'a, Buf> =
iter::Map<
iter::FlatMap<
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;
#[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 32..1000 {
unsafe { source.unsafe_poke_be(i, b'a'); }
i += 1;
}
let mut source = source.read_only();
let mut dst = BufSpan::new();
for _ in 0..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 0..1000 {
unsafe { source.unsafe_poke_be(i, b'a'); }
i += 1;
}
let mut source = source.read_only();
let mut dst = BufSpan::new();
for _ in 0..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 0..500 {
unsafe { source.unsafe_poke_be(i, b'a'); }
i += 1;
}
i = 500;
for _ in 500..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 0..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 0..500 {
unsafe { source.unsafe_poke_be(i, b'a'); }
i += 1;
}
let mut i = 500;
for _ in 500..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 0..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);
})
}
}