Skip to content

Commit a4b354c

Browse files
committed
core: Add binary_search and binary_search_elem methods to slices.
These are like the existing bsearch methods but if the search fails, it returns the next insertion point. The new `binary_search` returns a `BinarySearchResult` that is either `Found` or `NotFound`. For convenience, the `found` and `not_found` methods convert to `Option`, ala `Result`. Deprecate bsearch and bsearch_elem.
1 parent 76d46af commit a4b354c

File tree

8 files changed

+186
-47
lines changed

8 files changed

+186
-47
lines changed

src/etc/unicode.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -293,13 +293,12 @@ def emit_bsearch_range_table(f):
293293
f.write("""
294294
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
295295
use core::cmp::{Equal, Less, Greater};
296-
use core::slice::ImmutableVector;
297-
use core::option::None;
298-
r.bsearch(|&(lo,hi)| {
296+
use core::slice::ImmutableSlice;
297+
r.binary_search(|&(lo,hi)| {
299298
if lo <= c && c <= hi { Equal }
300299
else if hi < c { Less }
301300
else { Greater }
302-
}) != None
301+
}).found().is_some()
303302
}\n
304303
""")
305304

@@ -352,9 +351,10 @@ def emit_conversions_module(f, lowerupper, upperlower):
352351
f.write("pub mod conversions {")
353352
f.write("""
354353
use core::cmp::{Equal, Less, Greater};
355-
use core::slice::ImmutableVector;
354+
use core::slice::ImmutableSlice;
356355
use core::tuple::Tuple2;
357356
use core::option::{Option, Some, None};
357+
use core::slice;
358358
359359
pub fn to_lower(c: char) -> char {
360360
match bsearch_case_table(c, LuLl_table) {
@@ -371,11 +371,14 @@ def emit_conversions_module(f, lowerupper, upperlower):
371371
}
372372
373373
fn bsearch_case_table(c: char, table: &'static [(char, char)]) -> Option<uint> {
374-
table.bsearch(|&(key, _)| {
374+
match table.binary_search(|&(key, _)| {
375375
if c == key { Equal }
376376
else if key < c { Less }
377377
else { Greater }
378-
})
378+
}) {
379+
slice::Found(i) => Some(i),
380+
slice::NotFound(_) => None,
381+
}
379382
}
380383
381384
""")
@@ -387,8 +390,8 @@ def emit_conversions_module(f, lowerupper, upperlower):
387390

388391
def emit_grapheme_module(f, grapheme_table, grapheme_cats):
389392
f.write("""pub mod grapheme {
390-
use core::option::{Some, None};
391-
use core::slice::ImmutableVector;
393+
use core::slice::ImmutableSlice;
394+
use core::slice;
392395
393396
#[allow(non_camel_case_types)]
394397
#[deriving(Clone)]
@@ -400,16 +403,16 @@ def emit_grapheme_module(f, grapheme_table, grapheme_cats):
400403
401404
fn bsearch_range_value_table(c: char, r: &'static [(char, char, GraphemeCat)]) -> GraphemeCat {
402405
use core::cmp::{Equal, Less, Greater};
403-
match r.bsearch(|&(lo, hi, _)| {
406+
match r.binary_search(|&(lo, hi, _)| {
404407
if lo <= c && c <= hi { Equal }
405408
else if hi < c { Less }
406409
else { Greater }
407410
}) {
408-
Some(idx) => {
411+
slice::Found(idx) => {
409412
let (_, _, cat) = r[idx];
410413
cat
411414
}
412-
None => GC_Any
415+
slice::NotFound(_) => GC_Any
413416
}
414417
}
415418
@@ -427,20 +430,21 @@ def emit_grapheme_module(f, grapheme_table, grapheme_cats):
427430
def emit_charwidth_module(f, width_table):
428431
f.write("pub mod charwidth {\n")
429432
f.write(" use core::option::{Option, Some, None};\n")
430-
f.write(" use core::slice::ImmutableVector;\n")
433+
f.write(" use core::slice::ImmutableSlice;\n")
434+
f.write(" use core::slice;\n")
431435
f.write("""
432436
fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 {
433437
use core::cmp::{Equal, Less, Greater};
434-
match r.bsearch(|&(lo, hi, _, _)| {
438+
match r.binary_search(|&(lo, hi, _, _)| {
435439
if lo <= c && c <= hi { Equal }
436440
else if hi < c { Less }
437441
else { Greater }
438442
}) {
439-
Some(idx) => {
443+
slice::Found(idx) => {
440444
let (_, _, r_ncjk, r_cjk) = r[idx];
441445
if is_cjk { r_cjk } else { r_ncjk }
442446
}
443-
None => 1
447+
slice::NotFound(_) => 1
444448
}
445449
}
446450
""")
@@ -525,19 +529,19 @@ def comp_pfun(char):
525529

526530
f.write("""
527531
fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 {
528-
use core::option::{Some, None};
529532
use core::cmp::{Equal, Less, Greater};
530-
use core::slice::ImmutableVector;
531-
match r.bsearch(|&(lo, hi, _)| {
533+
use core::slice::ImmutableSlice;
534+
use core::slice;
535+
match r.binary_search(|&(lo, hi, _)| {
532536
if lo <= c && c <= hi { Equal }
533537
else if hi < c { Less }
534538
else { Greater }
535539
}) {
536-
Some(idx) => {
540+
slice::Found(idx) => {
537541
let (_, _, result) = r[idx];
538542
result
539543
}
540-
None => 0
544+
slice::NotFound(_) => 0
541545
}
542546
}\n
543547
""")

src/libcollections/slice.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ pub use core::slice::{Chunks, Slice, ImmutableSlice, ImmutablePartialEqSlice};
102102
pub use core::slice::{ImmutableOrdSlice, MutableSlice, Items, MutItems};
103103
pub use core::slice::{MutSplits, MutChunks};
104104
pub use core::slice::{bytes, MutableCloneableSlice};
105+
pub use core::slice::{BinarySearchResult, Found, NotFound};
105106

106107
// Functional utilities
107108

src/libcore/slice.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use raw::{Repr};
5151
// Avoid conflicts with *both* the Slice trait (buggy) and the `slice::raw` module.
5252
use RawSlice = raw::Slice;
5353

54+
5455
//
5556
// Extension traits
5657
//
@@ -205,8 +206,25 @@ pub trait ImmutableSlice<'a, T> {
205206
* Returns the index where the comparator returned `Equal`, or `None` if
206207
* not found.
207208
*/
209+
#[deprecated = "use binary_search"]
208210
fn bsearch(&self, f: |&T| -> Ordering) -> Option<uint>;
209211

212+
/**
213+
* Binary search a sorted vector with a comparator function.
214+
*
215+
* The comparator function should implement an order consistent
216+
* with the sort order of the underlying vector, returning an
217+
* order code that indicates whether its argument is `Less`,
218+
* `Equal` or `Greater` the desired target.
219+
*
220+
* If the value is found then `Found` is returned, containing the
221+
* index of the matching element; if the value is not found then
222+
* `NotFound` is returned, containing the index where a matching
223+
* element could be inserted while maintaining sorted order.
224+
*/
225+
#[unstable]
226+
fn binary_search(&self, f: |&T| -> Ordering) -> BinarySearchResult;
227+
210228
/**
211229
* Returns an immutable reference to the first element in this slice
212230
* and adjusts the slice in place so that it no longer contains
@@ -377,6 +395,7 @@ impl<'a,T> ImmutableSlice<'a, T> for &'a [T] {
377395
}
378396

379397

398+
#[deprecated = "use binary_search"]
380399
fn bsearch(&self, f: |&T| -> Ordering) -> Option<uint> {
381400
let mut base : uint = 0;
382401
let mut lim : uint = self.len();
@@ -396,6 +415,26 @@ impl<'a,T> ImmutableSlice<'a, T> for &'a [T] {
396415
return None;
397416
}
398417

418+
#[unstable]
419+
fn binary_search(&self, f: |&T| -> Ordering) -> BinarySearchResult {
420+
let mut base : uint = 0;
421+
let mut lim : uint = self.len();
422+
423+
while lim != 0 {
424+
let ix = base + (lim >> 1);
425+
match f(&self[ix]) {
426+
Equal => return Found(ix),
427+
Less => {
428+
base = ix + 1;
429+
lim -= 1;
430+
}
431+
Greater => ()
432+
}
433+
lim >>= 1;
434+
}
435+
return NotFound(base);
436+
}
437+
399438
fn shift_ref(&mut self) -> Option<&'a T> {
400439
unsafe {
401440
let s: &mut RawSlice<T> = transmute(self);
@@ -826,13 +865,31 @@ pub trait ImmutableOrdSlice<T: Ord> {
826865
*
827866
* Returns the index of the element or None if not found.
828867
*/
868+
#[deprecated = "use binary_search_elem"]
829869
fn bsearch_elem(&self, x: &T) -> Option<uint>;
870+
871+
/**
872+
* Binary search a sorted vector for a given element.
873+
*
874+
* If the value is found then `Found` is returned, containing the
875+
* index of the matching element; if the value is not found then
876+
* `NotFound` is returned, containing the index where a matching
877+
* element could be inserted while maintaining sorted order.
878+
*/
879+
#[unstable]
880+
fn binary_search_elem(&self, x: &T) -> BinarySearchResult;
830881
}
831882

832883
impl<'a, T: Ord> ImmutableOrdSlice<T> for &'a [T] {
884+
#[deprecated = "use binary_search_elem"]
833885
fn bsearch_elem(&self, x: &T) -> Option<uint> {
834886
self.bsearch(|p| p.cmp(x))
835887
}
888+
889+
#[unstable]
890+
fn binary_search_elem(&self, x: &T) -> BinarySearchResult {
891+
self.binary_search(|p| p.cmp(x))
892+
}
836893
}
837894

838895
/// Trait for &[T] where T is Cloneable
@@ -1337,6 +1394,41 @@ impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutChunks<'a, T> {
13371394

13381395

13391396

1397+
/// The result of calling `binary_search`.
1398+
///
1399+
/// `Found` means the search succeeded, and the contained value is the
1400+
/// index of the matching element. `NotFound` means the search
1401+
/// succeeded, and the contained value is an index where a matching
1402+
/// value could be inserted while maintaining sort order.
1403+
#[deriving(PartialEq, Show)]
1404+
pub enum BinarySearchResult {
1405+
/// The index of the found value.
1406+
Found(uint),
1407+
/// The index where the value should have been found.
1408+
NotFound(uint)
1409+
}
1410+
1411+
impl BinarySearchResult {
1412+
/// Converts a `Found` to `Some`, `NotFound` to `None`.
1413+
/// Similar to `Result::ok`.
1414+
pub fn found(&self) -> Option<uint> {
1415+
match *self {
1416+
Found(i) => Some(i),
1417+
NotFound(_) => None
1418+
}
1419+
}
1420+
1421+
/// Convert a `Found` to `None`, `NotFound` to `Some`.
1422+
/// Similar to `Result::err`.
1423+
pub fn not_found(&self) -> Option<uint> {
1424+
match *self {
1425+
Found(_) => None,
1426+
NotFound(i) => Some(i)
1427+
}
1428+
}
1429+
}
1430+
1431+
13401432

13411433
//
13421434
// Free functions

src/libcoretest/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ mod option;
2828
mod ptr;
2929
mod raw;
3030
mod result;
31+
mod slice;
3132
mod tuple;

src/libcoretest/slice.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::slice::{Found, NotFound};
12+
13+
#[test]
14+
fn binary_search_not_found() {
15+
let b = [1i, 2, 4, 6, 8, 9];
16+
assert!(b.binary_search(|v| v.cmp(&6)) == Found(3));
17+
let b = [1i, 2, 4, 6, 8, 9];
18+
assert!(b.binary_search(|v| v.cmp(&5)) == NotFound(3));
19+
let b = [1i, 2, 4, 6, 7, 8, 9];
20+
assert!(b.binary_search(|v| v.cmp(&6)) == Found(3));
21+
let b = [1i, 2, 4, 6, 7, 8, 9];
22+
assert!(b.binary_search(|v| v.cmp(&5)) == NotFound(3));
23+
let b = [1i, 2, 4, 6, 8, 9];
24+
assert!(b.binary_search(|v| v.cmp(&8)) == Found(4));
25+
let b = [1i, 2, 4, 6, 8, 9];
26+
assert!(b.binary_search(|v| v.cmp(&7)) == NotFound(4));
27+
let b = [1i, 2, 4, 6, 7, 8, 9];
28+
assert!(b.binary_search(|v| v.cmp(&8)) == Found(5));
29+
let b = [1i, 2, 4, 5, 6, 8, 9];
30+
assert!(b.binary_search(|v| v.cmp(&7)) == NotFound(5));
31+
let b = [1i, 2, 4, 5, 6, 8, 9];
32+
assert!(b.binary_search(|v| v.cmp(&0)) == NotFound(0));
33+
let b = [1i, 2, 4, 5, 6, 8];
34+
assert!(b.binary_search(|v| v.cmp(&9)) == NotFound(6));
35+
}

src/libregex/vm.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
use std::cmp;
3737
use std::mem;
38+
use std::slice;
3839
use std::slice::MutableSlice;
3940
use compile::{
4041
Program,
@@ -222,8 +223,8 @@ impl<'r, 't> Nfa<'r, 't> {
222223
let negate = flags & FLAG_NEGATED > 0;
223224
let casei = flags & FLAG_NOCASE > 0;
224225
let found = ranges.as_slice();
225-
let found = found.bsearch(|&rc| class_cmp(casei, c, rc));
226-
let found = found.is_some();
226+
let found = found.binary_search(|&rc| class_cmp(casei, c, rc))
227+
.found().is_some();
227228
if found ^ negate {
228229
self.add(nlist, pc+1, caps);
229230
}
@@ -513,15 +514,15 @@ pub fn is_word(c: Option<char>) -> bool {
513514
// Try the common ASCII case before invoking binary search.
514515
match c {
515516
'_' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' => true,
516-
_ => PERLW.bsearch(|&(start, end)| {
517+
_ => PERLW.binary_search(|&(start, end)| {
517518
if c >= start && c <= end {
518519
Equal
519520
} else if start > c {
520521
Greater
521522
} else {
522523
Less
523524
}
524-
}).is_some()
525+
}).found().is_some()
525526
}
526527
}
527528

0 commit comments

Comments
 (0)