Skip to content

Commit 9b903bf

Browse files
committed
Implement append and split_off for BTreeMap and BTreeSet
Changes the internal SearchStack API to return the key on removal as well.
1 parent 32a12c8 commit 9b903bf

File tree

5 files changed

+426
-11
lines changed

5 files changed

+426
-11
lines changed

src/libcollections/btree/map.rs

+136-11
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
348348

349349
loop {
350350
let result = stack.with(move |pusher, node| {
351-
// Same basic logic as found in `find`, but with PartialSearchStack mediating the
351+
// Same basic logic as found in `get`, but with PartialSearchStack mediating the
352352
// actual nodes for us
353353
match Node::search(node, &key) {
354354
Found(mut handle) => {
@@ -438,14 +438,14 @@ impl<K: Ord, V> BTreeMap<K, V> {
438438
/// ```
439439
#[stable(feature = "rust1", since = "1.0.0")]
440440
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V> where K: Borrow<Q>, Q: Ord {
441-
// See `swap` for a more thorough description of the stuff going on in here
441+
// See `insert` for a more thorough description of the stuff going on in here
442442
let mut stack = stack::PartialSearchStack::new(self);
443443
loop {
444444
let result = stack.with(move |pusher, node| {
445445
match Node::search(node, key) {
446446
Found(handle) => {
447447
// Perfect match. Terminate the stack here, and remove the entry
448-
Finished(Some(pusher.seal(handle).remove()))
448+
Finished(Some(pusher.seal(handle).remove().1))
449449
},
450450
GoDown(handle) => {
451451
// We need to keep searching, try to go down the next edge
@@ -463,6 +463,131 @@ impl<K: Ord, V> BTreeMap<K, V> {
463463
}
464464
}
465465
}
466+
467+
/// Moves all elements from `other` into `Self`, leaving `other` empty.
468+
///
469+
/// # Examples
470+
///
471+
/// ```
472+
/// # #![feature(btree_append_split_off)]
473+
/// use std::collections::BTreeMap;
474+
///
475+
/// let mut a = BTreeMap::new();
476+
/// a.insert(1, "a");
477+
/// a.insert(2, "b");
478+
/// a.insert(3, "c");
479+
///
480+
/// let mut b = BTreeMap::new();
481+
/// b.insert(3, "d");
482+
/// b.insert(4, "e");
483+
/// b.insert(5, "f");
484+
///
485+
/// a.append(&mut b);
486+
///
487+
/// assert_eq!(a.len(), 5);
488+
/// assert_eq!(b.len(), 0);
489+
///
490+
/// assert_eq!(a[&1], "a");
491+
/// assert_eq!(a[&2], "b");
492+
/// assert_eq!(a[&3], "d");
493+
/// assert_eq!(a[&4], "e");
494+
/// assert_eq!(a[&5], "f");
495+
/// ```
496+
#[unstable(feature = "append",
497+
reason = "recently added as part of collections reform 2")]
498+
pub fn append(&mut self, other: &mut Self) {
499+
let b = other.b;
500+
for (key, value) in mem::replace(other, BTreeMap::with_b(b)) {
501+
self.insert(key, value);
502+
}
503+
}
504+
505+
/// Splits the map into two at the given key,
506+
/// retaining the first half in-place and returning the second one.
507+
///
508+
/// # Examples
509+
///
510+
/// ```
511+
/// # #![feature(btree_append_split_off)]
512+
/// use std::collections::BTreeMap;
513+
///
514+
/// a.insert(1, "a");
515+
/// a.insert(2, "b");
516+
/// a.insert(3, "c");
517+
/// a.insert(4, "d");
518+
/// a.insert(5, "e");
519+
///
520+
/// let b = a.split_off(3);
521+
///
522+
/// assert_eq!(a.len(), 2);
523+
/// assert_eq!(b.len(), 3);
524+
///
525+
/// assert_eq!(a[&1], "a");
526+
/// assert_eq!(a[&2], "b");
527+
/// assert_eq!(b[&3], "c");
528+
/// assert_eq!(b[&4], "d");
529+
/// assert_eq!(b[&5], "e");
530+
/// ```
531+
#[unstable(feature = "split_off",
532+
reason = "recently added as part of collections reform 2")]
533+
pub fn split_off<Q: ?Sized>(&mut self, at: &Q) -> Self where K: Borrow<Q>, Q: Ord {
534+
let mut other = BTreeMap::new();
535+
536+
if self.len() == 0 {
537+
return other;
538+
}
539+
540+
// FIXME(RFC #811) We can't check for `at` pointing before the
541+
// first element and then swap `self` and `other`, because
542+
// `self` will still be borrowed immutably.
543+
// `unwrap` won't panic because `self.len()` > 0.
544+
let should_swap = at <= self.keys().next().unwrap().borrow();
545+
546+
// Does `at` point before the first element?
547+
if should_swap {
548+
mem::swap(self, &mut other);
549+
return other;
550+
}
551+
// Does `at` point behind the last element?
552+
// `unwrap` won't panic because `self.len()` > 0.
553+
else if at > self.keys().rev().next().unwrap().borrow() {
554+
return other;
555+
}
556+
557+
let mut remove_greater_or_equal = || {
558+
let mut stack = stack::PartialSearchStack::new(self);
559+
loop {
560+
let result = stack.with(move |pusher, node| {
561+
match Node::greater_or_equal(node, at) {
562+
Found(handle) => {
563+
// Found a matching key. Terminate the stack here, and remove the entry
564+
Finished(Some(pusher.seal(handle).remove()))
565+
},
566+
GoDown(handle) => {
567+
// We need to keep searching, try to go down the next edge
568+
match handle.force() {
569+
// We're at a leaf; no matching key found
570+
Leaf(_) => Finished(None),
571+
Internal(internal_handle) => Continue(pusher.push(internal_handle))
572+
}
573+
}
574+
}
575+
});
576+
match result {
577+
Finished(ret) => return ret,
578+
Continue(new_stack) => stack = new_stack
579+
}
580+
}
581+
};
582+
583+
// Remove and move all elements greater than or equal to at
584+
loop {
585+
match remove_greater_or_equal() {
586+
Some((key, value)) => other.insert(key, value),
587+
None => return other,
588+
};
589+
}
590+
}
466591
}
467592

468593
#[stable(feature = "rust1", since = "1.0.0")]
@@ -693,16 +818,16 @@ mod stack {
693818
impl<'a, K, V> SearchStack<'a, K, V, handle::KV, handle::Leaf> {
694819
/// Removes the key and value in the top element of the stack, then handles underflows as
695820
/// described in BTree's pop function.
696-
fn remove_leaf(mut self) -> V {
821+
fn remove_leaf(mut self) -> (K, V) {
697822
self.map.length -= 1;
698823

699824
// Remove the key-value pair from the leaf that this search stack points to.
700825
// Then, note if the leaf is underfull, and promptly forget the leaf and its ptr
701826
// to avoid ownership issues.
702-
let (value, mut underflow) = unsafe {
703-
let (_, value) = self.top.from_raw_mut().remove_as_leaf();
827+
let (key, value, mut underflow) = unsafe {
828+
let (key, value) = self.top.from_raw_mut().remove_as_leaf();
704829
let underflow = self.top.from_raw().node().is_underfull();
705-
(value, underflow)
830+
(key, value, underflow)
706831
};
707832

708833
loop {
@@ -717,7 +842,7 @@ mod stack {
717842
self.map.depth -= 1;
718843
self.map.root.hoist_lone_child();
719844
}
720-
return value;
845+
return (key, value);
721846
}
722847
Some(mut handle) => {
723848
if underflow {
@@ -728,7 +853,7 @@ mod stack {
728853
}
729854
} else {
730855
// All done!
731-
return value;
856+
return (key, value);
732857
}
733858
}
734859
}
@@ -739,7 +864,7 @@ mod stack {
739864
impl<'a, K, V> SearchStack<'a, K, V, handle::KV, handle::LeafOrInternal> {
740865
/// Removes the key and value in the top element of the stack, then handles underflows as
741866
/// described in BTree's pop function.
742-
pub fn remove(self) -> V {
867+
pub fn remove(self) -> (K, V) {
743868
// Ensure that the search stack goes to a leaf. This is necessary to perform deletion
744869
// in a BTree. Note that this may put the tree in an inconsistent state (further
745870
// described in into_leaf's comments), but this is immediately fixed by the
@@ -1220,7 +1345,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
12201345
/// Takes the value of the entry out of the map, and returns it.
12211346
#[stable(feature = "rust1", since = "1.0.0")]
12221347
pub fn remove(self) -> V {
1223-
self.stack.remove()
1348+
self.stack.remove().1
12241349
}
12251350
}
12261351

src/libcollections/btree/node.rs

+24
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,15 @@ impl<K: Ord, V> Node<K, V> {
557557
(index, false) => GoDown(Handle { node: node, index: index, marker: PhantomData }),
558558
}
559559
}
560+
561+
/// Searches for the first key greater than or equal to `key`.
562+
pub fn greater_or_equal<Q: ?Sized, NodeRef: Deref<Target=Node<K, V>>>(node: NodeRef, key: &Q)
563+
-> SearchResult<NodeRef> where K: Borrow<Q>, Q: Ord {
564+
match node.as_slices_internal().greater_or_equal_linear(key) {
565+
(index, true) => Found(Handle { node: node, index: index, marker: PhantomData }),
566+
(index, false) => GoDown(Handle { node: node, index: index, marker: PhantomData }),
567+
}
568+
}
560569
}
561570

562571
// Public interface
@@ -1609,3 +1618,18 @@ macro_rules! node_slice_impl {
16091618

16101619
node_slice_impl!(NodeSlice, Traversal, as_slices_internal, index, iter);
16111620
node_slice_impl!(MutNodeSlice, MutTraversal, as_slices_internal_mut, index_mut, iter_mut);
1621+
1622+
impl<'a, K: Ord + 'a, V: 'a> NodeSlice<'a, K, V> {
1623+
/// Performs linear search in a slice to find the first element greater than
1624+
/// or equal to `key`.
1625+
fn greater_or_equal_linear<Q: ?Sized>(&self, key: &Q) -> (usize, bool)
1626+
where K: Borrow<Q>, Q: Ord {
1627+
for (i, k) in self.keys.iter().enumerate() {
1628+
match key.cmp(k.borrow()) {
1629+
Greater => {}
1630+
Less | Equal => return (i, true),
1631+
}
1632+
}
1633+
(self.keys.len(), false)
1634+
}
1635+
}

src/libcollections/btree/set.rs

+68
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,74 @@ impl<T: Ord> BTreeSet<T> {
453453
pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool where T: Borrow<Q>, Q: Ord {
454454
self.map.remove(value).is_some()
455455
}
456+
457+
/// Moves all elements from `other` into `Self`, leaving `other` empty.
458+
///
459+
/// # Examples
460+
///
461+
/// ```
462+
/// # #![feature(btree_append_split_off)]
463+
/// use std::collections::BTreeMap;
464+
///
465+
/// let mut a = BTreeSet::new();
466+
/// a.insert(1);
467+
/// a.insert(2);
468+
/// a.insert(3);
469+
///
470+
/// let mut b = BTreeSet::new();
471+
/// b.insert(3);
472+
/// b.insert(4);
473+
/// b.insert(5);
474+
///
475+
/// a.append(&mut b);
476+
///
477+
/// assert_eq!(a.len(), 5);
478+
/// assert_eq!(b.len(), 0);
479+
///
480+
/// assert!(a.contains(&1));
481+
/// assert!(a.contains(&2));
482+
/// assert!(a.contains(&3));
483+
/// assert!(a.contains(&4));
484+
/// assert!(a.contains(&5));
485+
/// ```
486+
#[unstable(feature = "btree_append_split_off",
487+
reason = "recently added as part of collections reform 2")]
488+
pub fn append(&mut self, other: &mut Self) {
489+
self.map.append(&mut other.map);
490+
}
491+
492+
/// Splits the set into two at the given key,
493+
/// retaining the first half in-place and returning the second one.
494+
///
495+
/// # Examples
496+
///
497+
/// ```
498+
/// # #![feature(btree_append_split_off)]
499+
/// use std::collections::BTreeMap;
500+
///
501+
/// a.insert(1)
502+
/// a.insert(2)
503+
/// a.insert(3)
504+
/// a.insert(4)
505+
/// a.insert(5)
506+
///
507+
/// let b = a.split_off(3);
508+
///
509+
/// assert_eq!(a.len(), 2);
510+
/// assert_eq!(b.len(), 3);
511+
///
512+
/// assert!(a.contains(&1));
513+
/// assert!(a.contains(&2));
514+
/// assert!(b.contains(&3));
515+
/// assert!(b.contains(&4));
516+
/// assert!(b.contains(&5));
517+
/// ```
518+
#[unstable(feature = "btree_append_split_off",
519+
reason = "recently added as part of collections reform 2")]
520+
pub fn split_off<Q: ?Sized>(&mut self, at: &Q) -> Self
521+
where T: Borrow<Q>, Q: Ord {
522+
BTreeSet { map: self.map.split_off(at) }
523+
}
456524
}
457525

458526
#[stable(feature = "rust1", since = "1.0.0")]

0 commit comments

Comments
 (0)