Auto merge of #65637 - ssomers:master, r=scottmcm
proposal for BTreeMap/Set min/max, #62924 - Which pair of names: #62924 lists the existing possibilities min/max, first/last, (EDIT) front/back, peek(/peek_back?). Iterators have next/next_back or next/last. I'm slightly in favour of first/last because min/max might suggest they search over the entire map, and front/back pretends they are only about position. - Return key only instead of pair like iterator does? - If not, then keep the _key_value suffix? ~~Also provide variant with mutable value? But there is no such variant for get_key_value.~~ - Look for and upgrade more usages of `.iter().next()` and such in the libraries? I only upgraded the ones I contributed myself, all very recently.
This commit is contained in:
commit
374ad1b006
7 changed files with 314 additions and 11 deletions
|
@ -145,3 +145,28 @@ pub fn iter_1000(b: &mut Bencher) {
|
|||
pub fn iter_100000(b: &mut Bencher) {
|
||||
bench_iter(b, 100000);
|
||||
}
|
||||
|
||||
fn bench_first_and_last(b: &mut Bencher, size: i32) {
|
||||
let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();
|
||||
b.iter(|| {
|
||||
for _ in 0..10 {
|
||||
black_box(map.first_key_value());
|
||||
black_box(map.last_key_value());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
pub fn first_and_last_0(b: &mut Bencher) {
|
||||
bench_first_and_last(b, 0);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
pub fn first_and_last_100(b: &mut Bencher) {
|
||||
bench_first_and_last(b, 100);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
pub fn first_and_last_10k(b: &mut Bencher) {
|
||||
bench_first_and_last(b, 10_000);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![feature(map_first_last)]
|
||||
#![feature(repr_simd)]
|
||||
#![feature(test)]
|
||||
|
||||
|
|
|
@ -598,6 +598,121 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the first key-value pair in the map.
|
||||
/// The key in this pair is the minimum key in the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// assert_eq!(map.first_key_value(), None);
|
||||
/// map.insert(1, "b");
|
||||
/// map.insert(2, "a");
|
||||
/// assert_eq!(map.first_key_value(), Some((&1, &"b")));
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
pub fn first_key_value<T: ?Sized>(&self) -> Option<(&K, &V)>
|
||||
where T: Ord, K: Borrow<T>
|
||||
{
|
||||
let front = first_leaf_edge(self.root.as_ref());
|
||||
front.right_kv().ok().map(Handle::into_kv)
|
||||
}
|
||||
|
||||
/// Returns the first entry in the map for in-place manipulation.
|
||||
/// The key of this entry is the minimum key in the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Contrived way to `clear` a map:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// map.insert(1, "a");
|
||||
/// map.insert(2, "b");
|
||||
/// while let Some(entry) = map.first_entry() {
|
||||
/// let (key, val) = entry.remove_entry();
|
||||
/// assert!(!map.contains_key(&key));
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
pub fn first_entry<T: ?Sized>(&mut self) -> Option<OccupiedEntry<'_, K, V>>
|
||||
where T: Ord, K: Borrow<T>
|
||||
{
|
||||
match self.length {
|
||||
0 => None,
|
||||
_ => Some(OccupiedEntry {
|
||||
handle: self.root.as_mut().first_kv(),
|
||||
length: &mut self.length,
|
||||
_marker: PhantomData,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the last key-value pair in the map.
|
||||
/// The key in this pair is the maximum key in the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// map.insert(1, "b");
|
||||
/// map.insert(2, "a");
|
||||
/// assert_eq!(map.last_key_value(), Some((&2, &"a")));
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
pub fn last_key_value<T: ?Sized>(&self) -> Option<(&K, &V)>
|
||||
where T: Ord, K: Borrow<T>
|
||||
{
|
||||
let back = last_leaf_edge(self.root.as_ref());
|
||||
back.left_kv().ok().map(Handle::into_kv)
|
||||
}
|
||||
|
||||
/// Returns the last entry in the map for in-place manipulation.
|
||||
/// The key of this entry is the maximum key in the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Contrived way to `clear` a map:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// map.insert(1, "a");
|
||||
/// map.insert(2, "b");
|
||||
/// while let Some(entry) = map.last_entry() {
|
||||
/// let (key, val) = entry.remove_entry();
|
||||
/// assert!(!map.contains_key(&key));
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
pub fn last_entry<T: ?Sized>(&mut self) -> Option<OccupiedEntry<'_, K, V>>
|
||||
where T: Ord, K: Borrow<T>
|
||||
{
|
||||
match self.length {
|
||||
0 => None,
|
||||
_ => Some(OccupiedEntry {
|
||||
handle: self.root.as_mut().last_kv(),
|
||||
length: &mut self.length,
|
||||
_marker: PhantomData,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the map contains a value for the specified key.
|
||||
///
|
||||
/// The key may be any borrowed form of the map's key type, but the ordering
|
||||
|
|
|
@ -194,16 +194,16 @@ pub struct Difference<'a, T: 'a> {
|
|||
#[derive(Debug)]
|
||||
enum DifferenceInner<'a, T: 'a> {
|
||||
Stitch {
|
||||
// iterate all of self and some of other, spotting matches along the way
|
||||
// iterate all of `self` and some of `other`, spotting matches along the way
|
||||
self_iter: Iter<'a, T>,
|
||||
other_iter: Peekable<Iter<'a, T>>,
|
||||
},
|
||||
Search {
|
||||
// iterate a small set, look up in the large set
|
||||
// iterate `self`, look up in `other`
|
||||
self_iter: Iter<'a, T>,
|
||||
other_set: &'a BTreeSet<T>,
|
||||
},
|
||||
Iterate(Iter<'a, T>), // simply stream self's elements
|
||||
Iterate(Iter<'a, T>), // simply produce all values in `self`
|
||||
}
|
||||
|
||||
#[stable(feature = "collection_debug", since = "1.17.0")]
|
||||
|
@ -356,7 +356,7 @@ impl<T: Ord> BTreeSet<T> {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn difference<'a>(&'a self, other: &'a BTreeSet<T>) -> Difference<'a, T> {
|
||||
let (self_min, self_max) = if let (Some(self_min), Some(self_max)) =
|
||||
(self.iter().next(), self.iter().next_back())
|
||||
(self.first(), self.last())
|
||||
{
|
||||
(self_min, self_max)
|
||||
} else {
|
||||
|
@ -365,7 +365,7 @@ impl<T: Ord> BTreeSet<T> {
|
|||
};
|
||||
};
|
||||
let (other_min, other_max) = if let (Some(other_min), Some(other_max)) =
|
||||
(other.iter().next(), other.iter().next_back())
|
||||
(other.first(), other.last())
|
||||
{
|
||||
(other_min, other_max)
|
||||
} else {
|
||||
|
@ -450,7 +450,7 @@ impl<T: Ord> BTreeSet<T> {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn intersection<'a>(&'a self, other: &'a BTreeSet<T>) -> Intersection<'a, T> {
|
||||
let (self_min, self_max) = if let (Some(self_min), Some(self_max)) =
|
||||
(self.iter().next(), self.iter().next_back())
|
||||
(self.first(), self.last())
|
||||
{
|
||||
(self_min, self_max)
|
||||
} else {
|
||||
|
@ -459,7 +459,7 @@ impl<T: Ord> BTreeSet<T> {
|
|||
};
|
||||
};
|
||||
let (other_min, other_max) = if let (Some(other_min), Some(other_max)) =
|
||||
(other.iter().next(), other.iter().next_back())
|
||||
(other.first(), other.last())
|
||||
{
|
||||
(other_min, other_max)
|
||||
} else {
|
||||
|
@ -625,14 +625,14 @@ impl<T: Ord> BTreeSet<T> {
|
|||
return false;
|
||||
}
|
||||
let (self_min, self_max) = if let (Some(self_min), Some(self_max)) =
|
||||
(self.iter().next(), self.iter().next_back())
|
||||
(self.first(), self.last())
|
||||
{
|
||||
(self_min, self_max)
|
||||
} else {
|
||||
return true; // self is empty
|
||||
};
|
||||
let (other_min, other_max) = if let (Some(other_min), Some(other_max)) =
|
||||
(other.iter().next(), other.iter().next_back())
|
||||
(other.first(), other.last())
|
||||
{
|
||||
(other_min, other_max)
|
||||
} else {
|
||||
|
@ -654,14 +654,12 @@ impl<T: Ord> BTreeSet<T> {
|
|||
Less => (),
|
||||
}
|
||||
if self_iter.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF {
|
||||
// Big difference in number of elements.
|
||||
for next in self_iter {
|
||||
if !other.contains(next) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Self is not much smaller than other set.
|
||||
let mut other_iter = other.iter();
|
||||
other_iter.next();
|
||||
other_iter.next_back();
|
||||
|
@ -702,6 +700,96 @@ impl<T: Ord> BTreeSet<T> {
|
|||
other.is_subset(self)
|
||||
}
|
||||
|
||||
/// Returns a reference to the first value in the set, if any.
|
||||
/// This value is always the minimum of all values in the set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut map = BTreeSet::new();
|
||||
/// assert_eq!(map.first(), None);
|
||||
/// map.insert(1);
|
||||
/// assert_eq!(map.first(), Some(&1));
|
||||
/// map.insert(2);
|
||||
/// assert_eq!(map.first(), Some(&1));
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
pub fn first(&self) -> Option<&T> {
|
||||
self.map.first_key_value().map(|(k, _)| k)
|
||||
}
|
||||
|
||||
/// Returns a reference to the last value in the set, if any.
|
||||
/// This value is always the maximum of all values in the set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut map = BTreeSet::new();
|
||||
/// assert_eq!(map.first(), None);
|
||||
/// map.insert(1);
|
||||
/// assert_eq!(map.last(), Some(&1));
|
||||
/// map.insert(2);
|
||||
/// assert_eq!(map.last(), Some(&2));
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
pub fn last(&self) -> Option<&T> {
|
||||
self.map.last_key_value().map(|(k, _)| k)
|
||||
}
|
||||
|
||||
/// Removes the first value from the set and returns it, if any.
|
||||
/// The first value is always the minimum value in the set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut set = BTreeSet::new();
|
||||
///
|
||||
/// set.insert(1);
|
||||
/// while let Some(n) = set.pop_first() {
|
||||
/// assert_eq!(n, 1);
|
||||
/// }
|
||||
/// assert!(set.is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
pub fn pop_first(&mut self) -> Option<T> {
|
||||
self.map.first_entry().map(|entry| entry.remove_entry().0)
|
||||
}
|
||||
|
||||
/// Removes the last value from the set and returns it, if any.
|
||||
/// The last value is always the maximum value in the set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut set = BTreeSet::new();
|
||||
///
|
||||
/// set.insert(1);
|
||||
/// while let Some(n) = set.pop_last() {
|
||||
/// assert_eq!(n, 1);
|
||||
/// }
|
||||
/// assert!(set.is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
pub fn pop_last(&mut self) -> Option<T> {
|
||||
self.map.last_entry().map(|entry| entry.remove_entry().0)
|
||||
}
|
||||
|
||||
/// Adds a value to the set.
|
||||
///
|
||||
/// If the set did not have this value present, `true` is returned.
|
||||
|
|
|
@ -58,15 +58,35 @@ fn test_basic_large() {
|
|||
fn test_basic_small() {
|
||||
let mut map = BTreeMap::new();
|
||||
assert_eq!(map.remove(&1), None);
|
||||
assert_eq!(map.len(), 0);
|
||||
assert_eq!(map.first_key_value(), None);
|
||||
assert_eq!(map.last_key_value(), None);
|
||||
assert_eq!(map.get(&1), None);
|
||||
assert_eq!(map.insert(1, 1), None);
|
||||
assert_eq!(map.len(), 1);
|
||||
assert_eq!(map.get(&1), Some(&1));
|
||||
assert_eq!(map.first_key_value(), Some((&1, &1)));
|
||||
assert_eq!(map.last_key_value(), Some((&1, &1)));
|
||||
assert_eq!(map.insert(1, 2), Some(1));
|
||||
assert_eq!(map.len(), 1);
|
||||
assert_eq!(map.get(&1), Some(&2));
|
||||
assert_eq!(map.first_key_value(), Some((&1, &2)));
|
||||
assert_eq!(map.last_key_value(), Some((&1, &2)));
|
||||
assert_eq!(map.insert(2, 4), None);
|
||||
assert_eq!(map.len(), 2);
|
||||
assert_eq!(map.get(&2), Some(&4));
|
||||
assert_eq!(map.first_key_value(), Some((&1, &2)));
|
||||
assert_eq!(map.last_key_value(), Some((&2, &4)));
|
||||
assert_eq!(map.remove(&1), Some(2));
|
||||
assert_eq!(map.len(), 1);
|
||||
assert_eq!(map.get(&1), None);
|
||||
assert_eq!(map.get(&2), Some(&4));
|
||||
assert_eq!(map.first_key_value(), Some((&2, &4)));
|
||||
assert_eq!(map.last_key_value(), Some((&2, &4)));
|
||||
assert_eq!(map.remove(&2), Some(4));
|
||||
assert_eq!(map.len(), 0);
|
||||
assert_eq!(map.first_key_value(), None);
|
||||
assert_eq!(map.last_key_value(), None);
|
||||
assert_eq!(map.remove(&1), None);
|
||||
}
|
||||
|
||||
|
@ -605,6 +625,31 @@ fn test_vacant_entry_key() {
|
|||
assert_eq!(a[key], value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_first_last_entry() {
|
||||
let mut a = BTreeMap::new();
|
||||
assert!(a.first_entry().is_none());
|
||||
assert!(a.last_entry().is_none());
|
||||
a.insert(1, 42);
|
||||
assert_eq!(a.first_entry().unwrap().key(), &1);
|
||||
assert_eq!(a.last_entry().unwrap().key(), &1);
|
||||
a.insert(2, 24);
|
||||
assert_eq!(a.first_entry().unwrap().key(), &1);
|
||||
assert_eq!(a.last_entry().unwrap().key(), &2);
|
||||
a.insert(0, 6);
|
||||
assert_eq!(a.first_entry().unwrap().key(), &0);
|
||||
assert_eq!(a.last_entry().unwrap().key(), &2);
|
||||
let (k1, v1) = a.first_entry().unwrap().remove_entry();
|
||||
assert_eq!(k1, 0);
|
||||
assert_eq!(v1, 6);
|
||||
let (k2, v2) = a.last_entry().unwrap().remove_entry();
|
||||
assert_eq!(k2, 2);
|
||||
assert_eq!(v2, 24);
|
||||
assert_eq!(a.first_entry().unwrap().key(), &1);
|
||||
assert_eq!(a.last_entry().unwrap().key(), &1);
|
||||
}
|
||||
|
||||
|
||||
macro_rules! create_append_test {
|
||||
($name:ident, $len:expr) => {
|
||||
#[test]
|
||||
|
|
|
@ -470,6 +470,34 @@ fn test_append() {
|
|||
assert_eq!(a.contains(&5), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_first_last() {
|
||||
let mut a = BTreeSet::new();
|
||||
assert_eq!(a.first(), None);
|
||||
assert_eq!(a.last(), None);
|
||||
a.insert(1);
|
||||
assert_eq!(a.first(), Some(&1));
|
||||
assert_eq!(a.last(), Some(&1));
|
||||
a.insert(2);
|
||||
assert_eq!(a.first(), Some(&1));
|
||||
assert_eq!(a.last(), Some(&2));
|
||||
a.insert(3);
|
||||
assert_eq!(a.first(), Some(&1));
|
||||
assert_eq!(a.last(), Some(&3));
|
||||
|
||||
assert_eq!(a.len(), 3);
|
||||
assert_eq!(a.pop_first(), Some(1));
|
||||
assert_eq!(a.len(), 2);
|
||||
assert_eq!(a.pop_last(), Some(3));
|
||||
assert_eq!(a.len(), 1);
|
||||
assert_eq!(a.pop_first(), Some(2));
|
||||
assert_eq!(a.len(), 0);
|
||||
assert_eq!(a.pop_last(), None);
|
||||
assert_eq!(a.len(), 0);
|
||||
assert_eq!(a.pop_first(), None);
|
||||
assert_eq!(a.len(), 0);
|
||||
}
|
||||
|
||||
fn rand_data(len: usize) -> Vec<u32> {
|
||||
let mut rng = DeterministicRng::new();
|
||||
Vec::from_iter((0..len).map(|_| rng.next()))
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#![feature(box_syntax)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(map_first_last)]
|
||||
#![feature(new_uninit)]
|
||||
#![feature(pattern)]
|
||||
#![feature(trusted_len)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue