From 62945b6ce3e2b504fdc14341e06d191d64788d72 Mon Sep 17 00:00:00 2001 From: Kamal Marhubi Date: Tue, 22 Mar 2016 21:26:57 -0400 Subject: [PATCH] collections: Add slice::binary_search_by_key This method adds to the family of `_by_key` methods, and is the counterpart of `slice::sort_by_key`. It was mentioned on #30423 but was not implemented at that time. Refs #30423 --- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 38 +++++++++++++++++++++++++++++++++++++ src/libcore/slice.rs | 13 +++++++++++++ 3 files changed, 52 insertions(+) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 7540c51e236..88b3517fe71 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -27,6 +27,7 @@ test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![cfg_attr(test, allow(deprecated))] // rand +#![cfg_attr(not(test), feature(slice_binary_search_by_key))] // impl [T] #![cfg_attr(not(stage0), deny(warnings))] #![feature(alloc)] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index db91d911c73..07db33c6be8 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -741,6 +741,44 @@ impl [T] { core_slice::SliceExt::binary_search_by(self, f) } + /// Binary search a sorted slice with a key extraction function. + /// + /// Assumes that the slice is sorted by the key, for instance with + /// `sort_by_key` using the same key extraction function. + /// + /// If a matching value is found then returns `Ok`, containing the + /// index for the matched element; if no match is found then `Err` + /// is returned, containing the index where a matching element could + /// be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements in a slice of pairs sorted by + /// their second elements. The first is found, with a uniquely + /// determined position; the second and third are not found; the + /// fourth could match any position in `[1,4]`. + /// + /// ```rust + /// #![feature(slice_binary_search_by_key)] + /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), + /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), + /// (1, 21), (2, 34), (4, 55)]; + /// + /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); + /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7)); + /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13)); + /// let r = s.binary_search_by_key(&1, |&(a,b)| b); + /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// ``` + #[unstable(feature = "slice_binary_search_by_key", reason = "recently added", issue = "0")] + #[inline] + pub fn binary_search_by_key(&self, b: &B, f: F) -> Result + where F: FnMut(&T) -> B, + B: Ord + { + core_slice::SliceExt::binary_search_by_key(self, b, f) + } + /// Sorts the slice, in place. /// /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`. diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 2e91238bff3..68f5a725b74 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -157,6 +157,11 @@ pub trait SliceExt { fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone; #[stable(feature = "copy_from_slice", since = "1.9.0")] fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy; + + #[unstable(feature = "slice_binary_search_by_key", reason = "recently added", issue = "0")] + fn binary_search_by_key(&self, b: &B, f: F) -> Result + where F: FnMut(&Self::Item) -> B, + B: Ord; } // Use macros to be generic over const/mut @@ -507,6 +512,14 @@ impl SliceExt for [T] { src.as_ptr(), self.as_mut_ptr(), self.len()); } } + + #[inline] + fn binary_search_by_key(&self, b: &B, mut f: F) -> Result + where F: FnMut(&Self::Item) -> B, + B: Ord + { + self.binary_search_by(|k| f(k).cmp(b)) + } } #[stable(feature = "rust1", since = "1.0.0")]