// SPDX-License-Identifier: MPL-2.0 use alloc::sync::Arc; use core::ops::{Deref, DerefMut}; use ostd::{ sync::{SpinGuardian, SpinLockGuard, non_null::NonNullPtr}, task::atomic_mode::{AsAtomicModeGuard, InAtomicMode}, util::Either, }; use crate::{ SLOT_SIZE, XArray, XLockGuard, entry::NodeEntryRef, mark::{NoneMark, PRESENT_MARK, XMark}, node::{Height, XNode}, }; /// A type representing the state of a [`Cursor`] or a [`CursorMut`]. /// /// Currently, there are two possible states: /// - `Inactive`: The cursor is not positioned on any node. /// - `AtNode`: The cursor is positioned on some node and holds a shared reference /// to it. /// /// A cursor never ends up on an interior node. In other words, when methods /// of `Cursor` or `CursorMut` finish, the cursor will either not positioned on any node /// or positioned on some leaf node. #[derive(Default)] enum CursorState<'a, P> where P: NonNullPtr + Send + Sync, { #[default] Inactive, AtNode { node: NodeEntryRef<'a, P>, operation_offset: u8, }, } impl<'a, P: NonNullPtr + Send + Sync> CursorState<'a, P> { fn move_to(&mut self, node: NodeEntryRef<'a, P>, index: u64) { let operation_offset = node.entry_offset(index); *self = Self::AtNode { node, operation_offset, }; } fn as_node(&self) -> Option<(&NodeEntryRef<'a, P>, u8)> { match self { Self::AtNode { node, operation_offset, } => Some((node, *operation_offset)), Self::Inactive => None, } } fn into_node(self) -> Option<(NodeEntryRef<'a, P>, u8)> { match self { Self::AtNode { node, operation_offset, } => Some((node, operation_offset)), Self::Inactive => None, } } fn is_at_node(&self) -> bool { match self { Self::AtNode { .. } => true, Self::Inactive => false, } } fn is_at_leaf(&self) -> bool { match self { Self::AtNode { node, .. } => node.is_leaf(), Self::Inactive => false, } } } /// A `Cursor` can traverse in the [`XArray`] by setting or increasing the /// target index and can perform read-only operations to the target item. /// /// Multiple `Cursor`s of the same `XArray` can exist simultaneously, and their existence /// does not conflict with that of a [`CursorMut`]. /// /// A newly created `Cursor` can read all modifications that occurred before its creation. /// Additionally, a `Cursor` can ensure it reads all modifications made before a specific /// point by performing a [`Cursor::reset`] operation. /// /// The typical way to obtain a `Cursor` instance is to call [`XArray::cursor`]. pub struct Cursor<'a, P, M = NoneMark> where P: NonNullPtr + Send + Sync, { /// The `XArray` where the cursor locates. xa: &'a XArray
,
/// The target index of the cursor.
index: u64,
/// The atomic-mode guard that protects cursor operations.
guard: &'a dyn InAtomicMode,
/// The state of the cursor.
state: CursorState<'a, P>,
}
impl<'a, P: NonNullPtr + Send + Sync, M> Cursor<'a, P, M> {
/// Creates a `Cursor` to perform read-related operations in the `XArray`.
pub(super) fn new ,
guard: &'a G,
index: u64,
) -> Self {
Self {
xa,
index,
guard: guard.as_atomic_mode_guard(),
state: CursorState::Inactive,
}
}
/// Traverses from the root node to the leaf node according to the target index.
///
/// This method will not create new nodes. If the cursor can not reach the target
/// leaf node, the cursor will remain the inactive state.
fn traverse_to_target(&mut self) {
if self.state.is_at_node() {
return;
}
let Some(head) = self.xa.head.read_with(self.guard) else {
return;
};
let max_index = head.height().max_index();
if max_index < self.index {
return;
}
self.state.move_to(head, self.index);
self.continue_traverse_to_target();
}
/// Traverses from an interior node to the leaf node according to the target index.
///
/// This method will not create new nodes. If the cursor can not reach the target
/// leaf node, the cursor will be reset to the inactive state.
fn continue_traverse_to_target(&mut self) {
while !self.state.is_at_leaf() {
let (current_node, operation_offset) =
core::mem::take(&mut self.state).into_node().unwrap();
let Some(next_node) = current_node
.deref_target()
.entry_with(self.guard, operation_offset)
.map(|operated_entry| operated_entry.left().unwrap())
else {
self.reset();
return;
};
self.state.move_to(next_node, self.index);
}
}
/// Finds the next marked item and moves the cursor to it.
///
/// This method will return the index of the marked item, or `None` if no such item exists.
fn find_marked(&mut self, mark: usize) -> Option ,
guard: &'a SpinLockGuard<'a, (), G>,
index: u64,
) -> Self {
Self(Cursor::new(xa, guard, index))
}
/// Returns an `XLockGuard` that marks the `XArray` is locked.
fn lock_guard(&self) -> XLockGuard<'_> {
// Having a `CursorMut` means that the `XArray` is locked.
XLockGuard(self.guard)
}
/// Increases the height of the `XArray` so that the `index`-th element can be stored.
fn reserve(&self, index: u64) {
if self.xa.head.read_with(self.guard).is_none() {
let height = Height::from_index(index);
let new_head = Arc::new(XNode::new_root(height));
self.xa.head.update(Some(new_head));
return;
};
loop {
let head = self.xa.head.read_with(self.guard).unwrap();
let height = head.height();
if height.max_index() >= index {
return;
}
let new_head = Arc::new(XNode::new_root(height.go_root()));
new_head.set_entry(self.lock_guard(), 0, Some(Either::Left(head.clone())));
self.xa.head.update(Some(new_head));
}
}
/// Traverses from the root node to the leaf node according to the target index.
///
/// This method will potentially create new nodes.
fn expand_and_traverse_to_target(&mut self) {
if self.state.is_at_node() {
return;
}
let head = {
self.reserve(self.index);
self.xa.head.read_with(self.guard).unwrap()
};
self.0.state.move_to(head, self.0.index);
self.continue_traverse_to_target_mut();
}
/// Traverses from an interior node to the leaf node according to the target index.
///
/// This method will potentially create new nodes.
fn continue_traverse_to_target_mut(&mut self) {
while !self.state.is_at_leaf() {
let (current_node, operation_offset) =
core::mem::take(&mut self.state).into_node().unwrap();
if current_node
.entry_with(self.guard, operation_offset)
.is_none()
{
let new_node = XNode::new(current_node.height().go_leaf(), operation_offset);
let new_entry = Either::Left(Arc::new(new_node));
current_node.set_entry(self.lock_guard(), operation_offset, Some(new_entry));
}
let next_node = current_node
.deref_target()
.entry_with(self.guard, operation_offset)
.unwrap()
.left()
.unwrap();
self.0.state.move_to(next_node, self.0.index);
}
}
/**** Public ****/
/// Stores a new `item` at the target index.
pub fn store(&mut self, item: P) {
self.expand_and_traverse_to_target();
let (node, operation_offset) = self.state.as_node().unwrap();
node.set_entry(
self.lock_guard(),
operation_offset,
Some(Either::Right(item)),
);
}
/// Removes the item at the target index.
///
/// Returns the removed item if it previously exists.
//
// TODO: Remove the interior node once it becomes empty.
pub fn remove(&mut self) -> Option