Skip to content

Commit 5082adc

Browse files
committed
Expand guide-level
1 parent cbabf74 commit 5082adc

File tree

1 file changed

+57
-39
lines changed

1 file changed

+57
-39
lines changed

text/2978-stack_based_vec.md

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,56 +33,76 @@ Just like `Vec`, `ArrayVec` is also a primitive vector where high-level structur
3333
# Guide-level explanation
3434
[guide-level-explanation]: #guide-level-explanation
3535

36-
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.
3737

38-
```txt
39-
0 bits 32 bits 64 bits
38+
```rust
39+
let mut v: 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);
4051

52+
v.extend([1, 2, 3].iter().copied());
4153

42-
| | -> | | -> | |
43-
--------- --------- ---------
44-
| super | | sub |
45-
--------- ---------
46-
| super |
47-
---------
54+
for element in &v {
55+
println!("{}", element);
56+
}
57+
assert_eq!(v, [7, 1, 2, 3]);
4858
```
4959

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.
5161

52-
```txt
53-
64 bits 32 bits 0 bits
62+
```rust
63+
// `array_vec` can store up to 64 elements
64+
let mut array_vec: ArrayVec<i32, 64> = ArrayVec::new();
65+
```
5466

67+
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.
5568

56-
| | -> | | -> | |
57-
--------- --------- ---------
58-
| sub | | super |
59-
--------- ---------
60-
| super |
61-
---------
69+
```rust
70+
// This vector can store up to 0 elements, therefore, nothing at all
71+
let mut array_vec: ArrayVec<i32, 0> = ArrayVec::new();
72+
let push_result = array_vec.push(1);
73+
// Ooppss... Our push operation wasn't successful
74+
assert!(push_result.is_err());
6275
```
6376

64-
`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:
6588

6689
```rust
67-
fn main() {
68-
// `array_vec` has a pre-allocated memory of 2048 bits that can store up to 64 decimals.
69-
let mut array_vec: ArrayVec<i32, 64> = ArrayVec::new();
90+
// `array_vec` has a pre-allocated memory of 2048 bits (32 * 64) that can store up
91+
// to 64 decimals.
92+
let mut array_vec: ArrayVec<i32, 64> = ArrayVec::new();
7093

71-
// 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);
7396

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);
77100

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);
82104
```
83105

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.
85-
86106
# Reference-level explanation
87107
[reference-level-explanation]: #reference-level-explanation
88108

@@ -189,8 +209,6 @@ impl<T, const N: usize> ArrayVec<T, N> {
189209
}
190210
```
191211

192-
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-
194212
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.
195213

196214
# Drawbacks
@@ -230,11 +248,11 @@ Should it be included in the prelude?
230248
### Macros
231249

232250
```rust
233-
// Instance with 1i32, 2i32 and 3i32
234-
let _: ArrayVec<i32, 33> = array_vec![1, 2, 3];
251+
// Instance with 1i32, 2i32 and 3i32
252+
let _: ArrayVec<i32, 33> = array_vec![1, 2, 3];
235253

236-
// Instance with 1i32 and 1i32
237-
let _: ArrayVec<i32, 64> = array_vec![1; 2];
254+
// Instance with 1i32 and 1i32
255+
let _: ArrayVec<i32, 64> = array_vec![1; 2];
238256
```
239257

240258
# Future possibilities

0 commit comments

Comments
 (0)