Again, stacked borrows model makes the `self.set_len()` call illegal
because we are holding (and are going to use) another raw pointer
derived from self, `tail`.
This simplification -- borrowing self.len instead of self, leads to
an improvement in the extend_from_slice benchmark.
It's also guided by the discussion of stacked borrows; the old code
would be invalid, because the whole self is borrowed while ptr is derived from
self.
This way we cover all users up to 256 at least. The reason these are not
enabled by default is that they slow down the compilation of the crate
by a factor of 2-3x.
This should perform better in both release and debug mode.
NOTE: This is significant because it changes the drop order of the
elements, and how we handle panicking destructors. If just one of the
destructors panic during ArrayVec drop, clear or truncate, the rest of
the elements should still drop. If we encounter another panic during
that process, however, Rust will abort as usual for panic during
unwinding.
```
warning: the type of this value must be known in this context
--> src/lib.rs:312:32
|
312 | ptr::copy(p, p.offset(1), len - index);
| ^^^^^^
|
= note: #[warn(tyvar_behind_raw_pointer)] on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
```
Instead of being vague about it, we can promise it.
We continue to be a bit vague in ArrayString::set_len. I don't see how
to add a char boundary check in ArrayString::set_len unfortunately.
It's a tricky issue, checking char boundaries requires reading the
memory of the string, and we don't even know if the user of set_len has
initialized that area of memory yet (but they hopefully did).
We have to use the "SetLenOnDrop" pattern (see stdlib Vec) here.
Keep the length in a separate variable, write it back on scope exit. To
help the compiler with alias analysis and stuff. We update the length
to handle panic in the iteration of the user's iterator, without
dropping any elements on the floor.
Note: This code was tested without the scope guard using the new option
-Zmutable-noalias, which had no effect here.
benchmark:
```
name before.txt ns/iter after.txt ns/iter diff ns/iter diff %
extend_with_constant 280 (1828 MB/s) 74 (6918 MB/s) -206 -73.57%
extend_with_range 1,285 (398 MB/s) 979 (522 MB/s) -306 -23.81%
extend_with_slice 29 (17655 MB/s) 14 (36571 MB/s) -15 -51.72%
```