changeset 0:e342ded1647e

Initial commit Essentially seems to be working; better balance needed
author Lewin Bormann <lbo@spheniscida.de>
date Mon, 04 Jul 2022 16:59:06 -0700
parents
children 04b6ed18abf3
files .hgignore Cargo.toml src/lib.rs
diffstat 3 files changed, 230 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Mon Jul 04 16:59:06 2022 -0700
@@ -0,0 +1,2 @@
+^target/
+^Cargo.lock$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Cargo.toml	Mon Jul 04 16:59:06 2022 -0700
@@ -0,0 +1,9 @@
+[package]
+name = "btreex"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+ptree = "0.4"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib.rs	Mon Jul 04 16:59:06 2022 -0700
@@ -0,0 +1,219 @@
+use std::cmp::Ordering;
+use ptree::TreeBuilder;
+
+const ORDER: usize = 3;
+
+#[derive(Debug)]
+struct Node<T> {
+    entries: [Option<T>; ORDER - 1],
+    children: [Option<usize>; ORDER],
+    parent: Option<usize>,
+}
+
+impl<T: Ord> Node<T> {
+    fn new(parent: Option<usize>) -> Node<T> {
+        Node {
+            entries: Default::default(),
+            children: Default::default(),
+            parent: parent,
+        }
+    }
+}
+
+#[derive(Debug)]
+struct BTree<T> {
+    v: Vec<Node<T>>,
+    root: usize,
+}
+
+impl<T: Ord> BTree<T> {
+    fn new(initial_capacity: usize) -> BTree<T> {
+        BTree {
+            v: Vec::with_capacity(initial_capacity),
+            root: 0,
+        }
+    }
+
+    fn free(&self, node: usize) -> usize {
+        self.v[node]
+            .entries
+            .iter()
+            .map(|e| if e.is_some() { 0 } else { 1 })
+            .sum()
+    }
+    fn get(&self, node: usize, elem: usize) -> &Option<T> {
+        &self.v[node].entries[elem]
+    }
+    fn get_mut(&mut self, node: usize, elem: usize) -> &mut Option<T> {
+        &mut self.v[node].entries[elem]
+    }
+    fn get_child(&self, node: usize, child: usize) -> &Option<usize> {
+        &self.v[node].children[child]
+    }
+    fn get_child_mut(&mut self, node: usize, child: usize) -> &mut Option<usize> {
+        &mut self.v[node].children[child]
+    }
+
+    fn insert_inline(&mut self, node: usize, value: T) {
+        assert!(self.free(node) >= 1);
+        let node = &mut self.v[node];
+
+        let mut loc = ORDER - 2;
+
+        for i in 0..ORDER - 1 {
+            if let Some(ref el) = node.entries[i] {
+                if value.cmp(el) == Ordering::Less {
+                    // Found right location. Shift remaining elements.
+                    loc = i;
+                    break;
+                }
+            } else {
+                loc = i;
+                break;
+            }
+        }
+
+        for i in 0..(ORDER - 2 - loc) {
+            node.entries[ORDER - 2 - i] = node.entries[ORDER - 3 - i].take();
+            node.children[ORDER - 2 - i] = node.children[ORDER - 3 - i].take();
+        }
+        node.entries[loc] = Some(value);
+    }
+    fn insert(&mut self, value: T) -> bool {
+        // 1. Find appropriate node
+        // 2. Find appropriate order
+        // 3. Insert or split.
+
+        // Initialize empty tree
+        if self.v.is_empty() {
+            self.v.push(Node::new(None));
+            self.v[0].entries[0] = Some(value);
+            return true;
+        }
+
+        let mut node = self.root;
+        'CHILDREN: loop {
+            // 1. Descend as long as there are feasible children.
+            // 2. Insert or split once no more children to be found.
+            let mut found = false;
+            let mut i = 0;
+            'ELEMENTS: while i < ORDER - 1 {
+                if let Some(el) = self.get(node, i) {
+                    if value.cmp(el) == Ordering::Less {
+                        found = true;
+                        break 'ELEMENTS;
+                    }
+                } else {
+                    // Past last filled element.
+                    found = true;
+                    break 'ELEMENTS;
+                }
+                i += 1
+            }
+            // There is an element greater than `value`?
+            if let Some(child) = self.get_child(node, i) {
+                // Descend into child node.
+                node = *child;
+                continue 'CHILDREN;
+            } else if self.free(node) >= 1 {
+                self.insert_inline(node, value);
+                return true;
+            } else {
+                // We have to split.
+                self.split(node, value, i);
+                return true;
+            }
+        }
+    }
+
+    /// Split node `node` at `loc`, moving all values at `loc` and higher to the right node,
+    /// inserting `value` into a new parent node.
+    fn split(&mut self, node: usize, value: T, loc: usize) -> usize {
+        let leftix = node;
+        let rightix = self.v.len();
+        let topix = self.v.len() + 1;
+
+        let mut right = Node::new(Some(topix));
+        let mut top = Node::new(self.v[node].parent);
+
+        // Put pivot entry into top node.
+        top.entries[0] = Some(value);
+
+        // Copy greater elements to right node.
+        for i in loc..ORDER - 1 {
+            right.entries[i - loc] = self.get_mut(node, i).take();
+        }
+
+        // left
+        top.children[0] = Some(leftix);
+        // right
+        top.children[1] = Some(rightix);
+
+        // Update parent.
+        {
+            if let Some(parentix) = self.v[leftix].parent {
+                let parent = &mut self.v[parentix];
+                for i in 0..ORDER {
+                    if parent.children[i] == Some(node) {
+                        parent.children[i] = Some(topix);
+                        break;
+                    }
+                }
+            } else {
+                self.root = topix;
+            }
+        }
+        self.v[leftix].parent = Some(topix);
+        right.parent = Some(topix);
+
+        self.v.push(right);
+        self.v.push(top);
+
+        topix
+    }
+}
+impl<T: std::fmt::Debug> BTree<T> {
+    fn debug_print(&self) -> String {
+        let mut t = TreeBuilder::new("btree".to_string());
+        self.print_subtree(&mut t, self.root);
+        let mut o: Vec<u8> = Vec::new();
+        ptree::write_tree(&t.build(), &mut o);
+        String::from_utf8(o).unwrap()
+    }
+    fn print_subtree(&self, tb: &mut TreeBuilder, node: usize) {
+        let node = &self.v[node];
+        for i in 0..ORDER-1 {
+            if let Some(ch) = node.children[i] {
+                self.print_subtree(tb.begin_child(format!("<{}>", ch)), ch);
+                tb.end_child();
+            }
+            tb.add_empty_child(format!("{:?}", node.entries[i]));
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::BTree;
+    #[test]
+    fn basic_test() {
+        let mut bt = BTree::<i32>::new(16);
+
+        bt.insert(42);
+        bt.insert(52);
+        bt.insert(32);
+        bt.insert(22);
+        bt.insert(12);
+        bt.insert(62);
+        bt.insert(3);
+        bt.insert(1);
+        bt.insert(2);
+        bt.insert(4);
+
+        println!("{}", bt.debug_print());
+        println!("root: {}", bt.root);
+        for (i, e) in bt.v.iter().enumerate() {
+            println!("{} {:?}", i, e);
+        }
+    }
+}