-
Notifications
You must be signed in to change notification settings - Fork 13.9k
Description
The behaviour of the .reserve_at_least is much better asymptotically, since calling .reserve in a loop will cause quadratic behaviour. We should be using the short method name to encourage the faster behaviour.
.reserve(n) allocates exactly enough capacity to store n elements (if there isn't enough space already), while .reserve_at_least(n) will ensure that there is enough space, but overallocate to ensure that reallocations don't occur too often (i.e. increase the allocation size exponentially).
e.g. imagine a protocol which consists of a sets of messages, where set block as an initial message with the count for that set:
let received = ~[];
let mut total_messages = 0;
while listener.more_messages() {
let next_count = listener.recv();
total_messages += next_count;
// we know how many we're going to have total, so
// might as well allocate it up-front.
received.reserve(total_messages);
for _ in range(0, next_count) {
received.push(listener.recv());
}
}using (the current) .reserve causes every single set to do a reallocation and memcpy (i.e. O(n^2) behaviour), while using .reserve_at_least would mean the reallocation and memcpy only happens logarithmically often, preserving O(n) asymptotics.
(For vector specifically the above should really be using .reserve_additional, but other types like ~str and extra::{priority_queue, ring_buf} suffer the same problem.)