diff --git a/src/ring_buffer.rs b/src/ring_buffer.rs index 54e3a78..a3d17c6 100644 --- a/src/ring_buffer.rs +++ b/src/ring_buffer.rs @@ -9,7 +9,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; pub enum BufferError { /// This will occur when you try to set the capacity of the [`RingBuffer`] to - /// zero. + /// a size other than a power of two. InvalidCapacity, /// This will occur when the [`RingBuffer`] is unable to @@ -77,22 +77,29 @@ impl RingBuffer /// Create a new RingBuffer that can hold N items of type T. /// /// # Capacity - /// - Must be greater than 0. + /// - Must be a power of 2. /// - Faster operations if capacity is a power of 2. /// + /// This was changed from being anything except zero because values that + /// were not a power of two would incorrectly map to the buffer space + /// when wrapping occured in the counter space. This caused an uneven + /// mapping of values in counter space to indices in buffer space. + /// A smooth transition is required and the power of two fixes that + /// because the max size of the usize value will always be a power of two. + /// /// # Examples /// ```rust /// use example::RingBuffer; /// /// let buffer: RingBuffer = - /// RingBuffer::new().expect("Buffer size was set to 0"); + /// RingBuffer::new().expect("Buffer size must be a power of 2."); /// /// assert_eq!(buffer.len(), 0); /// assert_eq!(buffer.capacity(), 32); /// ``` pub fn new() -> Result { - if N == 0 { return Err(BufferError::InvalidCapacity) } + if !N.is_power_of_two() { return Err(BufferError::InvalidCapacity) } Ok(RingBuffer { @@ -109,7 +116,7 @@ impl RingBuffer /// use example::RingBuffer; /// /// let buffer: RingBuffer = - /// RingBuffer::new().expect("Buffer size was set to 0"); + /// RingBuffer::new().expect("Buffer size must be a power of 2."); /// let cap = buffer.capacity(); /// let len = buffer.len(); /// @@ -126,7 +133,7 @@ impl RingBuffer /// use example::RingBuffer; /// /// let buffer: RingBuffer = - /// RingBuffer::new().expect("Buffer size was set to 0"); + /// RingBuffer::new().expect("Buffer size must be a power of 2."); /// /// buffer.push_back(25).expect("Buffer is full."); /// buffer.push_back(42).expect("Buffer is full."); @@ -161,7 +168,7 @@ impl RingBuffer /// use example::RingBuffer; /// /// let buffer: RingBuffer = - /// RingBuffer::new().expect("Buffer size was set to 0"); + /// RingBuffer::new().expect("Buffer size must be a power of 2."); /// /// buffer.push_back(25).expect("Buffer is full."); /// let _ = buffer.pop_front(); @@ -188,11 +195,10 @@ impl RingBuffer /// ```rust /// use example::RingBuffer; /// - /// let buffer: RingBuffer = - /// RingBuffer::new().expect("Buffer size was set to 0"); + /// let buffer: RingBuffer = + /// RingBuffer::new().expect("Buffer size must be a power of 2."); /// /// buffer.push_back(25).expect("Buffer is full."); - /// buffer.push_back(15).expect("Buffer is full."); /// buffer.push_back(42).expect("Buffer is full."); /// buffer.push_back(1).expect("Buffer is full."); /// buffer.push_back(2).expect("Buffer is full."); @@ -221,8 +227,8 @@ impl RingBuffer /// ```rust /// use example::RingBuffer; /// - /// let buffer: RingBuffer = - /// RingBuffer::new().expect("Buffer size was set to 0"); + /// let buffer: RingBuffer = + /// RingBuffer::new().expect("Buffer size must be a power of 2."); /// /// buffer.push_back(1).expect("Buffer is full."); /// buffer.push_back(2).expect("Buffer is full."); @@ -269,8 +275,8 @@ impl RingBuffer /// ```rust /// use example::RingBuffer; /// - /// let buffer: RingBuffer = - /// RingBuffer::new().expect("Buffer size was set to 0"); + /// let buffer: RingBuffer = + /// RingBuffer::new().expect("Buffer size must be a power of 2."); /// /// buffer.push_back(1).expect("Buffer is full."); /// buffer.push_back(2).expect("Buffer is full."); @@ -340,8 +346,11 @@ impl Drop for RingBuffer // allows us to state that the buffer is designed to be used from multiple // threads from the same reference. The RingBuffer requires that its items all // be Send so that they can traverse the threads pushing and pulling from it. +// +// Normally these are derived automatically, but because this in now using +// UnsafeCell they need to be added manually. unsafe impl Sync for RingBuffer {} - +unsafe impl Send for RingBuffer {} /// Map the counter space to the buffer space.