Skip to content

Commit 466c8a2

Browse files
committed
Refactor modules and add atomic bounded buffer
Modules are now more organized with room for more queue and buffer types in the future. All buffers now implement a common set of traits.
1 parent a73a0f9 commit 466c8a2

7 files changed

Lines changed: 616 additions & 256 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ringtail"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
description = "Efficient ring buffer for byte buffers, FIFO queues, and SPSC channels"
55
authors = ["Stephen M. Coakley <me@stephencoakley.com>"]
66
license = "MIT"

src/arrays.rs

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Provides functions for dynamic array manipulation.
2+
use std::ops::{Index, IndexMut, Range};
23

34
/// Allocate an uninitialized array of a given size.
45
///
@@ -9,7 +10,7 @@ pub unsafe fn allocate<T>(len: usize) -> Box<[T]> {
910
vec.into_boxed_slice()
1011
}
1112

12-
/// Copy as many elements as possible from one array to another.
13+
/// Copy as many elements as possible from one slice to another.
1314
///
1415
/// Returns the number of elements copied.
1516
#[inline]
@@ -19,6 +20,23 @@ pub fn copy<T: Copy>(src: &[T], dest: &mut [T]) -> usize {
1920
len
2021
}
2122

23+
/// Copy as many elements as possible from a slice of slices to another.
24+
///
25+
/// Returns the number of elements copied.
26+
pub fn copy_seq<T: Copy>(seq: &[&[T]], dest: &mut [T]) -> usize {
27+
let mut copied = 0;
28+
29+
for slice in seq {
30+
if copied < dest.len() {
31+
copied += copy(slice, &mut dest[copied..]);
32+
} else {
33+
break;
34+
}
35+
}
36+
37+
copied
38+
}
39+
2240
/// Extension trait for slices for working with wrapping ranges and indicies.
2341
pub trait WrappingSlice<T> {
2442
/// Gets a pair of slices in the given range, wrapping around length.
@@ -47,3 +65,127 @@ impl<T> WrappingSlice<T> for [T] {
4765
}
4866
}
4967
}
68+
69+
/// A heap-allocated circular array, useful for implementing ring buffers.
70+
///
71+
/// This array type uses a _virtual indexing_ system. Indexing into the array applies a virtual mapping such that any
72+
/// index is always mapped to a valid position in the array. More than one virtual index may map to the same position.
73+
pub struct CircularArray<T> {
74+
array: Box<[T]>,
75+
mask: usize,
76+
}
77+
78+
impl<T> CircularArray<T> {
79+
/// Create a new array of a given length containing uninitialized data.
80+
pub unsafe fn uninitialized(len: usize) -> Self {
81+
let len = len.next_power_of_two();
82+
83+
Self {
84+
array: allocate(len),
85+
mask: len - 1,
86+
}
87+
}
88+
89+
/// Get the length of the array.
90+
#[inline]
91+
pub fn len(&self) -> usize {
92+
self.array.len()
93+
}
94+
95+
/// Gets a pair of slices in the given range, wrapping around length.
96+
pub fn as_slices(&self, range: Range<usize>) -> [&[T]; 2] {
97+
let start = self.internal_index(range.start);
98+
let end = self.internal_index(range.end);
99+
100+
if start < end {
101+
[&self.array[start..end], &[]]
102+
} else {
103+
[&self.array[start..], &self.array[..end]]
104+
}
105+
}
106+
107+
/// Gets a pair of mutable slices in the given range, wrapping around length.
108+
pub fn as_slices_mut(&mut self, range: Range<usize>) -> [&mut [T]; 2] {
109+
let start = self.internal_index(range.start);
110+
let end = self.internal_index(range.end);
111+
112+
if start < end {
113+
[&mut self.array[start..end], &mut []]
114+
} else {
115+
let (mid, right) = self.array.split_at_mut(start);
116+
let left = mid.split_at_mut(end).0;
117+
[right, left]
118+
}
119+
}
120+
121+
// /// Copies elements from this array into
122+
// pub fn copy_to_slice(&self, dest: &mut [T]) -> usize {
123+
// if self.is_empty() {
124+
// return 0;
125+
// }
126+
127+
// let slices = self.array
128+
// .wrapping_range(self.mask(self.head), self.mask(self.tail));
129+
130+
// let mut copied = arrays::copy(slices.0, dest);
131+
// copied += arrays::copy(slices.1, &mut dest[copied..]);
132+
133+
// copied
134+
// }
135+
136+
/// Get the internal index the given virtual index is mapped to.
137+
#[inline]
138+
fn internal_index(&self, virtual_index: usize) -> usize {
139+
virtual_index & self.mask
140+
}
141+
}
142+
143+
impl<T> AsRef<[T]> for CircularArray<T> {
144+
fn as_ref(&self) -> &[T] {
145+
&self.array
146+
}
147+
}
148+
149+
impl<T> AsMut<[T]> for CircularArray<T> {
150+
fn as_mut(&mut self) -> &mut [T] {
151+
&mut self.array
152+
}
153+
}
154+
155+
impl<T> Index<usize> for CircularArray<T> {
156+
type Output = T;
157+
158+
fn index(&self, index: usize) -> &T {
159+
self.array.index(self.internal_index(index))
160+
}
161+
}
162+
163+
impl<T> IndexMut<usize> for CircularArray<T> {
164+
fn index_mut(&mut self, index: usize) -> &mut T {
165+
let index = self.internal_index(index);
166+
self.array.index_mut(index)
167+
}
168+
}
169+
170+
#[cfg(test)]
171+
mod tests {
172+
use super::*;
173+
174+
#[test]
175+
fn copy_seq_with_less_elements() {
176+
let chunks: [&[i32]; 3] = [&[], &[1, 2], &[3]];
177+
let mut dest = [0; 6];
178+
179+
assert_eq!(copy_seq(&chunks, &mut dest), 3);
180+
assert_eq!(&dest, &[1, 2, 3, 0, 0, 0]);
181+
}
182+
183+
#[test]
184+
fn copy_seq_with_more_elements() {
185+
let chunks: [&[i32]; 5] = [&[], &[1, 2], &[], &[3], &[4, 5, 6]];
186+
let mut dest = [0; 4];
187+
188+
assert_eq!(copy_seq(&chunks, &mut dest), 4);
189+
assert_eq!(&dest, &[1, 2, 3, 4]);
190+
}
191+
}

0 commit comments

Comments
 (0)