Btreemap iter intertwined
3 commits:
1. Introduced benchmarks for `BTreeMap::iter()`. Benchmarks named `iter_20` were of the whole iteration process, so I renamed them. Also the benchmarks of `range` that I wrote earlier weren't very good. I included an (awkwardly named) one that compares `iter()` to `range(..)` on the same set, because the contrast is surprising:
```
name ns/iter
btree::map::range_unbounded_unbounded 28,176
btree::map::range_unbounded_vs_iter 89,369
```
Both dig up the same pair of leaf edges. `range(..)` also checks that some keys are correctly ordered, the only thing `iter()` does more is to copy the map's length.
2. Slightly refactoring the code to what I find more readable (not in chronological order of discovery), boosts performance:
```
>cargo-benchcmp.exe benchcmp a1 a2 --threshold 5
name a1 ns/iter a2 ns/iter diff ns/iter diff % speedup
btree::map::find_rand_100 18 17 -1 -5.56% x 1.06
btree::map::first_and_last_10k 64 71 7 10.94% x 0.90
btree::map::iter_0 2,939 2,209 -730 -24.84% x 1.33
btree::map::iter_1 6,845 2,696 -4,149 -60.61% x 2.54
btree::map::iter_100 8,556 3,672 -4,884 -57.08% x 2.33
btree::map::iter_10k 9,292 5,884 -3,408 -36.68% x 1.58
btree::map::iter_1m 10,268 6,510 -3,758 -36.60% x 1.58
btree::map::iteration_mut_100000 478,575 453,050 -25,525 -5.33% x 1.06
btree::map::range_unbounded_unbounded 28,176 36,169 7,993 28.37% x 0.78
btree::map::range_unbounded_vs_iter 89,369 38,290 -51,079 -57.16% x 2.33
btree::set::clone_100_and_remove_all 4,801 4,245 -556 -11.58% x 1.13
btree::set::clone_10k_and_remove_all 529,450 496,030 -33,420 -6.31% x 1.07
```
But you can tell from the `range_unbounded_*` lines that, despite an unwarranted, vengeful attack on the range_unbounded_unbounded benchmark, this change still doesn't allow `iter()` to catch up with `range(..)`.
3. I guess that `range(..)` copes so well because it intertwines the leftmost and rightmost descend towards leaf edges, doing the two root node accesses close together, perhaps exploiting a CPU's internal pipelining? So the third commit distils a version of `range_search` (which we can't use directly because of the `Ord` bound), and we get another boost:
```
cargo-benchcmp.exe benchcmp a2 a3 --threshold 5
name a2 ns/iter a3 ns/iter diff ns/iter diff % speedup
btree::map::first_and_last_100 40 43 3 7.50% x 0.93
btree::map::first_and_last_10k 71 64 -7 -9.86% x 1.11
btree::map::iter_0 2,209 1,719 -490 -22.18% x 1.29
btree::map::iter_1 2,696 2,205 -491 -18.21% x 1.22
btree::map::iter_100 3,672 2,943 -729 -19.85% x 1.25
btree::map::iter_10k 5,884 3,929 -1,955 -33.23% x 1.50
btree::map::iter_1m 6,510 5,532 -978 -15.02% x 1.18
btree::map::iteration_mut_100000 453,050 476,667 23,617 5.21% x 0.95
btree::map::range_included_excluded 405,075 371,297 -33,778 -8.34% x 1.09
btree::map::range_included_included 427,577 397,440 -30,137 -7.05% x 1.08
btree::map::range_unbounded_unbounded 36,169 28,175 -7,994 -22.10% x 1.28
btree::map::range_unbounded_vs_iter 38,290 30,838 -7,452 -19.46% x 1.24
```
But I think this is just fake news from the microbenchmarking media. `iter()` is still trying to catch up with `range(..)`. And we can sure do without another function. So I would skip this 3rd commit.
r? @Mark-Simulacrum
Update btree_map::VacantEntry::insert docs to actually call insert
It looks like they were copied from the `or_insert` docs. This change
makes the example more like the hash_map::VacantEntry::insert docs.
The `remove_current` method only returns the inner `T` and deallocates the list node. This is unnecessary for move operations, where the element is going to be linked back into this (or even a different) `LinkedList`. The `remove_current_as_list` method avoids this by returning the unlinked list node as a new single-element `LinkedList` structure .
Vec drop and truncate: drop using raw slice *mut [T]
By creating a *mut [T] directly (without going through &mut [T]), avoid
questions of validity of the contents of the slice.
Consider the following risky code:
```rust
unsafe {
let mut v = Vec::<bool>::with_capacity(16);
v.set_len(16);
}
```
The intention is that with this change, we avoid one of the soundness
questions about the above snippet, because Vec::drop no longer
produces a mutable slice of the vector's contents.
r? @RalfJung
Add a function to turn Box<T> into Box<[T]>
Hi,
I think this is very useful, as currently it's not possible in safe rust to do this without re-allocating.
an alternative implementation of the same function can be:
```rust
pub fn into_boxed_slice<T>(boxed: Box<T>) -> Box<[T]> {
unsafe {
let slice = slice::from_raw_parts_mut(Box::into_raw(boxed), 1);
Box::from_raw(slice)
}
}
```
The only thing that makes me a little uncomfortable is this line :
> The alignment of array types is greater or equal to the alignment of its element type
from https://rust-lang.github.io/unsafe-code-guidelines/layout/arrays-and-slices.html
But then I see:
> The alignment of &T, &mut T, *const T and *mut T are the same, and are at least the word size.
> The alignment of &[T] is the word size.
from https://rust-lang.github.io/unsafe-code-guidelines/layout/pointers.html#representation
So I do believe this is valid(FWIW it also passes in miri https://play.rust-lang.org/?gist=c002b99364ee6b29862aeb3565a91c19)
- Remove a type parameter from `[A]RcFromIter`.
- Remove an implementation of `[A]RcFromIter` that didn't actually
specialize anything.
- Remove unused implementation of `IsZero` for `Option<&mut T>`.
- Change specializations of `[A]RcEqIdent` to use a marker trait version
of `Eq`.
- Remove `BTreeClone`. I couldn't find a way to make this work with
`min_specialization`.
- Add `rustc_unsafe_specialization_marker` to `Copy` and `TrustedLen`.
Fix stable(since) attribute for BTreeMap::remove_entry
Stabilized in #70712.
Maybe checking that the since attributes are added correctly should be automated through tidy? This is the third PR I'm opening that fixes a stable(since) attribute for something meant to be stabilized in 1.43 / 1.44 initially but then only stabilized in 1.45. (the other two are #71571, #71574)
Rollup of 7 pull requests
Successful merges:
- #69041 (proc_macro: Stabilize `Span::resolved_at` and `Span::located_at`)
- #69813 (Implement BitOr and BitOrAssign for the NonZero integer types)
- #70712 (stabilize BTreeMap::remove_entry)
- #71168 (Deprecate `{Box,Rc,Arc}::into_raw_non_null`)
- #71544 (Replace filter_map().next() calls with find_map())
- #71545 (Fix comment in docstring example for Error::kind)
- #71548 (Add missing Send and Sync impls for linked list Cursor and CursorMut.)
Failed merges:
r? @ghost
Add missing Send and Sync impls for linked list Cursor and CursorMut.
Someone pointed out these to me, and i think it's indeed reasonable to add those impl.
r? @Amanieu
Take a single root node in range_search
The unsafe code can be justified within range_search, as it makes sure to not
overlap the returned references, but from the callers perspective it's an
entirely safe algorithm and there's no need for the caller to know about the
duplication.
cc @ssomers
r? @Amanieu
Add BinaryHeap::retain as suggested in #42849
This PR implements retain for BinaryHeap as suggested in #42849.
This is my first PR for Rust, so please let me know if I should be doing anything differently, thanks!
The unsafe code can be justified within range_search, as it makes sure to not
overlap the returned references, but from the callers perspective it's an
entirely safe algorithm and there's no need for the caller to know about the
duplication.
These forward `Borrowed`/`Owned` values to existing `Box::from` impls.
- `From<Cow<'_, [T]>> for Box<[T]>`
- `From<Cow<'_, str>> for Box<str>`
- `From<Cow<'_, CStr>> for Box<CStr>`
- `From<Cow<'_, OsStr>> for Box<OsStr>`
- `From<Cow<'_, Path>> for Box<Path>`
This adds a couple of more diagnostic items to be used in Clippy.
I chose these particular ones because they were the types which we seem
to check for the most in Clippy. I'm not sure if the
`cfg_attr(not(test))` is needed, but it was also used for `Vec` and a
few other types.
Address concerns of weak-into-raw
This should address the standing concerns in https://github.com/rust-lang/rust/issues/60728#issuecomment-612525616.
I've still left the ability to create a new dangling pointer from `null`, as I feel like this is the natural behaviour to expect, but I'm fine removing that too. I've modified the documentation to allow the `as_ptr` or `into_ptr` to return whatever garbage in case of a dangling pointer. I've also removed the guarantee to be able to do `from_raw(as_ptr)` from the documentation (but it would still work right now).
I've renamed the method and added implementations for `Rc`/`Arc`.
I've also tried if I can just „enable“ unsized types. I believe the current interface is compatible with them. But the inner implementation will be a bit challenging ‒ I can't use the `data_offset` as is used by `Rc` or `Arc` because it AFAIK „touches“ (creates a reference to) the live value of `T` ‒ and in case of `Weak`, it might be completely bogus or already dead ‒ so that would be UB.
`./x.py test tidy` is completely mad on my own system all over the code base :-(. I'll just hope it goes through CI, or will fix as necessary.
Is it OK if I ask @Amanieu for review, as the concerns are from you?
~r @Amanieu
big-O notation: parenthesis for function calls, explicit multiplication
I saw `O(n m log n)` in the docs and found that really hard to parse. In particular, I don't think we should use blank space as syntax for *both* multiplication and function calls, that is just confusing.
This PR makes both multiplication and function calls explicit using Rust-like syntax. If you prefer, I can also leave one of them implicit, but I believe explicit is better here.
While I was at it I also added backticks consistently.
Dogfood or_patterns in the standard library
We can start using `or_patterns` in the standard library as a step toward stabilization.
cc #54883 @Centril
Minor fixes to doc comments of 'VecDeque'
1. Changed descriptions of `fn get` & `fn get_mut`.
Since both of these functions are returning references, and not the owned value, I thought the doc comments could be fixed to be consistent with doc comments of `fn front` & `fn front_mut`.
2. Other changes are minor fixes or additions for clarification.
Thank you for taking a look :)
1. Changed descriptions of `fn get` & `fn get_mut`.
Since both of these functions are returning references, and not the owned value, I thought the doc comments could be fixed to be consistent with doc comments of `fn front` & `fn front_mut`.
2. Other changes are minor fixes or additions for clarification.
Thank you for taking a look :)
simplify `vec!` macro
Simplify `vec!` macro by replacing 2 following branches:
- `($($x:expr),*) => (...)`
- `($($x:expr,)*) => (...)`
with one:
- `($($x:expr),* $(,)?) => (...)`
This is a minor change, however, this will make the documentation cleaner
By creating a *mut [T] directly (without going through &mut [T]), avoid
questions of validity of the contents of the slice.
Consider the following risky code:
```rust
unsafe {
let mut v = Vec::<bool>::with_capacity(16);
v.set_len(16);
}
```
The intention is that with this change, the above snippet will be
sound because Vec::drop does no longer produces a mutable slice of
the vector's contents.
* Rename Weak::as_raw to Weak::as_ptr for consistency with some other
types.
* The as_ptr for a dangling Weak pointer might return whatever garbage
(and takes that advantage to avoid a conditional).
* Don't guarantee to be able to do `Weak::from_raw(weak.as_ptr())` (even
though it'll still work fine).
Add or_insert_with_key to Entry of HashMap/BTreeMap
Going along with `or_insert_with`, `or_insert_with_key` provides the `Entry`'s key to the lambda, avoiding the need to either clone the key or the need to reimplement this body of this method from scratch each time.
This is useful when the initial value for a map entry is derived from the key. For example, the introductory Rust book has an example Cacher struct that takes an expensive-to-compute lambda and then can, given an argument to the lambda, produce either the cached result or execute the lambda.
---
I'm fairly new to Rust, so any optimizations, corrections to types, better names, better documentation, or whatever else would be appreciated. I'd like to thank Arnavion on freenode for helping me to implement a very similar method when I found that `or_insert_with_key` was unavailable.
As a somewhat-related note, this implements https://github.com/rust-lang/rfcs/issues/1202 from 2015, so if this pull request is accepted, that should be closed.
Going along with or_insert_with, or_insert_with_key provides the
Entry's key to the lambda, avoiding the need to either clone the
key or the need to reimplement this body of this method from
scratch each time.
This is useful when the initial value for a map entry is derived
from the key. For example, the introductory Rust book has an
example Cacher struct that takes an expensive-to-compute lambda and
then can, given an argument to the lambda, produce either the
cached result or execute the lambda.
Rearrange BTreeMap::into_iter to match range_mut.
r? @Mark-Simulacrum
I wondered why you catered for the optional root differently in `into_iter` than in `range_mut`.
Replace "rc"/"arc" lang items with Rc/Arc diagnostic items.
`Rc`/`Arc` should have no special semantics, so it seems appropriate for them to not be lang items.
r? @matthewjasper
Remove the Ord bound that was plaguing drain_filter
Now that #70795 made it superfluous. Also removes superfluous lifetime specifiers (at least I think they are).
Disable try_reserve tests on Android
Calling `realloc` with large sizes seems to be broken on older Android versions that use dlmalloc as the default allocator. This is not an issue for modern Android versions that use jemalloc.
Fixes#55861
Don't import integer and float modules, use assoc consts 2
Follow up to #70777. I missed quite a lot of places. Partially because I wanted to keep the size of the last PR down, and partially because my regexes were not good enough :)
r? @dtolnay