Skip to content

Implementation of plan in issue #27787 for btree_range #38610

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Jan 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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