You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Instead of relying on a heap-allocator, stack-based memory area is added and removed on-demand in a last-in-first-out (LIFO) order according to the calling workflow of a program. Let's illustrate an imaginary function `super()` that allocates 32 bits before calling another function named `sub()` that also allocates 32 bits of auxiliary memory:
36
+
`ArrayVec`is a container that encapsulates fixed size buffers.
37
37
38
-
```txt
39
-
0 bits 32 bits 64 bits
38
+
```rust
39
+
letmutv:ArrayVec<i32, 4> =ArrayVec::new();
40
+
let_=v.push(1);
41
+
let_=v.push(2);
42
+
43
+
assert_eq!(v.len(), 2);
44
+
assert_eq!(v[0], 1);
45
+
46
+
assert_eq!(v.pop(), Some(2));
47
+
assert_eq!(v.len(), 1);
48
+
49
+
v[0] =7;
50
+
assert_eq!(v[0], 7);
40
51
52
+
v.extend([1, 2, 3].iter().copied());
41
53
42
-
| | -> | | -> | |
43
-
--------- --------- ---------
44
-
| super | | sub |
45
-
--------- ---------
46
-
| super |
47
-
---------
54
+
forelementin&v {
55
+
println!("{}", element);
56
+
}
57
+
assert_eq!(v, [7, 1, 2, 3]);
48
58
```
49
59
50
-
* Now `super()` returns and the exactly same thing happens in reverse order, dropping everything when out of scope.
60
+
Instead of relying on a heap-allocator, stack-based memory area is added and removed on-demand in a last-in-first-out (LIFO) order according to the calling workflow of a program. `ArrayVec` takes advantage of this predictable behavior to reserve an exactly amount of uninitialized bytes up-front and these bytes form a buffer where elements can be included dynamically.
Of course, fixed buffers lead to inflexibility because unlike `Vec`, the underlying capacity can not expand at run-time and there will never be more than 64 elements in the above example.
55
68
56
-
| | -> | | -> | |
57
-
--------- --------- ---------
58
-
| sub | | super |
59
-
--------- ---------
60
-
| super |
61
-
---------
69
+
```rust
70
+
// This vector can store up to 0 elements, therefore, nothing at all
`ArrayVec` takes advantage of this predictable behavior to reserve an exactly amount of uninitialized bytes up-front and these bytes form a buffer where elements can be included dynamically.
77
+
A good question is: Should I use `core::collections::ArrayVec<T>` or `alloc::collections::Vec<T>`? Well, `Vec` is already good enough for most situations while stack allocation usually shines for small sizes.
78
+
79
+
* Do you have a known upper bound?
80
+
81
+
* How much memory are you going to allocate for your program? The default values of `RUST_MIN_STACK` or `ulimit -s` might not be enough.
82
+
83
+
* Are you using nested `Vec`s? `Vec<ArrayVec<T, N>>` might be better than `Vec<Vec<T>>`.
84
+
85
+
Each use-case is different and should be pondered individually. In case of doubt, stick with `Vec`.
86
+
87
+
For a more technical overview, take a look at the following operations:
65
88
66
89
```rust
67
-
fnmain() {
68
-
// `array_vec` has a pre-allocated memory of 2048 bits that can store up to 64 decimals.
// Although reserved, there isn't anything explicitly stored yet
72
-
assert_eq!(array_vec.len(), 0);
94
+
// Although reserved, there isn't anything explicitly stored yet
95
+
assert_eq!(array_vec.len(), 0);
73
96
74
-
// Initializes the first 32 bits with a simple '1' decimal or
75
-
// 00000000 00000000 00000000 00000001 bits
76
-
array_vec.push(1);
97
+
// Initializes the first 32 bits with a simple '1' decimal or
98
+
// 00000000 00000000 00000000 00000001 bits
99
+
array_vec.push(1);
77
100
78
-
// Our vector memory is now split into a 32/2016 pair of initialized and
79
-
// uninitialized memory respectively
80
-
assert_eq!(array_vec.len(), 1);
81
-
}
101
+
// Our vector memory is now split into a 32/2016 pair of initialized and
102
+
// uninitialized memory respectively
103
+
assert_eq!(array_vec.len(), 1);
82
104
```
83
105
84
-
Of course, fixed buffers lead to some inflexibility because unlike `Vec`, the underlying capacity can not expand at run-time and there will never be more than 64 elements in the above example.
Since it is known at compile-time the upper capacity bound, the compiler is likely going to remove the conditional bounding checking of the newly
193
-
194
212
Meaningless, unstable and deprecated methods like `reserve` or `drain_filter` weren't considered. A concrete implementation is available at https://github.com/c410-f3r/stack-based-vec.
195
213
196
214
# Drawbacks
@@ -230,11 +248,11 @@ Should it be included in the prelude?
0 commit comments