extend queue api and fix string
This commit is contained in:
parent
fe9b7df81f
commit
03455df253
@ -1,2 +1,3 @@
|
|||||||
pub mod btree;
|
pub mod btree;
|
||||||
pub mod queue;
|
pub mod queue;
|
||||||
|
pub mod string;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned};
|
use zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned};
|
||||||
|
|
||||||
@ -108,40 +109,82 @@ impl<T: FromBytes + FromZeroes + AsBytes + Unaligned + Clone + Copy> FilePointer
|
|||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
};
|
};
|
||||||
|
|
||||||
// println!("length: {}", old.length.get());
|
|
||||||
|
|
||||||
let mut ptr = data.head;
|
let mut ptr = data.head;
|
||||||
|
|
||||||
let skip_n = old.length.get().checked_sub(n).unwrap();
|
let skip_n = old.length.get().checked_sub(n).unwrap();
|
||||||
|
|
||||||
// println!("skip_n: {skip_n}");
|
|
||||||
|
|
||||||
// skip the head
|
// skip the head
|
||||||
for i in 0..skip_n {
|
for i in 0..skip_n {
|
||||||
// println!("skip [{i}] {ptr:?}");
|
|
||||||
|
|
||||||
ptr = *transaction.read(field_ptr!(ptr, QueueElement<T>, next));
|
ptr = *transaction.read(field_ptr!(ptr, QueueElement<T>, next));
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the tail
|
// remove the tail
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
// println!("free [{i}] {ptr:?}");
|
|
||||||
|
|
||||||
let element = *transaction.read(ptr);
|
let element = *transaction.read(ptr);
|
||||||
transaction.free(ptr);
|
|
||||||
|
|
||||||
f(element.data);
|
f(element.data);
|
||||||
|
transaction.free(ptr);
|
||||||
ptr = element.next;
|
ptr = element.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(queue)
|
Some(queue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dequeue_many_back<R>(
|
||||||
|
self,
|
||||||
|
transaction: &mut TransactionHandle<R>,
|
||||||
|
n: u64,
|
||||||
|
) -> Option<(Self, Vec<T>)> {
|
||||||
|
let mut res = Vec::with_capacity(n.try_into().unwrap());
|
||||||
|
self.dequeue_many_inner(transaction, n, |t| res.push(t))
|
||||||
|
.map(|ptr| {
|
||||||
|
res.reverse();
|
||||||
|
(ptr, res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: calls f with the elements in reverse order.
|
||||||
|
fn dequeue_many_back_inner<R>(
|
||||||
|
self,
|
||||||
|
transaction: &mut TransactionHandle<R>,
|
||||||
|
n: u64,
|
||||||
|
mut f: impl FnMut(T),
|
||||||
|
) -> Option<Self> {
|
||||||
|
if n == 0 {
|
||||||
|
return Some(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
let old = *transaction.read(self);
|
||||||
|
|
||||||
|
if old.length.get() < n {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ptr = old.head;
|
||||||
|
|
||||||
|
for i in 0..n {
|
||||||
|
let element = *transaction.read(ptr);
|
||||||
|
f(element.data);
|
||||||
|
transaction.free(ptr);
|
||||||
|
ptr = element.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (queue, data) = transaction.modify(self);
|
||||||
|
|
||||||
|
*data = Queue {
|
||||||
|
head: ptr,
|
||||||
|
length: (old.length.get().checked_sub(n).unwrap()).into(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(queue)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_empty(self, reader: &impl ReaderTrait) -> bool {
|
pub fn is_empty(self, reader: &impl ReaderTrait) -> bool {
|
||||||
self.length(reader) == 0
|
self.length(reader) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn last(self, reader: &impl ReaderTrait) -> Option<T> {
|
// TODO: use get(0) instead
|
||||||
|
pub fn next(self, reader: &impl ReaderTrait) -> Option<T> {
|
||||||
let this = reader.read(self);
|
let this = reader.read(self);
|
||||||
|
|
||||||
if this.length.get() == 0 {
|
if this.length.get() == 0 {
|
||||||
@ -159,6 +202,68 @@ impl<T: FromBytes + FromZeroes + AsBytes + Unaligned + Clone + Copy> FilePointer
|
|||||||
Some(*reader.read(field_ptr!(next, QueueElement<T>, data)))
|
Some(*reader.read(field_ptr!(next, QueueElement<T>, data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_range(self, reader: &impl ReaderTrait, range: Range<u64>) -> Option<Vec<T>> {
|
||||||
|
let mut res = Vec::with_capacity(range.clone().count());
|
||||||
|
|
||||||
|
self.get_range_inner(reader, range, |element| {
|
||||||
|
res.push(element);
|
||||||
|
});
|
||||||
|
|
||||||
|
res.reverse();
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 is the next item to be dequeued
|
||||||
|
pub fn get_range_inner(
|
||||||
|
self,
|
||||||
|
reader: &impl ReaderTrait,
|
||||||
|
range: Range<u64>,
|
||||||
|
mut f: impl FnMut(T),
|
||||||
|
) -> Option<()> {
|
||||||
|
if range.is_empty() {
|
||||||
|
return Some(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = range.clone().count();
|
||||||
|
|
||||||
|
let this = reader.read(self);
|
||||||
|
|
||||||
|
if range.end > this.length.get() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = this.length.get();
|
||||||
|
let start = len.checked_sub(range.end).unwrap();
|
||||||
|
let end = len.checked_sub(range.start).unwrap();
|
||||||
|
|
||||||
|
let range = start..end;
|
||||||
|
|
||||||
|
let mut ptr = this.head;
|
||||||
|
|
||||||
|
// skip the elements before the start of the list
|
||||||
|
for i in 0..range.start {
|
||||||
|
ptr = *reader.read(field_ptr!(ptr, QueueElement<T>, next));
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..n {
|
||||||
|
let element = *reader.read(ptr);
|
||||||
|
|
||||||
|
f(element.data);
|
||||||
|
|
||||||
|
ptr = element.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self, reader: &impl ReaderTrait, index: u64) -> Option<T> {
|
||||||
|
let mut res = None;
|
||||||
|
self.get_range_inner(reader, index..index + 1, |element| {
|
||||||
|
assert!(res.replace(element).is_none());
|
||||||
|
})?;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
pub fn length(self, reader: &impl ReaderTrait) -> u64 {
|
pub fn length(self, reader: &impl ReaderTrait) -> u64 {
|
||||||
reader.read(field_ptr!(self, Queue<T>, length)).get()
|
reader.read(field_ptr!(self, Queue<T>, length)).get()
|
||||||
}
|
}
|
||||||
|
54
src/datastructures/string.rs
Normal file
54
src/datastructures/string.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
transaction, FilePointer, FileRange, RawFilePointer, ReaderTrait, TransactionHandle, U64,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, FromBytes, FromZeroes, AsBytes, Unaligned)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct Str {
|
||||||
|
data: FileRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Str {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
data: RawFilePointer::null().range(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Str {
|
||||||
|
fn set<R>(self, transaction: &mut TransactionHandle<R>, s: &str) -> Self {
|
||||||
|
let data = if s.is_empty() {
|
||||||
|
Str::new().data
|
||||||
|
} else {
|
||||||
|
let (range, data) = transaction.allocate_range(s.len() as u64);
|
||||||
|
data.copy_from_slice(s.as_bytes());
|
||||||
|
range
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.data.len() != 0 {
|
||||||
|
transaction.free_range(self.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Str { data }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(self, reader: &impl ReaderTrait) -> &str {
|
||||||
|
std::str::from_utf8(reader.read_raw(self.data)).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FilePointer<Str> {
|
||||||
|
fn set<R>(self, transaction: &mut TransactionHandle<R>, s: &str) -> FilePointer<Str> {
|
||||||
|
let new_str = transaction.read::<Str>(self).set(transaction, s);
|
||||||
|
let (ptr, data) = transaction.modify(self);
|
||||||
|
*data = new_str;
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(self, reader: &impl ReaderTrait) -> &str {
|
||||||
|
reader.read(self).get(reader)
|
||||||
|
}
|
||||||
|
}
|
14
src/tests.rs
14
src/tests.rs
@ -862,8 +862,6 @@ fn queue() {
|
|||||||
|
|
||||||
let n = queue.length(snapshot);
|
let n = queue.length(snapshot);
|
||||||
|
|
||||||
dbg!(n);
|
|
||||||
|
|
||||||
let mut next = *snapshot.read(field_ptr!(queue, Queue<U64>, head));
|
let mut next = *snapshot.read(field_ptr!(queue, Queue<U64>, head));
|
||||||
|
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
@ -927,6 +925,18 @@ fn queue() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !root.is_empty(transaction) {
|
||||||
|
let s = rng.gen_range(0..root.length(transaction));
|
||||||
|
let e = rng.gen_range(s..=root.length(transaction));
|
||||||
|
|
||||||
|
let elements = root.get_range(transaction, s..e).unwrap();
|
||||||
|
|
||||||
|
dbg!(&elements);
|
||||||
|
for (i, element) in elements.into_iter().enumerate() {
|
||||||
|
assert_eq!(element.get(), j + s + i as u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
root
|
root
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user