What's the difference between len() and capacity()? - rust

When I create a vector, the length and the capacity are the same. What is the difference between these methods?
fn main() {
let vec = vec![1, 2, 3, 4, 5];
println!("Length: {}", vec.len()); // Length: 5
println!("Capacity: {}", vec.capacity()); // Capacity: 5
}

Growable vectors reserve space for future additions, hence the difference between allocated space (capacity) and actually used space (length).
This is explained in the standard library's documentation for Vec:
The capacity of a vector is the amount of space allocated for any future elements that will be added onto the vector. This is not to be confused with the length of a vector, which specifies the number of actual elements within the vector. If a vector's length exceeds its capacity, its capacity will automatically be increased, but its elements will have to be reallocated.
For example, a vector with capacity 10 and length 0 would be an empty vector with space for 10 more elements. Pushing 10 or fewer elements onto the vector will not change its capacity or cause reallocation to occur. However, if the vector's length is increased to 11, it will have to reallocate, which can be slow. For this reason, it is recommended to use Vec::with_capacity whenever possible to specify how big the vector is expected to get.

len() returns the number of elements in the vector (i.e., the vector's length). In the example below, vec contains 5 elements, so len() returns 5.
capacity() returns the number of elements the vector can hold (without reallocating memory). In the example below, vec can hold 105 elements, since we use reserve() to allocate at least 100 slots in addition to the original 5 (more might be allocated in order to minimize the number of allocations).
fn main() {
let mut vec = vec![1, 2, 3, 4, 5];
vec.reserve(100);
assert!(vec.len() == 5);
assert!(vec.capacity() >= 105);
}

Related

Capacity of vectors created with macro

let vec_macro = vec![0, 1, 2, 3, 4];
let mut vec = Vec::new();
for i in 0..5 {
vec.push(i)
}
println!("Capacity of vec with macro: {}", vec_macro.capacity());
println!("Capacity of vec push: {}", vec.capacity());
// Result:
// Capacity of vec with macro: 5
// Capacity of vec push: 8
I created 2 vectors, first one with macro vec! and the second one with Vec::new(), then I push item from 0 to 4 into them. The expected result is the capacity of these two vectors are the same, but it's not. Is this the bug in the implementation of vec!?
The macro knows the number of elements, so it creates the vector with the optimal capacity (see also with_capacity()).
Your loop invokes push() several times, but this operation does not know by itself when we will stop pushing elements.
So the strategy behind this is to amortize the cost of dynamic memory reallocation with an exponential capacity (0, 4, 8, 16, 32... for example on my computer).
When you push very few elements, the capacity stays low (we do not waste too much unused allocated memory), but if you push many elements, the reallocations will grow by bigger and bigger steps in order to happen not too often.
At the moment, we see that it simply doubles the capacity (whatever it is) when it is exhausted.
If we start from zero then just push, it seems to choose 4 as initial capacity then doubles it as needed, but if we start with 5 it will still continue to double the capacity (10, 20...).
However, what we see now is not guaranteed and might change at any time in future releases.
vec![a, b, ...] is not the same as a repeated push. If you look at the source code for the macro, it looks like this:
($($x:expr),+ $(,)?) => (
$crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+]))
);
The important part is the <[_]>::into_vec(box [$($x),+]):
box [$($x),+] is special syntax to create a "boxed slice" directly on the heap, as opposed to creating it on the stack and then moving it to the heap
<[_]>::into_vec calls slice::into_vec
If we look at the source code of into_vec:
pub fn into_vec<T, A: Allocator>(b: Box<[T], A>) -> Vec<T, A> {
unsafe {
let len = b.len();
let (b, alloc) = Box::into_raw_with_allocator(b);
Vec::from_raw_parts_in(b as *mut T, len, len, alloc)
}
}
And the signature of Vec::from_raw_parts_in:
pub unsafe fn from_raw_parts_in(
ptr: *mut T,
length: usize,
capacity: usize,
alloc: A
) -> Self;
You can see that the slice length is passed as both the Vec length and capacity.
The Vec documentation specifies this behavior of the macro:
vec![x; n], vec![a, b, c, d], and
[Vec::with_capacity(n)][Vec::with_capacity], will all produce a Vec
with exactly the requested capacity. If [len] == [capacity],
(as is the case for the [vec!] macro), then a Vec<T> can be converted to
and from a [Box<[T]>][owned slice] without reallocating or moving the elements.
As prog-fh said, Vec::push will exponentially reallocate when necessary, and will not end on a capacity of 5 unless you otherwise set the capacity manually via with_capacity or otherwise. It should be noted that this exponential growth is an implementation detail, not guaranteed by the Vec documentation.

What does it mean for all values of a type must use the same amount of memory in Rust?

Forgive me if there is an obvious answer to the question I'm asking, but I just don't quite understand it.
The Dynamically Sized Types and the Sized Trait section in chapter 19.3 Advanced Types of the 《The Rust Programming Language》 mentions:
Rust needs to know how much memory to allocate for any value of a particular type, and all values of a type must use the same amount of memory. If Rust allowed us to write this code, these two str values would need to take up the same amount of space. But they have different lengths: s1 needs 12 bytes of storage and s2 needs 15. This is why it’s not possible to create a variable holding a dynamically sized type.
When it says "and all values of a type must use the same amount of memory", it is meant to refer to dynamically sized types, not types such as vectors or arrays, right? v1 and v2 are also unlikely to occupy the same amount of memory.
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3, 4, 5, 6];
It's correct and considers vectors as well. A Vec<T> is roughly just a pointer to a position on the heap, a capacity, and a length. It could be defined, more or less, as
pub struct Vec<T>(T*, usize, usize);
And every value of that structure clearly has the same size. When Rust says that every value of a type has to have the same size, it only refers to the size of the structure itself, not to the recursive size of all things it points to. Box<T> has a constant size, regardless of T, which is why Box can hold even things that are dynamically sized, such as trait objects. Likewise, String is basically just a pointer.
Likewise, if we define
pub enum MyEnum {
A(i32),
B(i32, i32),
}
Then MyEnum::A is no smaller than MyEnum::B, for similar reasons, despite the latter having more data than the former.
Every type that can be stored and accessed without the indirection of a reference or Box must have the Sized trait implemented. This means that every instance of the type will have the same size. A str is a DST, as the data it holds can be of a variable length, and thus, you can only access strs as references, or from String, which holds the str data on the heap, through a pointer.
Every Vec also takes the same space, which is 24 bytes on a 64-bit machine.
For example:
let vec = vec![1, 2, 3, 4];
println!("{}", std::mem::size_of_val(&vec)); // Prints '24'.

Is there a way to partition a vector into odd and even numbers in place?

Is there an easy way to find all of the even numbers and move them all to the end of vector? The order doesn't matter, all that matters is that evens were moved to the end. However, it would be nice if order was preserved.
For example: [1, 2, 3, 4, 5] => [1, 3, 5, 2, 4]
I'd like to have the signature pub fn move_by_filter(nums: &mut Vec<i32>).
I tried to filter and combine vector slices, but I am running into a problem combining array slices:
let evens = nums.iter().filter(|&&i| i % 2 == 0).collect::<Vec<_>>();
let odds = nums.iter().filter(|&&i| i % 2 != 0).collect::<Vec<_>>();
// then I want to do something like: nums = odds.push(evens)
This doesn't push them to the end of the vector.
I'm not sure if it is the best approach since I have to use iter() twice (which is O(N) + O(N) I think, but would like to do it in one operation if possible)
The easiest solution is to sort the vector with a custom sort key:
pub fn sort_by_parity(nums: &mut [i32]) {
nums.sort_by_key(|&x| x % 2 == 0);
}
Rust's standard sort algorithm is stable, so this will preserve the original order of the odd and even numbers.
The closure passed to create sort keys evaluates to false for odd numbers and to true for even numbers. This makes sure that all odd numbers are sorted before the even numbers.
Instead of accepting a mutable reference to a vector, this function accepts a mutable slice reference, which is more generic.
The runtime of this approach is O(n log n), which is not optimal for in-place partitioning. You can achieve linear runtime, O(n), e.g. using the partition() method:
pub fn partition_by_parity(nums: &mut [i32]) {
let (even, odd): (Vec<_>, Vec<_>) = nums.iter().partition(|&x| x % 2 == 0);
nums[..odd.len()].copy_from_slice(&odd);
nums[odd.len()..].copy_from_slice(&even);
}
The runtime difference between the two approaches is unlikely to matter in practice.
If you don't require to preserve the original order of the odd and even elements, you can partition the slice in place in linear time, without needing an additional buffer. Rust Nightly offers the unstable partition_in_place() method for this purpose, but it's not too difficult to implement yourself – it's basically the partitioning step in Quicksort.

Reverse order of a reference to immutable array slice

I would like to reverse the order of a slice:
&[1, 2, 3] -> &[3, 2, 1]
This is my code:
fn iterate_over_file(data: &[u8], ...) -> ... {
...
for cur_data in data.chunks(chunk_size) {
let reversed_cur_data = cur_data.reverse() // this returns ()
...
...
}
This data parameter comes from a file I read in using FileBuffer, and I'd like to keep it as a referenced slice (and not turn it into an owned Vec, since it's a heavy computation to make).
How could I reverse the order of cur_data with the minimal amount of operations and memory allocation? Its length is known for a specific runtime of my program (called here chunk_size), but it changes between different runs. reversed() seems to return (), which makes sense as it's done in-place, and I only have a referenced slice. .iter().rev() creates an iterator, but then I'd have to call .next() on it several times to get the slice back, which is both not elegant and not effective, as I have at least tens of millions of cur_data lines per file.
Not only does reverse return (), it also requires a mutable slice, which you do not have. The optimal solution depends on exactly what you need to do with the data. If you only need to iterate over the data, cur_data.iter().rev() is exactly the right and the most efficient choice.
If you need the reversed data inside a slice for further processing, such as to send the reversed chunk to a function that expects a slice, you can collect the data into a vector. To avoid a new allocation for each chunk, you can reuse the same vector across all loop iterations:
let mut reversed = Vec::with_capacity(chunk_size);
for cur_data in data.chunks(chunk_size) {
// truncate the slice at the beginning of each iteration.
// Vec explicitly guarantees that this will *not* deallocate,
// it will only reset its internal length. An allocation will
// thus only happen prior to the loop.
reversed.truncate(0);
reversed.extend(cur_data.iter().rev());
// &reversed is now the reversed_cur_data you need
...
}

What happens if I call Vec::from_raw_parts with a smaller capacity than the pointer actually has?

I have a vector of u8 that I want to interpret as a vector of u32. It is assumed that the bytes are in the right order. I don't want to allocate new memory and copy bytes after casting. I got the following to work:
use std::mem;
fn reinterpret(mut v: Vec<u8>) -> Option<Vec<u32>> {
let v_len = v.len();
v.shrink_to_fit();
if v_len % 4 != 0 {
None
} else {
let v_cap = v.capacity();
let v_ptr = v.as_mut_ptr();
println!("{:?}|{:?}|{:?}", v_len, v_cap, v_ptr);
let v_reinterpret = unsafe { Vec::from_raw_parts(v_ptr as *mut u32, v_len / 4, v_cap / 4) };
println!("{:?}|{:?}|{:?}",
v_reinterpret.len(),
v_reinterpret.capacity(),
v_reinterpret.as_ptr());
println!("{:?}", v_reinterpret);
println!("{:?}", v); // v is still alive, but is same as rebuilt
mem::forget(v);
Some(v_reinterpret)
}
}
fn main() {
let mut v: Vec<u8> = vec![1, 1, 1, 1, 1, 1, 1, 1];
let test = reinterpret(v);
println!("{:?}", test);
}
However, there's an obvious problem here. From the shrink_to_fit documentation:
It will drop down as close as possible to the length but the allocator may still inform the vector that there is space for a few more elements.
Does this mean that my capacity may still not be a multiple of the size of u32 after calling shrink_to_fit? If in from_raw_parts I set capacity to v_len/4 with v.capacity() not an exact multiple of 4, do I leak those 1-3 bytes, or will they go back into the memory pool because of mem::forget on v?
Is there any other problem I am overlooking here?
I think moving v into reinterpret guarantees that it's not accessible from that point on, so there's only one owner from the mem::forget(v) call onwards.
This is an old question, and it looks like it has a working solution in the comments. I've just written up what exactly goes wrong here, and some solutions that one might create/use in today's Rust.
This is undefined behavior
Vec::from_raw_parts is an unsafe function, and thus you must satisfy its invariants, or you invoke undefined behavior.
Quoting from the documentation for Vec::from_raw_parts:
ptr needs to have been previously allocated via String/Vec (at least, it's highly likely to be incorrect if it wasn't).
T needs to have the same size and alignment as what ptr was allocated with. (T having a less strict alignment is not sufficient, the alignment really needs to be equal to satsify the dealloc requirement that memory must be allocated and deallocated with the same layout.)
length needs to be less than or equal to capacity.
capacity needs to be the capacity that the pointer was allocated with.
So, to answer your question, if capacity is not equal to the capacity of the original vec, then you've broken this invariant. This gives you undefined behavior.
Note that the requirement isn't on size_of::<T>() * capacity either, though, which brings us to the next topic.
Is there any other problem I am overlooking here?
Three things.
First, the function as written is disregarding another requirement of from_raw_parts. Specifically, T must have the same size as alignment as the original T. u32 is four times as big as u8, so this again breaks this requirement. Even if capacity*size remains the same, size isn't, and capacity isn't. This function will never be sound as implemented.
Second, even if all of the above was valid, you've also ignored the alignment. u32 must be aligned to 4-byte boundaries, while a Vec<u8> is only guaranteed to be aligned to a 1-byte boundary.
A comment on the OP mentions:
I think on x86_64, misalignment will have performance penalty
It's worth noting that while this may be true of machine language, it is not true for Rust. The rust reference explicitly states "A value of alignment n must only be stored at an address that is a multiple of n." This is a hard requirement.
Why the exact type requirement?
Vec::from_raw_parts seems like it's pretty strict, and that's for a reason. In Rust, the allocator API operates not only on allocation size, but on a Layout, which is the combination of size, number of things, and alignment of individual elements. In C with memalloc, all the allocator can rely upon is that the size is the same, and some minimum alignment. In Rust, though, it's allowed to rely on the entire Layout, and invoke undefined behavior if not.
So in order to correctly deallocate the memory, Vec needs to know the exact type that it was allocated with. By converting a Vec<u32> into Vec<u8>, it no longer knows this information, and so it can no longer properly deallocate this memory.
Alternative - Transforming slices
Vec::from_raw_parts's strictness comes from the fact that it needs to deallocate the memory. If we create a borrowing slice, &[u32] instead, we no longer need to deal with it! There is no capacity when turning a &[u8] into &[u32], so we should be all good, right?
Well, almost. You still have to deal with alignment. Primitives are generally aligned to their size, so a [u8] is only guaranteed to be aligned to 1-byte boundaries, while [u32] must be aligned to a 4-byte boundary.
If you want to chance it, though, and create a [u32] if possible, there's a function for that - <[T]>::align_to:
pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T])
This will trim of any starting and ending misaligned values, and then give you a slice in the middle of your new type. It's unsafe, but the only invariant you need to satisfy is that the elements in the middle slice are valid.
It's sound to reinterpret 4 u8 values as a u32 value, so we're good.
Putting it all together, a sound version of the original function would look like this. This operates on borrowed rather than owned values, but given that reinterpreting an owned Vec is instant-undefined-behavior in any case, I think it's safe to say this is the closest sound function:
use std::mem;
fn reinterpret(v: &[u8]) -> Option<&[u32]> {
let (trimmed_front, u32s, trimmed_back) = unsafe { v.align_to::<u32>() };
if trimmed_front.is_empty() && trimmed_back.is_empty() {
Some(u32s)
} else {
// either alignment % 4 != 0 or len % 4 != 0, so we can't do this op
None
}
}
fn main() {
let mut v: Vec<u8> = vec![1, 1, 1, 1, 1, 1, 1, 1];
let test = reinterpret(&v);
println!("{:?}", test);
}
As a note, this could also be done with std::slice::from_raw_parts rather than align_to. However, that requires manually dealing with the alignment, and all it really gives is more things we need to ensure we're doing right. Well, that and compatibility with older compilers - align_to was introduced in 2018 in Rust 1.30.0, and wouldn't have existed when this question was asked.
Alternative - Copying
If you do need a Vec<u32> for long term data storage, I think the best option is to just allocate new memory. The old memory is allocated for u8s anyways, and wouldn't work.
This can be made fairly simple with some functional programming:
fn reinterpret(v: &[u8]) -> Option<Vec<u32>> {
let v_len = v.len();
if v_len % 4 != 0 {
None
} else {
let result = v
.chunks_exact(4)
.map(|chunk: &[u8]| -> u32 {
let chunk: [u8; 4] = chunk.try_into().unwrap();
let value = u32::from_ne_bytes(chunk);
value
})
.collect();
Some(result)
}
}
First, we use <[T]>::chunks_exact to iterate over chunks of 4 u8s. Next, try_into to convert from &[u8] to [u8; 4]. The &[u8] is guaranteed to be length 4, so this never fails.
We use u32::from_ne_bytes to convert the bytes into a u32 using native endianness. If interacting with a network protocol, or on-disk serialization, then using from_be_bytes or from_le_bytes may be preferable. And finally, we collect to turn our result back into a Vec<u32>.
As a last note, a truly general solution might use both of these techniques. If we change the return type to Cow<'_, [u32]>, we could return aligned, borrowed data if it works, and allocate a new array if it doesn't! Not quite the best of both worlds, but close.

Resources