Skip to content

Commit 91df9aa

Browse files
committed
Address some comments
1 parent a4dba69 commit 91df9aa

File tree

1 file changed

+139
-23
lines changed

1 file changed

+139
-23
lines changed

text/2978-stack_vec.md renamed to text/2978-stack_based_vec.md

Lines changed: 139 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
- Feature Name: `stack_vec`
1+
- Feature Name: `stack_based_vec`
22
- Start Date: 2020-09-27
33
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
44
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)
55

66
# Summary
77
[summary]: #summary
88

9-
This RFC proposes the creation of a new "growable" vector named `StackVec` that manages stack memory and can be seen as an alternative for the built-in structure that handles heap-allocated memory, aka `alloc::vec::Vec<T>`.
9+
This RFC, which depends and takes advantage of the upcoming stabilization of constant generics (min_const_generics), tries to propose the creation of a new "growable" vector named `ArrayVec` that manages stack memory and can be seen as an alternative for the built-in structure that handles heap-allocated memory, aka `alloc::vec::Vec<T>`.
1010

1111
# Motivation
1212
[motivation]: #motivation
1313

14-
`core::collections::StackVec<T>` has several use-cases and should be conveniently added into the standard library due to its importance.
14+
`core::collections::ArrayVec<T>` has several use-cases and should be conveniently added into the standard library due to its importance.
1515

1616
### Unification
1717

@@ -23,15 +23,12 @@ Stack-based allocation is generally faster than heap-based allocation and can be
2323

2424
### Building block
2525

26-
Just like `Vec`, `StackVec` is a primitive vector where high-level structures can use it as a building block. For example, a stack-based matrix or binary heap.
26+
Just like `Vec`, `ArrayVec` is also a primitive vector where high-level structures can use it as a building block. For example, a stack-based matrix or binary heap.
2727

2828
### Useful in the real world
2929

3030
`arrayvec` is one of the most downloaded project of `crates.io` and is used by thousand of projects, including Rustc itself.
3131

32-
### Compiler internals
33-
34-
Unstable features can be used internally to make operations more efficient, e.g., `specialization`.
3532

3633
# Guide-level explanation
3734
[guide-level-explanation]: #guide-level-explanation
@@ -64,23 +61,23 @@ Instead of relying on a heap-allocator, stack-based memory area is added and rem
6461
---------
6562
```
6663

67-
`StackVec` 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.
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.
6865

6966
```rust
7067
fn main() {
71-
// `stack_vec` has a pre-allocated memory of 2048 bits that can store up to 64 decimals.
72-
let mut stack_vec: StackVec<i32, 64> = StackVec::new();
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();
7370

7471
// Although reserved, there isn't anything explicitly stored yet
75-
assert_eq!(stack_vec.len(), 0);
72+
assert_eq!(array_vec.len(), 0);
7673

7774
// Initializes the first 32 bits with a simple '1' decimal or
7875
// 00000000 00000000 00000000 00000001 bits
79-
stack_vec.push(1);
76+
array_vec.push(1);
8077

8178
// Our vector memory is now split into a 32/2016 pair of initialized and
8279
// uninitialized memory respectively
83-
assert_eq!(stack_vec.len(), 1);
80+
assert_eq!(array_vec.len(), 1);
8481
}
8582
```
8683

@@ -89,21 +86,140 @@ Of course, fixed buffers lead to some inflexibility because unlike `Vec`, the un
8986
# Reference-level explanation
9087
[reference-level-explanation]: #reference-level-explanation
9188

92-
The most natural module for `StackVec` is `core::collections` with an API that basically mimics most of the current `Vec<T>` surface.
89+
`ArrayVec` is a contiguous memory block where elements can be collected, threfore, a collection by definition and even though `core::collections` doesn't exist, it is the most natural modulo placement.
90+
91+
The API basically mimics most of the current `Vec` surface with some tweaks and additional methods to manage capacity. Notably, these additional methods are fallible versions of some well-known functions like `insert` that will return `Result` instead of panicking at run-time.
9392

9493
```rust
9594
// core::collections
9695

97-
pub struct StackVec<T, const N: usize> {
98-
data: MaybeUninit<[T, N]>,
96+
pub struct ArrayVec<T, const N: usize> {
97+
data: MaybeUninit<[T; N]>,
9998
len: usize
10099
}
101100

102-
impl<T, const N: usize> StackVec<T, N> {
103-
// Much of the `Vec` API goes here
101+
impl<T, const N: usize> ArrayVec<T, N> {
102+
// Constructors
103+
104+
pub unsafe fn from_raw_parts(_ptr: *mut T, _len: usize) -> Self;
105+
106+
#[inline]
107+
pub const fn new() -> Self;
108+
109+
// Methods
110+
111+
#[inline]
112+
pub fn as_mut_ptr(&mut self) -> *mut T;
113+
114+
#[inline]
115+
pub fn as_mut_slice(&mut self) -> &mut [T];
116+
117+
#[inline]
118+
pub fn as_ptr(&self) -> *const T;
119+
120+
#[inline]
121+
pub fn as_slice(&self) -> &[T];
122+
123+
#[inline]
124+
pub const fn capacity(&self) -> usize;
125+
126+
pub fn clear(&mut self);
127+
128+
pub fn dedup(&mut self);
129+
130+
pub fn dedup_by<F>(&mut self, same_bucket: F)
131+
where
132+
F: FnMut(&mut T, &mut T) -> bool;
133+
134+
pub fn dedup_by_key<F, K>(&mut self, key: F)
135+
where
136+
F: FnMut(&mut T) -> K,
137+
K: PartialEq<K>;
138+
139+
pub fn drain<R>(&mut self, range: R)
140+
where
141+
R: RangeBounds<usize>;
142+
143+
pub fn extend_from_cloneable_slice(&mut self, other: &[T])
144+
where
145+
T: Clone; // Panics at run-time
146+
147+
pub fn extend_from_copyable_slice(&mut self, other: &[T])
148+
where
149+
T: Copy; // Panics at run-time
150+
151+
pub fn insert(&mut self, idx: usize, element: T); // Panics at run-time
152+
153+
#[inline]
154+
pub const fn is_empty(&self) -> bool;
155+
156+
#[inline]
157+
pub const fn len(&self) -> usize;
158+
159+
pub fn pop(&mut self) -> T; // Panics at run-time
160+
161+
pub fn push(&mut self, element: T); // Panics at run-time
162+
163+
pub fn remove(&mut self, idx: usize) -> T; // Panics at run-time
164+
165+
pub fn retain<F>(&mut self, f: F)
166+
where
167+
F: FnMut(&mut T) -> bool;
168+
169+
#[inline]
170+
pub unsafe fn set_len(&mut self, len: usize);
171+
172+
pub fn splice<R, I>(&mut self, range: R, replace_with: I)
173+
where
174+
I: IntoIterator<Item = T>,
175+
R: RangeBounds<usize>;
176+
177+
pub fn split_off(&mut self, at: usize) -> Self;
178+
179+
pub fn swap_remove(&mut self, idx: usize) -> T; // Panics at run-time
180+
181+
pub fn truncate(&mut self, len: usize);
182+
183+
pub fn try_extend_from_cloneable_slice(&mut self, other: &[T]) -> Result<(), ArrayVecError>
184+
where
185+
T: Clone;
186+
187+
pub fn try_extend_from_copyable_slice(&mut self, other: &[T]) -> Result<(), ArrayVecError>
188+
where
189+
T: Copy;
190+
191+
pub fn try_insert(&mut self, _idx: usize, element: T) -> Result<(), ArrayVecError>;
192+
193+
pub fn try_pop(&mut self) -> Result<(), ArrayVecError>;
194+
195+
pub fn try_push(&mut self, element: T) -> Result<(), ArrayVecError>;
196+
197+
pub fn try_remove(&mut self, idx: usize) -> Result<(), ArrayVecError>;
198+
199+
pub fn try_swap_remove(&mut self, idx: usize) -> Result<(), ArrayVecError>;
200+
}
201+
202+
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
203+
pub enum ArrayVecError {
204+
CapacityOverflow,
205+
NoElement
206+
}
207+
208+
impl fmt::Display for ArrayVecError {
209+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210+
let s = match *self {
211+
Self::CapacityOverflow => "It is not possible to add more elements",
212+
Self::NoElement => "There are no elements in the vector",
213+
};
214+
write!(f, "{}", s)
215+
}
104216
}
105217
```
106218

219+
Meaningless, unstable and deprecated methods like `reserve` or `drain_filter` weren't considered and in general, everything that includes or removes elements have a fallible version: `extend_from_cloneable_slice`, `extend_from_copyable_slice`, `pop`, `remove` and `swap_remove`.
220+
221+
A concrete implementation is available at https://github.com/c410-f3r/stack-based-vec.
222+
107223
# Drawbacks
108224
[drawbacks]: #drawbacks
109225

@@ -132,7 +248,7 @@ As seen, there isn't an implementation that stands out among the others because
132248

133249
### Nomenclature
134250

135-
`StackVec` will probably avoid conflicts with existing crates but another name might be a better option.
251+
`ArrayVec` will conflict with `arrayvec::ArrayVec` and `tinyvec::ArrayVec`.
136252

137253
### Prelude
138254

@@ -142,10 +258,10 @@ Should it be included in the prelude?
142258

143259
```rust
144260
// Instance with 1i32, 2i32 and 3i32
145-
let _: StackVec<i32, 33> = stack_vec![1, 2, 3];
261+
let _: ArrayVec<i32, 33> = array_vec![1, 2, 3];
146262

147263
// Instance with 1i32 and 1i32
148-
let _: StackVec<i32, 64> = stack_vec![1; 2];
264+
let _: ArrayVec<i32, 64> = array_vec![1; 2];
149265
```
150266

151267
# Future possibilities
@@ -168,7 +284,7 @@ impl<T, const N: usize> DynVec<T, N> {
168284
// This is just an example. `Vec<T>` could be `Box` and `enum` an `union`.
169285
enum DynVecData<T, const N: usize> {
170286
Heap(Vec<T>),
171-
Inline(StackVec<T, N>),
287+
Inline(ArrayVec<T, N>),
172288
}
173289
```
174290

@@ -181,5 +297,5 @@ Many structures that use `alloc::vec::Vec` as the underlying storage can also us
181297
```rust
182298
type DynString = GenericString<DynVec<u8>>;
183299
type HeapString = GenericString<Vec<u8>>;
184-
type StackString = GenericString<StackVec<u8>>;
300+
type StackString = GenericString<ArrayVec<u8>>;
185301
```

0 commit comments

Comments
 (0)