-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c4206b3
Showing
26 changed files
with
11,840 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/target | ||
/Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[package] | ||
name = "copse" | ||
version = "0.1.0" | ||
license = "MIT OR Apache-2.0" | ||
repository = "https://github.com/eggyal/copse.git" | ||
edition = "2021" | ||
|
||
[dependencies] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use super::merge_iter::MergeIterInner; | ||
use super::node::{self, Root}; | ||
use core::alloc::Allocator; | ||
use core::iter::FusedIterator; | ||
|
||
impl<K, V> Root<K, V> { | ||
/// Appends all key-value pairs from the union of two ascending iterators, | ||
/// incrementing a `length` variable along the way. The latter makes it | ||
/// easier for the caller to avoid a leak when a drop handler panicks. | ||
/// | ||
/// If both iterators produce the same key, this method drops the pair from | ||
/// the left iterator and appends the pair from the right iterator. | ||
/// | ||
/// If you want the tree to end up in a strictly ascending order, like for | ||
/// a `BTreeMap`, both iterators should produce keys in strictly ascending | ||
/// order, each greater than all keys in the tree, including any keys | ||
/// already in the tree upon entry. | ||
pub fn append_from_sorted_iters<I, A: Allocator + Clone>( | ||
&mut self, | ||
left: I, | ||
right: I, | ||
length: &mut usize, | ||
alloc: A, | ||
) where | ||
K: Ord, | ||
I: Iterator<Item = (K, V)> + FusedIterator, | ||
{ | ||
// We prepare to merge `left` and `right` into a sorted sequence in linear time. | ||
let iter = MergeIter(MergeIterInner::new(left, right)); | ||
|
||
// Meanwhile, we build a tree from the sorted sequence in linear time. | ||
self.bulk_push(iter, length, alloc) | ||
} | ||
|
||
/// Pushes all key-value pairs to the end of the tree, incrementing a | ||
/// `length` variable along the way. The latter makes it easier for the | ||
/// caller to avoid a leak when the iterator panicks. | ||
pub fn bulk_push<I, A: Allocator + Clone>(&mut self, iter: I, length: &mut usize, alloc: A) | ||
where | ||
I: Iterator<Item = (K, V)>, | ||
{ | ||
let mut cur_node = self.borrow_mut().last_leaf_edge().into_node(); | ||
// Iterate through all key-value pairs, pushing them into nodes at the right level. | ||
for (key, value) in iter { | ||
// Try to push key-value pair into the current leaf node. | ||
if cur_node.len() < node::CAPACITY { | ||
cur_node.push(key, value); | ||
} else { | ||
// No space left, go up and push there. | ||
let mut open_node; | ||
let mut test_node = cur_node.forget_type(); | ||
loop { | ||
match test_node.ascend() { | ||
Ok(parent) => { | ||
let parent = parent.into_node(); | ||
if parent.len() < node::CAPACITY { | ||
// Found a node with space left, push here. | ||
open_node = parent; | ||
break; | ||
} else { | ||
// Go up again. | ||
test_node = parent.forget_type(); | ||
} | ||
} | ||
Err(_) => { | ||
// We are at the top, create a new root node and push there. | ||
open_node = self.push_internal_level(alloc.clone()); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
// Push key-value pair and new right subtree. | ||
let tree_height = open_node.height() - 1; | ||
let mut right_tree = Root::new(alloc.clone()); | ||
for _ in 0..tree_height { | ||
right_tree.push_internal_level(alloc.clone()); | ||
} | ||
open_node.push(key, value, right_tree); | ||
|
||
// Go down to the right-most leaf again. | ||
cur_node = open_node.forget_type().last_leaf_edge().into_node(); | ||
} | ||
|
||
// Increment length every iteration, to make sure the map drops | ||
// the appended elements even if advancing the iterator panicks. | ||
*length += 1; | ||
} | ||
self.fix_right_border_of_plentiful(); | ||
} | ||
} | ||
|
||
// An iterator for merging two sorted sequences into one | ||
struct MergeIter<K, V, I: Iterator<Item = (K, V)>>(MergeIterInner<I>); | ||
|
||
impl<K: Ord, V, I> Iterator for MergeIter<K, V, I> | ||
where | ||
I: Iterator<Item = (K, V)> + FusedIterator, | ||
{ | ||
type Item = (K, V); | ||
|
||
/// If two keys are equal, returns the key-value pair from the right source. | ||
fn next(&mut self) -> Option<(K, V)> { | ||
let (a_next, b_next) = self.0.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0)); | ||
b_next.or(a_next) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use core::marker::PhantomData; | ||
use core::ptr::NonNull; | ||
|
||
/// Models a reborrow of some unique reference, when you know that the reborrow | ||
/// and all its descendants (i.e., all pointers and references derived from it) | ||
/// will not be used any more at some point, after which you want to use the | ||
/// original unique reference again. | ||
/// | ||
/// The borrow checker usually handles this stacking of borrows for you, but | ||
/// some control flows that accomplish this stacking are too complicated for | ||
/// the compiler to follow. A `DormantMutRef` allows you to check borrowing | ||
/// yourself, while still expressing its stacked nature, and encapsulating | ||
/// the raw pointer code needed to do this without undefined behavior. | ||
pub struct DormantMutRef<'a, T> { | ||
ptr: NonNull<T>, | ||
_marker: PhantomData<&'a mut T>, | ||
} | ||
|
||
unsafe impl<'a, T> Sync for DormantMutRef<'a, T> where &'a mut T: Sync {} | ||
unsafe impl<'a, T> Send for DormantMutRef<'a, T> where &'a mut T: Send {} | ||
|
||
impl<'a, T> DormantMutRef<'a, T> { | ||
/// Capture a unique borrow, and immediately reborrow it. For the compiler, | ||
/// the lifetime of the new reference is the same as the lifetime of the | ||
/// original reference, but you promise to use it for a shorter period. | ||
pub fn new(t: &'a mut T) -> (&'a mut T, Self) { | ||
let ptr = NonNull::from(t); | ||
// SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose | ||
// only this reference, so it is unique. | ||
let new_ref = unsafe { &mut *ptr.as_ptr() }; | ||
(new_ref, Self { ptr, _marker: PhantomData }) | ||
} | ||
|
||
/// Revert to the unique borrow initially captured. | ||
/// | ||
/// # Safety | ||
/// | ||
/// The reborrow must have ended, i.e., the reference returned by `new` and | ||
/// all pointers and references derived from it, must not be used anymore. | ||
pub unsafe fn awaken(self) -> &'a mut T { | ||
// SAFETY: our own safety conditions imply this reference is again unique. | ||
unsafe { &mut *self.ptr.as_ptr() } | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use super::DormantMutRef; | ||
|
||
#[test] | ||
fn test_borrow() { | ||
let mut data = 1; | ||
let mut stack = vec![]; | ||
let mut rr = &mut data; | ||
for factor in [2, 3, 7].iter() { | ||
let (r, dormant_r) = DormantMutRef::new(rr); | ||
rr = r; | ||
assert_eq!(*rr, 1); | ||
stack.push((factor, dormant_r)); | ||
} | ||
while let Some((factor, dormant_r)) = stack.pop() { | ||
let r = unsafe { dormant_r.awaken() }; | ||
*r *= factor; | ||
} | ||
assert_eq!(data, 42); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
use core::iter::Peekable; | ||
|
||
/// A iterator for deduping the key of a sorted iterator. | ||
/// When encountering the duplicated key, only the last key-value pair is yielded. | ||
/// | ||
/// Used by [`BTreeMap::bulk_build_from_sorted_iter`][1]. | ||
/// | ||
/// [1]: crate::collections::BTreeMap::bulk_build_from_sorted_iter | ||
pub struct DedupSortedIter<K, V, I> | ||
where | ||
I: Iterator<Item = (K, V)>, | ||
{ | ||
iter: Peekable<I>, | ||
} | ||
|
||
impl<K, V, I> DedupSortedIter<K, V, I> | ||
where | ||
I: Iterator<Item = (K, V)>, | ||
{ | ||
pub fn new(iter: I) -> Self { | ||
Self { iter: iter.peekable() } | ||
} | ||
} | ||
|
||
impl<K, V, I> Iterator for DedupSortedIter<K, V, I> | ||
where | ||
K: Eq, | ||
I: Iterator<Item = (K, V)>, | ||
{ | ||
type Item = (K, V); | ||
|
||
fn next(&mut self) -> Option<(K, V)> { | ||
loop { | ||
let next = match self.iter.next() { | ||
Some(next) => next, | ||
None => return None, | ||
}; | ||
|
||
let peeked = match self.iter.peek() { | ||
Some(peeked) => peeked, | ||
None => return Some(next), | ||
}; | ||
|
||
if next.0 != peeked.0 { | ||
return Some(next); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.