Struct thingbuf::recycling::WithCapacity

source ·
pub struct WithCapacity { /* private fields */ }
Expand description

A Recycle implementation for types that provide with_capacity, clear, and shrink_to methods.

This includes all array-based collections in the Rust standard library, such as Vec, String, VecDeque, and BinaryHeap, as well as HashMap and HashSet.

§Usage

By default, this type will always recycle elements by clearing all values in place, returning all allocated capacity. [New elements] are allocated with capacity for 0 values; they will allocate when first used.

§Implementations for Other Types

Recycle implementations may be added for similar data structures implemented in other libraries. The min_capacity and max_capacity methods expose the configured initial capacity and upper bound.

As an example, a library that implements an array-based data structure with with_capacity, clear, and shrink_to methods can implement Recycle for WithCapacity like so:

use thingbuf::recycling::{self, Recycle};

/// Some kind of exciting new heap-allocated collection.
pub struct MyCollection<T> {
    // ...
}

impl<T> MyCollection<T> {
    /// Returns a new `MyCollection` with enough capacity to hold
    /// `capacity` elements without reallocationg.
    pub fn with_capacity(capacity: usize) -> Self {
        // ...
    }

    /// Returns the current allocated capacity of this `MyCollection`.
    pub fn capacity(&self) -> usize {
        // ...
    }

    /// Shrinks the capacity of the `MyCollection` with a lower bound.
    ///
    /// The capacity will remain at least as large as both the length
    /// and the supplied value.
    ///
    /// If the current capacity is less than the lower limit, this is a no-op.
    pub fn shrink_to(&mut self, min_capacity: usize) {
        if self.capacity() > min_capacity {
            // ...
        }
    }

    /// Clears the `MyCollection`, removing all values.
    ///
    /// This does not change the current allocated capacity. The
    /// `MyCollection` will still have enough allocated storage to hold
    /// at least the current number of values.
    pub fn clear(&mut self) {
        // ...
    }

    // Other cool and exciting methods go here!
}

// Because `MyCollection<T>` has `with_capacity`, `shrink_to`, and `clear` methods,
// we can implement `Recycle<MyCollection<T>>` for `WithCapacity` exactly the same
// way as it is implemented for standard library collections.
impl<T> Recycle<MyCollection<T>> for recycling::WithCapacity {
    fn new_element(&self) -> MyCollection<T> {
        // Allocate a new element with the minimum initial capacity:
        MyCollection::with_capacity(self.min_capacity())
    }

    fn recycle(&self, element: &mut MyCollection<T>) {
        // Recycle the element by clearing it in place, and then limiting the
        // allocated capacity to the upper bound, if one is set:
        element.clear();
        element.shrink_to(self.max_capacity());
    }
}

§Allocation Reuse

When an upper bound is not set, this recycling policy will always reuse any allocated capacity when recycling an element. Over time, the number of reallocations required to grow items in a pool should decrease, amortizing reallocations over the lifetime of the program.

Of course, this means that it is technically possible for the allocated capacity of the pool to grow infinitely, which can cause a memory leak if used incorrectly. Therefore, it is also possible to set an upper bound on idle capacity, using with_max_capacity. When such a bound is set, recycled elements will be shrunk down to that capacity if they have grown past the upper bound while in use. If this is the case, reallocations may occur more often, but if the upper bound is higher than the typical required capacity, they should remain infrequent.

If elements will not require allocations of differing sizes, and the size is known in advance (e.g. a pool of HashMaps that always have exactly 64 elements), the with_max_capacity and with_min_capacity methods can be called with the same value. This way, elements will always be initially allocated with exactly that much capacity, and will only be shrunk if they ever exceed that capacity. If the elements never grow beyond the specified capacity, this should mean that no additional allocations will ever occur once the initial pool of elements are allocated.

Implementations§

source§

impl WithCapacity

source

pub const fn new() -> Self

Returns a new WithCapacity.

By default, the maximum capacity is unconstrained, and the minimum capacity is 0. Existing allocations will always be reused, regardless of size, and new elements will be created with 0 capacity.

To add an upper bound on re-used capacity, use WithCapacity::with_max_capacity. To allocate elements with an initial capacity, use WithCapacity::with_min_capacity.

source

pub const fn with_max_capacity(self, max: usize) -> Self

Sets an upper bound on the capacity that will be reused when recycling elements.

When an element is recycled, if its capacity exceeds the max value, it will be shrunk down to that capacity. This will result in a reallocation, but limits the total capacity allocated by the pool, preventing unbounded memory use.

Elements may still exceed the configured max capacity while they are in use; this value only configures what happens when they are returned to the pool.

§Examples
use thingbuf::recycling::{Recycle, WithCapacity};

// Create a recycler with max capacity of 8.
let recycle = WithCapacity::new().with_max_capacity(8);

// Create a new string using that recycler.
let mut s: String = recycle.new_element();
assert_eq!(s.capacity(), 0);

// Now, write some data to the string.
s.push_str("hello, world");

// The string's capacity must be at least the length of the
// string 'hello, world'.
assert!(s.capacity() >= "hello, world".len());

// After recycling the string, its capacity will be shrunk down
// to the configured max capacity.
recycle.recycle(&mut s);
assert_eq!(s.capacity(), 8);
source

pub const fn with_min_capacity(self, min: usize) -> Self

Sets the minimum capacity when allocating new elements.

When new elements are created, they will be allocated with at least min capacity.

Note that this is a lower bound. Elements may be allocated with greater than the minimum capacity, depending on the behavior of the element being allocated, but there will always be at least min capacity.

§Examples
use thingbuf::recycling::{Recycle, WithCapacity};

// A recycler without a minimum capacity.
let no_min = WithCapacity::new();

// A new element created by this recycler will not
// allocate any capacity until it is used.
let s: String = no_min.new_element();
assert_eq!(s.capacity(), 0);

// Now, configure a minimum capacity.
let with_min = WithCapacity::new().with_min_capacity(8);

// New elements created by this recycler will always be allocated
// with at least the specified capacity.
let s: String = with_min.new_element();
assert!(s.capacity() >= 8);
source

pub fn min_capacity(&self) -> usize

Returns the minimum initial capacity when allocating new elements.

This method can be used to implement Recycle<T> for WithCapacity where T is a type defined outside of this crate. See the WithCapacity documentation for details.

§Examples
use thingbuf::recycling::{Recycle, WithCapacity};

let recycle = WithCapacity::new();
assert_eq!(recycle.min_capacity(), 0);
use thingbuf::recycling::{Recycle, WithCapacity};

let recycle = WithCapacity::new().with_min_capacity(64);
assert_eq!(recycle.min_capacity(), 64);
source

pub fn max_capacity(&self) -> usize

Returns the maximum retained capacity when recycling elements.

If no upper bound is configured, this will return usize::MAX.

This method can be used to implement Recycle<T> for WithCapacity where T is a type defined outside of this crate. See the WithCapacity documentation for details.

§Examples
use thingbuf::recycling::{Recycle, WithCapacity};

let recycle = WithCapacity::new();
assert_eq!(recycle.max_capacity(), usize::MAX);
use thingbuf::recycling::{Recycle, WithCapacity};

let recycle = WithCapacity::new().with_max_capacity(64);
assert_eq!(recycle.max_capacity(), 64);

Trait Implementations§

source§

impl Clone for WithCapacity

source§

fn clone(&self) -> WithCapacity

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for WithCapacity

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for WithCapacity

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<T: Ord> Recycle<BinaryHeap<T>> for WithCapacity

Available on crate feature alloc only.
source§

fn new_element(&self) -> BinaryHeap<T>

Returns a new instance of type T. Read more
source§

fn recycle(&self, element: &mut BinaryHeap<T>)

Prepares element element for reuse. Read more
source§

impl<K, V, S> Recycle<HashMap<K, V, S>> for WithCapacity
where K: Hash + Eq, S: BuildHasher + Default,

Available on crate feature std only.
source§

fn new_element(&self) -> HashMap<K, V, S>

Returns a new instance of type T. Read more
source§

fn recycle(&self, element: &mut HashMap<K, V, S>)

Prepares element element for reuse. Read more
source§

impl<K, S> Recycle<HashSet<K, S>> for WithCapacity
where K: Hash + Eq, S: BuildHasher + Default,

Available on crate feature std only.
source§

fn new_element(&self) -> HashSet<K, S>

Returns a new instance of type T. Read more
source§

fn recycle(&self, element: &mut HashSet<K, S>)

Prepares element element for reuse. Read more
source§

impl Recycle<String> for WithCapacity

Available on crate feature alloc only.
source§

fn new_element(&self) -> String

Returns a new instance of type T. Read more
source§

fn recycle(&self, element: &mut String)

Prepares element element for reuse. Read more
source§

impl<T> Recycle<Vec<T>> for WithCapacity

Available on crate feature alloc only.
source§

fn new_element(&self) -> Vec<T>

Returns a new instance of type T. Read more
source§

fn recycle(&self, element: &mut Vec<T>)

Prepares element element for reuse. Read more
source§

impl<T> Recycle<VecDeque<T>> for WithCapacity

Available on crate feature alloc only.
source§

fn new_element(&self) -> VecDeque<T>

Returns a new instance of type T. Read more
source§

fn recycle(&self, element: &mut VecDeque<T>)

Prepares element element for reuse. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.