datastructures vec
This commit is contained in:
parent
65946147a7
commit
9f14c85f55
6 changed files with 356 additions and 1 deletions
|
@ -31,8 +31,9 @@ members = [
|
||||||
"crates/rfd-demo",
|
"crates/rfd-demo",
|
||||||
"crates/iter-prod",
|
"crates/iter-prod",
|
||||||
"crates/tpdemo",
|
"crates/tpdemo",
|
||||||
|
"crates/datastructures",
|
||||||
"crates/graph",
|
"crates/graph",
|
||||||
"crates/sdl-idiot", "minitree",
|
"crates/sdl-idiot"
|
||||||
]
|
]
|
||||||
default-members = ["."]
|
default-members = ["."]
|
||||||
|
|
||||||
|
|
6
crates/datastructures/Cargo.toml
Normal file
6
crates/datastructures/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "minitree"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
87
crates/datastructures/src/btree.rs
Normal file
87
crates/datastructures/src/btree.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct BTree<K: Ord, V> {
|
||||||
|
root: Option<Node<K, V>>,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Node<K, V> {
|
||||||
|
key: K,
|
||||||
|
value: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> Node<K, V> {
|
||||||
|
pub fn new_root(key: K, value: V) -> Self {
|
||||||
|
Node { key, value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Ord, V> BTree<K, V> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { root: None, len: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.root = None;
|
||||||
|
self.len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rebalance() {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
|
||||||
|
if let Some(root) = &self.root {
|
||||||
|
todo!()
|
||||||
|
} else {
|
||||||
|
let new_node = Node::new_root(key, value);
|
||||||
|
self.root = Some(new_node);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, key: K) -> Option<V> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_key(&self, key: K) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, key: K) -> Option<&V> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_node(&self, key: K) -> Option<&Node<K, V>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_node_mut(&mut self, key: K) -> Option<&mut Node<K, V>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn test_create() {
|
||||||
|
let _tree = BTree::<u32, u32>::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_insert() {
|
||||||
|
let mut tree = BTree::<u32, &str>::default();
|
||||||
|
tree.insert(19, "19");
|
||||||
|
tree.insert(9, "09");
|
||||||
|
tree.insert(14, "14");
|
||||||
|
|
||||||
|
assert!(tree.get(19).is_some_and(|s| *s == "19"));
|
||||||
|
assert!(tree.get(9).is_some_and(|s| *s == "09"));
|
||||||
|
assert!(tree.get(14).is_some_and(|s| *s == "14"));
|
||||||
|
}
|
||||||
|
}
|
2
crates/datastructures/src/lib.rs
Normal file
2
crates/datastructures/src/lib.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod raw_vec;
|
||||||
|
pub mod vec;
|
69
crates/datastructures/src/raw_vec.rs
Normal file
69
crates/datastructures/src/raw_vec.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
use std::{
|
||||||
|
alloc::{self, Layout},
|
||||||
|
ptr::NonNull,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub(crate) struct RawVec<T> {
|
||||||
|
pub(crate) ptr: NonNull<T>,
|
||||||
|
pub(crate) capacity: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> RawVec<T> {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
ptr: NonNull::dangling(),
|
||||||
|
capacity: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See rustonomicon, chapter 9.2
|
||||||
|
pub(crate) fn grow(&mut self) {
|
||||||
|
let (new_cap, new_layout) = if self.capacity == 0 {
|
||||||
|
(1, Layout::array::<T>(1).unwrap())
|
||||||
|
} else {
|
||||||
|
// This can't overflow since self.cap <= isize::MAX.
|
||||||
|
let new_cap = 2 * self.capacity;
|
||||||
|
|
||||||
|
// `Layout::array` checks that the number of bytes is <= usize::MAX,
|
||||||
|
// but this is redundant since old_layout.size() <= isize::MAX,
|
||||||
|
// so the `unwrap` should never fail.
|
||||||
|
let new_layout = Layout::array::<T>(new_cap).unwrap();
|
||||||
|
(new_cap, new_layout)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ensure that the new allocation doesn't exceed `isize::MAX` bytes.
|
||||||
|
if new_layout.size() > isize::MAX as usize {
|
||||||
|
alloc::handle_alloc_error(new_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_ptr = if self.capacity == 0 {
|
||||||
|
unsafe { alloc::alloc(new_layout) }
|
||||||
|
} else {
|
||||||
|
let old_layout = Layout::array::<T>(self.capacity).unwrap();
|
||||||
|
let old_ptr = self.ptr.as_ptr() as *mut u8;
|
||||||
|
unsafe { alloc::realloc(old_ptr, old_layout, new_layout.size()) }
|
||||||
|
};
|
||||||
|
|
||||||
|
// If allocation fails, `new_ptr` will be null, in which case we abort.
|
||||||
|
self.ptr = match NonNull::new(new_ptr as *mut T) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => alloc::handle_alloc_error(new_layout),
|
||||||
|
};
|
||||||
|
self.capacity = new_cap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for RawVec<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self.capacity != 0 {
|
||||||
|
let layout = Layout::array::<T>(self.capacity).unwrap();
|
||||||
|
unsafe {
|
||||||
|
alloc::dealloc(self.ptr.as_ptr() as *mut u8, layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Send> Send for RawVec<T> {}
|
||||||
|
unsafe impl<T: Sync> Sync for RawVec<T> {}
|
190
crates/datastructures/src/vec.rs
Normal file
190
crates/datastructures/src/vec.rs
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
//! Custom implementation of the Vector datastructure
|
||||||
|
//!
|
||||||
|
//! Many thanks to the rustonomicon, chapter 9:
|
||||||
|
//! https://doc.rust-lang.org/nomicon/vec/vec.html
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
alloc::{self, Layout},
|
||||||
|
marker::PhantomData,
|
||||||
|
mem,
|
||||||
|
ops::{Deref, DerefMut, Index},
|
||||||
|
ptr::{self, NonNull},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::raw_vec::RawVec;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Vec<T> {
|
||||||
|
used: usize,
|
||||||
|
marker: PhantomData<T>,
|
||||||
|
buf: RawVec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for Vec<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Vec<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
if mem::size_of::<T>() == 0 {
|
||||||
|
panic!("We're not ready to handle ZSTs");
|
||||||
|
}
|
||||||
|
Vec {
|
||||||
|
used: 0,
|
||||||
|
marker: PhantomData::default(),
|
||||||
|
buf: RawVec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) -> Option<T> {
|
||||||
|
if self.used == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.used -= 1;
|
||||||
|
unsafe { Some(ptr::read(self.buf.ptr.as_ptr().add(self.used))) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn get(&self, index: usize) -> Option<&T> {
|
||||||
|
if index > self.used {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
unsafe { Some(ptr::read(src)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_mut(&self, index: usize) -> Option<&mut T> {
|
||||||
|
if index > self.used { None } else { todo!() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, value: T) {
|
||||||
|
if self.used == self.buf.capacity {
|
||||||
|
self.buf.grow();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ptr::write(self.buf.ptr.as_ptr().add(self.used), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.used += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.used
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn capacity(&self) -> usize {
|
||||||
|
self.buf.capacity
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, index: usize, elem: T) {
|
||||||
|
// Note: `<=` because it's valid to insert after everything
|
||||||
|
// which would be equivalent to push.
|
||||||
|
assert!(index <= self.used, "index out of bounds");
|
||||||
|
if self.used == self.buf.capacity {
|
||||||
|
self.buf.grow();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// ptr::copy(src, dest, len): "copy from src to dest len elems"
|
||||||
|
ptr::copy(
|
||||||
|
self.buf.ptr.as_ptr().add(index),
|
||||||
|
self.buf.ptr.as_ptr().add(index + 1),
|
||||||
|
self.used - index,
|
||||||
|
);
|
||||||
|
ptr::write(self.buf.ptr.as_ptr().add(index), elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.used += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, index: usize) -> T {
|
||||||
|
// Note: `<` because it's *not* valid to remove after everything
|
||||||
|
assert!(index < self.used, "index out of bounds");
|
||||||
|
unsafe {
|
||||||
|
self.used -= 1;
|
||||||
|
let result = ptr::read(self.buf.ptr.as_ptr().add(index));
|
||||||
|
ptr::copy(
|
||||||
|
self.buf.ptr.as_ptr().add(index + 1),
|
||||||
|
self.buf.ptr.as_ptr().add(index),
|
||||||
|
self.used - index,
|
||||||
|
);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Index<usize> for Vec<T> {
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
self.get(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for Vec<T> {
|
||||||
|
type Target = [T];
|
||||||
|
fn deref(&self) -> &[T] {
|
||||||
|
unsafe { std::slice::from_raw_parts(self.buf.ptr.as_ptr(), self.used) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for Vec<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut [T] {
|
||||||
|
unsafe { std::slice::from_raw_parts_mut(self.buf.ptr.as_ptr(), self.used) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for Vec<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
while self.pop().is_some() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Send> Send for Vec<T> {}
|
||||||
|
unsafe impl<T: Sync> Sync for Vec<T> {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn test_create() {
|
||||||
|
let _v = Vec::<u64>::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pushpop_num() {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
let vals = &[19, 9, 14, 255, 19191919, 13890, 21521, 1251, 6216, 1830];
|
||||||
|
|
||||||
|
for val in vals {
|
||||||
|
v.push(*val);
|
||||||
|
}
|
||||||
|
for val in vals.iter().rev() {
|
||||||
|
assert_eq!(v.pop().unwrap(), *val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pushpop_str() {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
let vals = &["AAAA", "ABBAB", "BBABBABBAJJJ"];
|
||||||
|
|
||||||
|
for val in vals {
|
||||||
|
v.push(*val);
|
||||||
|
}
|
||||||
|
for val in vals.iter().rev() {
|
||||||
|
assert_eq!(v.pop().unwrap(), *val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue