Skip to content

Commit 64896d6

Browse files
committed
libcollections: Fix RingBuf growth for non-power-of-two capacities
1 parent 51e19e7 commit 64896d6

File tree

1 file changed

+44
-3
lines changed

1 file changed

+44
-3
lines changed

src/libcollections/ringbuf.rs

+44-3
Original file line numberDiff line numberDiff line change
@@ -403,11 +403,11 @@ impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {}
403403
fn grow<T>(nelts: uint, loptr: &mut uint, elts: &mut Vec<Option<T>>) {
404404
assert_eq!(nelts, elts.len());
405405
let lo = *loptr;
406-
let newlen = nelts * 2;
407-
elts.reserve(newlen);
406+
elts.reserve(nelts * 2);
407+
let newlen = elts.capacity();
408408

409409
/* fill with None */
410-
for _ in range(elts.len(), elts.capacity()) {
410+
for _ in range(elts.len(), newlen) {
411411
elts.push(None);
412412
}
413413

@@ -750,6 +750,47 @@ mod tests {
750750
assert_eq!(d.len(), 1);
751751
}
752752

753+
#[test]
754+
fn test_with_capacity_non_power_two() {
755+
let mut d3 = RingBuf::with_capacity(3);
756+
d3.push(1i);
757+
758+
// X = None, | = lo
759+
// [|1, X, X]
760+
assert_eq!(d3.pop_front(), Some(1));
761+
// [X, |X, X]
762+
assert_eq!(d3.front(), None);
763+
764+
// [X, |3, X]
765+
d3.push(3);
766+
// [X, |3, 6]
767+
d3.push(6);
768+
// [X, X, |6]
769+
assert_eq!(d3.pop_front(), Some(3));
770+
771+
// Pushing the lo past half way point to trigger
772+
// the 'B' scenario for growth
773+
// [9, X, |6]
774+
d3.push(9);
775+
// [9, 12, |6]
776+
d3.push(12);
777+
778+
d3.push(15);
779+
// There used to be a bug here about how the
780+
// RingBuf made growth assumptions about the
781+
// underlying Vec which didn't hold and lead
782+
// to corruption.
783+
// (Vec grows to next power of two)
784+
//good- [9, 12, 15, X, X, X, X, |6]
785+
//bug- [15, 12, X, X, X, |6, X, X]
786+
assert_eq!(d3.pop_front(), Some(6));
787+
788+
// Which leads us to the following state which
789+
// would be a failure case.
790+
//bug- [15, 12, X, X, X, X, |X, X]
791+
assert_eq!(d3.front(), Some(&9));
792+
}
793+
753794
#[test]
754795
fn test_reserve_exact() {
755796
let mut d = RingBuf::new();

0 commit comments

Comments
 (0)