about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2013-01-04 13:52:18 -0800
committerGraydon Hoare <graydon@mozilla.com>2013-04-18 14:39:40 -0700
commit14b7277c4fe6fe7ef26a28931962d8557e2670a7 (patch)
tree289add5430c55677491b6b3ff460ec45c6bf0d0c
parent2a864852774e924f1f9bb68da34adca736211545 (diff)
downloadrust-14b7277c4fe6fe7ef26a28931962d8557e2670a7.tar.gz
rust-14b7277c4fe6fe7ef26a28931962d8557e2670a7.zip
core: add vec::bsearch.
-rw-r--r--src/libcore/vec.rs85
1 files changed, 85 insertions, 0 deletions
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index eebe6a7a37f..01d1a57d78c 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -1223,6 +1223,46 @@ pub fn rposition_between<T>(v: &[T], start: uint, end: uint,
     None
 }
 
+
+
+/**
+ * Binary search a sorted vector with a comparator function.
+ *
+ * The comparator should implement an order consistent with the sort
+ * order of the underlying vector, returning an order code that indicates
+ * whether its argument is `Less`, `Equal` or `Greater` the desired target.
+ *
+ * Returns the index where the comparator returned `Equal`, or `None` if
+ * not found.
+ */
+pub pure fn bsearch<T>(v: &[T], f: &fn(&T) -> Ordering) -> Option<uint> {
+    let mut base : uint = 0;
+    let mut lim : uint = v.len();
+
+    while lim != 0 {
+        let ix = base + (lim >> 1);
+        match f(&v[ix]) {
+            Equal => return Some(ix),
+            Less => {
+                base = ix + 1;
+                lim -= 1;
+            }
+            Greater => ()
+        }
+        lim >>= 1;
+    }
+    return None;
+}
+
+/**
+ * Binary search a sorted vector for a given element.
+ *
+ * Returns the index of the element or None if not found.
+ */
+pub pure fn bsearch_elem<T:TotalOrd>(v: &[T], x: &T) -> Option<uint> {
+    bsearch(v, |p| p.cmp(x))
+}
+
 // FIXME: if issue #586 gets implemented, could have a postcondition
 // saying the two result lists have the same length -- or, could
 // return a nominal record with a constraint saying that, instead of
@@ -3711,6 +3751,51 @@ mod tests {
     }
 
     #[test]
+    fn test_bsearch_elem() {
+        fail_unless!(bsearch_elem([1,2,3,4,5], &5) == Some(4));
+        fail_unless!(bsearch_elem([1,2,3,4,5], &4) == Some(3));
+        fail_unless!(bsearch_elem([1,2,3,4,5], &3) == Some(2));
+        fail_unless!(bsearch_elem([1,2,3,4,5], &2) == Some(1));
+        fail_unless!(bsearch_elem([1,2,3,4,5], &1) == Some(0));
+
+        fail_unless!(bsearch_elem([2,4,6,8,10], &1) == None);
+        fail_unless!(bsearch_elem([2,4,6,8,10], &5) == None);
+        fail_unless!(bsearch_elem([2,4,6,8,10], &4) == Some(1));
+        fail_unless!(bsearch_elem([2,4,6,8,10], &10) == Some(4));
+
+        fail_unless!(bsearch_elem([2,4,6,8], &1) == None);
+        fail_unless!(bsearch_elem([2,4,6,8], &5) == None);
+        fail_unless!(bsearch_elem([2,4,6,8], &4) == Some(1));
+        fail_unless!(bsearch_elem([2,4,6,8], &8) == Some(3));
+
+        fail_unless!(bsearch_elem([2,4,6], &1) == None);
+        fail_unless!(bsearch_elem([2,4,6], &5) == None);
+        fail_unless!(bsearch_elem([2,4,6], &4) == Some(1));
+        fail_unless!(bsearch_elem([2,4,6], &6) == Some(2));
+
+        fail_unless!(bsearch_elem([2,4], &1) == None);
+        fail_unless!(bsearch_elem([2,4], &5) == None);
+        fail_unless!(bsearch_elem([2,4], &2) == Some(0));
+        fail_unless!(bsearch_elem([2,4], &4) == Some(1));
+
+        fail_unless!(bsearch_elem([2], &1) == None);
+        fail_unless!(bsearch_elem([2], &5) == None);
+        fail_unless!(bsearch_elem([2], &2) == Some(0));
+
+        fail_unless!(bsearch_elem([], &1) == None);
+        fail_unless!(bsearch_elem([], &5) == None);
+
+        fail_unless!(bsearch_elem([1,1,1,1,1], &1) != None);
+        fail_unless!(bsearch_elem([1,1,1,1,2], &1) != None);
+        fail_unless!(bsearch_elem([1,1,1,2,2], &1) != None);
+        fail_unless!(bsearch_elem([1,1,2,2,2], &1) != None);
+        fail_unless!(bsearch_elem([1,2,2,2,2], &1) == Some(0));
+
+        fail_unless!(bsearch_elem([1,2,3,4,5], &6) == None);
+        fail_unless!(bsearch_elem([1,2,3,4,5], &0) == None);
+    }
+
+    #[test]
     fn reverse_and_reversed() {
         let mut v: ~[int] = ~[10, 20];
         assert!(v[0] == 10);