use crate::TryReserveError;
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::Debug;
use core::hash::{Hash, Hasher};
use core::iter::{FromIterator, FusedIterator, Peekable};
use core::marker::PhantomData;
use core::ops::Bound::{Excluded, Included, Unbounded};
use core::ops::{Index, RangeBounds};
use core::{fmt, intrinsics, mem, ptr};
use super::node::{self, marker, ForceResult::*, Handle, InsertResult::*, NodeRef};
use super::search::{self, SearchResult::*};
use Entry::*;
use UnderflowResult::*;
/// A map based on a B-Tree.
///
/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing
/// the amount of work performed in a search. In theory, a binary search tree (BST) is the optimal
/// choice for a sorted map, as a perfectly balanced BST performs the theoretical minimum amount of
/// comparisons necessary to find an element (log2n). However, in practice the way this
/// is done is *very* inefficient for modern computer architectures. In particular, every element
/// is stored in its own individually heap-allocated node. This means that every single insertion
/// triggers a heap-allocation, and every single comparison should be a cache-miss. Since these
/// are both notably expensive things to do in practice, we are forced to at very least reconsider
/// the BST strategy.
///
/// A B-Tree instead makes each node contain B-1 to 2B-1 elements in a contiguous array. By doing
/// this, we reduce the number of allocations by a factor of B, and improve cache efficiency in
/// searches. However, this does mean that searches will have to do *more* comparisons on average.
/// The precise number of comparisons depends on the node search strategy used. For optimal cache
/// efficiency, one could search the nodes linearly. For optimal comparisons, one could search
/// the node using binary search. As a compromise, one could also perform a linear search
/// that initially only checks every ith element for some choice of i.
///
/// Currently, our implementation simply performs naive linear search. This provides excellent
/// performance on *small* nodes of elements which are cheap to compare. However in the future we
/// would like to further explore choosing the optimal search strategy based on the choice of B,
/// and possibly other factors. Using linear search, searching for a random element is expected
/// to take O(B logBn) comparisons, which is generally worse than a BST. In practice,
/// however, performance is excellent.
///
/// It is a logic error for a key to be modified in such a way that the key's ordering relative to
/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
///
/// [`Ord`]: ../../std/cmp/trait.Ord.html
/// [`Cell`]: ../../std/cell/struct.Cell.html
/// [`RefCell`]: ../../std/cell/struct.RefCell.html
///
/// # Examples
///
/// ```
/// use std::collections::BTreeMap;
///
/// // type inference lets us omit an explicit type signature (which
/// // would be `BTreeMap<&str, &str>` in this example).
/// let mut movie_reviews = BTreeMap::new();
///
/// // review some movies.
/// movie_reviews.insert("Office Space", "Deals with real issues in the workplace.");
/// movie_reviews.insert("Pulp Fiction", "Masterpiece.");
/// movie_reviews.insert("The Godfather", "Very enjoyable.");
/// movie_reviews.insert("The Blues Brothers", "Eye lyked it a lot.");
///
/// // check for a specific one.
/// if !movie_reviews.contains_key("Les Misérables") {
/// println!("We've got {} reviews, but Les Misérables ain't one.",
/// movie_reviews.len());
/// }
///
/// // oops, this review has a lot of spelling mistakes, let's delete it.
/// movie_reviews.remove("The Blues Brothers");
///
/// // look up the values associated with some keys.
/// let to_find = ["Up!", "Office Space"];
/// for book in &to_find {
/// match movie_reviews.get(book) {
/// Some(review) => println!("{}: {}", book, review),
/// None => println!("{} is unreviewed.", book)
/// }
/// }
///
/// // Look up the value for a key (will panic if the key is not found).
/// println!("Movie review: {}", movie_reviews["Office Space"]);
///
/// // iterate over everything.
/// for (movie, review) in &movie_reviews {
/// println!("{}: \"{}\"", movie, review);
/// }
/// ```
///
/// `BTreeMap` also implements an [`Entry API`](#method.entry), which allows
/// for more complex methods of getting, setting, updating and removing keys and
/// their values:
///
/// ```
/// use std::collections::BTreeMap;
///
/// // type inference lets us omit an explicit type signature (which
/// // would be `BTreeMap<&str, u8>` in this example).
/// let mut player_stats = BTreeMap::new();
///
/// fn random_stat_buff() -> u8 {
/// // could actually return some random value here - let's just return
/// // some fixed value for now
/// 42
/// }
///
/// // insert a key only if it doesn't already exist
/// player_stats.entry("health").or_insert(100);
///
/// // insert a key using a function that provides a new value only if it
/// // doesn't already exist
/// player_stats.entry("defence").or_insert_with(random_stat_buff);
///
/// // update a key, guarding against the key possibly not being set
/// let stat = player_stats.entry("attack").or_insert(100);
/// *stat += random_stat_buff();
/// ```
pub struct BTreeMap {
root: node::Root,
length: usize,
}
unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap {
fn drop(&mut self) {
unsafe {
drop(ptr::read(self).into_iter());
}
}
}
use crate::TryClone;
impl TryClone for BTreeMap {
fn try_clone(&self) -> Result, TryReserveError> {
fn clone_subtree<'a, K: TryClone, V: TryClone>(
node: node::NodeRef, K, V, marker::LeafOrInternal>,
) -> Result, TryReserveError>
where
K: 'a,
V: 'a,
{
match node.force() {
Leaf(leaf) => {
let mut out_tree = BTreeMap {
root: node::Root::new_leaf()?,
length: 0,
};
{
let mut out_node = match out_tree.root.as_mut().force() {
Leaf(leaf) => leaf,
Internal(_) => unreachable!(),
};
let mut in_edge = leaf.first_edge();
while let Ok(kv) = in_edge.right_kv() {
let (k, v) = kv.into_kv();
in_edge = kv.right_edge();
out_node.push(k.try_clone()?, v.try_clone()?);
out_tree.length += 1;
}
}
Ok(out_tree)
}
Internal(internal) => {
let mut out_tree = clone_subtree(internal.first_edge().descend())?;
{
let mut out_node = out_tree.root.push_level()?;
let mut in_edge = internal.first_edge();
while let Ok(kv) = in_edge.right_kv() {
let (k, v) = kv.into_kv();
in_edge = kv.right_edge();
let k = (*k).try_clone()?;
let v = (*v).try_clone()?;
let subtree = clone_subtree(in_edge.descend())?;
// We can't destructure subtree directly
// because BTreeMap implements Drop
let (subroot, sublength) = unsafe {
let root = ptr::read(&subtree.root);
let length = subtree.length;
mem::forget(subtree);
(root, length)
};
out_node.push(k, v, subroot);
out_tree.length += 1 + sublength;
}
}
Ok(out_tree)
}
}
}
if self.len() == 0 {
// Ideally we'd call `BTreeMap::new` here, but that has the `K:
// Ord` constraint, which this method lacks.
Ok(BTreeMap {
root: node::Root::shared_empty_root(),
length: 0,
})
} else {
clone_subtree(self.root.as_ref())
}
}
}
impl Clone for BTreeMap {
fn clone(&self) -> BTreeMap {
fn clone_subtree<'a, K: Clone, V: Clone>(
node: node::NodeRef, K, V, marker::LeafOrInternal>,
) -> BTreeMap
where
K: 'a,
V: 'a,
{
match node.force() {
Leaf(leaf) => {
let mut out_tree = BTreeMap {
root: node::Root::new_leaf().expect("Out of Mem"),
length: 0,
};
{
let mut out_node = match out_tree.root.as_mut().force() {
Leaf(leaf) => leaf,
Internal(_) => unreachable!(),
};
let mut in_edge = leaf.first_edge();
while let Ok(kv) = in_edge.right_kv() {
let (k, v) = kv.into_kv();
in_edge = kv.right_edge();
out_node.push(k.clone(), v.clone());
out_tree.length += 1;
}
}
out_tree
}
Internal(internal) => {
let mut out_tree = clone_subtree(internal.first_edge().descend());
{
let mut out_node = out_tree.root.push_level().expect("Out of Mem");
let mut in_edge = internal.first_edge();
while let Ok(kv) = in_edge.right_kv() {
let (k, v) = kv.into_kv();
in_edge = kv.right_edge();
let k = (*k).clone();
let v = (*v).clone();
let subtree = clone_subtree(in_edge.descend());
// We can't destructure subtree directly
// because BTreeMap implements Drop
let (subroot, sublength) = unsafe {
let root = ptr::read(&subtree.root);
let length = subtree.length;
mem::forget(subtree);
(root, length)
};
out_node.push(k, v, subroot);
out_tree.length += 1 + sublength;
}
}
out_tree
}
}
}
if self.len() == 0 {
// Ideally we'd call `BTreeMap::new` here, but that has the `K:
// Ord` constraint, which this method lacks.
BTreeMap {
root: node::Root::shared_empty_root(),
length: 0,
}
} else {
clone_subtree(self.root.as_ref())
}
}
}
impl super::Recover for BTreeMap
where
K: Borrow + Ord,
Q: Ord,
{
type Key = K;
fn get(&self, key: &Q) -> Option<&K> {
match search::search_tree(self.root.as_ref(), key) {
Found(handle) => Some(handle.into_kv().0),
GoDown(_) => None,
}
}
fn take(&mut self, key: &Q) -> Option {
match search::search_tree(self.root.as_mut(), key) {
Found(handle) => Some(
OccupiedEntry {
handle,
length: &mut self.length,
_marker: PhantomData,
}
.remove_kv()
.0,
),
GoDown(_) => None,
}
}
fn replace(&mut self, key: K) -> Result