Auto merge of #38610 - djzin:master, r=sfackler
Implementation of plan in issue #27787 for btree_range Still some ergonomics to be worked on, the ::<str,_> is particularly unsightly
This commit is contained in:
commit
0ef85a6b1c
10 changed files with 190 additions and 77 deletions
|
@ -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;
|
||||
|
@ -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
|
||||
///
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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) };
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -207,10 +207,12 @@ 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
|
||||
///
|
||||
|
@ -218,27 +220,24 @@ impl<T: Ord> BTreeSet<T> {
|
|||
/// #![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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -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.
|
||||
|
|
|
@ -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'.
|
||||
///
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ fn test_range_small() {
|
|||
let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();
|
||||
|
||||
let mut j = 0;
|
||||
for ((&k, &v), i) in map.range(Included(&2), Unbounded).zip(2..size) {
|
||||
for ((&k, &v), i) in map.range(2..).zip(2..size) {
|
||||
assert_eq!(k, i);
|
||||
assert_eq!(v, i);
|
||||
j += 1;
|
||||
|
@ -184,7 +184,7 @@ fn test_range_1000() {
|
|||
let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();
|
||||
|
||||
fn test(map: &BTreeMap<u32, u32>, size: u32, min: Bound<&u32>, max: Bound<&u32>) {
|
||||
let mut kvs = map.range(min, max).map(|(&k, &v)| (k, v));
|
||||
let mut kvs = map.range((min, max)).map(|(&k, &v)| (k, v));
|
||||
let mut pairs = (0..size).map(|i| (i, i));
|
||||
|
||||
for (kv, pair) in kvs.by_ref().zip(pairs.by_ref()) {
|
||||
|
@ -201,6 +201,20 @@ fn test_range_1000() {
|
|||
test(&map, size, Unbounded, Unbounded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_borrowed_key() {
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert("aardvark".to_string(), 1);
|
||||
map.insert("baboon".to_string(), 2);
|
||||
map.insert("coyote".to_string(), 3);
|
||||
map.insert("dingo".to_string(), 4);
|
||||
// NOTE: would like to use simply "b".."d" here...
|
||||
let mut iter = map.range::<str, _>((Included("b"),Excluded("d")));
|
||||
assert_eq!(iter.next(), Some((&"baboon".to_string(), &2)));
|
||||
assert_eq!(iter.next(), Some((&"coyote".to_string(), &3)));
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range() {
|
||||
let size = 200;
|
||||
|
@ -208,7 +222,26 @@ fn test_range() {
|
|||
|
||||
for i in 0..size {
|
||||
for j in i..size {
|
||||
let mut kvs = map.range(Included(&i), Included(&j)).map(|(&k, &v)| (k, v));
|
||||
let mut kvs = map.range((Included(&i), Included(&j))).map(|(&k, &v)| (k, v));
|
||||
let mut pairs = (i..j + 1).map(|i| (i, i));
|
||||
|
||||
for (kv, pair) in kvs.by_ref().zip(pairs.by_ref()) {
|
||||
assert_eq!(kv, pair);
|
||||
}
|
||||
assert_eq!(kvs.next(), None);
|
||||
assert_eq!(pairs.next(), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_mut() {
|
||||
let size = 200;
|
||||
let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();
|
||||
|
||||
for i in 0..size {
|
||||
for j in i..size {
|
||||
let mut kvs = map.range_mut((Included(&i), Included(&j))).map(|(&k, &mut v)| (k, v));
|
||||
let mut pairs = (i..j + 1).map(|i| (i, i));
|
||||
|
||||
for (kv, pair) in kvs.by_ref().zip(pairs.by_ref()) {
|
||||
|
|
|
@ -19,6 +19,7 @@ use std::slice;
|
|||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::collections::range::RangeArgument;
|
||||
use std::collections::Bound::{Excluded, Included, Unbounded};
|
||||
|
||||
pub unsafe trait Array {
|
||||
type Element;
|
||||
|
@ -119,8 +120,16 @@ impl<A: Array> ArrayVec<A> {
|
|||
// 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);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#![feature(shared)]
|
||||
#![feature(collections_range)]
|
||||
#![feature(collections_bound)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(staged_api)]
|
||||
|
|
|
@ -57,11 +57,11 @@ fn main() {
|
|||
all_sync_send!(BinaryHeap::<usize>::new(), iter, drain, into_iter);
|
||||
|
||||
all_sync_send!(BTreeMap::<usize, usize>::new(), iter, iter_mut, into_iter, keys, values);
|
||||
is_sync_send!(BTreeMap::<usize, usize>::new(), range(Included(&0), Included(&9)));
|
||||
is_sync_send!(BTreeMap::<usize, usize>::new(), range_mut(Included(&0), Included(&9)));
|
||||
is_sync_send!(BTreeMap::<usize, usize>::new(), range((Included(&0), Included(&9))));
|
||||
is_sync_send!(BTreeMap::<usize, usize>::new(), range_mut((Included(&0), Included(&9))));
|
||||
|
||||
all_sync_send!(BTreeSet::<usize>::new(), iter, into_iter);
|
||||
is_sync_send!(BTreeSet::<usize>::new(), range(Included(&0), Included(&9)));
|
||||
is_sync_send!(BTreeSet::<usize>::new(), range((Included(&0), Included(&9))));
|
||||
is_sync_send!(BTreeSet::<usize>::new(), difference(&BTreeSet::<usize>::new()));
|
||||
is_sync_send!(BTreeSet::<usize>::new(), symmetric_difference(&BTreeSet::<usize>::new()));
|
||||
is_sync_send!(BTreeSet::<usize>::new(), intersection(&BTreeSet::<usize>::new()));
|
||||
|
|
Loading…
Add table
Reference in a new issue