[−][src]Struct sized_chunks::sized_chunk::Chunk
A fixed capacity smart array.
An inline array of items with a variable length but a fixed, preallocated
capacity given by the N
type, which must be an Unsigned
type
level numeral.
It's 'smart' because it's able to reorganise its contents based on expected
behaviour. If you construct one using push_back
, it will be laid out like
a Vec
with space at the end. If you push_front
it will start filling in
values from the back instead of the front, so that you still get linear time
push as long as you don't reverse direction. If you do, and there's no room
at the end you're pushing to, it'll shift its contents over to the other
side, creating more space to push into. This technique is tuned for
Chunk
's expected use case in im::Vector: usually, chunks always see
either push_front
or push_back
, but not both unless they move around
inside the tree, in which case they're able to reorganise themselves with
reasonable efficiency to suit their new usage patterns.
It maintains a left
index and a right
index instead of a simple length
counter in order to accomplish this, much like a ring buffer would, except
that the Chunk
keeps all its items sequentially in memory so that you can
always get a &[A]
slice for them, at the price of the occasional
reordering operation. The allocated size of a Chunk
is thus usize
* 2 +
A
* N
.
This technique also lets us choose to shift the shortest side to account for
the inserted or removed element when performing insert and remove
operations, unlike Vec
where you always need to shift the right hand side.
Unlike a Vec
, the Chunk
has a fixed capacity and cannot grow beyond it.
Being intended for low level use, it expects you to know or test whether
you're pushing to a full array, and has an API more geared towards panics
than returning Option
s, on the assumption that you know what you're doing.
Of course, if you don't, you can expect it to panic immediately rather than
do something undefined and usually bad.
Isn't this just a less efficient ring buffer?
You might be wondering why you would want to use this data structure rather
than a RingBuffer
, which is similar but doesn't need to
shift its content around when it hits the sides of the allocated buffer. The
answer is that Chunk
can be dereferenced into a slice, while a ring buffer
can not. You'll also save a few cycles on index lookups, as a Chunk
's data
is guaranteed to be contiguous in memory, so there's no need to remap logical
indices to a ring buffer's physical layout.
Examples
// Construct a chunk with a 64 item capacity let mut chunk = Chunk::<i32, U64>::new(); // Fill it with descending numbers chunk.extend((0..64).rev()); // It derefs to a slice so we can use standard slice methods chunk.sort(); // It's got all the amenities like `FromIterator` and `Eq` let expected: Chunk<i32, U64> = (0..64).collect(); assert_eq!(expected, chunk);
Methods
impl<A, N> Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
pub const CAPACITY: usize
[src]
The maximum number of elements this Chunk
can contain.
pub fn new() -> Self
[src]
Construct a new empty chunk.
pub fn unit(value: A) -> Self
[src]
Construct a new chunk with one item.
pub fn pair(left: A, right: A) -> Self
[src]
Construct a new chunk with two items.
pub fn drain_from(other: &mut Self) -> Self
[src]
Construct a new chunk and move every item from other
into the new
chunk.
Time: O(n)
pub fn collect_from<I>(iter: &mut I, count: usize) -> Self where
I: Iterator<Item = A>,
[src]
I: Iterator<Item = A>,
Construct a new chunk and populate it by taking count
items from the
iterator iter
.
Panics if the iterator contains less than count
items.
Time: O(n)
pub fn from_front(other: &mut Self, count: usize) -> Self
[src]
Construct a new chunk and populate it by taking count
items from the
front of other
.
Time: O(n) for the number of items moved
pub fn from_back(other: &mut Self, count: usize) -> Self
[src]
Construct a new chunk and populate it by taking count
items from the
back of other
.
Time: O(n) for the number of items moved
pub fn len(&self) -> usize
[src]
Get the length of the chunk.
pub fn is_empty(&self) -> bool
[src]
Test if the chunk is empty.
pub fn is_full(&self) -> bool
[src]
Test if the chunk is at capacity.
pub fn push_front(&mut self, value: A)
[src]
Push an item to the front of the chunk.
Panics if the capacity of the chunk is exceeded.
Time: O(1) if there's room at the front, O(n) otherwise
pub fn push_back(&mut self, value: A)
[src]
Push an item to the back of the chunk.
Panics if the capacity of the chunk is exceeded.
Time: O(1) if there's room at the back, O(n) otherwise
pub fn pop_front(&mut self) -> A
[src]
Pop an item off the front of the chunk.
Panics if the chunk is empty.
Time: O(1)
pub fn pop_back(&mut self) -> A
[src]
Pop an item off the back of the chunk.
Panics if the chunk is empty.
Time: O(1)
pub fn drop_left(&mut self, index: usize)
[src]
Discard all items up to but not including index
.
Panics if index
is out of bounds.
Time: O(n) for the number of items dropped
pub fn drop_right(&mut self, index: usize)
[src]
Discard all items from index
onward.
Panics if index
is out of bounds.
Time: O(n) for the number of items dropped
pub fn split_off(&mut self, index: usize) -> Self
[src]
Split a chunk into two, the original chunk containing
everything up to index
and the returned chunk containing
everything from index
onwards.
Panics if index
is out of bounds.
Time: O(n) for the number of items in the new chunk
pub fn append(&mut self, other: &mut Self)
[src]
Remove all items from other
and append them to the back of self
.
Panics if the capacity of the chunk is exceeded.
Time: O(n) for the number of items moved
pub fn drain_from_front(&mut self, other: &mut Self, count: usize)
[src]
Remove count
items from the front of other
and append them to the
back of self
.
Panics if self
doesn't have count
items left, or if other
has
fewer than count
items.
Time: O(n) for the number of items moved
pub fn drain_from_back(&mut self, other: &mut Self, count: usize)
[src]
Remove count
items from the back of other
and append them to the
front of self
.
Panics if self
doesn't have count
items left, or if other
has
fewer than count
items.
Time: O(n) for the number of items moved
pub fn set(&mut self, index: usize, value: A) -> A
[src]
Update the value at index index
, returning the old value.
Panics if index
is out of bounds.
Time: O(1)
pub fn insert(&mut self, index: usize, value: A)
[src]
Insert a new value at index index
, shifting all the following values
to the right.
Panics if the index is out of bounds or the chunk is full.
Time: O(n) for the number of elements shifted
pub fn insert_ordered(&mut self, value: A) where
A: Ord,
[src]
A: Ord,
Insert a new value into the chunk in sorted order.
This assumes every element of the chunk is already in sorted order. If not, the value will still be inserted but the ordering is not guaranteed.
Time: O(log n) to find the insert position, then O(n) for the number of elements shifted.
Examples
let mut chunk = Chunk::<i32, U64>::from_iter(0..5); chunk.insert_ordered(3); assert_eq!(&[0, 1, 2, 3, 3, 4], chunk.as_slice());
pub fn insert_from<Iterable, I>(&mut self, index: usize, iter: Iterable) where
Iterable: IntoIterator<Item = A, IntoIter = I>,
I: ExactSizeIterator<Item = A>,
[src]
Iterable: IntoIterator<Item = A, IntoIter = I>,
I: ExactSizeIterator<Item = A>,
Insert multiple values at index index
, shifting all the following values
to the right.
Panics if the index is out of bounds or the chunk doesn't have room for all the values.
Time: O(m+n) where m is the number of elements inserted and n is the number
of elements following the insertion index. Calling insert
repeatedly would be O(m*n).
pub fn remove(&mut self, index: usize) -> A
[src]
Remove the value at index index
, shifting all the following values to
the left.
Returns the removed value.
Panics if the index is out of bounds.
Time: O(n) for the number of items shifted
pub fn drain(&mut self) -> Drain<A, N>
[src]
Construct an iterator that drains values from the front of the chunk.
pub fn clear(&mut self)
[src]
Discard the contents of the chunk.
Time: O(n)
pub fn as_slice(&self) -> &[A]
[src]
Get a reference to the contents of the chunk as a slice.
pub fn as_mut_slice(&mut self) -> &mut [A]
[src]
Get a reference to the contents of the chunk as a mutable slice.
Trait Implementations
impl<A, N> Arbitrary for Chunk<A, N> where
A: Arbitrary,
N: ChunkLength<A> + 'static,
[src]
A: Arbitrary,
N: ChunkLength<A> + 'static,
fn arbitrary(u: &mut Unstructured) -> Result<Self>
[src]
fn arbitrary_take_rest(u: Unstructured) -> Result<Self>
[src]
fn size_hint(depth: usize) -> (usize, Option<usize>)
[src]
fn shrink(&self) -> Box<dyn Iterator<Item = Self>>
[src]
impl<A, N> AsMut<[A]> for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
impl<A, N> AsRef<[A]> for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
impl<A, N> Borrow<[A]> for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
impl<A, N> BorrowMut<[A]> for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
fn borrow_mut(&mut self) -> &mut [A]
[src]
impl<A, N> Clone for Chunk<A, N> where
A: Clone,
N: ChunkLength<A>,
[src]
A: Clone,
N: ChunkLength<A>,
fn clone(&self) -> Self
[src]
fn clone_from(&mut self, source: &Self)
1.0.0[src]
impl<A, N> Debug for Chunk<A, N> where
A: Debug,
N: ChunkLength<A>,
[src]
A: Debug,
N: ChunkLength<A>,
impl<A, N> Default for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
impl<A, N> Deref for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
impl<A, N> DerefMut for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
impl<A, N> Drop for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
impl<A, N> Eq for Chunk<A, N> where
A: Eq,
N: ChunkLength<A>,
[src]
A: Eq,
N: ChunkLength<A>,
impl<'a, A, N> Extend<&'a A> for Chunk<A, N> where
A: 'a + Copy,
N: ChunkLength<A>,
[src]
A: 'a + Copy,
N: ChunkLength<A>,
fn extend<I>(&mut self, it: I) where
I: IntoIterator<Item = &'a A>,
[src]
I: IntoIterator<Item = &'a A>,
Append the contents of the iterator to the back of the chunk.
Panics if the chunk exceeds its capacity.
Time: O(n) for the length of the iterator
impl<A, N> Extend<A> for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
fn extend<I>(&mut self, it: I) where
I: IntoIterator<Item = A>,
[src]
I: IntoIterator<Item = A>,
Append the contents of the iterator to the back of the chunk.
Panics if the chunk exceeds its capacity.
Time: O(n) for the length of the iterator
impl<'a, A, N, T> From<&'a mut InlineArray<A, T>> for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
fn from(array: &mut InlineArray<A, T>) -> Self
[src]
impl<A, N, T> From<InlineArray<A, T>> for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
fn from(array: InlineArray<A, T>) -> Self
[src]
impl<A, N> FromIterator<A> for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
fn from_iter<I>(it: I) -> Self where
I: IntoIterator<Item = A>,
[src]
I: IntoIterator<Item = A>,
impl<A, N> Hash for Chunk<A, N> where
A: Hash,
N: ChunkLength<A>,
[src]
A: Hash,
N: ChunkLength<A>,
fn hash<H>(&self, hasher: &mut H) where
H: Hasher,
[src]
H: Hasher,
fn hash_slice<H>(data: &[Self], state: &mut H) where
H: Hasher,
1.3.0[src]
H: Hasher,
impl<A, N, I> Index<I> for Chunk<A, N> where
I: SliceIndex<[A]>,
N: ChunkLength<A>,
[src]
I: SliceIndex<[A]>,
N: ChunkLength<A>,
type Output = I::Output
The returned type after indexing.
fn index(&self, index: I) -> &Self::Output
[src]
impl<A, N, I> IndexMut<I> for Chunk<A, N> where
I: SliceIndex<[A]>,
N: ChunkLength<A>,
[src]
I: SliceIndex<[A]>,
N: ChunkLength<A>,
impl<'a, A, N> IntoIterator for &'a Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
type Item = &'a A
The type of the elements being iterated over.
type IntoIter = SliceIter<'a, A>
Which kind of iterator are we turning this into?
fn into_iter(self) -> Self::IntoIter
[src]
impl<'a, A, N> IntoIterator for &'a mut Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
type Item = &'a mut A
The type of the elements being iterated over.
type IntoIter = SliceIterMut<'a, A>
Which kind of iterator are we turning this into?
fn into_iter(self) -> Self::IntoIter
[src]
impl<A, N> IntoIterator for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
type Item = A
The type of the elements being iterated over.
type IntoIter = Iter<A, N>
Which kind of iterator are we turning this into?
fn into_iter(self) -> Self::IntoIter
[src]
impl<A, N> Ord for Chunk<A, N> where
A: Ord,
N: ChunkLength<A>,
[src]
A: Ord,
N: ChunkLength<A>,
fn cmp(&self, other: &Self) -> Ordering
[src]
#[must_use]
fn max(self, other: Self) -> Self
1.21.0[src]
#[must_use]
fn min(self, other: Self) -> Self
1.21.0[src]
#[must_use]
fn clamp(self, min: Self, max: Self) -> Self
[src]
impl<A, N, Slice> PartialEq<Slice> for Chunk<A, N> where
Slice: Borrow<[A]>,
A: PartialEq,
N: ChunkLength<A>,
[src]
Slice: Borrow<[A]>,
A: PartialEq,
N: ChunkLength<A>,
impl<A, N> PartialOrd<Chunk<A, N>> for Chunk<A, N> where
A: PartialOrd,
N: ChunkLength<A>,
[src]
A: PartialOrd,
N: ChunkLength<A>,
fn partial_cmp(&self, other: &Self) -> Option<Ordering>
[src]
#[must_use]
fn lt(&self, other: &Rhs) -> bool
1.0.0[src]
#[must_use]
fn le(&self, other: &Rhs) -> bool
1.0.0[src]
#[must_use]
fn gt(&self, other: &Rhs) -> bool
1.0.0[src]
#[must_use]
fn ge(&self, other: &Rhs) -> bool
1.0.0[src]
impl<A, N> PoolClone for Chunk<A, N> where
A: Clone,
N: ChunkLength<A>,
[src]
A: Clone,
N: ChunkLength<A>,
unsafe fn clone_uninit(&self, target: &mut MaybeUninit<Self>)
[src]
impl<A, N> PoolDefault for Chunk<A, N> where
N: ChunkLength<A>,
[src]
N: ChunkLength<A>,
unsafe fn default_uninit(target: &mut MaybeUninit<Self>)
[src]
impl<N: ChunkLength<u8>> Read for Chunk<u8, N>
[src]
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
[src]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut]) -> Result<usize, Error>
1.36.0[src]
unsafe fn initializer(&self) -> Initializer
[src]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, Error>
1.0.0[src]
fn read_to_string(&mut self, buf: &mut String) -> Result<usize, Error>
1.0.0[src]
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error>
1.6.0[src]
fn by_ref(&mut self) -> &mut Self
1.0.0[src]
fn bytes(self) -> Bytes<Self>
1.0.0[src]
fn chain<R>(self, next: R) -> Chain<Self, R> where
R: Read,
1.0.0[src]
R: Read,
fn take(self, limit: u64) -> Take<Self>
1.0.0[src]
impl<N> Write for Chunk<u8, N> where
N: ChunkLength<u8>,
[src]
N: ChunkLength<u8>,
fn write(&mut self, buf: &[u8]) -> Result<usize>
[src]
fn flush(&mut self) -> Result<()>
[src]
fn write_vectored(&mut self, bufs: &[IoSlice]) -> Result<usize, Error>
1.36.0[src]
fn write_all(&mut self, buf: &[u8]) -> Result<(), Error>
1.0.0[src]
fn write_fmt(&mut self, fmt: Arguments) -> Result<(), Error>
1.0.0[src]
fn by_ref(&mut self) -> &mut Self
1.0.0[src]
Auto Trait Implementations
impl<A, N> RefUnwindSafe for Chunk<A, N> where
<N as ChunkLength<A>>::SizedType: RefUnwindSafe,
<N as ChunkLength<A>>::SizedType: RefUnwindSafe,
impl<A, N> Send for Chunk<A, N> where
<N as ChunkLength<A>>::SizedType: Send,
<N as ChunkLength<A>>::SizedType: Send,
impl<A, N> Sync for Chunk<A, N> where
<N as ChunkLength<A>>::SizedType: Sync,
<N as ChunkLength<A>>::SizedType: Sync,
impl<A, N> Unpin for Chunk<A, N> where
<N as ChunkLength<A>>::SizedType: Unpin,
<N as ChunkLength<A>>::SizedType: Unpin,
impl<A, N> UnwindSafe for Chunk<A, N> where
<N as ChunkLength<A>>::SizedType: UnwindSafe,
<N as ChunkLength<A>>::SizedType: UnwindSafe,
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<I> IntoIterator for I where
I: Iterator,
[src]
I: Iterator,
type Item = <I as Iterator>::Item
The type of the elements being iterated over.
type IntoIter = I
Which kind of iterator are we turning this into?
fn into_iter(self) -> I
[src]
impl<A> PoolClone for A where
A: PoolDefaultImpl + Clone,
A: PoolDefaultImpl + Clone,
unsafe fn clone_uninit(&self, target: &mut MaybeUninit<A>)
impl<A> PoolDefault for A where
A: PoolDefaultImpl,
A: PoolDefaultImpl,
unsafe fn default_uninit(target: &mut MaybeUninit<A>)
impl<T> Same<T> for T
[src]
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]
T: Clone,
type Owned = T
The resulting type after obtaining ownership.
fn to_owned(&self) -> T
[src]
fn clone_into(&self, target: &mut T)
[src]
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,