Struct granite::SparseStorage[][src]

pub struct SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
{ /* fields omitted */ }

A wrapper around a list-like storage type which considerably improves performance when removing elements.

Sparse storage with element type E wraps a normal storage which stores Slot<E>, which is a tagged union storing either an element or a “hole”. Those holes count as regular elements, but trying to get their value produces a panic, since the storage provides E as its element type, rather than Slot<E>. This behavior does not depend on whether checked or unchecked get/get_mut methods are used - all of those are guaranteed to panic upon fetching a hole.

When remove_and_shiftfix is called, elements are not actually shifted, but the element is replaced with a hole. If the elements of the storage store indicies towards other elements of the storage, they don’t get invalidated.

Example

use granite::{
    ListStorage, // ListStorage trait, for interfacing with the sparse
                 // storage's generic list-like storage capabilities
    SparseVec, // A sparse storage type definition for Vec
    DummyMoveFix, // Utility struct to have elements which can be removed with
                  // a move fix but which actually don't react to the hooks at all.
};

// Use the new() method from the Storage trait to create a sparse storage:
let mut storage = SparseVec::<DummyMoveFix<u32>>::new();
// Or, the with_capacity() method to preallocate some space for the elements:
let mut storage = SparseVec::<DummyMoveFix<u32>>::with_capacity(32);

// Let's put some elements in!
storage.add(0.into());
storage.add(1.into());
storage.add(2.into());

// Now that we have some elements, we can remove the one in the
// middle to create a hole, and see what sparse storage is about.
let val = storage.remove_and_shiftfix(1);
assert_eq!(val, 1);

// Let's check the length of the storage:
let len = storage.len();
// It hasn't changed, because the element from the wrapped storage wasn't actually removed...
assert_eq!(len, 3);

// ...but instead dropped and turned into a hole:
let num_holes = storage.num_holes();
assert_eq!(num_holes, 1);

// Let's remove yet another element:
let val = storage.remove_and_shiftfix(2);
assert_eq!(val, 2);
// It's the third element (index 2), because removing the
// previous one did not shift the elements from their indicies.

// The previous hole is still there, and we have a new one:
let num_holes = storage.num_holes();
assert_eq!(num_holes, 2);

// Let's remove the holes from the storage entirely:
storage.defragment();
// We could've called defragment_and_fix, but since we have
// the dummy move fix wrapper, that wouldn't make a difference.

// The holes are gone!
let num_holes = storage.num_holes();
assert_eq!(num_holes, 0);
// We can also use the is_dense() method to check for this:
assert!(storage.is_dense());
// The method is specific to sparse storage and is not a part of the Storage trait.

Implementations

impl<E, S> SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
[src]

pub fn defragment(&mut self)[src]

Removes all holes from the sparse storage, without fixing elements’ indicies. This is an expensive operation and should only be called if is_dense is false to avoid needless overhead.

pub fn defragment_and_fix(&mut self) where
    E: MoveFix
[src]

Removes all holes from the sparse storage, fixing elements’ indicies. This is an expensive operation and should only be called if is_dense is false to avoid needless overhead.

pub fn into_inner(self) -> S[src]

Consumes the sparse storage and returns its inner storage.

pub fn num_holes(&self) -> usize[src]

Returns the number of holes in the storage. This operation returns immediately instead of looping through the entire storage, since the sparse storage automatically tracks the number of holes it creates and destroys.

pub fn is_dense(&self) -> bool[src]

Returns true if there are no holes in the storage, false otherwise. This operation returns immediately instead of looping through the entire storage, since the sparse storage automatically tracks the number of holes it creates and destroys.

Trait Implementations

impl<E: Clone, S: Clone> Clone for SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
[src]

impl<E: Copy, S: Copy> Copy for SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
[src]

impl<E: Debug, S: Debug> Debug for SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
[src]

impl<E: Default, S: Default> Default for SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
[src]

impl<E: Eq, S: Eq> Eq for SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
[src]

impl<E, S> ListStorage for SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
[src]

type Element = E

The type of values in the container.

impl<E: PartialEq, S: PartialEq> PartialEq<SparseStorage<E, S>> for SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
[src]

impl<E, S> StructuralEq for SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
[src]

impl<E, S> StructuralPartialEq for SparseStorage<E, S> where
    S: ListStorage<Element = Slot<E>>, 
[src]

Auto Trait Implementations

impl<E, S> RefUnwindSafe for SparseStorage<E, S> where
    S: RefUnwindSafe

impl<E, S> Send for SparseStorage<E, S> where
    S: Send

impl<E, S> Sync for SparseStorage<E, S> where
    S: Sync

impl<E, S> Unpin for SparseStorage<E, S> where
    S: Unpin

impl<E, S> UnwindSafe for SparseStorage<E, S> where
    S: UnwindSafe

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Slottable for T where
    T: Copy
[src]

impl<T, E> Storage for T where
    T: ListStorage<Element = E>,
    E: MoveFix
[src]

type Key = usize

The type used for element naming.

type Element = E

The type of the elements stored.

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

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

The type returned in the event of a conversion error.