From 22fe20d6795183be0ce8e7ec0898b41a2f4cfcc0 Mon Sep 17 00:00:00 2001 From: Colin Sherratt Date: Sun, 19 Oct 2014 16:19:07 -0400 Subject: [PATCH 1/7] The current ringbuf benchmarks can be unpredictable since there performance depends on how big the ring buffer grows during the test. This is determined not by the test, but by how many iterations the Bencher chooses to run. This change should make the benchmarks more reliable. --- src/libcollections/ringbuf.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index e32e8145d172e..805ca9ab12364 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -642,27 +642,33 @@ mod tests { } #[bench] - fn bench_push_back(b: &mut test::Bencher) { - let mut deq = RingBuf::new(); + fn bench_push_back_100(b: &mut test::Bencher) { + let mut deq = RingBuf::with_capacity(100); b.iter(|| { - deq.push(0i); + for i in range(0i, 100) { + deq.push(i); + } + deq.clear(); }) } #[bench] - fn bench_push_front(b: &mut test::Bencher) { - let mut deq = RingBuf::new(); + fn bench_push_front_100(b: &mut test::Bencher) { + let mut deq = RingBuf::with_capacity(100); b.iter(|| { - deq.push_front(0i); + for i in range(0i, 100) { + deq.push_front(i); + } + deq.clear(); }) } #[bench] - fn bench_grow(b: &mut test::Bencher) { - let mut deq = RingBuf::new(); + fn bench_grow_1025(b: &mut test::Bencher) { b.iter(|| { - for _ in range(0i, 65) { - deq.push_front(1i); + let mut deq = RingBuf::new(); + for i in range(0i, 1025) { + deq.push_front(i); } }) } From b7c85fca0354d4b920dd0b7496c68e3d0485a2b1 Mon Sep 17 00:00:00 2001 From: Colin Sherratt Date: Sun, 19 Oct 2014 16:11:38 -0400 Subject: [PATCH 2/7] Added drop tests to ringbuf --- src/libcollections/ringbuf.rs | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index 805ca9ab12364..b6d3367d22d60 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -1012,4 +1012,70 @@ mod tests { .collect(); assert!(format!("{}", ringbuf).as_slice() == "[just, one, test, more]"); } + + #[test] + fn test_drop() { + static mut drops: uint = 0; + struct Elem; + impl Drop for Elem { + fn drop(&mut self) { + unsafe { drops += 1; } + } + } + + let mut ring = RingBuf::new(); + ring.push(Elem); + ring.push_front(Elem); + ring.push(Elem); + ring.push_front(Elem); + drop(ring); + + assert_eq!(unsafe {drops}, 4); + } + + #[test] + fn test_drop_with_pop() { + static mut drops: uint = 0; + struct Elem; + impl Drop for Elem { + fn drop(&mut self) { + unsafe { drops += 1; } + } + } + + let mut ring = RingBuf::new(); + ring.push(Elem); + ring.push_front(Elem); + ring.push(Elem); + ring.push_front(Elem); + + drop(ring.pop()); + drop(ring.pop_front()); + assert_eq!(unsafe {drops}, 2); + + drop(ring); + assert_eq!(unsafe {drops}, 4); + } + + #[test] + fn test_drop_clear() { + static mut drops: uint = 0; + struct Elem; + impl Drop for Elem { + fn drop(&mut self) { + unsafe { drops += 1; } + } + } + + let mut ring = RingBuf::new(); + ring.push(Elem); + ring.push_front(Elem); + ring.push(Elem); + ring.push_front(Elem); + ring.clear(); + assert_eq!(unsafe {drops}, 4); + + drop(ring); + assert_eq!(unsafe {drops}, 4); + } } From e26f199a57e36b0aaf0c79ae3d466b3b124c2f01 Mon Sep 17 00:00:00 2001 From: Colin Sherratt Date: Sun, 19 Oct 2014 16:28:47 -0400 Subject: [PATCH 3/7] added pop and pop_front ringbuf benchmark --- src/libcollections/ringbuf.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index b6d3367d22d60..a933138ca3923 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -663,6 +663,38 @@ mod tests { }) } + #[bench] + fn bench_pop_100(b: &mut test::Bencher) { + let mut deq = RingBuf::with_capacity(100); + + // this will make sure the bencher wraps + for i in range(0i, 25) { deq.push(i); } + while None != deq.pop_front() {} + + b.iter(|| { + for i in range(0i, 100) { + deq.push(i); + } + while None != deq.pop() {} + }) + } + + #[bench] + fn bench_pop_front_100(b: &mut test::Bencher) { + let mut deq = RingBuf::with_capacity(100); + + // this will make sure the bencher wraps + for i in range(0i, 25) { deq.push(i); } + while None != deq.pop_front() {} + + b.iter(|| { + for i in range(0i, 100) { + deq.push(i); + } + while None != deq.pop_front() {} + }) + } + #[bench] fn bench_grow_1025(b: &mut test::Bencher) { b.iter(|| { From 6d561452098650a0b5ac527bbf410a7d4d4a3995 Mon Sep 17 00:00:00 2001 From: Colin Sherratt Date: Sun, 19 Oct 2014 19:10:09 -0400 Subject: [PATCH 4/7] added iter benchmarks for ringbuf --- src/libcollections/ringbuf.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index a933138ca3923..e6dddb1e982c5 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -705,6 +705,31 @@ mod tests { }) } + #[bench] + fn bench_iter_1000(b: &mut test::Bencher) { + let ring: RingBuf = range(0i, 1000).collect(); + + b.iter(|| { + let mut sum = 0; + for &i in ring.iter() { + sum += i; + } + sum + }) + } + + #[bench] + fn bench_mut_iter_1000(b: &mut test::Bencher) { + let mut ring: RingBuf = range(0i, 1000).collect(); + + b.iter(|| { + for i in ring.iter_mut() { + *i += 1; + } + }) + } + + #[deriving(Clone, PartialEq, Show)] enum Taggy { One(int), From 88bcc8529045fdfdf3a11386f90428335c110bf5 Mon Sep 17 00:00:00 2001 From: Colin Sherratt Date: Sun, 19 Oct 2014 16:57:47 -0400 Subject: [PATCH 5/7] -Use head/tail rather then nelts and lo. -Require the buffer to be a power of 2, and use that knowledge to allow for cheap index calculations. -Remove the use of a Vec> for storage and move to a unmanaged buffer. --- src/libcollections/ringbuf.rs | 400 +++++++++++++++++++--------------- 1 file changed, 228 insertions(+), 172 deletions(-) diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index e6dddb1e982c5..5e3019d4bceaf 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -15,101 +15,138 @@ use core::prelude::*; -use core::cmp; use core::default::Default; use core::fmt; use core::iter; use core::slice; +use core::raw::Slice as RawSlice; +use core::ptr; +use core::kinds::marker; +use core::mem; +use core::num; + use std::hash::{Writer, Hash}; +use std::cmp; + +use alloc::heap::{allocate, reallocate, deallocate}; use {Deque, Mutable, MutableSeq}; -use vec::Vec; static INITIAL_CAPACITY: uint = 8u; // 2^3 static MINIMUM_CAPACITY: uint = 2u; /// `RingBuf` is a circular buffer that implements `Deque`. -#[deriving(Clone)] pub struct RingBuf { - nelts: uint, - lo: uint, - elts: Vec> + head: uint, + tail: uint, + len: uint, + ptr: *mut T +} + +impl Clone for RingBuf { + fn clone(&self) -> RingBuf { + self.iter().map(|t| t.clone()).collect() + } +} + +#[unsafe_destructor] +impl Drop for RingBuf { + fn drop(&mut self) { + while self.len() > 0 { + drop(self.pop_front()) + } + unsafe { + deallocate(self.ptr as *mut u8, + self.len * mem::size_of::(), + mem::min_align_of::()) + } + } } impl Collection for RingBuf { /// Returns the number of elements in the `RingBuf`. - fn len(&self) -> uint { self.nelts } + fn len(&self) -> uint { + (self.tail - self.head) & (self.len - 1) + } } impl Mutable for RingBuf { /// Clears the `RingBuf`, removing all values. fn clear(&mut self) { - for x in self.elts.iter_mut() { *x = None } - self.nelts = 0; - self.lo = 0; + while self.head != self.tail { + let _ = self.pop_front(); + } + self.head = 0; + self.tail = 0; } } impl Deque for RingBuf { /// Returns a reference to the first element in the `RingBuf`. fn front<'a>(&'a self) -> Option<&'a T> { - if self.nelts > 0 { Some(&self[0]) } else { None } + if self.len() > 0 { Some(&self[0]) } else { None } } /// Returns a mutable reference to the first element in the `RingBuf`. fn front_mut<'a>(&'a mut self) -> Option<&'a mut T> { - if self.nelts > 0 { Some(self.get_mut(0)) } else { None } + if self.len() > 0 { Some(self.get_mut(0)) } else { None } } /// Returns a reference to the last element in the `RingBuf`. fn back<'a>(&'a self) -> Option<&'a T> { - if self.nelts > 0 { Some(&self[self.nelts - 1]) } else { None } + if self.len() > 0 { Some(&self[self.len() - 1]) } else { None } } /// Returns a mutable reference to the last element in the `RingBuf`. fn back_mut<'a>(&'a mut self) -> Option<&'a mut T> { - let nelts = self.nelts; - if nelts > 0 { Some(self.get_mut(nelts - 1)) } else { None } + if self.len() > 0 { + let last = self.len() - 1; + Some(self.get_mut(last)) + } else { None } } /// Removes and returns the first element in the `RingBuf`, or `None` if it /// is empty. fn pop_front(&mut self) -> Option { - let result = self.elts.get_mut(self.lo).take(); - if result.is_some() { - self.lo = (self.lo + 1u) % self.elts.len(); - self.nelts -= 1u; + if self.head == self.tail { + None + } else { + let head = self.head; + self.head = self.wrap_ptr(self.head + 1); + unsafe { Some(self.buffer_read(head)) } } - result } /// Prepends an element to the `RingBuf`. fn push_front(&mut self, t: T) { - if self.nelts == self.elts.len() { - grow(self.nelts, &mut self.lo, &mut self.elts); + if self.wrap_ptr(self.head - 1) == self.tail { + let len = self.len * 2; + self.grow(len); } - if self.lo == 0u { - self.lo = self.elts.len() - 1u; - } else { self.lo -= 1u; } - *self.elts.get_mut(self.lo) = Some(t); - self.nelts += 1u; + + self.head = self.wrap_ptr(self.head - 1); + let head = self.head; + unsafe { self.buffer_write(head, t); } } } impl MutableSeq for RingBuf { fn push(&mut self, t: T) { - if self.nelts == self.elts.len() { - grow(self.nelts, &mut self.lo, &mut self.elts); + if self.wrap_ptr(self.tail + 1) == self.head { + let len = self.len * 2; + self.grow(len); } - let hi = self.raw_index(self.nelts); - *self.elts.get_mut(hi) = Some(t); - self.nelts += 1u; + + let tail = self.tail; + self.tail = self.wrap_ptr(self.tail + 1); + unsafe { self.buffer_write(tail, t) } } + fn pop(&mut self) -> Option { - if self.nelts > 0 { - self.nelts -= 1; - let hi = self.raw_index(self.nelts); - self.elts.get_mut(hi).take() + if self.len() > 0 { + self.tail = self.wrap_ptr(self.tail - 1); + let tail = self.tail; + unsafe { Some(self.buffer_read(tail)) } } else { None } @@ -129,8 +166,88 @@ impl RingBuf { /// Creates an empty `RingBuf` with space for at least `n` elements. pub fn with_capacity(n: uint) -> RingBuf { - RingBuf{nelts: 0, lo: 0, - elts: Vec::from_fn(cmp::max(MINIMUM_CAPACITY, n), |_| None)} + let count = num::next_power_of_two(cmp::max(n, MINIMUM_CAPACITY)); + let size = count.checked_mul(&mem::size_of::()) + .expect("capacity overflow"); + + RingBuf { + head: 0, + tail: 0, + len: count, + ptr: unsafe { allocate(size, mem::min_align_of::()) as *mut T } + } + } + + /// Turn ptr into a slice + #[inline] + fn buffer_as_slice(&self) -> &[T] { + unsafe { mem::transmute(RawSlice { data: self.ptr as *const T, len: self.len }) } + } + + /// Turn ptr into a mutable slice + #[inline] + fn buffer_as_slice_mut(&mut self) -> &mut [T] { + unsafe { mem::transmute(RawSlice { data: self.ptr as *const T, len: self.len }) } + } + + /// move an element from the buffer + #[inline] + unsafe fn buffer_read(&mut self, off: uint) -> T { + ptr::read(self.ptr.offset(off as int) as *const T) + } + + /// write an element without dropping unused slot + #[inline] + unsafe fn buffer_write(&mut self, off: uint, t: T) { + let pos = (self.ptr as *const T).offset(off as int) as *mut T; + ptr::write(&mut *pos, t); + } + + /// caclulate index from offset + fn wrap_ptr(&self, idx: uint) -> uint { idx & (self.len - 1) } + + /// Grow the buffer to a new length + #[inline] + fn grow(&mut self, newlen: uint) { + assert!(newlen > self.len); + let old = self.len * mem::size_of::(); + let new = newlen.checked_mul(&mem::size_of::()) + .expect("capacity overflow"); + unsafe { + self.ptr = reallocate(self.ptr as *mut u8, + old, + new, + mem::min_align_of::()) as *mut T; + } + + // Move the shortest half into the newly reserved area. + // W R + // [o o . o o o o o ] + // R W + // A [. . . o o o o o o o . . . . . . ] + // W R + // [o o o o o . o o ] + // W R + // B [o o o o o . . . . . . . . . o o ] + + let oldlen = self.len; + self.len = newlen; + + if self.head == 0 { + return + } + + if self.tail < oldlen - self.head { // A + for i in range(0u, self.tail) { + self.buffer_as_slice_mut().swap(i, oldlen + i); + } + self.tail += oldlen; + } else { // B + for i in range(self.head, oldlen) { + self.buffer_as_slice_mut().swap(i, newlen - oldlen + i); + } + self.head = newlen - oldlen + self.head; + } } /// Retrieves an element in the `RingBuf` by index. @@ -151,10 +268,7 @@ impl RingBuf { /// ``` pub fn get_mut<'a>(&'a mut self, i: uint) -> &'a mut T { let idx = self.raw_index(i); - match *self.elts.get_mut(idx) { - None => fail!(), - Some(ref mut v) => v - } + &mut self.buffer_as_slice_mut()[idx] } /// Swaps elements at indices `i` and `j`. @@ -181,20 +295,22 @@ impl RingBuf { assert!(j < self.len()); let ri = self.raw_index(i); let rj = self.raw_index(j); - self.elts.as_mut_slice().swap(ri, rj); + self.buffer_as_slice_mut().swap(ri, rj); } /// Returns the index in the underlying `Vec` for a given logical element /// index. fn raw_index(&self, idx: uint) -> uint { - raw_index(self.lo, self.elts.len(), idx) + assert!(self.len() > idx); + wrap_index(self.head + idx, self.len) } /// Reserves capacity for exactly `n` elements in the given `RingBuf`, /// doing nothing if `self`'s capacity is already equal to or greater /// than the requested capacity. + #[deprecated = "use reserve, Ringbuf can no longer be an exact size."] pub fn reserve_exact(&mut self, n: uint) { - self.elts.reserve_exact(n); + self.reserve(n); } /// Reserves capacity for at least `n` elements in the given `RingBuf`, @@ -204,7 +320,8 @@ impl RingBuf { /// Do nothing if `self`'s capacity is already equal to or greater /// than the requested capacity. pub fn reserve(&mut self, n: uint) { - self.elts.reserve(n); + let count = num::next_power_of_two(n); + self.grow(count); } /// Returns a front-to-back iterator. @@ -222,7 +339,11 @@ impl RingBuf { /// assert_eq!(buf.iter().collect::>().as_slice(), b); /// ``` pub fn iter<'a>(&'a self) -> Items<'a, T> { - Items{index: 0, rindex: self.nelts, lo: self.lo, elts: self.elts.as_slice()} + Items { + head: self.head, + tail: self.tail, + ring: self.buffer_as_slice() + } } /// Returns a front-to-back iterator which returns mutable references. @@ -243,57 +364,52 @@ impl RingBuf { /// assert_eq!(buf.iter_mut().collect::>()[], b); /// ``` pub fn iter_mut<'a>(&'a mut self) -> MutItems<'a, T> { - let start_index = raw_index(self.lo, self.elts.len(), 0); - let end_index = raw_index(self.lo, self.elts.len(), self.nelts); - - // Divide up the array - if end_index <= start_index { - // Items to iterate goes from: - // start_index to self.elts.len() - // and then - // 0 to end_index - let (temp, remaining1) = self.elts.split_at_mut(start_index); - let (remaining2, _) = temp.split_at_mut(end_index); - MutItems { - remaining1: remaining1.iter_mut(), - remaining2: remaining2.iter_mut(), - nelts: self.nelts, - } - } else { - // Items to iterate goes from start_index to end_index: - let (empty, elts) = self.elts.split_at_mut(0); - let remaining1 = elts[mut start_index..end_index]; - MutItems { - remaining1: remaining1.iter_mut(), - remaining2: empty.iter_mut(), - nelts: self.nelts, - } + MutItems { + head: self.head, + tail: self.tail, + len: self.len, + ptr: self.ptr, + marker: marker::ContravariantLifetime::<'a>, + marker2: marker::NoCopy } } } +/// Returns the index in the underlying `Vec` for a given logical element index. +#[inline] +fn wrap_index(index: uint, size: uint) -> uint { + // size is always a power ot 2 + index & (size - 1) +} + +/// Calculate the number of elements left to be read in the buffer +#[inline] +fn count(head: uint, tail: uint, size: uint) -> uint { + // size is always a power ot 2 + (tail - head) & (size - 1) +} + /// `RingBuf` iterator. pub struct Items<'a, T:'a> { - lo: uint, - index: uint, - rindex: uint, - elts: &'a [Option], + ring: &'a [T], + head: uint, + tail: uint } impl<'a, T> Iterator<&'a T> for Items<'a, T> { #[inline] fn next(&mut self) -> Option<&'a T> { - if self.index == self.rindex { + if self.head == self.tail { return None; } - let raw_index = raw_index(self.lo, self.elts.len(), self.index); - self.index += 1; - Some(self.elts[raw_index].as_ref().unwrap()) + let head = self.head; + self.head = wrap_index(self.head + 1, self.ring.len()); + Some(&self.ring[head]) } #[inline] fn size_hint(&self) -> (uint, Option) { - let len = self.rindex - self.index; + let len = count(self.head, self.tail, self.ring.len()); (len, Some(len)) } } @@ -301,129 +417,81 @@ impl<'a, T> Iterator<&'a T> for Items<'a, T> { impl<'a, T> DoubleEndedIterator<&'a T> for Items<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a T> { - if self.index == self.rindex { + if self.head == self.tail { return None; } - self.rindex -= 1; - let raw_index = raw_index(self.lo, self.elts.len(), self.rindex); - Some(self.elts[raw_index].as_ref().unwrap()) + self.tail = wrap_index(self.tail - 1, self.ring.len()); + Some(&self.ring[self.tail]) } } + impl<'a, T> ExactSize<&'a T> for Items<'a, T> {} impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> { #[inline] - fn indexable(&self) -> uint { self.rindex - self.index } + fn indexable(&self) -> uint { + let (len, _) = self.size_hint(); + len + } #[inline] fn idx(&mut self, j: uint) -> Option<&'a T> { if j >= self.indexable() { None } else { - let raw_index = raw_index(self.lo, self.elts.len(), self.index + j); - Some(self.elts[raw_index].as_ref().unwrap()) + let idx = wrap_index(self.head + j, self.ring.len()); + Some(&self.ring[idx]) } } } -/// `RingBuf` mutable iterator. + +/// `RingBuf` iterator. pub struct MutItems<'a, T:'a> { - remaining1: slice::MutItems<'a, Option>, - remaining2: slice::MutItems<'a, Option>, - nelts: uint, + ptr: *mut T, + head: uint, + tail: uint, + len: uint, + marker: marker::ContravariantLifetime<'a>, + marker2: marker::NoCopy } impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> { #[inline] fn next(&mut self) -> Option<&'a mut T> { - if self.nelts == 0 { + if self.head == self.tail { return None; } - self.nelts -= 1; - match self.remaining1.next() { - Some(ptr) => return Some(ptr.as_mut().unwrap()), - None => {} - } - match self.remaining2.next() { - Some(ptr) => return Some(ptr.as_mut().unwrap()), - None => unreachable!(), - } + let head = self.head; + self.head = wrap_index(self.head + 1, self.len); + unsafe { Some(mem::transmute(self.ptr.offset(head as int))) } } #[inline] fn size_hint(&self) -> (uint, Option) { - (self.nelts, Some(self.nelts)) + let len = count(self.head, self.tail, self.len); + (len, Some(len)) } } impl<'a, T> DoubleEndedIterator<&'a mut T> for MutItems<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a mut T> { - if self.nelts == 0 { + if self.head == self.tail { return None; } - self.nelts -= 1; - match self.remaining2.next_back() { - Some(ptr) => return Some(ptr.as_mut().unwrap()), - None => {} - } - match self.remaining1.next_back() { - Some(ptr) => return Some(ptr.as_mut().unwrap()), - None => unreachable!(), - } + self.tail = wrap_index(self.tail - 1, self.len); + unsafe { Some(mem::transmute(self.ptr.offset(self.tail as int))) } } } -impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {} - -/// Grow is only called on full elts, so nelts is also len(elts), unlike -/// elsewhere. -fn grow(nelts: uint, loptr: &mut uint, elts: &mut Vec>) { - assert_eq!(nelts, elts.len()); - let lo = *loptr; - elts.reserve(nelts * 2); - let newlen = elts.capacity(); - - /* fill with None */ - for _ in range(elts.len(), newlen) { - elts.push(None); - } - - /* - Move the shortest half into the newly reserved area. - lo ---->| - nelts ----------->| - [o o o|o o o o o] - A [. . .|o o o o o o o o|. . . . .] - B [o o o|. . . . . . . .|o o o o o] - */ - - assert!(newlen - nelts/2 >= nelts); - if lo <= (nelts - lo) { // A - for i in range(0u, lo) { - elts.as_mut_slice().swap(i, nelts + i); - } - } else { // B - for i in range(lo, nelts) { - elts.as_mut_slice().swap(i, newlen - nelts + i); - } - *loptr += newlen - nelts; - } -} -/// Returns the index in the underlying `Vec` for a given logical element index. -fn raw_index(lo: uint, len: uint, index: uint) -> uint { - if lo >= len - index { - lo + index - len - } else { - lo + index - } -} +impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {} impl PartialEq for RingBuf { fn eq(&self, other: &RingBuf) -> bool { - self.nelts == other.nelts && + self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a.eq(b)) } fn ne(&self, other: &RingBuf) -> bool { @@ -829,28 +897,16 @@ mod tests { assert_eq!(d3.front(), Some(&9)); } - #[test] - fn test_reserve_exact() { - let mut d = RingBuf::new(); - d.push(0u64); - d.reserve_exact(50); - assert_eq!(d.elts.capacity(), 50); - let mut d = RingBuf::new(); - d.push(0u32); - d.reserve_exact(50); - assert_eq!(d.elts.capacity(), 50); - } - #[test] fn test_reserve() { let mut d = RingBuf::new(); d.push(0u64); d.reserve(50); - assert_eq!(d.elts.capacity(), 64); + assert_eq!(d.len, 64); let mut d = RingBuf::new(); d.push(0u32); d.reserve(50); - assert_eq!(d.elts.capacity(), 64); + assert_eq!(d.len, 64); } #[test] From 6c8cdffc5eb2826310ca5a0f6fcb833fdc20cf93 Mon Sep 17 00:00:00 2001 From: Colin Sherratt Date: Tue, 21 Oct 2014 00:53:55 -0400 Subject: [PATCH 6/7] -Swap naming of head/tail. Changed len to cap. -Add is_full() and use it to check push push_back -use is_empty() for pop/pop_back -read get and make it return Option<&T> -change get_mut to return to Option<&mut T> --- src/libcollections/ringbuf.rs | 373 ++++++++++++++++++++-------------- 1 file changed, 222 insertions(+), 151 deletions(-) diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index 5e3019d4bceaf..6ce57ad82e674 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -18,7 +18,6 @@ use core::prelude::*; use core::default::Default; use core::fmt; use core::iter; -use core::slice; use core::raw::Slice as RawSlice; use core::ptr; use core::kinds::marker; @@ -28,7 +27,7 @@ use core::num; use std::hash::{Writer, Hash}; use std::cmp; -use alloc::heap::{allocate, reallocate, deallocate}; +use alloc::heap; use {Deque, Mutable, MutableSeq}; @@ -37,9 +36,15 @@ static MINIMUM_CAPACITY: uint = 2u; /// `RingBuf` is a circular buffer that implements `Deque`. pub struct RingBuf { - head: uint, + // tail and head are pointers into the buffer. Tail always points + // to the first element that could be read, Head always points + // to where data should be written. + // If tail == head the buffer is empty. The length of the ringbuf + // is defined as the distance between the two, + tail: uint, - len: uint, + head: uint, + cap: uint, ptr: *mut T } @@ -56,99 +61,92 @@ impl Drop for RingBuf { drop(self.pop_front()) } unsafe { - deallocate(self.ptr as *mut u8, - self.len * mem::size_of::(), - mem::min_align_of::()) + heap::deallocate(self.ptr as *mut u8, + self.cap * mem::size_of::(), + mem::min_align_of::()) } } } impl Collection for RingBuf { /// Returns the number of elements in the `RingBuf`. - fn len(&self) -> uint { - (self.tail - self.head) & (self.len - 1) - } + fn len(&self) -> uint { count(self.tail, self.head, self.cap) } } impl Mutable for RingBuf { /// Clears the `RingBuf`, removing all values. fn clear(&mut self) { - while self.head != self.tail { + while self.tail != self.head { let _ = self.pop_front(); } - self.head = 0; self.tail = 0; + self.head = 0; } } impl Deque for RingBuf { /// Returns a reference to the first element in the `RingBuf`. - fn front<'a>(&'a self) -> Option<&'a T> { - if self.len() > 0 { Some(&self[0]) } else { None } - } + fn front<'a>(&'a self) -> Option<&'a T> { self.get(0) } /// Returns a mutable reference to the first element in the `RingBuf`. - fn front_mut<'a>(&'a mut self) -> Option<&'a mut T> { - if self.len() > 0 { Some(self.get_mut(0)) } else { None } - } + fn front_mut<'a>(&'a mut self) -> Option<&'a mut T> { self.get_mut(0) } /// Returns a reference to the last element in the `RingBuf`. fn back<'a>(&'a self) -> Option<&'a T> { - if self.len() > 0 { Some(&self[self.len() - 1]) } else { None } + let idx = self.len() - 1; + self.get(idx) } /// Returns a mutable reference to the last element in the `RingBuf`. fn back_mut<'a>(&'a mut self) -> Option<&'a mut T> { - if self.len() > 0 { - let last = self.len() - 1; - Some(self.get_mut(last)) - } else { None } + let idx = self.len() - 1; + self.get_mut(idx) } /// Removes and returns the first element in the `RingBuf`, or `None` if it /// is empty. fn pop_front(&mut self) -> Option { - if self.head == self.tail { + if self.is_empty() { None } else { - let head = self.head; - self.head = self.wrap_ptr(self.head + 1); - unsafe { Some(self.buffer_read(head)) } + let tail = self.tail; + self.tail = wrap_index(self.tail + 1, self.cap); + unsafe { Some(self.buffer_read(tail)) } } } /// Prepends an element to the `RingBuf`. fn push_front(&mut self, t: T) { - if self.wrap_ptr(self.head - 1) == self.tail { - let len = self.len * 2; - self.grow(len); + if self.is_full() { + let newcap = self.cap * 2; + self.grow(newcap); } - self.head = self.wrap_ptr(self.head - 1); - let head = self.head; - unsafe { self.buffer_write(head, t); } + self.tail = wrap_index(self.tail - 1, self.cap); + let tail = self.tail; + unsafe { self.buffer_write(tail, t); } } } impl MutableSeq for RingBuf { fn push(&mut self, t: T) { - if self.wrap_ptr(self.tail + 1) == self.head { - let len = self.len * 2; - self.grow(len); + if self.is_full() { + let newcap = self.cap * 2; + self.grow(newcap); } - let tail = self.tail; - self.tail = self.wrap_ptr(self.tail + 1); - unsafe { self.buffer_write(tail, t) } + let head = self.head; + self.head = wrap_index(self.head + 1, self.cap); + unsafe { self.buffer_write(head, t) } } fn pop(&mut self) -> Option { - if self.len() > 0 { - self.tail = self.wrap_ptr(self.tail - 1); - let tail = self.tail; - unsafe { Some(self.buffer_read(tail)) } - } else { + if self.is_empty() { None + } else { + self.head = wrap_index(self.head - 1, self.cap); + let head = self.head; + unsafe { Some(self.buffer_read(head)) } } } } @@ -166,93 +164,132 @@ impl RingBuf { /// Creates an empty `RingBuf` with space for at least `n` elements. pub fn with_capacity(n: uint) -> RingBuf { - let count = num::next_power_of_two(cmp::max(n, MINIMUM_CAPACITY)); - let size = count.checked_mul(&mem::size_of::()) - .expect("capacity overflow"); + // +1 since the ringbuffer always leaves one space empty + let cap = num::next_power_of_two(cmp::max(n + 1, MINIMUM_CAPACITY)); + let size = cap.checked_mul(&mem::size_of::()) + .expect("capacity overflow"); RingBuf { - head: 0, tail: 0, - len: count, - ptr: unsafe { allocate(size, mem::min_align_of::()) as *mut T } + head: 0, + cap: cap, + ptr: unsafe { heap::allocate(size, mem::min_align_of::()) as *mut T } } } /// Turn ptr into a slice #[inline] fn buffer_as_slice(&self) -> &[T] { - unsafe { mem::transmute(RawSlice { data: self.ptr as *const T, len: self.len }) } + unsafe { mem::transmute(RawSlice { data: self.ptr as *const T, len: self.cap }) } } /// Turn ptr into a mutable slice #[inline] fn buffer_as_slice_mut(&mut self) -> &mut [T] { - unsafe { mem::transmute(RawSlice { data: self.ptr as *const T, len: self.len }) } + unsafe { mem::transmute(RawSlice { data: self.ptr as *const T, len: self.cap }) } } - /// move an element from the buffer + /// Moves an element out of the buffer #[inline] unsafe fn buffer_read(&mut self, off: uint) -> T { ptr::read(self.ptr.offset(off as int) as *const T) } - /// write an element without dropping unused slot + /// Writes an element into the buffer, moving it. #[inline] unsafe fn buffer_write(&mut self, off: uint, t: T) { - let pos = (self.ptr as *const T).offset(off as int) as *mut T; - ptr::write(&mut *pos, t); + ptr::write(self.ptr.offset(off as int), t); } - /// caclulate index from offset - fn wrap_ptr(&self, idx: uint) -> uint { idx & (self.len - 1) } + /// Returns true iff the buffer is at capacity + #[inline] + fn is_full(&self) -> bool { self.cap - self.len() == 1 } - /// Grow the buffer to a new length + /// Grows the buffer to a new length, this expected the new size + /// to be greated then the current size and a power of two. #[inline] fn grow(&mut self, newlen: uint) { - assert!(newlen > self.len); - let old = self.len * mem::size_of::(); + assert!(newlen > self.cap); + assert!(newlen == num::next_power_of_two(newlen)); + let old = self.cap * mem::size_of::(); let new = newlen.checked_mul(&mem::size_of::()) .expect("capacity overflow"); unsafe { - self.ptr = reallocate(self.ptr as *mut u8, - old, - new, - mem::min_align_of::()) as *mut T; + self.ptr = heap::reallocate(self.ptr as *mut u8, + old, + new, + mem::min_align_of::()) as *mut T; } // Move the shortest half into the newly reserved area. - // W R + // T H + // [o o o o o o o . ] + // T H + // A [o o o o o o o . . . . . . . . . ] + // H T // [o o . o o o o o ] - // R W - // A [. . . o o o o o o o . . . . . . ] - // W R + // T H + // B [. . . o o o o o o o . . . . . . ] + // H T // [o o o o o . o o ] - // W R - // B [o o o o o . . . . . . . . . o o ] - - let oldlen = self.len; - self.len = newlen; - - if self.head == 0 { - return - } - - if self.tail < oldlen - self.head { // A - for i in range(0u, self.tail) { - self.buffer_as_slice_mut().swap(i, oldlen + i); + // H T + // C [o o o o o . . . . . . . . . o o ] + + let oldlen = self.cap; + self.cap = newlen; + + if self.tail < self.head { // A + // Nop + } else if self.head < oldlen - self.tail { // B + unsafe { + ptr::copy_nonoverlapping_memory( + self.ptr.offset(oldlen as int) as *mut T, + self.ptr.offset(0 as int) as *const T, + self.head + ); } - self.tail += oldlen; - } else { // B - for i in range(self.head, oldlen) { - self.buffer_as_slice_mut().swap(i, newlen - oldlen + i); + self.head += oldlen; + } else { // C + unsafe { + ptr::copy_nonoverlapping_memory( + self.ptr.offset((newlen - oldlen + self.tail) as int) as *mut T, + self.ptr.offset(self.tail as int) as *const T, + self.head + ); } - self.head = newlen - oldlen + self.head; + self.tail = newlen - oldlen + self.tail; + } + } + + /// Retrieve an element in the `RingBuf` by index. + /// + /// Returns None if there is no element with the given index. + /// + /// # Example + /// + /// ```rust + /// #![allow(deprecated)] + /// + /// use std::collections::RingBuf; + /// + /// let mut buf = RingBuf::new(); + /// buf.push(3i); + /// buf.push(4); + /// buf.push(5); + /// assert_eq!(buf.get(1), Some(&4)); + /// ``` + pub fn get<'a>(&'a self, i: uint) -> Option<&'a T> { + if self.len() > i { + let idx = wrap_index(self.tail + i, self.cap); + Some(&self.buffer_as_slice()[idx]) + } else { + None } } /// Retrieves an element in the `RingBuf` by index. /// - /// Fails if there is no element with the given index. + /// Returns None if there is no element with the given index. /// /// # Example /// @@ -263,12 +300,19 @@ impl RingBuf { /// buf.push(3i); /// buf.push(4); /// buf.push(5); - /// *buf.get_mut(1) = 7; + /// match buf.get_mut(1) { + /// Some(v) => *v = 7, + /// None => () + /// }; /// assert_eq!(buf[1], 7); /// ``` - pub fn get_mut<'a>(&'a mut self, i: uint) -> &'a mut T { - let idx = self.raw_index(i); - &mut self.buffer_as_slice_mut()[idx] + pub fn get_mut<'a>(&'a mut self, i: uint) -> Option<&'a mut T> { + if self.len() > i { + let idx = wrap_index(self.tail + i, self.cap); + Some(&mut self.buffer_as_slice_mut()[idx]) + } else { + None + } } /// Swaps elements at indices `i` and `j`. @@ -293,18 +337,11 @@ impl RingBuf { pub fn swap(&mut self, i: uint, j: uint) { assert!(i < self.len()); assert!(j < self.len()); - let ri = self.raw_index(i); - let rj = self.raw_index(j); + let ri = wrap_index(self.tail + i, self.cap); + let rj = wrap_index(self.tail + j, self.cap); self.buffer_as_slice_mut().swap(ri, rj); } - /// Returns the index in the underlying `Vec` for a given logical element - /// index. - fn raw_index(&self, idx: uint) -> uint { - assert!(self.len() > idx); - wrap_index(self.head + idx, self.len) - } - /// Reserves capacity for exactly `n` elements in the given `RingBuf`, /// doing nothing if `self`'s capacity is already equal to or greater /// than the requested capacity. @@ -320,8 +357,11 @@ impl RingBuf { /// Do nothing if `self`'s capacity is already equal to or greater /// than the requested capacity. pub fn reserve(&mut self, n: uint) { - let count = num::next_power_of_two(n); - self.grow(count); + // +1 since the buffer needs one more space then the expected size. + let count = num::next_power_of_two(n + 1); + if count > self.cap { + self.grow(count); + } } /// Returns a front-to-back iterator. @@ -340,8 +380,8 @@ impl RingBuf { /// ``` pub fn iter<'a>(&'a self) -> Items<'a, T> { Items { - head: self.head, tail: self.tail, + head: self.head, ring: self.buffer_as_slice() } } @@ -365,9 +405,9 @@ impl RingBuf { /// ``` pub fn iter_mut<'a>(&'a mut self) -> MutItems<'a, T> { MutItems { - head: self.head, tail: self.tail, - len: self.len, + head: self.head, + cap: self.cap, ptr: self.ptr, marker: marker::ContravariantLifetime::<'a>, marker2: marker::NoCopy @@ -378,38 +418,38 @@ impl RingBuf { /// Returns the index in the underlying `Vec` for a given logical element index. #[inline] fn wrap_index(index: uint, size: uint) -> uint { - // size is always a power ot 2 + // size is always a power of 2 index & (size - 1) } /// Calculate the number of elements left to be read in the buffer #[inline] -fn count(head: uint, tail: uint, size: uint) -> uint { - // size is always a power ot 2 - (tail - head) & (size - 1) +fn count(tail: uint, head: uint, size: uint) -> uint { + // size is always a power of 2 + (head - tail) & (size - 1) } /// `RingBuf` iterator. pub struct Items<'a, T:'a> { ring: &'a [T], - head: uint, - tail: uint + tail: uint, + head: uint } impl<'a, T> Iterator<&'a T> for Items<'a, T> { #[inline] fn next(&mut self) -> Option<&'a T> { - if self.head == self.tail { + if self.tail == self.head { return None; } - let head = self.head; - self.head = wrap_index(self.head + 1, self.ring.len()); - Some(&self.ring[head]) + let tail = self.tail; + self.tail = wrap_index(self.tail + 1, self.ring.len()); + unsafe { Some(self.ring.unsafe_get(tail)) } } #[inline] fn size_hint(&self) -> (uint, Option) { - let len = count(self.head, self.tail, self.ring.len()); + let len = count(self.tail, self.head, self.ring.len()); (len, Some(len)) } } @@ -417,11 +457,11 @@ impl<'a, T> Iterator<&'a T> for Items<'a, T> { impl<'a, T> DoubleEndedIterator<&'a T> for Items<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a T> { - if self.head == self.tail { + if self.tail == self.head { return None; } - self.tail = wrap_index(self.tail - 1, self.ring.len()); - Some(&self.ring[self.tail]) + self.head = wrap_index(self.head - 1, self.ring.len()); + unsafe { Some(self.ring.unsafe_get(self.head)) } } } @@ -440,8 +480,8 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> { if j >= self.indexable() { None } else { - let idx = wrap_index(self.head + j, self.ring.len()); - Some(&self.ring[idx]) + let idx = wrap_index(self.tail + j, self.ring.len()); + unsafe { Some(self.ring.unsafe_get(idx)) } } } } @@ -450,9 +490,9 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> { /// `RingBuf` iterator. pub struct MutItems<'a, T:'a> { ptr: *mut T, - head: uint, tail: uint, - len: uint, + head: uint, + cap: uint, marker: marker::ContravariantLifetime<'a>, marker2: marker::NoCopy } @@ -460,17 +500,17 @@ pub struct MutItems<'a, T:'a> { impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> { #[inline] fn next(&mut self) -> Option<&'a mut T> { - if self.head == self.tail { + if self.tail == self.head { return None; } - let head = self.head; - self.head = wrap_index(self.head + 1, self.len); - unsafe { Some(mem::transmute(self.ptr.offset(head as int))) } + let tail = self.tail; + self.tail = wrap_index(self.tail + 1, self.cap); + unsafe { Some(&mut *self.ptr.offset(tail as int)) } } #[inline] fn size_hint(&self) -> (uint, Option) { - let len = count(self.head, self.tail, self.len); + let len = count(self.tail, self.head, self.cap); (len, Some(len)) } } @@ -478,11 +518,11 @@ impl<'a, T> Iterator<&'a mut T> for MutItems<'a, T> { impl<'a, T> DoubleEndedIterator<&'a mut T> for MutItems<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a mut T> { - if self.head == self.tail { + if self.tail == self.head { return None; } - self.tail = wrap_index(self.tail - 1, self.len); - unsafe { Some(mem::transmute(self.ptr.offset(self.tail as int))) } + self.head = wrap_index(self.head - 1, self.cap); + unsafe { Some(&mut *self.ptr.offset(self.head as int)) } } } @@ -526,21 +566,16 @@ impl> Hash for RingBuf { impl Index for RingBuf { #[inline] fn index<'a>(&'a self, i: &uint) -> &'a A { - let idx = self.raw_index(*i); - match self.elts[idx] { - None => fail!(), - Some(ref v) => v, - } + self.get(*i).expect("Index out of bounds") } } -// FIXME(#12825) Indexing will always try IndexMut first and that causes issues. -/*impl IndexMut for RingBuf { +impl IndexMut for RingBuf { #[inline] fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut A { - self.get_mut(*index) + self.get_mut(*index).expect("Index out of bounds") } -}*/ +} impl FromIterator for RingBuf { fn from_iter>(iterator: T) -> RingBuf { @@ -735,10 +770,6 @@ mod tests { fn bench_pop_100(b: &mut test::Bencher) { let mut deq = RingBuf::with_capacity(100); - // this will make sure the bencher wraps - for i in range(0i, 25) { deq.push(i); } - while None != deq.pop_front() {} - b.iter(|| { for i in range(0i, 100) { deq.push(i); @@ -751,10 +782,6 @@ mod tests { fn bench_pop_front_100(b: &mut test::Bencher) { let mut deq = RingBuf::with_capacity(100); - // this will make sure the bencher wraps - for i in range(0i, 25) { deq.push(i); } - while None != deq.pop_front() {} - b.iter(|| { for i in range(0i, 100) { deq.push(i); @@ -902,11 +929,11 @@ mod tests { let mut d = RingBuf::new(); d.push(0u64); d.reserve(50); - assert_eq!(d.len, 64); + assert_eq!(d.cap, 64); let mut d = RingBuf::new(); d.push(0u32); d.reserve(50); - assert_eq!(d.len, 64); + assert_eq!(d.cap, 64); } #[test] @@ -1191,4 +1218,48 @@ mod tests { drop(ring); assert_eq!(unsafe {drops}, 4); } + + #[test] + fn test_reserve_grow() { + // test growth path A + // [T o o H] -> [T o o H . . . . ] + let mut ring = RingBuf::with_capacity(4); + for i in range(0i, 3) { + ring.push(i); + } + ring.reserve(7); + for i in range(0i, 3) { + assert_eq!(ring.pop_front(), Some(i)); + } + + // test growth path B + // [H T o o] -> [. T o o H . . . ] + let mut ring = RingBuf::with_capacity(4); + for i in range(0i, 1) { + ring.push(i); + assert_eq!(ring.pop_front(), Some(i)); + } + for i in range(0i, 3) { + ring.push(i); + } + ring.reserve(7); + for i in range(0i, 3) { + assert_eq!(ring.pop_front(), Some(i)); + } + + // test growth path C + // [o o H T] -> [o o H . . . . T ] + let mut ring = RingBuf::with_capacity(4); + for i in range(0i, 3) { + ring.push(i); + assert_eq!(ring.pop_front(), Some(i)); + } + for i in range(0i, 3) { + ring.push(i); + } + ring.reserve(7); + for i in range(0i, 3) { + assert_eq!(ring.pop_front(), Some(i)); + } + } } From 7f79cef7a8d6f636fafe3d156c11a233576190ba Mon Sep 17 00:00:00 2001 From: Colin Sherratt Date: Wed, 22 Oct 2014 01:44:11 -0400 Subject: [PATCH 7/7] -Fixed one of the contiguous entry moves in grow() -Use unsafe for get()/get_mut() -Correct some comment language. -Rearrange the internal functions from external functions --- src/libcollections/ringbuf.rs | 58 ++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index 6ce57ad82e674..0921fce4b5d2a 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -40,7 +40,7 @@ pub struct RingBuf { // to the first element that could be read, Head always points // to where data should be written. // If tail == head the buffer is empty. The length of the ringbuf - // is defined as the distance between the two, + // is defined as the distance between the two. tail: uint, head: uint, @@ -157,26 +157,6 @@ impl Default for RingBuf { } impl RingBuf { - /// Creates an empty `RingBuf`. - pub fn new() -> RingBuf { - RingBuf::with_capacity(INITIAL_CAPACITY) - } - - /// Creates an empty `RingBuf` with space for at least `n` elements. - pub fn with_capacity(n: uint) -> RingBuf { - // +1 since the ringbuffer always leaves one space empty - let cap = num::next_power_of_two(cmp::max(n + 1, MINIMUM_CAPACITY)); - let size = cap.checked_mul(&mem::size_of::()) - .expect("capacity overflow"); - - RingBuf { - tail: 0, - head: 0, - cap: cap, - ptr: unsafe { heap::allocate(size, mem::min_align_of::()) as *mut T } - } - } - /// Turn ptr into a slice #[inline] fn buffer_as_slice(&self) -> &[T] { @@ -221,7 +201,7 @@ impl RingBuf { mem::min_align_of::()) as *mut T; } - // Move the shortest half into the newly reserved area. + // Move the shortest contiguous section of the ring buffer // T H // [o o o o o o o . ] // T H @@ -238,7 +218,7 @@ impl RingBuf { let oldlen = self.cap; self.cap = newlen; - if self.tail < self.head { // A + if self.tail <= self.head { // A // Nop } else if self.head < oldlen - self.tail { // B unsafe { @@ -254,14 +234,36 @@ impl RingBuf { ptr::copy_nonoverlapping_memory( self.ptr.offset((newlen - oldlen + self.tail) as int) as *mut T, self.ptr.offset(self.tail as int) as *const T, - self.head + oldlen - self.tail ); } self.tail = newlen - oldlen + self.tail; } } +} + +impl RingBuf { + /// Creates an empty `RingBuf`. + pub fn new() -> RingBuf { + RingBuf::with_capacity(INITIAL_CAPACITY) + } + + /// Creates an empty `RingBuf` with space for at least `n` elements. + pub fn with_capacity(n: uint) -> RingBuf { + // +1 since the ringbuffer always leaves one space empty + let cap = num::next_power_of_two(cmp::max(n + 1, MINIMUM_CAPACITY)); + let size = cap.checked_mul(&mem::size_of::()) + .expect("capacity overflow"); + + RingBuf { + tail: 0, + head: 0, + cap: cap, + ptr: unsafe { heap::allocate(size, mem::min_align_of::()) as *mut T } + } + } - /// Retrieve an element in the `RingBuf` by index. + /// Retrieves an element in the `RingBuf` by index. /// /// Returns None if there is no element with the given index. /// @@ -281,7 +283,7 @@ impl RingBuf { pub fn get<'a>(&'a self, i: uint) -> Option<&'a T> { if self.len() > i { let idx = wrap_index(self.tail + i, self.cap); - Some(&self.buffer_as_slice()[idx]) + unsafe { Some(self.buffer_as_slice().unsafe_get(idx)) } } else { None } @@ -309,7 +311,7 @@ impl RingBuf { pub fn get_mut<'a>(&'a mut self, i: uint) -> Option<&'a mut T> { if self.len() > i { let idx = wrap_index(self.tail + i, self.cap); - Some(&mut self.buffer_as_slice_mut()[idx]) + unsafe { Some(self.buffer_as_slice_mut().unsafe_mut(idx)) } } else { None } @@ -415,7 +417,7 @@ impl RingBuf { } } -/// Returns the index in the underlying `Vec` for a given logical element index. +/// Returns the index in the underlying buffer for a given logical element index. #[inline] fn wrap_index(index: uint, size: uint) -> uint { // size is always a power of 2