capybaraaaa!!
This commit is contained in:
parent
57ea368511
commit
3182f4e7f0
34
Cargo.lock
generated
Normal file
34
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit_field"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field",
|
||||||
|
"bitflags",
|
||||||
|
"seq-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rbtree"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "seq-macro"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
|
||||||
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[workspace]
|
||||||
|
resolver = "3"
|
||||||
|
|
||||||
|
members = [
|
||||||
|
"crates/*",
|
||||||
|
"kernel",
|
||||||
|
]
|
||||||
7
crates/rbtree/Cargo.lock
generated
Normal file
7
crates/rbtree/Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rbtree"
|
||||||
|
version = "0.1.0"
|
||||||
6
crates/rbtree/Cargo.toml
Normal file
6
crates/rbtree/Cargo.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "rbtree"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
594
crates/rbtree/src/lib.rs
Normal file
594
crates/rbtree/src/lib.rs
Normal file
|
|
@ -0,0 +1,594 @@
|
||||||
|
#![cfg_attr(not(test), no_std)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
pub trait Node {
|
||||||
|
type Id: Eq + Copy;
|
||||||
|
type Key: Ord;
|
||||||
|
|
||||||
|
fn parent(&self) -> Option<Self::Id>;
|
||||||
|
fn set_parent(&mut self, parent: Option<Self::Id>);
|
||||||
|
|
||||||
|
fn left(&self) -> Option<Self::Id>;
|
||||||
|
fn set_left(&mut self, left: Option<Self::Id>);
|
||||||
|
|
||||||
|
fn right(&self) -> Option<Self::Id>;
|
||||||
|
fn set_right(&mut self, right: Option<Self::Id>);
|
||||||
|
|
||||||
|
fn child(&self, left: bool) -> Option<Self::Id> {
|
||||||
|
if left { self.left() } else { self.right() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children(&self) -> (Option<Self::Id>, Option<Self::Id>) {
|
||||||
|
(self.left(), self.right())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key(&self) -> &Self::Key;
|
||||||
|
fn color(&self) -> bool;
|
||||||
|
fn set_color(&mut self, color: bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::missing_safety_doc)]
|
||||||
|
pub trait NodeStore<N: Node> {
|
||||||
|
fn get(&self, id: N::Id) -> Option<&N>;
|
||||||
|
unsafe fn get_unchecked(&self, id: N::Id) -> &N {
|
||||||
|
self.get(id).unwrap()
|
||||||
|
}
|
||||||
|
fn get_mut(&mut self, id: N::Id) -> Option<&mut N>;
|
||||||
|
unsafe fn get_mut_unchecked(&mut self, id: N::Id) -> &mut N {
|
||||||
|
self.get_mut(id).unwrap()
|
||||||
|
}
|
||||||
|
fn insert(&mut self, node: N) -> N::Id;
|
||||||
|
fn remove(&mut self, id: N::Id) -> Option<N>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RBTree<N: Node, S: NodeStore<N>> {
|
||||||
|
root: Option<N::Id>,
|
||||||
|
store: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Node, S: NodeStore<N>> RBTree<N, S> {
|
||||||
|
pub fn new(store: S) -> Self {
|
||||||
|
Self { root: None, store }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_get(&self, id: N::Id) -> Option<&N> {
|
||||||
|
self.store.get(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_get_mut(&mut self, id: N::Id) -> Option<&mut N> {
|
||||||
|
self.store.get_mut(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, node: N) -> N::Id {
|
||||||
|
self.store.insert(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn minimum_of(&self, mut id: N::Id) -> N::Id {
|
||||||
|
while let Some(left_id) = self.store.get(id).and_then(|node| node.left()) {
|
||||||
|
id = left_id;
|
||||||
|
}
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maximum_of(&self, mut id: N::Id) -> N::Id {
|
||||||
|
while let Some(right_id) = self.store.get(id).and_then(|node| node.right()) {
|
||||||
|
id = right_id;
|
||||||
|
}
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_of(&self, mut id: N::Id) -> Option<N::Id> {
|
||||||
|
let node = self.store.get(id)?;
|
||||||
|
match node.right() {
|
||||||
|
Some(r) => Some(self.minimum_of(r)),
|
||||||
|
None => {
|
||||||
|
let mut p = node.parent()?;
|
||||||
|
while id == self.store.get(p)?.right()? {
|
||||||
|
id = p;
|
||||||
|
p = self.store.get(p)?.parent()?;
|
||||||
|
}
|
||||||
|
Some(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_back_of(&self, mut id: N::Id) -> Option<N::Id> {
|
||||||
|
let node = self.store.get(id)?;
|
||||||
|
match node.left() {
|
||||||
|
Some(l) => Some(self.maximum_of(l)),
|
||||||
|
None => {
|
||||||
|
let mut p = node.parent()?;
|
||||||
|
while id == self.store.get(p)?.left()? {
|
||||||
|
id = p;
|
||||||
|
p = self.store.get(p)?.parent()?;
|
||||||
|
}
|
||||||
|
Some(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// x y
|
||||||
|
// / \ / \
|
||||||
|
// a y => x c
|
||||||
|
// / \ / \
|
||||||
|
// b c a b
|
||||||
|
pub fn rotate_left(&mut self, x: N::Id) -> Option<()> {
|
||||||
|
let y = self.right_child_of(x)?;
|
||||||
|
let b = self.left_child_of(y);
|
||||||
|
|
||||||
|
let x_parent = self.parent_of(x);
|
||||||
|
|
||||||
|
if let Some(node) = self.store.get_mut(x) {
|
||||||
|
node.set_right(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(b_mut) = b.and_then(|id| self.store.get_mut(id)) {
|
||||||
|
b_mut.set_parent(Some(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(node) = self.store.get_mut(y) {
|
||||||
|
node.set_left(Some(x));
|
||||||
|
|
||||||
|
if let Some(parent) = x_parent {
|
||||||
|
node.set_parent(Some(parent));
|
||||||
|
if self.store.get(parent).unwrap().left() == Some(x) {
|
||||||
|
self.store.get_mut(parent).unwrap().set_left(Some(y));
|
||||||
|
} else {
|
||||||
|
self.store.get_mut(parent).unwrap().set_right(Some(y));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.root = Some(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// x y
|
||||||
|
// / \ / \
|
||||||
|
// y c => a x
|
||||||
|
// / \ / \
|
||||||
|
// a b b c
|
||||||
|
pub fn rotate_right(&mut self, x: N::Id) -> Option<()> {
|
||||||
|
let y = self.left_child_of(x)?;
|
||||||
|
let b = self.right_child_of(y);
|
||||||
|
|
||||||
|
let x_parent = self.parent_of(x);
|
||||||
|
|
||||||
|
if let Some(node) = self.store.get_mut(x) {
|
||||||
|
node.set_left(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(b_mut) = b.and_then(|id| self.store.get_mut(id)) {
|
||||||
|
b_mut.set_parent(Some(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(node) = self.store.get_mut(y) {
|
||||||
|
node.set_right(Some(x));
|
||||||
|
|
||||||
|
if let Some(parent) = x_parent {
|
||||||
|
node.set_parent(Some(parent));
|
||||||
|
if self.store.get(parent).unwrap().left() == Some(x) {
|
||||||
|
self.store.get_mut(parent).unwrap().set_left(Some(y));
|
||||||
|
} else {
|
||||||
|
self.store.get_mut(parent).unwrap().set_right(Some(y));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.root = Some(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotate(&mut self, x: N::Id, left: bool) -> Option<()> {
|
||||||
|
if left {
|
||||||
|
self.rotate_left(x)
|
||||||
|
} else {
|
||||||
|
self.rotate_right(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_by_key<Q>(&self, key: &Q) -> SearchResult<N::Id>
|
||||||
|
where
|
||||||
|
N::Key: core::borrow::Borrow<Q>,
|
||||||
|
Q: Ord + ?Sized,
|
||||||
|
{
|
||||||
|
use core::borrow::Borrow;
|
||||||
|
use core::cmp::Ordering::*;
|
||||||
|
|
||||||
|
let Some(mut current) = self.root else {
|
||||||
|
return SearchResult::Empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let node = self.store.get(current).unwrap();
|
||||||
|
|
||||||
|
match key.cmp(node.key().borrow()) {
|
||||||
|
Less => {
|
||||||
|
if let Some(left) = node.left() {
|
||||||
|
current = left;
|
||||||
|
} else {
|
||||||
|
return SearchResult::NotFoundLeftOf(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Greater => {
|
||||||
|
if let Some(right) = node.right() {
|
||||||
|
current = right;
|
||||||
|
} else {
|
||||||
|
return SearchResult::NotFoundRightOf(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Equal => return SearchResult::FoundAt(current),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_id(&mut self, id: N::Id) {
|
||||||
|
let node = self.store.get(id).unwrap();
|
||||||
|
|
||||||
|
match self.find_by_key(node.key()) {
|
||||||
|
SearchResult::FoundAt(_) => {
|
||||||
|
panic!("Duplicate key insertion is not allowed");
|
||||||
|
}
|
||||||
|
SearchResult::NotFoundRightOf(parent) => {
|
||||||
|
self.store.get_mut(parent).unwrap().set_right(Some(id));
|
||||||
|
self.store.get_mut(id).unwrap().set_parent(Some(parent));
|
||||||
|
self.store.get_mut(id).unwrap().set_color(true); // new node is always red
|
||||||
|
}
|
||||||
|
SearchResult::NotFoundLeftOf(parent) => {
|
||||||
|
self.store.get_mut(parent).unwrap().set_left(Some(id));
|
||||||
|
self.store.get_mut(id).unwrap().set_parent(Some(parent));
|
||||||
|
self.store.get_mut(id).unwrap().set_color(true); // new node is always red
|
||||||
|
}
|
||||||
|
SearchResult::Empty => {
|
||||||
|
let node = self.store.get_mut(id).unwrap();
|
||||||
|
node.set_parent(None);
|
||||||
|
node.set_color(false); // root is always black
|
||||||
|
|
||||||
|
self.root = Some(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fix_insert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fix_insert(&mut self, mut id: N::Id) {
|
||||||
|
while let Some(parent) = self
|
||||||
|
.store
|
||||||
|
.get(id)
|
||||||
|
.and_then(|node| node.parent())
|
||||||
|
.filter(|&p| self.store.get(p).unwrap().color())
|
||||||
|
{
|
||||||
|
// gp is guaranteed to exist because parent is red and the root is black
|
||||||
|
let grandparent = self
|
||||||
|
.store
|
||||||
|
.get(parent)
|
||||||
|
.and_then(|node| node.parent())
|
||||||
|
.unwrap();
|
||||||
|
let (uncle, is_left) = if self.store.get(grandparent).unwrap().left() == Some(parent) {
|
||||||
|
(self.store.get(grandparent).unwrap().right(), true)
|
||||||
|
} else {
|
||||||
|
(self.store.get(grandparent).unwrap().left(), false)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(uncle_id) = uncle
|
||||||
|
&& self.store.get(uncle_id).unwrap().color()
|
||||||
|
{
|
||||||
|
// Case 1: Uncle is red
|
||||||
|
self.store.get_mut(parent).unwrap().set_color(false);
|
||||||
|
self.store.get_mut(uncle_id).unwrap().set_color(false);
|
||||||
|
self.store.get_mut(grandparent).unwrap().set_color(true);
|
||||||
|
id = grandparent;
|
||||||
|
} else {
|
||||||
|
// Case 2: Uncle is black
|
||||||
|
if self.store.get(parent).unwrap().child(!is_left) == Some(id) {
|
||||||
|
// Case 2a: id is on the same side as uncle
|
||||||
|
self.rotate(parent, is_left);
|
||||||
|
id = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2b: id is on the opposite side as uncle
|
||||||
|
self.store.get_mut(parent).unwrap().set_color(false);
|
||||||
|
self.store.get_mut(grandparent).unwrap().set_color(true);
|
||||||
|
self.rotate(grandparent, !is_left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(root_id) = self.root {
|
||||||
|
self.store.get_mut(root_id).unwrap().set_color(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn color_of(&self, id: Option<N::Id>) -> bool {
|
||||||
|
id.map(|id| self.store.get(id).unwrap().color())
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_color_of(&mut self, id: Option<N::Id>, color: bool) {
|
||||||
|
if let Some(id) = id {
|
||||||
|
self.store.get_mut(id).unwrap().set_color(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent_of(&self, id: N::Id) -> Option<N::Id> {
|
||||||
|
self.store.get(id).unwrap().parent()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn left_child_of(&self, id: N::Id) -> Option<N::Id> {
|
||||||
|
self.store.get(id).unwrap().left()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn right_child_of(&self, id: N::Id) -> Option<N::Id> {
|
||||||
|
self.store.get(id).unwrap().right()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn child_of(&self, id: N::Id, left: bool) -> Option<N::Id> {
|
||||||
|
self.store.get(id).unwrap().child(left)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children_of(&self, id: N::Id) -> (Option<N::Id>, Option<N::Id>) {
|
||||||
|
self.store.get(id).unwrap().children()
|
||||||
|
}
|
||||||
|
|
||||||
|
// When removing an node from an RB tree, we have to potentially fix the
|
||||||
|
// invariants of the tree starting from the node X that replaced a deleted
|
||||||
|
// node Y.
|
||||||
|
|
||||||
|
// X is either root, or X is None and the child of a parent node P which is
|
||||||
|
// guaranteed to have a non-nil sibling W, since X is doubly-black, and so
|
||||||
|
// the path through W must hold at least 2 black nodes, including implicit
|
||||||
|
// black nil-leafs.
|
||||||
|
pub fn remove(&mut self, z: N::Id) {
|
||||||
|
// Y is either Z, the removed node in the case that Z has at most
|
||||||
|
// one child, or Y is Z's successor which is guaranteed to have at most one
|
||||||
|
// child (the right child).
|
||||||
|
|
||||||
|
let y = match self.children_of(z) {
|
||||||
|
(None, None) | (Some(_), None) | (None, Some(_)) => z,
|
||||||
|
// z has a successor, since it has two children.
|
||||||
|
_ => self.next_of(z).unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// In either case, X is the only child of Y, if it exists.
|
||||||
|
let x = match self.children_of(y) {
|
||||||
|
(Some(left), _) => Some(left),
|
||||||
|
(None, Some(right)) => Some(right),
|
||||||
|
(None, None) => None,
|
||||||
|
};
|
||||||
|
// Therefore, X must be red or None, and if X is red Y must be black.
|
||||||
|
|
||||||
|
let parent = self.store.get(y).unwrap().parent();
|
||||||
|
|
||||||
|
// If Y's parent was None, then Y was the root, and the tree is empty.
|
||||||
|
let Some(parent) = parent else {
|
||||||
|
self.root = x;
|
||||||
|
|
||||||
|
if let Some(x) = x {
|
||||||
|
self.store.get_mut(x).unwrap().set_parent(None);
|
||||||
|
self.store.get_mut(x).unwrap().set_color(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// X is promoted to Y's position, and Y is unlinked from the tree.
|
||||||
|
if self.store.get(parent).unwrap().left() == Some(y) {
|
||||||
|
self.store.get_mut(parent).unwrap().set_left(x);
|
||||||
|
} else {
|
||||||
|
self.store.get_mut(parent).unwrap().set_right(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(x_id) = x {
|
||||||
|
// If X was red, color it black. Since it replaces a black node, the
|
||||||
|
// black-height of the subtree is preserved.
|
||||||
|
let x = self.store.get_mut(x_id).unwrap();
|
||||||
|
x.set_parent(Some(parent));
|
||||||
|
x.set_color(false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let color = self.store.get(y).unwrap().color();
|
||||||
|
// If Y is Z's successor, move Y's data into Z (or move Z's meta into Y).
|
||||||
|
if y != z {
|
||||||
|
self.copy_meta_to(z, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If X is None and Y was black, then a black node was removed, and the tree
|
||||||
|
// needs to be rebalanced.
|
||||||
|
if !color {
|
||||||
|
// x is the NIL leaf child of parent, and is doubly black.
|
||||||
|
let mut x = None;
|
||||||
|
let mut parent = Some(parent);
|
||||||
|
while x != self.root && !self.color_of(x) {
|
||||||
|
// safe because x is not root.
|
||||||
|
let parent_id = parent.unwrap();
|
||||||
|
|
||||||
|
// w exists because it is the sibling of x; the subtree at x has
|
||||||
|
// a black-height of 2, the subtree at w must equally have a
|
||||||
|
// black-height of 2.
|
||||||
|
let (mut w, is_left) = if self.store.get(parent_id).unwrap().left() == x {
|
||||||
|
(self.store.get(parent_id).unwrap().right().unwrap(), true)
|
||||||
|
} else {
|
||||||
|
(self.store.get(parent_id).unwrap().left().unwrap(), false)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Case 1: w is red -> parent and w's children are black
|
||||||
|
if self.color_of(Some(w)) {
|
||||||
|
// set w to black and parent to red
|
||||||
|
self.set_color_of(Some(w), false);
|
||||||
|
self.set_color_of(Some(parent_id), true);
|
||||||
|
|
||||||
|
// rotate around parent such that w becomes the parent of parent
|
||||||
|
self.rotate(parent_id, is_left);
|
||||||
|
|
||||||
|
// x hasn't change, but now the sibling is the child of w, which is black
|
||||||
|
w = if is_left {
|
||||||
|
self.store.get(parent_id).unwrap().right().unwrap()
|
||||||
|
} else {
|
||||||
|
self.store.get(parent_id).unwrap().left().unwrap()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2: w is black
|
||||||
|
|
||||||
|
match (
|
||||||
|
self.color_of(self.left_child_of(w)),
|
||||||
|
self.color_of(self.right_child_of(w)),
|
||||||
|
) {
|
||||||
|
(false, false) => {
|
||||||
|
// Case 2a: w's children are both black
|
||||||
|
// x carries a phantom black, and its sibling w is black
|
||||||
|
// we can remove one black from x and w by colouring w
|
||||||
|
// red and giving x's phantom black to the
|
||||||
|
// parent.
|
||||||
|
self.set_color_of(Some(w), true);
|
||||||
|
x = Some(parent_id);
|
||||||
|
parent = self.store.get(parent_id).unwrap().parent();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(near_cousin @ true, false) | (near_cousin @ false, true) => {
|
||||||
|
// Case 2b: x's near-cousin is red and its far-cousin is black
|
||||||
|
// colour the near-cousin black and w red, rotate so
|
||||||
|
// that the near cousin becomes the sibling of x
|
||||||
|
if near_cousin == is_left {
|
||||||
|
self.set_color_of(self.child_of(w, !is_left), false);
|
||||||
|
self.set_color_of(Some(w), true);
|
||||||
|
self.rotate(w, !is_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fall through to case 2c
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2c: x's far-cousin is red
|
||||||
|
// we can now rotate around the parent to balance the
|
||||||
|
// subtree at parent without increasing the
|
||||||
|
// black-height.
|
||||||
|
// However, in the case that the far-cousin is red and
|
||||||
|
// the parent is black, this will result, after
|
||||||
|
// rotating, in the far-cousin's path having fewer black
|
||||||
|
// nodes than the parent's path: we have taken a black
|
||||||
|
// node from above the far-cousin and moved it into its
|
||||||
|
// sibling branch.
|
||||||
|
// This is fixed by colouring w the colour of the
|
||||||
|
// parent, and colouring the parent and w's far-cousin
|
||||||
|
// black.
|
||||||
|
self.set_color_of(Some(w), self.color_of(Some(parent_id)));
|
||||||
|
self.set_color_of(Some(parent_id), false);
|
||||||
|
self.set_color_of(self.child_of(w, !is_left), false);
|
||||||
|
self.rotate(parent_id, is_left);
|
||||||
|
|
||||||
|
// After the rotation, the inbalance has been resolved.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_meta_to(&mut self, from: N::Id, to: N::Id) {
|
||||||
|
let (parent, color, left, right) = {
|
||||||
|
let from_node = self.store.get(from).unwrap();
|
||||||
|
(
|
||||||
|
from_node.parent(),
|
||||||
|
from_node.color(),
|
||||||
|
from_node.left(),
|
||||||
|
from_node.right(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let to_node = self.store.get_mut(to).unwrap();
|
||||||
|
|
||||||
|
to_node.set_parent(parent);
|
||||||
|
to_node.set_color(color);
|
||||||
|
to_node.set_left(left);
|
||||||
|
to_node.set_right(right);
|
||||||
|
|
||||||
|
if let Some(parent) = parent {
|
||||||
|
let parent_node = self.store.get_mut(parent).unwrap();
|
||||||
|
if parent_node.left() == Some(from) {
|
||||||
|
parent_node.set_left(Some(to));
|
||||||
|
} else {
|
||||||
|
parent_node.set_right(Some(to));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.root = Some(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(left) = left {
|
||||||
|
self.store.get_mut(left).unwrap().set_parent(Some(to));
|
||||||
|
}
|
||||||
|
if let Some(right) = right {
|
||||||
|
self.store.get_mut(right).unwrap().set_parent(Some(to));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SearchResult<T> {
|
||||||
|
FoundAt(T),
|
||||||
|
NotFoundRightOf(T),
|
||||||
|
NotFoundLeftOf(T),
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
|
mod default_node {
|
||||||
|
use crate::Node;
|
||||||
|
|
||||||
|
type DefaultNodeId = u64;
|
||||||
|
|
||||||
|
struct DefaultNodeStore {
|
||||||
|
nodes: alloc::collections::BTreeMap<DefaultNodeId, DefaultNode>,
|
||||||
|
next_id: DefaultNodeId,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DefaultNode {
|
||||||
|
parent: Option<DefaultNodeId>,
|
||||||
|
left: Option<DefaultNodeId>,
|
||||||
|
right: Option<DefaultNodeId>,
|
||||||
|
key: u64,
|
||||||
|
color: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for DefaultNode {
|
||||||
|
type Id = DefaultNodeId;
|
||||||
|
type Key = u64;
|
||||||
|
|
||||||
|
fn parent(&self) -> Option<Self::Id> {
|
||||||
|
self.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_parent(&mut self, parent: Option<Self::Id>) {
|
||||||
|
self.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn left(&self) -> Option<Self::Id> {
|
||||||
|
self.left
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_left(&mut self, left: Option<Self::Id>) {
|
||||||
|
self.left = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn right(&self) -> Option<Self::Id> {
|
||||||
|
self.right
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_right(&mut self, right: Option<Self::Id>) {
|
||||||
|
self.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key(&self) -> &Self::Key {
|
||||||
|
&self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn color(&self) -> bool {
|
||||||
|
self.color
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_color(&mut self, color: bool) {
|
||||||
|
self.color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
[profile.dev]
|
|
||||||
codegen-backend = "llvm"
|
|
||||||
|
|
||||||
[unstable]
|
[unstable]
|
||||||
json-target-spec = true # lets us specify a custom target specification file
|
json-target-spec = true # lets us specify a custom target specification file
|
||||||
build-std-features = ["compiler-builtins-mem"]
|
build-std-features = ["compiler-builtins-mem"]
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@ fn main() {
|
||||||
println!("cargo::rerun-if-changed=build.rs");
|
println!("cargo::rerun-if-changed=build.rs");
|
||||||
println!("cargo::rerun-if-changed=kernel.lds");
|
println!("cargo::rerun-if-changed=kernel.lds");
|
||||||
|
|
||||||
println!("cargo::rustc-link-arg=-Tkernel.lds");
|
println!("cargo::rustc-link-arg=-Tkernel/kernel.lds");
|
||||||
// println!("cargo::rustc-link-arg-tests=-Tkernel.lds");
|
// println!("cargo::rustc-link-arg-tests=-Tkernel.lds");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
use kernel::{
|
use kernel::{
|
||||||
memory::VirtAddr,
|
memory::VirtAddr,
|
||||||
|
serial_println,
|
||||||
sync::LazyLock,
|
sync::LazyLock,
|
||||||
x86_64::{gdt::GlobalDescriptorTable, idt::InterruptDescriptorTable},
|
x86_64::{gdt::GlobalDescriptorTable, idt::InterruptDescriptorTable},
|
||||||
};
|
};
|
||||||
|
|
@ -68,7 +69,10 @@ extern "C" fn _start() -> ! {
|
||||||
.memory_map,
|
.memory_map,
|
||||||
);
|
);
|
||||||
|
|
||||||
kernel::serial_println!("PMM: {pmm:#?}");
|
let leaf = kernel::x86_64::cpuid::Leaf8000008::get();
|
||||||
|
serial_println!("max phy: {:#?}", leaf);
|
||||||
|
|
||||||
|
// kernel::serial_println!("PMM: {pmm:#?}");
|
||||||
|
|
||||||
let fb = limine_requests::FRAMEBUFFER_REQUEST
|
let fb = limine_requests::FRAMEBUFFER_REQUEST
|
||||||
.framebuffers()
|
.framebuffers()
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,22 @@ pub struct PageChunk {
|
||||||
pub count: usize,
|
pub count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PhysicalMemoryManager {
|
||||||
|
/// On amd64 platforms, there are at most 2^40 pages of addressable physical
|
||||||
|
/// memory. We maintain a binary tree of free page chunks for each
|
||||||
|
/// power-of-two range of free pages.
|
||||||
|
///
|
||||||
|
/// When a range of (contiguous) pages is allocated, we find the smallest
|
||||||
|
/// power-of-two which is larger or equal to the number of pages requested,
|
||||||
|
/// and try top pop the head of the corresponding free list. If the free
|
||||||
|
/// list is empty, we try to find a larger free chunk and split it into two
|
||||||
|
/// smaller chunks recursively until we have a chunk of the desired size.
|
||||||
|
///
|
||||||
|
/// When a range of pages is freed, we try to locate its buddy and merge
|
||||||
|
/// them into a larger chunk recursively.
|
||||||
|
buddies: [u64; 40],
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PhysicalMemoryAllocator {
|
pub struct PhysicalMemoryAllocator {
|
||||||
tree: PageTree,
|
tree: PageTree,
|
||||||
}
|
}
|
||||||
|
|
@ -556,6 +572,8 @@ pub mod bump {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod page_tree {
|
mod page_tree {
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
memory::{PAGE_SIZE, PhyAddr},
|
memory::{PAGE_SIZE, PhyAddr},
|
||||||
serial_println,
|
serial_println,
|
||||||
|
|
@ -563,10 +581,53 @@ mod page_tree {
|
||||||
|
|
||||||
use core::ops::{Index, IndexMut};
|
use core::ops::{Index, IndexMut};
|
||||||
|
|
||||||
enum SearchResult<T> {
|
pub enum SearchResult<T> {
|
||||||
Found(T),
|
Found(T),
|
||||||
NotFound(T),
|
NotFound(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// On amd64 platforms, the maximum physical address is 52 bits, the lower
|
||||||
|
/// 12 of which are zero for page aligned addresses.
|
||||||
|
/// Our Tree Node entry needs to store 3 page indices (left, right, parent) and a color bit.
|
||||||
|
struct CompactPage(u128);
|
||||||
|
|
||||||
|
impl CompactPage {
|
||||||
|
fn parent(&self) -> usize {
|
||||||
|
self.0.get_bits(0..40) as usize
|
||||||
|
}
|
||||||
|
fn set_parent(&mut self, parent: usize) {
|
||||||
|
self.0.set_bits(0..40, parent as u128);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn left_child(&self) -> usize {
|
||||||
|
self.0.get_bits(40..80) as usize
|
||||||
|
}
|
||||||
|
fn set_left_child(&mut self, left: usize) {
|
||||||
|
self.0.set_bits(40..80, left as u128);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn right_child(&self) -> usize {
|
||||||
|
self.0.get_bits(80..120) as usize
|
||||||
|
}
|
||||||
|
fn set_right_child(&mut self, right: usize) {
|
||||||
|
self.0.set_bits(80..120, right as u128);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn color(&self) -> bool {
|
||||||
|
self.0.get_bit(120)
|
||||||
|
}
|
||||||
|
fn set_color(&mut self, color: bool) {
|
||||||
|
self.0.set_bit(120, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn data(&self) -> u8 {
|
||||||
|
self.0.get_bits(121..128) as u8
|
||||||
|
}
|
||||||
|
fn set_data(&mut self, data: u8) {
|
||||||
|
self.0.set_bits(121..128, data as u128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Page {
|
struct Page {
|
||||||
left_idx: usize,
|
left_idx: usize,
|
||||||
right_idx: usize,
|
right_idx: usize,
|
||||||
|
|
@ -960,11 +1021,12 @@ mod page_tree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let color = self.color_of(y);
|
||||||
if y != z {
|
if y != z {
|
||||||
self.replace(z, y);
|
self.replace(z, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.color_of(y) {
|
if !color {
|
||||||
self.fixup_remove(x);
|
self.fixup_remove(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#![allow(clippy::identity_op)]
|
#![allow(clippy::identity_op)]
|
||||||
|
|
||||||
|
use core::fmt::Debug;
|
||||||
|
|
||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
|
|
@ -339,18 +341,22 @@ bitflags! {
|
||||||
pub struct Leaf8000008(CpuidResult);
|
pub struct Leaf8000008(CpuidResult);
|
||||||
|
|
||||||
impl Leaf8000008 {
|
impl Leaf8000008 {
|
||||||
|
pub fn get() -> Self {
|
||||||
|
let result = cpuid(0x80000008, 0);
|
||||||
|
Self(result)
|
||||||
|
}
|
||||||
pub fn physical_address_bits(&self) -> u8 {
|
pub fn physical_address_bits(&self) -> u8 {
|
||||||
self.0.eax.get_bits(0..8) as u8
|
self.0.eax.get_bits(0..8) as u8
|
||||||
}
|
}
|
||||||
pub fn num_linear_address_bits(&self) -> u8 {
|
pub fn num_linear_address_bits(&self) -> u8 {
|
||||||
self.0.eax.get_bits(8..16) as u8
|
self.0.eax.get_bits(8..16) as u8
|
||||||
}
|
}
|
||||||
pub fn gest_physical_address_bits(&self) -> u8 {
|
pub fn guest_physical_address_bits(&self) -> u8 {
|
||||||
self.0.eax.get_bits(16..24) as u8
|
self.0.eax.get_bits(16..24) as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn num_physical_threads(&self) -> u8 {
|
pub fn num_physical_threads(&self) -> u8 {
|
||||||
self.0.ecx.get_bits(0..8) as u8 - 1
|
self.0.ecx.get_bits(0..8) as u8 + 1
|
||||||
}
|
}
|
||||||
pub fn apic_id_size(&self) -> u8 {
|
pub fn apic_id_size(&self) -> u8 {
|
||||||
self.0.ecx.get_bits(12..16) as u8
|
self.0.ecx.get_bits(12..16) as u8
|
||||||
|
|
@ -371,7 +377,30 @@ impl Leaf8000008 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Leaf8000008 {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.debug_struct("Leaf8000008")
|
||||||
|
.field("physical_address_bits", &self.physical_address_bits())
|
||||||
|
.field("num_linear_address_bits", &self.num_linear_address_bits())
|
||||||
|
.field(
|
||||||
|
"guest_physical_address_bits",
|
||||||
|
&self.guest_physical_address_bits(),
|
||||||
|
)
|
||||||
|
.field("num_physical_threads", &self.num_physical_threads())
|
||||||
|
.field("apic_id_size", &self.apic_id_size())
|
||||||
|
.field(
|
||||||
|
"performance_timestamp_counter_size",
|
||||||
|
&self.performance_timestamp_counter_size(),
|
||||||
|
)
|
||||||
|
.field("max_invlpgb_page_count", &self.max_invlpgb_page_count())
|
||||||
|
.field("max_rdpru_ecx", &self.max_rdpru_ecx())
|
||||||
|
.field("flags", &self.flags())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct Leaf8000008Flags: u32 {
|
pub struct Leaf8000008Flags: u32 {
|
||||||
const CLZERO = 1 << 0;
|
const CLZERO = 1 << 0;
|
||||||
const RETIRED_INSTR = 1 << 1;
|
const RETIRED_INSTR = 1 << 1;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue