Skip to content

Commit

Permalink
Auto merge of #38610 - djzin:master, r=sfackler
Browse files Browse the repository at this point in the history
Implementation of plan in issue #27787 for btree_range

Still some ergonomics to be worked on, the ::<str,_> is particularly unsightly
  • Loading branch information
bors committed Jan 15, 2017
2 parents c21f73e + bd04c30 commit 0ef85a6
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 77 deletions.
52 changes: 27 additions & 25 deletions src/libcollections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use core::ops::Index;
use core::{fmt, intrinsics, mem, ptr};

use borrow::Borrow;
use Bound::{self, Excluded, Included, Unbounded};
use Bound::{Excluded, Included, Unbounded};
use range::RangeArgument;

use super::node::{self, Handle, NodeRef, marker};
use super::search;
Expand Down Expand Up @@ -654,10 +655,12 @@ impl<K: Ord, V> BTreeMap<K, V> {
self.fix_right_edge();
}

/// Constructs a double-ended iterator over a sub-range of elements in the map, starting
/// at min, and ending at max. If min is `Unbounded`, then it will be treated as "negative
/// infinity", and if max is `Unbounded`, then it will be treated as "positive infinity".
/// Thus range(Unbounded, Unbounded) will yield the whole collection.
/// Constructs a double-ended iterator over a sub-range of elements in the map.
/// The simplest way is to use the range synax `min..max`, thus `range(min..max)` will
/// yield elements from min (inclusive) to max (exclusive).
/// The range may also be entered as `(Bound<T>, Bound<T>)`, so for example
/// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive
/// range from 4 to 10.
///
/// # Examples
///
Expand All @@ -667,26 +670,25 @@ impl<K: Ord, V> BTreeMap<K, V> {
/// #![feature(btree_range, collections_bound)]
///
/// use std::collections::BTreeMap;
/// use std::collections::Bound::{Included, Unbounded};
/// use std::collections::Bound::Included;
///
/// let mut map = BTreeMap::new();
/// map.insert(3, "a");
/// map.insert(5, "b");
/// map.insert(8, "c");
/// for (&key, &value) in map.range(Included(&4), Included(&8)) {
/// for (&key, &value) in map.range((Included(&4), Included(&8))) {
/// println!("{}: {}", key, value);
/// }
/// assert_eq!(Some((&5, &"b")), map.range(Included(&4), Unbounded).next());
/// assert_eq!(Some((&5, &"b")), map.range(4..).next());
/// ```
#[unstable(feature = "btree_range",
reason = "matches collection reform specification, waiting for dust to settle",
issue = "27787")]
pub fn range<Min: ?Sized + Ord, Max: ?Sized + Ord>(&self,
min: Bound<&Min>,
max: Bound<&Max>)
-> Range<K, V>
where K: Borrow<Min> + Borrow<Max>
pub fn range<T: ?Sized, R>(&self, range: R) -> Range<K, V>
where T: Ord, K: Borrow<T>, R: RangeArgument<T>
{
let min = range.start();
let max = range.end();
let front = match min {
Included(key) => {
match search::search_tree(self.root.as_ref(), key) {
Expand Down Expand Up @@ -745,25 +747,26 @@ impl<K: Ord, V> BTreeMap<K, V> {
}
}

/// Constructs a mutable double-ended iterator over a sub-range of elements in the map, starting
/// at min, and ending at max. If min is `Unbounded`, then it will be treated as "negative
/// infinity", and if max is `Unbounded`, then it will be treated as "positive infinity".
/// Thus range(Unbounded, Unbounded) will yield the whole collection.
/// Constructs a mutable double-ended iterator over a sub-range of elements in the map.
/// The simplest way is to use the range synax `min..max`, thus `range(min..max)` will
/// yield elements from min (inclusive) to max (exclusive).
/// The range may also be entered as `(Bound<T>, Bound<T>)`, so for example
/// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive
/// range from 4 to 10.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(btree_range, collections_bound)]
/// #![feature(btree_range)]
///
/// use std::collections::BTreeMap;
/// use std::collections::Bound::{Included, Excluded};
///
/// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"].iter()
/// .map(|&s| (s, 0))
/// .collect();
/// for (_, balance) in map.range_mut(Included("B"), Excluded("Cheryl")) {
/// for (_, balance) in map.range_mut("B".."Cheryl") {
/// *balance += 100;
/// }
/// for (name, balance) in &map {
Expand All @@ -773,12 +776,11 @@ impl<K: Ord, V> BTreeMap<K, V> {
#[unstable(feature = "btree_range",
reason = "matches collection reform specification, waiting for dust to settle",
issue = "27787")]
pub fn range_mut<Min: ?Sized + Ord, Max: ?Sized + Ord>(&mut self,
min: Bound<&Min>,
max: Bound<&Max>)
-> RangeMut<K, V>
where K: Borrow<Min> + Borrow<Max>
pub fn range_mut<T: ?Sized, R>(&mut self, range: R) -> RangeMut<K, V>
where T: Ord, K: Borrow<T>, R: RangeArgument<T>
{
let min = range.start();
let max = range.end();
let root1 = self.root.as_mut();
let root2 = unsafe { ptr::read(&root1) };

Expand Down
27 changes: 13 additions & 14 deletions src/libcollections/btree/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use core::ops::{BitOr, BitAnd, BitXor, Sub};
use borrow::Borrow;
use btree_map::{BTreeMap, Keys};
use super::Recover;
use Bound;
use range::RangeArgument;

// FIXME(conventions): implement bounded iterators

Expand Down Expand Up @@ -207,38 +207,37 @@ impl<T> BTreeSet<T> {
}

impl<T: Ord> BTreeSet<T> {
/// Constructs a double-ended iterator over a sub-range of elements in the set, starting
/// at min, and ending at max. If min is `Unbounded`, then it will be treated as "negative
/// infinity", and if max is `Unbounded`, then it will be treated as "positive infinity".
/// Thus range(Unbounded, Unbounded) will yield the whole collection.
/// Constructs a double-ended iterator over a sub-range of elements in the set.
/// The simplest way is to use the range synax `min..max`, thus `range(min..max)` will
/// yield elements from min (inclusive) to max (exclusive).
/// The range may also be entered as `(Bound<T>, Bound<T>)`, so for example
/// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive
/// range from 4 to 10.
///
/// # Examples
///
/// ```
/// #![feature(btree_range, collections_bound)]
///
/// use std::collections::BTreeSet;
/// use std::collections::Bound::{Included, Unbounded};
/// use std::collections::Bound::Included;
///
/// let mut set = BTreeSet::new();
/// set.insert(3);
/// set.insert(5);
/// set.insert(8);
/// for &elem in set.range(Included(&4), Included(&8)) {
/// for &elem in set.range((Included(&4), Included(&8))) {
/// println!("{}", elem);
/// }
/// assert_eq!(Some(&5), set.range(Included(&4), Unbounded).next());
/// assert_eq!(Some(&5), set.range(4..).next());
/// ```
#[unstable(feature = "btree_range",
reason = "matches collection reform specification, waiting for dust to settle",
issue = "27787")]
pub fn range<'a, Min: ?Sized + Ord, Max: ?Sized + Ord>(&'a self,
min: Bound<&Min>,
max: Bound<&Max>)
-> Range<'a, T>
where T: Borrow<Min> + Borrow<Max>
pub fn range<K: ?Sized, R>(&self, range: R) -> Range<T>
where K: Ord, T: Borrow<K>, R: RangeArgument<K>
{
Range { iter: self.map.range(min, max) }
Range { iter: self.map.range(range) }
}
}

Expand Down
90 changes: 66 additions & 24 deletions src/libcollections/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,78 +15,120 @@
//! Range syntax.

use core::ops::{RangeFull, Range, RangeTo, RangeFrom};
use Bound::{self, Excluded, Included, Unbounded};

/// **RangeArgument** is implemented by Rust's built-in range types, produced
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
pub trait RangeArgument<T> {
/// Start index (inclusive)
pub trait RangeArgument<T: ?Sized> {
/// Start index bound
///
/// Return start value if present, else `None`.
/// Return start value as a `Bound`
///
/// # Examples
///
/// ```
/// #![feature(collections)]
/// #![feature(collections_range)]
/// #![feature(collections_bound)]
///
/// extern crate collections;
///
/// # fn main() {
/// use collections::range::RangeArgument;
/// use collections::Bound::*;
///
/// assert_eq!((..10).start(), None);
/// assert_eq!((3..10).start(), Some(&3));
/// assert_eq!((..10).start(), Unbounded);
/// assert_eq!((3..10).start(), Included(&3));
/// # }
/// ```
fn start(&self) -> Option<&T> {
None
}
fn start(&self) -> Bound<&T>;

/// End index (exclusive)
/// End index bound
///
/// Return end value if present, else `None`.
/// Return end value as a `Bound`
///
/// # Examples
///
/// ```
/// #![feature(collections)]
/// #![feature(collections_range)]
/// #![feature(collections_bound)]
///
/// extern crate collections;
///
/// # fn main() {
/// use collections::range::RangeArgument;
/// use collections::Bound::*;
///
/// assert_eq!((3..).end(), None);
/// assert_eq!((3..10).end(), Some(&10));
/// assert_eq!((3..).end(), Unbounded);
/// assert_eq!((3..10).end(), Excluded(&10));
/// # }
/// ```
fn end(&self) -> Option<&T> {
None
}
fn end(&self) -> Bound<&T>;
}

// FIXME add inclusive ranges to RangeArgument

impl<T> RangeArgument<T> for RangeFull {}
impl<T: ?Sized> RangeArgument<T> for RangeFull {
fn start(&self) -> Bound<&T> {
Unbounded
}
fn end(&self) -> Bound<&T> {
Unbounded
}
}

impl<T> RangeArgument<T> for RangeFrom<T> {
fn start(&self) -> Option<&T> {
Some(&self.start)
fn start(&self) -> Bound<&T> {
Included(&self.start)
}
fn end(&self) -> Bound<&T> {
Unbounded
}
}

impl<T> RangeArgument<T> for RangeTo<T> {
fn end(&self) -> Option<&T> {
Some(&self.end)
fn start(&self) -> Bound<&T> {
Unbounded
}
fn end(&self) -> Bound<&T> {
Excluded(&self.end)
}
}

impl<T> RangeArgument<T> for Range<T> {
fn start(&self) -> Option<&T> {
Some(&self.start)
fn start(&self) -> Bound<&T> {
Included(&self.start)
}
fn end(&self) -> Option<&T> {
Some(&self.end)
fn end(&self) -> Bound<&T> {
Excluded(&self.end)
}
}

impl<T> RangeArgument<T> for (Bound<T>, Bound<T>) {
fn start(&self) -> Bound<&T> {
match *self {
(Included(ref start), _) => Included(start),
(Excluded(ref start), _) => Excluded(start),
(Unbounded, _) => Unbounded,
}
}

fn end(&self) -> Bound<&T> {
match *self {
(_, Included(ref end)) => Included(end),
(_, Excluded(ref end)) => Excluded(end),
(_, Unbounded) => Unbounded,
}
}
}

impl<'a, T: ?Sized + 'a> RangeArgument<T> for (Bound<&'a T>, Bound<&'a T>) {
fn start(&self) -> Bound<&T> {
self.0
}

fn end(&self) -> Bound<&T> {
self.1
}
}
13 changes: 11 additions & 2 deletions src/libcollections/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ use std_unicode::str as unicode_str;

use borrow::{Cow, ToOwned};
use range::RangeArgument;
use Bound::{Excluded, Included, Unbounded};
use str::{self, FromStr, Utf8Error, Chars};
use vec::Vec;
use boxed::Box;
Expand Down Expand Up @@ -1350,8 +1351,16 @@ impl String {
// Because the range removal happens in Drop, if the Drain iterator is leaked,
// the removal will not happen.
let len = self.len();
let start = *range.start().unwrap_or(&0);
let end = *range.end().unwrap_or(&len);
let start = match range.start() {
Included(&n) => n,
Excluded(&n) => n + 1,
Unbounded => 0,
};
let end = match range.end() {
Included(&n) => n + 1,
Excluded(&n) => n,
Unbounded => len,
};

// Take out two simultaneous borrows. The &mut String won't be accessed
// until iteration is over, in Drop.
Expand Down
13 changes: 11 additions & 2 deletions src/libcollections/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ use core::ptr::Shared;
use core::slice;

use super::range::RangeArgument;
use Bound::{Excluded, Included, Unbounded};

/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
///
Expand Down Expand Up @@ -1060,8 +1061,16 @@ impl<T> Vec<T> {
// the hole, and the vector length is restored to the new length.
//
let len = self.len();
let start = *range.start().unwrap_or(&0);
let end = *range.end().unwrap_or(&len);
let start = match range.start() {
Included(&n) => n,
Excluded(&n) => n + 1,
Unbounded => 0,
};
let end = match range.end() {
Included(&n) => n + 1,
Excluded(&n) => n,
Unbounded => len,
};
assert!(start <= end);
assert!(end <= len);

Expand Down
13 changes: 11 additions & 2 deletions src/libcollections/vec_deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use core::cmp;
use alloc::raw_vec::RawVec;

use super::range::RangeArgument;
use Bound::{Excluded, Included, Unbounded};
use super::vec::Vec;

const INITIAL_CAPACITY: usize = 7; // 2^3 - 1
Expand Down Expand Up @@ -852,8 +853,16 @@ impl<T> VecDeque<T> {
// and the head/tail values will be restored correctly.
//
let len = self.len();
let start = *range.start().unwrap_or(&0);
let end = *range.end().unwrap_or(&len);
let start = match range.start() {
Included(&n) => n,
Excluded(&n) => n + 1,
Unbounded => 0,
};
let end = match range.end() {
Included(&n) => n + 1,
Excluded(&n) => n,
Unbounded => len,
};
assert!(start <= end, "drain lower bound was too large");
assert!(end <= len, "drain upper bound was too large");

Expand Down
Loading

0 comments on commit 0ef85a6

Please sign in to comment.