diff --git a/src/liballoc/benches/btree/map.rs b/src/liballoc/benches/btree/map.rs index 4c17bdc3e9e9d..b541fa94e954e 100644 --- a/src/liballoc/benches/btree/map.rs +++ b/src/liballoc/benches/btree/map.rs @@ -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); +} diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 4bf5ec10c41e7..9acda886064ce 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -1,3 +1,4 @@ +#![feature(map_first_last)] #![feature(repr_simd)] #![feature(test)] diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 83fd4485f7321..5b48b594ff907 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -598,6 +598,121 @@ impl BTreeMap { } } + /// 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(&self) -> Option<(&K, &V)> + where T: Ord, K: Borrow + { + 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(&mut self) -> Option> + where T: Ord, K: Borrow + { + 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(&self) -> Option<(&K, &V)> + where T: Ord, K: Borrow + { + 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(&mut self) -> Option> + where T: Ord, K: Borrow + { + 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 diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index f0796354e00c3..85b93e0eda45b 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -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>, }, 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, }, - 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 BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] pub fn difference<'a>(&'a self, other: &'a BTreeSet) -> 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 BTreeSet { }; }; 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 BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] pub fn intersection<'a>(&'a self, other: &'a BTreeSet) -> 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 BTreeSet { }; }; 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 BTreeSet { 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 BTreeSet { 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 BTreeSet { 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 { + 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 { + 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. diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 266a0d055d5bc..27843aeaeb0c8 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -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] diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index e4883abc8b56c..13cd26280227e 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -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 { let mut rng = DeterministicRng::new(); Vec::from_iter((0..len).map(|_| rng.next())) diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 3273feb7b5dd4..605e0ef55d707 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -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)]