1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! How the arrays underneath a collection get bigger.
//!
//! `Vec` doubles, and doubling is the right policy while an array is small and
//! the wrong one once it is large. The cost of being wrong is not subtle. A
//! sorted set of six hundred thousand members holds a row array with room for a
//! million and change, because a million and change is the next power of two,
//! and the four hundred thousand rows nobody asked for are ten megabytes of
//! nothing. The name blob under it does the same thing on top of that. Measured
//! on a six hundred thousand member sorted set with sixteen byte members, the
//! slack was thirty of the fifty six bytes an element cost, which is more than
//! everything else in the structure put together.
//!
//! So this doubles under a threshold and grows by an eighth over it. Under the
//! threshold the slack is a handful of kilobytes however wrong the policy is,
//! and the copies are what matter. Over it the copies are amortised either way
//! and the slack is megabytes, so the slack is what matters.
//!
//! # What the eighth costs, and why it is less than it looks
//!
//! Counting bytes moved, an element is copied about nine times over the life of
//! an array that grows by an eighth, against five for a quarter and two for
//! doubling. That is the arithmetic this module used to stop at, and it is the
//! wrong count for exactly the arrays the threshold selects.
//!
//! A growing array is grown with `realloc`, not with an allocate and a copy and
//! a free. Past the system allocator's mmap threshold a block is its own
//! mapping, and growing a mapping is a page table edit rather than a walk over
//! the bytes. glibc does this with `mremap` and macOS does it by remapping the
//! object, and in both cases the cost of the growth stops scaling with the
//! contents of the array and starts scaling with the number of pages, which is
//! three orders of magnitude smaller. So the arrays where nine copies would
//! actually hurt are the arrays where nine copies do not happen.
//!
//! It is not free and it is not guaranteed. glibc raises its own mmap threshold
//! as it sees large blocks freed, so an array can find itself back on the heap
//! where a growth really is a copy, and a mapping can only grow in place if the
//! address after it is unmapped. The claim is not that the eighth is free, it is
//! that the eighth is cheap enough to be worth two bytes a member, and
//! `benches/grow.rs` is where that is checked rather than asserted.
//!
//! # Why not ask for exactly what is needed
//!
//! Because then every insert is a reallocation, and even a page remap is a
//! syscall. A growth factor over one is what keeps an append amortised constant,
//! and the only question is which one.
use size_of;
/// Where doubling stops paying for itself, in bytes of allocation.
///
/// Under this an array's worst case slack is sixty four kilobytes, which is not
/// worth a single extra memcpy to avoid. A server holding a million small
/// collections never reaches it, so the small case keeps `Vec`'s policy exactly.
const DOUBLE_UNDER: usize = 64 * 1024;
/// One over the growth factor past [`DOUBLE_UNDER`].
///
/// An eighth. The worst slack an array can be holding is one over this and the
/// average over the life of the array is half of that, so on a row array of
/// eight byte rows it is one byte a member at the worst point and half a byte
/// on average, against two and one at a quarter.
const OVER_BY: usize = 8;
/// The next capacity for an array that has `cap` and needs at least `want`.
///
/// Public and separate from [`reserve`] so that it can be tested without an
/// allocation, and so that a structure holding its bytes some other way than in
/// a `Vec` can use the same policy.
/// Make room for `extra` more elements, growing by the policy above.
///
/// [`Vec::reserve_exact`] rather than [`Vec::reserve`], because the point is to
/// take the size this decided and not the size `Vec` would have decided.