use core::{fmt, iter, mem, ptr::NonNull};
use arrayvec::ArrayVec;
use super::SkipMap;
use crate::{
comparator::{Comparator, OrdComparator},
level_generator::{LevelGenerator, geometric::Geometric},
node::{
Node,
link::Link,
visitor::{OrdIndexMutVisitor, Visitor},
},
};
pub struct OccupiedEntry<
'a,
K,
V,
const N: usize = 16,
C: Comparator<K> = OrdComparator,
G: LevelGenerator = Geometric,
> {
node: NonNull<Node<(K, V), N>>,
precursors: ArrayVec<NonNull<Node<(K, V), N>>, N>,
map: &'a mut SkipMap<K, V, N, C, G>,
}
impl<K: fmt::Debug, V: fmt::Debug, const N: usize, C: Comparator<K>, G: LevelGenerator> fmt::Debug
for OccupiedEntry<'_, K, V, N, C, G>
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OccupiedEntry")
.field("key", self.key())
.field("value", self.get())
.finish()
}
}
impl<'a, K, V, const N: usize, C: Comparator<K>, G: LevelGenerator>
OccupiedEntry<'a, K, V, N, C, G>
{
#[expect(
clippy::expect_used,
clippy::missing_panics_doc,
reason = "data nodes always have a value; the head sentinel \
is never exposed as an OccupiedEntry"
)]
#[inline]
#[must_use]
pub fn key(&self) -> &K {
&unsafe { self.node.as_ref() }.value().expect("data node").0
}
#[expect(
clippy::expect_used,
clippy::missing_panics_doc,
reason = "data nodes always have a value; the head sentinel \
is never exposed as an OccupiedEntry"
)]
#[inline]
#[must_use]
pub fn get(&self) -> &V {
&unsafe { self.node.as_ref() }.value().expect("data node").1
}
#[expect(
clippy::expect_used,
clippy::missing_panics_doc,
reason = "data nodes always have a value; the head sentinel \
is never exposed as an OccupiedEntry"
)]
#[inline]
pub fn get_mut(&mut self) -> &mut V {
unsafe { &mut self.node.as_mut().value_mut().expect("data node").1 }
}
#[expect(
clippy::expect_used,
clippy::missing_panics_doc,
reason = "data nodes always have a value; the head sentinel \
is never exposed as an OccupiedEntry"
)]
#[inline]
#[must_use]
pub fn into_mut(self) -> &'a mut V {
let mut node = self.node;
unsafe { &mut node.as_mut().value_mut().expect("data node").1 }
}
#[expect(
clippy::expect_used,
clippy::missing_panics_doc,
reason = "data nodes always have a value; the head sentinel \
is never exposed as an OccupiedEntry"
)]
#[inline]
pub fn insert(&mut self, value: V) -> V {
unsafe {
let pair = self.node.as_mut().value_mut().expect("data node");
mem::replace(&mut pair.1, value)
}
}
#[inline]
#[must_use]
pub fn remove(self) -> V {
self.remove_entry().1
}
#[expect(
clippy::expect_used,
clippy::missing_panics_doc,
reason = "new_dist >= 1 because skip-link distances are computed from consecutive \
node ranks; decrement_distance requires distance >= 2 for spanning links; \
take_value on a data node always returns Some; \
all expects fire only on internal invariant violations"
)]
#[expect(
clippy::indexing_slicing,
reason = "l iterates 0..max_levels; precursors[l] is valid because \
OrdIndexMutVisitor fills all max_levels entries; \
links_mut()[l] is valid because l < node.level() <= max_levels; \
precursors[0] is valid because max_levels >= 1"
)]
#[expect(
clippy::multiple_unsafe_ops_per_block,
reason = "head level read, link splicing, and node pop touch provably disjoint \
heap nodes; splitting across blocks would require unsafe-crossing \
raw-pointer variables"
)]
#[inline]
#[must_use]
pub fn remove_entry(self) -> (K, V) {
let Self {
node: target_ptr,
precursors,
map,
} = self;
let max_levels = unsafe { map.head.as_ref() }.level();
let (key, val, new_tail) = unsafe {
let target_height = target_ptr.as_ref().level();
let target_raw = target_ptr.as_ptr();
for (l, pred_nn) in precursors.iter().enumerate().take(max_levels) {
let pred_ptr = pred_nn.as_ptr();
if l < target_height {
let old_link = (*pred_ptr).links_mut()[l].take();
let target_link = (*target_raw).links_mut()[l].take();
(*pred_ptr).links_mut()[l] = match (old_link, target_link) {
(Some(pred_to_target), Some(target_to_succ)) => {
let new_dist = pred_to_target
.distance()
.get()
.saturating_add(target_to_succ.distance().get())
.saturating_sub(1);
Some(Link::new(target_to_succ.node(), new_dist).expect("new_dist >= 1"))
}
(_, None) => None,
(None, tgt) => tgt,
};
} else if let Some(link) = (*pred_ptr).links_mut()[l].as_mut() {
link.decrement_distance()
.expect("skip link spanning target has distance >= 2");
}
}
let new_tail = (*target_raw).prev();
let mut popped = (*target_raw).pop();
let (k, v) = popped.take_value().expect("data node has a value");
(k, v, new_tail)
};
if map.tail == Some(target_ptr) {
map.tail = if map.len == 1 { None } else { new_tail };
}
map.len = map.len.saturating_sub(1);
(key, val)
}
}
pub struct VacantEntry<
'a,
K,
V,
const N: usize = 16,
C: Comparator<K> = OrdComparator,
G: LevelGenerator = Geometric,
> {
key: K,
current: NonNull<Node<(K, V), N>>,
current_rank: usize,
precursors: ArrayVec<NonNull<Node<(K, V), N>>, N>,
precursor_distances: ArrayVec<usize, N>,
map: &'a mut SkipMap<K, V, N, C, G>,
}
impl<K: fmt::Debug, V, const N: usize, C: Comparator<K>, G: LevelGenerator> fmt::Debug
for VacantEntry<'_, K, V, N, C, G>
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("VacantEntry").field(&self.key).finish()
}
}
impl<'a, K, V, const N: usize, C: Comparator<K>, G: LevelGenerator> VacantEntry<'a, K, V, N, C, G> {
#[inline]
#[must_use]
pub fn key(&self) -> &K {
&self.key
}
#[inline]
#[must_use]
pub fn into_key(self) -> K {
self.key
}
#[expect(
clippy::expect_used,
clippy::missing_panics_doc,
reason = "value_mut on the freshly-created data node returned by \
insert_raw always returns Some; this expect fires only on \
internal invariant violations"
)]
#[inline]
pub fn insert(self, value: V) -> &'a mut V {
let (node, _, _map) = self.insert_raw(value);
unsafe { &mut (*node.as_ptr()).value_mut().expect("data node").1 }
}
#[inline]
pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, N, C, G> {
let (node, precursors, map) = self.insert_raw(value);
OccupiedEntry {
node,
precursors,
map,
}
}
#[expect(
clippy::expect_used,
reason = "Link::new distances are >= 1 by construction; increment_distance \
overflow requires > usize::MAX nodes; precursors[0] always exists \
because max_levels >= 1; value_mut on a freshly-created data node \
always returns Some; all expects fire only on internal invariant violations"
)]
#[expect(
clippy::indexing_slicing,
reason = "precursors[0] is valid: max_levels >= 1 so precursors.len() >= 1; \
precursors[l] and new_raw.links_mut()[l] are bounded by \
l < height <= node.level() = max_levels"
)]
#[expect(
clippy::multiple_unsafe_ops_per_block,
reason = "insertion and link wiring touch provably disjoint heap nodes; \
splitting across blocks would require unsafe-crossing raw-pointer \
variables"
)]
#[expect(
clippy::type_complexity,
reason = "return type is a private implementation detail; \
a type alias here would add noise without clarity"
)]
fn insert_raw(
self,
value: V,
) -> (
NonNull<Node<(K, V), N>>,
ArrayVec<NonNull<Node<(K, V), N>>, N>,
&'a mut SkipMap<K, V, N, C, G>,
) {
let Self {
key,
current,
current_rank,
precursors,
precursor_distances,
map,
} = self;
let height = map.generator.level();
let new_rank = current_rank.saturating_add(1);
let new_node_nonnull: NonNull<Node<(K, V), N>> = unsafe {
let new_raw: *mut Node<(K, V), N> =
Node::insert_after(current, Node::with_value(height, (key, value))).as_ptr();
for (l, (pred_nn, pred_rank)) in precursors
.iter()
.copied()
.zip(precursor_distances.iter().copied())
.enumerate()
{
let pred_ptr = pred_nn.as_ptr();
if l < height {
let distance = new_rank.saturating_sub(pred_rank);
let old_link = (*pred_ptr).links_mut()[l].take();
(*pred_ptr).links_mut()[l] = Some(
Link::new(NonNull::new_unchecked(new_raw), distance)
.expect("distance >= 1"),
);
(*new_raw).links_mut()[l] = if let Some(old) = old_link {
let new_d = old
.distance()
.get()
.saturating_sub(distance)
.saturating_add(1);
Some(Link::new(old.node(), new_d).expect("new_d >= 1"))
} else {
None
};
} else if let Some(link) = (*pred_ptr).links_mut()[l].as_mut() {
link.increment_distance()
.expect("distance overflow requires > usize::MAX nodes");
}
}
NonNull::new_unchecked(new_raw)
};
let is_new_tail = unsafe { new_node_nonnull.as_ref() }.next().is_none();
if is_new_tail {
map.tail = Some(new_node_nonnull);
}
map.len = map.len.saturating_add(1);
(new_node_nonnull, precursors, map)
}
}
#[expect(
clippy::exhaustive_enums,
reason = "Entry is intentionally exhaustive with only Occupied and Vacant variants"
)]
pub enum Entry<
'a,
K,
V,
const N: usize = 16,
C: Comparator<K> = OrdComparator,
G: LevelGenerator = Geometric,
> {
Occupied(OccupiedEntry<'a, K, V, N, C, G>),
Vacant(VacantEntry<'a, K, V, N, C, G>),
}
impl<K: fmt::Debug, V: fmt::Debug, const N: usize, C: Comparator<K>, G: LevelGenerator> fmt::Debug
for Entry<'_, K, V, N, C, G>
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Occupied(e) => f.debug_tuple("Entry::Occupied").field(e).finish(),
Self::Vacant(e) => f.debug_tuple("Entry::Vacant").field(e).finish(),
}
}
}
impl<'a, K, V, const N: usize, C: Comparator<K>, G: LevelGenerator> Entry<'a, K, V, N, C, G> {
#[inline]
#[must_use]
pub fn key(&self) -> &K {
match self {
Self::Occupied(e) => e.key(),
Self::Vacant(e) => e.key(),
}
}
#[inline]
pub fn or_insert(self, default: V) -> &'a mut V {
match self {
Self::Occupied(e) => e.into_mut(),
Self::Vacant(e) => e.insert(default),
}
}
#[inline]
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
match self {
Self::Occupied(e) => e.into_mut(),
Self::Vacant(e) => e.insert(default()),
}
}
#[inline]
pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V {
match self {
Self::Occupied(e) => e.into_mut(),
Self::Vacant(e) => {
let v = default(e.key());
e.insert(v)
}
}
}
#[inline]
#[must_use]
pub fn and_modify<F: FnOnce(&mut V)>(self, f: F) -> Self {
match self {
Self::Occupied(mut e) => {
f(e.get_mut());
Self::Occupied(e)
}
Self::Vacant(e) => Self::Vacant(e),
}
}
#[inline]
pub fn or_default(self) -> &'a mut V
where
V: Default,
{
match self {
Self::Occupied(e) => e.into_mut(),
Self::Vacant(e) => e.insert(V::default()),
}
}
#[inline]
pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, N, C, G> {
match self {
Self::Occupied(mut e) => {
e.insert(value);
e
}
Self::Vacant(e) => e.insert_entry(value),
}
}
}
#[non_exhaustive]
pub struct OccupiedError<
'a,
K,
V,
const N: usize = 16,
C: Comparator<K> = OrdComparator,
G: LevelGenerator = Geometric,
> {
pub entry: OccupiedEntry<'a, K, V, N, C, G>,
pub value: V,
}
impl<K: fmt::Debug, V: fmt::Debug, const N: usize, C: Comparator<K>, G: LevelGenerator> fmt::Debug
for OccupiedError<'_, K, V, N, C, G>
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OccupiedError")
.field("entry", &self.entry)
.field("value", &self.value)
.finish()
}
}
impl<K: fmt::Debug, V: fmt::Debug, const N: usize, C: Comparator<K>, G: LevelGenerator> fmt::Display
for OccupiedError<'_, K, V, N, C, G>
{
#[expect(
clippy::use_debug,
reason = "the key is displayed via its Debug impl, mirroring BTreeMap::OccupiedError"
)]
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "entry with key {:?} already exists", self.entry.key())
}
}
impl<K: fmt::Debug, V: fmt::Debug, const N: usize, C: Comparator<K>, G: LevelGenerator>
std::error::Error for OccupiedError<'_, K, V, N, C, G>
{
}
impl<K, V, const N: usize, C: Comparator<K>, G: LevelGenerator> SkipMap<K, V, N, C, G> {
#[inline]
pub fn entry(&mut self, key: K) -> Entry<'_, K, V, N, C, G> {
let (current_rank, current, found, precursors, precursor_distances) = {
let head = self.head;
let cmp = |entry: &(K, V), k: &K| self.comparator.compare(&entry.0, k);
let mut visitor = OrdIndexMutVisitor::new(head, &key, cmp);
visitor.traverse();
let rank = visitor.current_rank_internal();
let (current, found, precursors, precursor_distances) = visitor.into_parts();
(rank, current, found, precursors, precursor_distances)
};
if found {
Entry::Occupied(OccupiedEntry {
node: current,
precursors,
map: self,
})
} else {
Entry::Vacant(VacantEntry {
key,
current,
current_rank,
precursors,
precursor_distances,
map: self,
})
}
}
#[inline]
pub fn try_insert(
&mut self,
key: K,
value: V,
) -> Result<&mut V, OccupiedError<'_, K, V, N, C, G>> {
match self.entry(key) {
Entry::Occupied(entry) => Err(OccupiedError { entry, value }),
Entry::Vacant(entry) => Ok(entry.insert(value)),
}
}
#[inline]
pub fn first_entry(&mut self) -> Option<OccupiedEntry<'_, K, V, N, C, G>> {
let (node, max_levels) = {
let head_ref = unsafe { self.head.as_ref() };
(head_ref.next()?, head_ref.level())
};
let precursors = iter::repeat_n(self.head, max_levels).collect();
Some(OccupiedEntry {
node,
precursors,
map: self,
})
}
#[expect(
clippy::indexing_slicing,
reason = "l is in 0..max_levels; precursors[l] is always in bounds (len == \
max_levels); links_mut()[l] is safe because the precursor at level l \
is always a node with height > l: every node advanced to via a level-l \
link has height >= l+1, and head (the fallback when no advance occurs) \
has height max_levels > any valid l"
)]
#[inline]
pub fn last_entry(&mut self) -> Option<OccupiedEntry<'_, K, V, N, C, G>> {
let tail_ptr = self.tail?;
let tail_height = unsafe { tail_ptr.as_ref() }.level();
let max_levels = unsafe { self.head.as_ref() }.level();
let mut precursors: ArrayVec<NonNull<Node<(K, V), N>>, N> =
iter::repeat_n(self.head, max_levels).collect();
let mut current = self.head;
for l in (0..max_levels).rev() {
loop {
let maybe_link = unsafe { current.as_ref() }
.links()
.get(l)
.and_then(|lk| lk.as_ref());
match maybe_link {
None => break,
Some(link) if l < tail_height && link.node() == tail_ptr => break,
Some(link) => current = link.node(),
}
}
precursors[l] = current;
}
Some(OccupiedEntry {
node: tail_ptr,
precursors,
map: self,
})
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::super::SkipMap;
use crate::skip_map::entry::Entry;
#[test]
fn entry_occupied_on_existing_key() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(1, "a");
assert!(matches!(map.entry(1), Entry::Occupied(_)));
}
#[test]
fn entry_vacant_on_missing_key() {
let mut map = SkipMap::<i32, &str>::new();
assert!(matches!(map.entry(1), Entry::Vacant(_)));
}
#[test]
fn occupied_entry_key() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(42, "x");
if let Entry::Occupied(e) = map.entry(42) {
assert_eq!(e.key(), &42);
} else {
panic!("expected Occupied");
}
}
#[test]
fn occupied_entry_get() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(1, 10);
if let Entry::Occupied(e) = map.entry(1) {
assert_eq!(e.get(), &10);
} else {
panic!("expected Occupied");
}
}
#[test]
fn occupied_entry_get_mut() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(1, 10);
if let Entry::Occupied(mut e) = map.entry(1) {
*e.get_mut() += 5;
assert_eq!(e.get(), &15);
} else {
panic!("expected Occupied");
}
assert_eq!(map.get(&1), Some(&15));
}
#[test]
fn occupied_entry_into_mut() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(1, 10);
let v = match map.entry(1) {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(_) => panic!("expected Occupied"),
};
*v += 5;
assert_eq!(map.get(&1), Some(&15));
}
#[test]
fn occupied_entry_insert_returns_old_value() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(1, "a");
if let Entry::Occupied(mut e) = map.entry(1) {
assert_eq!(e.insert("b"), "a");
} else {
panic!("expected Occupied");
}
assert_eq!(map.get(&1), Some(&"b"));
}
#[test]
fn occupied_insert_mut() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(1, "a");
if let Entry::Occupied(mut e) = map.entry(1) {
assert_eq!(e.insert("b"), "a");
assert_eq!(e.insert("c"), "b");
assert_eq!(e.get(), &"c");
} else {
panic!("expected Occupied");
}
assert_eq!(map.get(&1), Some(&"c"));
}
#[test]
fn occupied_entry_remove() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(1, "a");
if let Entry::Occupied(e) = map.entry(1) {
assert_eq!(e.remove(), "a");
} else {
panic!("expected Occupied");
}
assert!(map.is_empty());
}
#[test]
fn occupied_entry_remove_entry() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(7, "seven");
if let Entry::Occupied(e) = map.entry(7) {
assert_eq!(e.remove_entry(), (7, "seven"));
} else {
panic!("expected Occupied");
}
assert!(map.is_empty());
}
#[test]
fn occupied_entry_remove_first_of_many() {
let mut map = SkipMap::<i32, i32>::new();
for i in 1..=5_i32 {
map.insert(i, i * 10);
}
if let Entry::Occupied(e) = map.entry(1) {
assert_eq!(e.remove(), 10);
}
assert_eq!(map.len(), 4);
assert_eq!(map.first_key_value(), Some((&2, &20)));
}
#[test]
fn occupied_entry_remove_last_of_many() {
let mut map = SkipMap::<i32, i32>::new();
for i in 1..=5_i32 {
map.insert(i, i * 10);
}
if let Entry::Occupied(e) = map.entry(5) {
assert_eq!(e.remove(), 50);
}
assert_eq!(map.len(), 4);
assert_eq!(map.last_key_value(), Some((&4, &40)));
}
#[test]
fn occupied_entry_remove_middle_of_many() {
let mut map = SkipMap::<i32, i32>::new();
for i in 1..=5_i32 {
map.insert(i, i * 10);
}
if let Entry::Occupied(e) = map.entry(3) {
assert_eq!(e.remove(), 30);
}
assert_eq!(map.len(), 4);
assert_eq!(map.get(&3), None);
}
#[test]
fn vacant_entry_key() {
let mut map = SkipMap::<i32, &str>::new();
if let Entry::Vacant(e) = map.entry(99) {
assert_eq!(e.key(), &99);
} else {
panic!("expected Vacant");
}
}
#[test]
fn vacant_entry_into_key() {
let mut map = SkipMap::<i32, &str>::new();
if let Entry::Vacant(e) = map.entry(42) {
assert_eq!(e.into_key(), 42);
} else {
panic!("expected Vacant");
}
assert!(map.is_empty());
}
#[test]
fn vacant_entry_insert() {
let mut map = SkipMap::<i32, &str>::new();
if let Entry::Vacant(e) = map.entry(1) {
let v = e.insert("hello");
assert_eq!(*v, "hello");
} else {
panic!("expected Vacant");
}
assert_eq!(map.get(&1), Some(&"hello"));
}
#[test]
fn vacant_entry_insert_into_empty_map() {
let mut map = SkipMap::<i32, i32>::new();
if let Entry::Vacant(e) = map.entry(5) {
e.insert(50);
}
assert_eq!(map.len(), 1);
assert_eq!(map.first_key_value(), Some((&5, &50)));
assert_eq!(map.last_key_value(), Some((&5, &50)));
}
#[test]
fn vacant_insert_entry_returns_occupied() {
let mut map = SkipMap::<i32, &str>::new();
if let Entry::Vacant(e) = map.entry(7) {
let occupied = e.insert_entry("hello");
assert_eq!(occupied.key(), &7);
assert_eq!(occupied.get(), &"hello");
} else {
panic!("expected Vacant");
}
assert_eq!(map.get(&7), Some(&"hello"));
}
#[test]
fn vacant_entry_insert_new_maximum() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(1, 10);
map.insert(2, 20);
if let Entry::Vacant(e) = map.entry(5) {
e.insert(50);
}
assert_eq!(map.last_key_value(), Some((&5, &50)));
}
#[test]
fn entry_or_insert_vacant() {
let mut map = SkipMap::<i32, i32>::new();
let v = map.entry(1).or_insert(10);
assert_eq!(*v, 10);
assert_eq!(map.get(&1), Some(&10));
}
#[test]
fn entry_or_insert_occupied() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(1, 10);
let v = map.entry(1).or_insert(99);
assert_eq!(*v, 10);
assert_eq!(map.get(&1), Some(&10));
}
#[test]
fn entry_or_insert_with_vacant() {
let mut map = SkipMap::<i32, String>::new();
map.entry(1).or_insert_with(|| "hello".to_owned());
assert_eq!(map.get(&1).map(String::as_str), Some("hello"));
}
#[test]
fn entry_or_insert_with_occupied() {
let mut map = SkipMap::<i32, String>::new();
map.insert(1, "original".to_owned());
map.entry(1).or_insert_with(|| "new".to_owned());
assert_eq!(map.get(&1).map(String::as_str), Some("original"));
}
#[test]
fn entry_or_insert_with_key_vacant() {
let mut map = SkipMap::<i32, i32>::new();
map.entry(5).or_insert_with_key(|k| *k * 10);
assert_eq!(map.get(&5), Some(&50));
}
#[test]
fn entry_or_insert_with_key_occupied() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(5, 99);
map.entry(5).or_insert_with_key(|k| *k * 10);
assert_eq!(map.get(&5), Some(&99));
}
#[test]
fn entry_and_modify_occupied() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(1, 10);
map.entry(1).and_modify(|v| *v += 1).or_insert(0);
assert_eq!(map.get(&1), Some(&11));
}
#[test]
fn entry_and_modify_vacant() {
let mut map = SkipMap::<i32, i32>::new();
map.entry(2).and_modify(|v| *v += 1).or_insert(0);
assert_eq!(map.get(&2), Some(&0));
}
#[test]
fn entry_or_default_vacant() {
let mut map = SkipMap::<i32, i32>::new();
map.entry(1).or_default();
assert_eq!(map.get(&1), Some(&0));
}
#[test]
fn entry_or_default_occupied() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(1, 42);
map.entry(1).or_default();
assert_eq!(map.get(&1), Some(&42));
}
#[test]
fn entry_key_occupied() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(1, "a");
assert_eq!(map.entry(1).key(), &1);
}
#[test]
fn entry_key_vacant() {
let mut map = SkipMap::<i32, &str>::new();
assert_eq!(map.entry(99).key(), &99);
}
#[test]
fn entry_insert_entry_vacant() {
let mut map = SkipMap::<i32, &str>::new();
let e = map.entry(1).insert_entry("a");
assert_eq!(e.key(), &1);
assert_eq!(e.get(), &"a");
assert_eq!(map.get(&1), Some(&"a"));
}
#[test]
fn entry_insert_entry_occupied() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(1, "a");
let e = map.entry(1).insert_entry("b");
assert_eq!(e.key(), &1);
assert_eq!(e.get(), &"b");
assert_eq!(map.get(&1), Some(&"b"));
}
#[test]
fn try_insert_absent_key() {
let mut map = SkipMap::<i32, &str>::new();
assert_eq!(
*map.try_insert(1, "a").expect("absent key should succeed"),
"a"
);
assert_eq!(map.get(&1), Some(&"a"));
}
#[test]
fn try_insert_present_key_returns_error() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(1, "a");
let Err(err) = map.try_insert(1, "b") else {
panic!("expected Err from try_insert on occupied key");
};
assert_eq!(err.value, "b");
assert_eq!(err.entry.get(), &"a");
}
#[test]
fn try_insert_error_entry_can_update() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(1, 10);
let Err(err) = map.try_insert(1, 99) else {
panic!("expected Err from try_insert on occupied key");
};
*err.entry.into_mut() += 5;
assert_eq!(map.get(&1), Some(&15));
}
#[test]
fn first_entry_empty_is_none() {
let mut map = SkipMap::<i32, &str>::new();
assert!(map.first_entry().is_none());
}
#[test]
fn first_entry_single_element() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(42, "x");
let e = map.first_entry().expect("non-empty");
assert_eq!(e.key(), &42);
assert_eq!(e.get(), &"x");
}
#[test]
fn first_entry_remove_updates_map() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(3, 30);
map.insert(1, 10);
map.insert(2, 20);
let e = map.first_entry().expect("non-empty");
assert_eq!(e.key(), &1);
assert_eq!(e.remove(), 10);
assert_eq!(map.len(), 2);
assert_eq!(map.first_key_value(), Some((&2, &20)));
}
#[test]
fn first_entry_remove_only_element() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(1, "a");
assert_eq!(map.first_entry().expect("non-empty").remove(), "a");
assert!(map.is_empty());
assert_eq!(map.first_key_value(), None);
assert_eq!(map.last_key_value(), None);
}
#[test]
fn last_entry_empty_is_none() {
let mut map = SkipMap::<i32, &str>::new();
assert!(map.last_entry().is_none());
}
#[test]
fn last_entry_single_element() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(42, "x");
let e = map.last_entry().expect("non-empty");
assert_eq!(e.key(), &42);
assert_eq!(e.get(), &"x");
}
#[test]
fn last_entry_remove_updates_map() {
let mut map = SkipMap::<i32, i32>::new();
map.insert(1, 10);
map.insert(3, 30);
map.insert(2, 20);
let e = map.last_entry().expect("non-empty");
assert_eq!(e.key(), &3);
assert_eq!(e.remove(), 30);
assert_eq!(map.len(), 2);
assert_eq!(map.last_key_value(), Some((&2, &20)));
}
#[test]
fn last_entry_remove_only_element() {
let mut map = SkipMap::<i32, &str>::new();
map.insert(1, "a");
assert_eq!(map.last_entry().expect("non-empty").remove(), "a");
assert!(map.is_empty());
assert_eq!(map.first_key_value(), None);
assert_eq!(map.last_key_value(), None);
}
#[test]
fn occupied_entry_remove_entry_large_map() {
let mut map = SkipMap::<i32, i32>::new();
for i in 0..20_i32 {
map.insert(i, i * 10);
}
for i in (0..20_i32).step_by(2) {
if let Entry::Occupied(e) = map.entry(i) {
assert_eq!(e.remove(), i * 10);
}
}
assert_eq!(map.len(), 10);
for i in (1..20_i32).step_by(2) {
assert_eq!(map.get(&i), Some(&(i * 10)));
}
for i in (0..20_i32).step_by(2) {
assert_eq!(map.get(&i), None);
}
}
}