extend queue api and fix string
This commit is contained in:
parent
fe9b7df81f
commit
03455df253
@ -1,2 +1,3 @@
|
||||
pub mod btree;
|
||||
pub mod queue;
|
||||
pub mod string;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Range;
|
||||
|
||||
use zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned};
|
||||
|
||||
@ -108,40 +109,82 @@ impl<T: FromBytes + FromZeroes + AsBytes + Unaligned + Clone + Copy> FilePointer
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
|
||||
// println!("length: {}", old.length.get());
|
||||
|
||||
let mut ptr = data.head;
|
||||
|
||||
let skip_n = old.length.get().checked_sub(n).unwrap();
|
||||
|
||||
// println!("skip_n: {skip_n}");
|
||||
|
||||
// skip the head
|
||||
for i in 0..skip_n {
|
||||
// println!("skip [{i}] {ptr:?}");
|
||||
|
||||
ptr = *transaction.read(field_ptr!(ptr, QueueElement<T>, next));
|
||||
}
|
||||
|
||||
// remove the tail
|
||||
for i in 0..n {
|
||||
// println!("free [{i}] {ptr:?}");
|
||||
|
||||
let element = *transaction.read(ptr);
|
||||
transaction.free(ptr);
|
||||
|
||||
f(element.data);
|
||||
transaction.free(ptr);
|
||||
ptr = element.next;
|
||||
}
|
||||
|
||||
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 {
|
||||
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);
|
||||
|
||||
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)))
|
||||
}
|
||||
|
||||
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 {
|
||||
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);
|
||||
|
||||
dbg!(n);
|
||||
|
||||
let mut next = *snapshot.read(field_ptr!(queue, Queue<U64>, head));
|
||||
|
||||
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
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user