Skip to content

Commit cd641d2

Browse files
authored
Merge pull request #282 from Eh2406/binary_search
add binary_search and friends
2 parents 0d5ee80 + 7326a6e commit cd641d2

File tree

6 files changed

+591
-0
lines changed

6 files changed

+591
-0
lines changed

src/map.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,63 @@ where
794794
});
795795
}
796796

797+
/// Search over a sorted map for a key.
798+
///
799+
/// Returns the position where that key is present, or the position where it can be inserted to
800+
/// maintain the sort. See [`slice::binary_search`] for more details.
801+
///
802+
/// Computes in **O(log(n))** time, which is notably less scalable than looking the key up
803+
/// using [`get_index_of`][IndexMap::get_index_of], but this can also position missing keys.
804+
pub fn binary_search_keys(&self, x: &K) -> Result<usize, usize>
805+
where
806+
K: Ord,
807+
{
808+
self.as_slice().binary_search_keys(x)
809+
}
810+
811+
/// Search over a sorted map with a comparator function.
812+
///
813+
/// Returns the position where that value is present, or the position where it can be inserted
814+
/// to maintain the sort. See [`slice::binary_search_by`] for more details.
815+
///
816+
/// Computes in **O(log(n))** time.
817+
#[inline]
818+
pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
819+
where
820+
F: FnMut(&'a K, &'a V) -> Ordering,
821+
{
822+
self.as_slice().binary_search_by(f)
823+
}
824+
825+
/// Search over a sorted map with an extraction function.
826+
///
827+
/// Returns the position where that value is present, or the position where it can be inserted
828+
/// to maintain the sort. See [`slice::binary_search_by_key`] for more details.
829+
///
830+
/// Computes in **O(log(n))** time.
831+
#[inline]
832+
pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
833+
where
834+
F: FnMut(&'a K, &'a V) -> B,
835+
B: Ord,
836+
{
837+
self.as_slice().binary_search_by_key(b, f)
838+
}
839+
840+
/// Returns the index of the partition point of a sorted map according to the given predicate
841+
/// (the index of the first element of the second partition).
842+
///
843+
/// See [`slice::partition_point`] for more details.
844+
///
845+
/// Computes in **O(log(n))** time.
846+
#[must_use]
847+
pub fn partition_point<P>(&self, pred: P) -> usize
848+
where
849+
P: FnMut(&K, &V) -> bool,
850+
{
851+
self.as_slice().partition_point(pred)
852+
}
853+
797854
/// Reverses the order of the map’s key-value pairs in place.
798855
///
799856
/// Computes in **O(n)** time and **O(1)** space.

src/map/slice.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,65 @@ impl<K, V> Slice<K, V> {
211211
pub fn into_values(self: Box<Self>) -> IntoValues<K, V> {
212212
IntoValues::new(self.into_entries())
213213
}
214+
215+
/// Search over a sorted map for a key.
216+
///
217+
/// Returns the position where that key is present, or the position where it can be inserted to
218+
/// maintain the sort. See [`slice::binary_search`] for more details.
219+
///
220+
/// Computes in **O(log(n))** time, which is notably less scalable than looking the key up in
221+
/// the map this is a slice from using [`IndexMap::get_index_of`], but this can also position
222+
/// missing keys.
223+
pub fn binary_search_keys(&self, x: &K) -> Result<usize, usize>
224+
where
225+
K: Ord,
226+
{
227+
self.binary_search_by(|p, _| p.cmp(x))
228+
}
229+
230+
/// Search over a sorted map with a comparator function.
231+
///
232+
/// Returns the position where that value is present, or the position where it can be inserted
233+
/// to maintain the sort. See [`slice::binary_search_by`] for more details.
234+
///
235+
/// Computes in **O(log(n))** time.
236+
#[inline]
237+
pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
238+
where
239+
F: FnMut(&'a K, &'a V) -> Ordering,
240+
{
241+
self.entries.binary_search_by(move |a| f(&a.key, &a.value))
242+
}
243+
244+
/// Search over a sorted map with an extraction function.
245+
///
246+
/// Returns the position where that value is present, or the position where it can be inserted
247+
/// to maintain the sort. See [`slice::binary_search_by_key`] for more details.
248+
///
249+
/// Computes in **O(log(n))** time.
250+
#[inline]
251+
pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
252+
where
253+
F: FnMut(&'a K, &'a V) -> B,
254+
B: Ord,
255+
{
256+
self.binary_search_by(|k, v| f(k, v).cmp(b))
257+
}
258+
259+
/// Returns the index of the partition point of a sorted map according to the given predicate
260+
/// (the index of the first element of the second partition).
261+
///
262+
/// See [`slice::partition_point`] for more details.
263+
///
264+
/// Computes in **O(log(n))** time.
265+
#[must_use]
266+
pub fn partition_point<P>(&self, mut pred: P) -> usize
267+
where
268+
P: FnMut(&K, &V) -> bool,
269+
{
270+
self.entries
271+
.partition_point(move |a| pred(&a.key, &a.value))
272+
}
214273
}
215274

216275
impl<'a, K, V> IntoIterator for &'a Slice<K, V> {

src/map/tests.rs

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,3 +447,224 @@ fn iter_default() {
447447
assert_default::<ValuesMut<'static, K, V>>();
448448
assert_default::<IntoValues<K, V>>();
449449
}
450+
451+
#[test]
452+
fn test_binary_search_by() {
453+
// adapted from std's test for binary_search
454+
let b: IndexMap<_, i32> = []
455+
.into_iter()
456+
.enumerate()
457+
.map(|(i, x)| (i + 100, x))
458+
.collect();
459+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(0));
460+
461+
let b: IndexMap<_, i32> = [4]
462+
.into_iter()
463+
.enumerate()
464+
.map(|(i, x)| (i + 100, x))
465+
.collect();
466+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&3)), Err(0));
467+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&4)), Ok(0));
468+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(1));
469+
470+
let b: IndexMap<_, i32> = [1, 2, 4, 6, 8, 9]
471+
.into_iter()
472+
.enumerate()
473+
.map(|(i, x)| (i + 100, x))
474+
.collect();
475+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(3));
476+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&6)), Ok(3));
477+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&7)), Err(4));
478+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&8)), Ok(4));
479+
480+
let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8]
481+
.into_iter()
482+
.enumerate()
483+
.map(|(i, x)| (i + 100, x))
484+
.collect();
485+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&9)), Err(6));
486+
487+
let b: IndexMap<_, i32> = [1, 2, 4, 6, 7, 8, 9]
488+
.into_iter()
489+
.enumerate()
490+
.map(|(i, x)| (i + 100, x))
491+
.collect();
492+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&6)), Ok(3));
493+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(3));
494+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&8)), Ok(5));
495+
496+
let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8, 9]
497+
.into_iter()
498+
.enumerate()
499+
.map(|(i, x)| (i + 100, x))
500+
.collect();
501+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&7)), Err(5));
502+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&0)), Err(0));
503+
504+
let b: IndexMap<_, i32> = [1, 3, 3, 3, 7]
505+
.into_iter()
506+
.enumerate()
507+
.map(|(i, x)| (i + 100, x))
508+
.collect();
509+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&0)), Err(0));
510+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&1)), Ok(0));
511+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&2)), Err(1));
512+
assert!(match b.binary_search_by(|_, x| x.cmp(&3)) {
513+
Ok(1..=3) => true,
514+
_ => false,
515+
});
516+
assert!(match b.binary_search_by(|_, x| x.cmp(&3)) {
517+
Ok(1..=3) => true,
518+
_ => false,
519+
});
520+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&4)), Err(4));
521+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&5)), Err(4));
522+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&6)), Err(4));
523+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&7)), Ok(4));
524+
assert_eq!(b.binary_search_by(|_, x| x.cmp(&8)), Err(5));
525+
}
526+
527+
#[test]
528+
fn test_binary_search_by_key() {
529+
// adapted from std's test for binary_search
530+
let b: IndexMap<_, i32> = []
531+
.into_iter()
532+
.enumerate()
533+
.map(|(i, x)| (i + 100, x))
534+
.collect();
535+
assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(0));
536+
537+
let b: IndexMap<_, i32> = [4]
538+
.into_iter()
539+
.enumerate()
540+
.map(|(i, x)| (i + 100, x))
541+
.collect();
542+
assert_eq!(b.binary_search_by_key(&3, |_, &x| x), Err(0));
543+
assert_eq!(b.binary_search_by_key(&4, |_, &x| x), Ok(0));
544+
assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(1));
545+
546+
let b: IndexMap<_, i32> = [1, 2, 4, 6, 8, 9]
547+
.into_iter()
548+
.enumerate()
549+
.map(|(i, x)| (i + 100, x))
550+
.collect();
551+
assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(3));
552+
assert_eq!(b.binary_search_by_key(&6, |_, &x| x), Ok(3));
553+
assert_eq!(b.binary_search_by_key(&7, |_, &x| x), Err(4));
554+
assert_eq!(b.binary_search_by_key(&8, |_, &x| x), Ok(4));
555+
556+
let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8]
557+
.into_iter()
558+
.enumerate()
559+
.map(|(i, x)| (i + 100, x))
560+
.collect();
561+
assert_eq!(b.binary_search_by_key(&9, |_, &x| x), Err(6));
562+
563+
let b: IndexMap<_, i32> = [1, 2, 4, 6, 7, 8, 9]
564+
.into_iter()
565+
.enumerate()
566+
.map(|(i, x)| (i + 100, x))
567+
.collect();
568+
assert_eq!(b.binary_search_by_key(&6, |_, &x| x), Ok(3));
569+
assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(3));
570+
assert_eq!(b.binary_search_by_key(&8, |_, &x| x), Ok(5));
571+
572+
let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8, 9]
573+
.into_iter()
574+
.enumerate()
575+
.map(|(i, x)| (i + 100, x))
576+
.collect();
577+
assert_eq!(b.binary_search_by_key(&7, |_, &x| x), Err(5));
578+
assert_eq!(b.binary_search_by_key(&0, |_, &x| x), Err(0));
579+
580+
let b: IndexMap<_, i32> = [1, 3, 3, 3, 7]
581+
.into_iter()
582+
.enumerate()
583+
.map(|(i, x)| (i + 100, x))
584+
.collect();
585+
assert_eq!(b.binary_search_by_key(&0, |_, &x| x), Err(0));
586+
assert_eq!(b.binary_search_by_key(&1, |_, &x| x), Ok(0));
587+
assert_eq!(b.binary_search_by_key(&2, |_, &x| x), Err(1));
588+
assert!(match b.binary_search_by_key(&3, |_, &x| x) {
589+
Ok(1..=3) => true,
590+
_ => false,
591+
});
592+
assert!(match b.binary_search_by_key(&3, |_, &x| x) {
593+
Ok(1..=3) => true,
594+
_ => false,
595+
});
596+
assert_eq!(b.binary_search_by_key(&4, |_, &x| x), Err(4));
597+
assert_eq!(b.binary_search_by_key(&5, |_, &x| x), Err(4));
598+
assert_eq!(b.binary_search_by_key(&6, |_, &x| x), Err(4));
599+
assert_eq!(b.binary_search_by_key(&7, |_, &x| x), Ok(4));
600+
assert_eq!(b.binary_search_by_key(&8, |_, &x| x), Err(5));
601+
}
602+
603+
#[test]
604+
fn test_partition_point() {
605+
// adapted from std's test for partition_point
606+
let b: IndexMap<_, i32> = []
607+
.into_iter()
608+
.enumerate()
609+
.map(|(i, x)| (i + 100, x))
610+
.collect();
611+
assert_eq!(b.partition_point(|_, &x| x < 5), 0);
612+
613+
let b: IndexMap<_, i32> = [4]
614+
.into_iter()
615+
.enumerate()
616+
.map(|(i, x)| (i + 100, x))
617+
.collect();
618+
assert_eq!(b.partition_point(|_, &x| x < 3), 0);
619+
assert_eq!(b.partition_point(|_, &x| x < 4), 0);
620+
assert_eq!(b.partition_point(|_, &x| x < 5), 1);
621+
622+
let b: IndexMap<_, i32> = [1, 2, 4, 6, 8, 9]
623+
.into_iter()
624+
.enumerate()
625+
.map(|(i, x)| (i + 100, x))
626+
.collect();
627+
assert_eq!(b.partition_point(|_, &x| x < 5), 3);
628+
assert_eq!(b.partition_point(|_, &x| x < 6), 3);
629+
assert_eq!(b.partition_point(|_, &x| x < 7), 4);
630+
assert_eq!(b.partition_point(|_, &x| x < 8), 4);
631+
632+
let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8]
633+
.into_iter()
634+
.enumerate()
635+
.map(|(i, x)| (i + 100, x))
636+
.collect();
637+
assert_eq!(b.partition_point(|_, &x| x < 9), 6);
638+
639+
let b: IndexMap<_, i32> = [1, 2, 4, 6, 7, 8, 9]
640+
.into_iter()
641+
.enumerate()
642+
.map(|(i, x)| (i + 100, x))
643+
.collect();
644+
assert_eq!(b.partition_point(|_, &x| x < 6), 3);
645+
assert_eq!(b.partition_point(|_, &x| x < 5), 3);
646+
assert_eq!(b.partition_point(|_, &x| x < 8), 5);
647+
648+
let b: IndexMap<_, i32> = [1, 2, 4, 5, 6, 8, 9]
649+
.into_iter()
650+
.enumerate()
651+
.map(|(i, x)| (i + 100, x))
652+
.collect();
653+
assert_eq!(b.partition_point(|_, &x| x < 7), 5);
654+
assert_eq!(b.partition_point(|_, &x| x < 0), 0);
655+
656+
let b: IndexMap<_, i32> = [1, 3, 3, 3, 7]
657+
.into_iter()
658+
.enumerate()
659+
.map(|(i, x)| (i + 100, x))
660+
.collect();
661+
assert_eq!(b.partition_point(|_, &x| x < 0), 0);
662+
assert_eq!(b.partition_point(|_, &x| x < 1), 0);
663+
assert_eq!(b.partition_point(|_, &x| x < 2), 1);
664+
assert_eq!(b.partition_point(|_, &x| x < 3), 1);
665+
assert_eq!(b.partition_point(|_, &x| x < 4), 4);
666+
assert_eq!(b.partition_point(|_, &x| x < 5), 4);
667+
assert_eq!(b.partition_point(|_, &x| x < 6), 4);
668+
assert_eq!(b.partition_point(|_, &x| x < 7), 4);
669+
assert_eq!(b.partition_point(|_, &x| x < 8), 5);
670+
}

0 commit comments

Comments
 (0)