Skip to content

Commit

Permalink
Remove P: PoolAllocator bounds on pools
Browse files Browse the repository at this point in the history
- Move the bounds to the implementations, not the struct
- Non-breaking change
- Makes it nicer to use the structs in other places now.
  • Loading branch information
v0x0g committed Jun 25, 2024
1 parent 317a382 commit 4b70191
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 66 deletions.
66 changes: 34 additions & 32 deletions src/concurrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,15 @@ use crossbeam_queue::ArrayQueue;
/// This struct uses an allocator to create and manage objects, and stores them
/// in an ArrayQueue.
#[derive(Debug)]
pub struct Pool<P: PoolAllocator<T>, T> {
pub struct Pool<P, T> {
allocator: P,
storage: ArrayQueue<T>,
}

// If T is Send it is safe to move object pool between threads
unsafe impl<P: PoolAllocator<T>, T: Send> Send for Pool<P, T> {}

impl<P: PoolAllocator<T>, T> Pool<P, T> {
/// Creates a new Pool with a given size and allocator.
///
/// This method immediately fills the pool with new objects created by the
/// allocator.
pub fn new_prefilled(pool_size: usize, allocator: P) -> Self {
let storage = ArrayQueue::new(pool_size);
for _ in 0..pool_size {
let _ = storage.push(allocator.allocate());
}
Pool { allocator, storage }
}
unsafe impl<P: Send, T: Send> Send for Pool<P, T> {}

impl<P, T> Pool<P, T> {
/// Creates a new Object Pool with a given size and allocator.
///
/// Unlike [`Self::new_prefilled`], this method does not immediately fill
Expand All @@ -50,6 +38,37 @@ impl<P: PoolAllocator<T>, T> Pool<P, T> {
Arc::new(self)
}

/// Gets the number of objects currently in the pool.
///
/// Returns the length of the internal storage, indicating the number of
/// objects that are ready to be recycled from the pool.
pub fn len(&self) -> usize {
self.storage.len()
}

/// Gets the capacity of the pool.
///
/// Returns the maximum number of objects that the pool can hold. This does
/// not indicate the maximum number of objects that can be allocated,
/// but maximum objects that can be stored and recycled from the pool.
pub fn cap(&self) -> usize {
self.storage.capacity()
}
}

impl<P: PoolAllocator<T>, T> Pool<P, T> {
/// Creates a new Pool with a given size and allocator.
///
/// This method immediately fills the pool with new objects created by the
/// allocator.
pub fn new_prefilled(pool_size: usize, allocator: P) -> Self {
let storage = ArrayQueue::new(pool_size);
for _ in 0..pool_size {
let _ = storage.push(allocator.allocate());
}
Pool { allocator, storage }
}

/// Gets an object from the pool.
///
/// If the pool is empty, a new object is created using the allocator.
Expand Down Expand Up @@ -78,23 +97,6 @@ impl<P: PoolAllocator<T>, T> Pool<P, T> {
None => RcGuard::new(self.allocator.allocate(), &self),
}
}

/// Gets the number of objects currently in the pool.
///
/// Returns the length of the internal storage, indicating the number of
/// objects that are ready to be recycled from the pool.
pub fn len(&self) -> usize {
self.storage.len()
}

/// Gets the capacity of the pool.
///
/// Returns the maximum number of objects that the pool can hold. This does
/// not indicate the maximum number of objects that can be allocated,
/// but maximum objects that can be stored and recycled from the pool.
pub fn cap(&self) -> usize {
self.storage.capacity()
}
}

/// A struct representing a guard over an object in the pool.
Expand Down
70 changes: 36 additions & 34 deletions src/thread_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,14 @@ use core::{
/// This struct uses an allocator to create and manage objects, and stores them
/// in an array.
#[derive(Debug)]
pub struct LocalPool<P: PoolAllocator<T>, T> {
pub struct LocalPool<P, T> {
allocator: P,
storage: UnsafeCell<VecDeque<T>>,
// force the struct to be !Send
_phantom: PhantomData<*mut usize>,
}

impl<P: PoolAllocator<T>, T> LocalPool<P, T> {
/// Creates a new LocalPool with a given size and allocator.
///
/// This method immediately fills the pool with new objects created by the
/// allocator.
pub fn new_prefilled(pool_size: usize, allocator: P) -> Self {
let mut storage = VecDeque::with_capacity(pool_size);
for _ in 0..pool_size {
storage.push_back(allocator.allocate());
}
LocalPool {
allocator,
storage: UnsafeCell::new(storage),
_phantom: PhantomData,
}
}

/// Creates a new Object Pool with a given size and allocator.
///
/// Unlike [`Self::new_prefilled`], this method does not immediately fill
Expand Down Expand Up @@ -72,6 +56,41 @@ impl<P: PoolAllocator<T>, T> LocalPool<P, T> {
Rc::new(self)
}

/// Gets the number of objects currently in the pool.
///
/// Returns the length of the internal storage, indicating the number of
/// objects that are ready to be recycled from the pool.
pub fn len(&self) -> usize {
self.storage_borrow().len()
}

/// Gets the capacity of the pool.
///
/// Returns the maximum number of objects that the pool can hold. This does
/// not indicate the maximum number of objects that can be allocated,
/// but maximum objects that can be stored and recycled from the pool.
pub fn cap(&self) -> usize {
self.storage_borrow().capacity()
}
}

impl<P: PoolAllocator<T>, T> LocalPool<P, T> {
/// Creates a new LocalPool with a given size and allocator.
///
/// This method immediately fills the pool with new objects created by the
/// allocator.
pub fn new_prefilled(pool_size: usize, allocator: P) -> Self {
let mut storage = VecDeque::with_capacity(pool_size);
for _ in 0..pool_size {
storage.push_back(allocator.allocate());
}
LocalPool {
allocator,
storage: UnsafeCell::new(storage),
_phantom: PhantomData,
}
}

/// Gets an object from the pool.
///
/// If the pool is empty, a new object is created using the allocator.
Expand Down Expand Up @@ -100,23 +119,6 @@ impl<P: PoolAllocator<T>, T> LocalPool<P, T> {
None => RcLocalGuard::new(self.allocator.allocate(), &self),
}
}

/// Gets the number of objects currently in the pool.
///
/// Returns the length of the internal storage, indicating the number of
/// objects that are ready to be recycled from the pool.
pub fn len(&self) -> usize {
self.storage_borrow().len()
}

/// Gets the capacity of the pool.
///
/// Returns the maximum number of objects that the pool can hold. This does
/// not indicate the maximum number of objects that can be allocated,
/// but maximum objects that can be stored and recycled from the pool.
pub fn cap(&self) -> usize {
self.storage_borrow().capacity()
}
}

/// A struct representing a guard over an object in the pool.
Expand Down

0 comments on commit 4b70191

Please sign in to comment.