mirror of
https://github.com/bobwen-dev/hunter
synced 2025-04-12 00:55:41 +02:00
add alloc.rs and iter.rs
This commit is contained in:
parent
a101010fc1
commit
fa9f48ae8d
195
src/alloc.rs
Normal file
195
src/alloc.rs
Normal file
@ -0,0 +1,195 @@
|
||||
use bumpalo::{collections::Vec, Bump};
|
||||
use crossbeam::utils::{Backoff, CachePadded};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
// Concurrent access to the Bump allocator is prevented through the
|
||||
// use of a simple atomics based spin loop.
|
||||
unsafe impl Send for Allocator {}
|
||||
unsafe impl Sync for Allocator {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Allocator {
|
||||
bump: Bump,
|
||||
lock: CachePadded<std::sync::atomic::AtomicBool>,
|
||||
}
|
||||
|
||||
pub struct Mem {
|
||||
ptr: NonNull<u8>,
|
||||
cap: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
pub enum RawAlloc {
|
||||
PathBuf(Mem),
|
||||
String(Mem),
|
||||
}
|
||||
|
||||
impl Allocator {
|
||||
pub fn new() -> Allocator {
|
||||
Allocator {
|
||||
bump: Bump::new(),
|
||||
lock: CachePadded::new(AtomicBool::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pathbuf(&self, size: usize) -> RawAlloc {
|
||||
self.lock();
|
||||
let vec = Vec::with_capacity_in(size, &self.bump);
|
||||
self.unlock();
|
||||
let mem = Mem {
|
||||
ptr: unsafe { NonNull::new_unchecked(vec.into_bump_slice_mut().as_mut_ptr()) },
|
||||
cap: size,
|
||||
len: 0,
|
||||
};
|
||||
|
||||
RawAlloc::PathBuf(mem)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn string(&self, size: usize) -> RawAlloc {
|
||||
self.lock();
|
||||
let vec = Vec::with_capacity_in(size, &self.bump);
|
||||
self.unlock();
|
||||
let mem = Mem {
|
||||
ptr: unsafe { NonNull::new_unchecked(vec.into_bump_slice_mut().as_mut_ptr()) },
|
||||
cap: size,
|
||||
len: 0,
|
||||
};
|
||||
|
||||
RawAlloc::String(mem)
|
||||
}
|
||||
|
||||
// Only reason this ISN'T wrong is that capacity will always be
|
||||
// larger than size. Otherwise a race during reallocation could
|
||||
// cause bad things to happen.
|
||||
#[inline]
|
||||
pub fn tmpfiles(&self, cap: usize) -> Vec<crate::files::File> {
|
||||
self.lock();
|
||||
let vec = Vec::with_capacity_in(cap, &self.bump);
|
||||
self.unlock();
|
||||
vec
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dentbuf(&self, cap: usize) -> *mut u8 {
|
||||
let align = std::mem::align_of::<crate::files::linux_dirent>();
|
||||
let layout = std::alloc::Layout::from_size_align(cap, align).unwrap();
|
||||
self.lock();
|
||||
let buf = self.bump.alloc_layout(layout);
|
||||
self.unlock();
|
||||
buf.as_ptr()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn lock(&self) {
|
||||
let backoff = Backoff::new();
|
||||
while self.lock.compare_and_swap(false, true, Ordering::Acquire) {
|
||||
backoff.snooze();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unlock(&self) {
|
||||
self.lock.store(false, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
impl RawAlloc {
|
||||
#[inline]
|
||||
fn get_mem(&mut self) -> &mut Mem {
|
||||
let mem = match self {
|
||||
RawAlloc::PathBuf(mem) => mem,
|
||||
RawAlloc::String(mem) => mem,
|
||||
};
|
||||
mem
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write(&mut self, src: &[u8]) {
|
||||
let mem = self.get_mem();
|
||||
let len = mem.len;
|
||||
let src_len = src.len();
|
||||
|
||||
if (mem.len + src_len) > mem.cap {
|
||||
let mem_bytes = unsafe { std::slice::from_raw_parts(mem.ptr.as_ptr(), len) };
|
||||
|
||||
let mem_string = String::from_utf8_lossy(mem_bytes);
|
||||
let src_string = String::from_utf8_lossy(src);
|
||||
panic!(
|
||||
"Can't write this much into {:?}\nWanted to add:{}",
|
||||
mem_string, src_string
|
||||
);
|
||||
};
|
||||
|
||||
mem.len += src_len;
|
||||
|
||||
unsafe {
|
||||
let ptr = mem.ptr.as_ptr().offset(len as isize);
|
||||
ptr.copy_from_nonoverlapping(src.as_ptr(), src_len)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn finalize_pathbuf(mut self) -> PathBuf {
|
||||
let mem = self.get_mem();
|
||||
let len = mem.len;
|
||||
let cap = mem.cap;
|
||||
let ptr = mem.ptr.as_ptr();
|
||||
|
||||
let pathbuf = unsafe {
|
||||
let mut stdvec = std::vec::Vec::from_raw_parts(ptr, len, cap);
|
||||
let ptr = &mut stdvec as *mut std::vec::Vec<u8>;
|
||||
std::mem::forget(stdvec);
|
||||
ptr.cast::<PathBuf>().read()
|
||||
};
|
||||
return pathbuf;
|
||||
}
|
||||
|
||||
// #[inline]
|
||||
// #[target_feature(enable = "avx2")]
|
||||
// unsafe fn verify_string(&self) -> bool {
|
||||
// if let RawAlloc::String(mem) = self {
|
||||
// let ptr = mem.ptr.as_ptr();
|
||||
// let len = mem.len;
|
||||
// let slice = // unsafe {
|
||||
// std::slice::from_raw_parts(ptr, len);
|
||||
// //};
|
||||
|
||||
// let valid = is_utf8::lemire::avx::is_utf8_ascii_path(slice);
|
||||
// return valid;
|
||||
|
||||
// } else { panic!("Called verify_string() on non-string allocation!"); }
|
||||
// }
|
||||
|
||||
pub fn finalize_string(mut self) -> String {
|
||||
let mem = self.get_mem();
|
||||
let len = mem.len;
|
||||
let cap = mem.cap;
|
||||
let ptr = mem.ptr.as_ptr();
|
||||
|
||||
let string = unsafe {
|
||||
// match self.verify_string() {
|
||||
// true =>
|
||||
String::from_raw_parts(ptr, len, cap) // ,
|
||||
// false => {
|
||||
// let slice = std::slice::from_raw_parts(ptr, len);
|
||||
// String::from_utf8_lossy(slice).to_string()
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Allocator {
|
||||
fn drop(&mut self) {
|
||||
// if Arc::strong_count(&self.bump) <= 1 {
|
||||
self.bump.reset();
|
||||
// }
|
||||
}
|
||||
}
|
464
src/iter.rs
Normal file
464
src/iter.rs
Normal file
@ -0,0 +1,464 @@
|
||||
use splay_tree::set::{SplaySet, VecLike, VecLikeMut};
|
||||
|
||||
use crate::files::File;
|
||||
use std::sync::RwLockWriteGuard;
|
||||
|
||||
pub struct FileIter<'a> {
|
||||
files: &'a mut SplaySet<File>,
|
||||
current: Option<&'a File>,
|
||||
filter_fn: Box<dyn Fn(&File) -> bool>,
|
||||
done: bool,
|
||||
n: usize,
|
||||
}
|
||||
|
||||
impl<'a> FileIter<'a> {
|
||||
pub fn new(files: &'a mut SplaySet<File>, filter_fn: Box<dyn Fn(&File) -> bool>) -> Self {
|
||||
let mut iter = FileIter {
|
||||
files: files,
|
||||
current: None,
|
||||
filter_fn,
|
||||
done: false,
|
||||
n: 0,
|
||||
};
|
||||
|
||||
let file = iter.find_first_nonhidden();
|
||||
iter.current = file;
|
||||
iter
|
||||
}
|
||||
|
||||
pub fn start_from(mut self, file: &'a File) -> Self {
|
||||
// let mut first = file.clone();
|
||||
|
||||
// while let Some(current) = self.files.find_less(&first) {
|
||||
// if (self.filter_fn)(current) == true {
|
||||
// first = current.clone();
|
||||
// break;
|
||||
// } else {
|
||||
// first = current.clone();
|
||||
// }
|
||||
// }
|
||||
dbg!("STARTING FROM");
|
||||
dbg!(&file);
|
||||
self.current = Some(file);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn seek_back(mut self, n: usize) -> Self {
|
||||
if n > 0 {
|
||||
dbg!(n);
|
||||
dbg!(&self.current);
|
||||
self.nth_back(n - 1);
|
||||
dbg!(&self.current);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
fn find_prev_nonhidden(&mut self, of: &'a File) -> Option<&'a File> {
|
||||
let mut prev = of;
|
||||
while let Some(current) = self.files.find_less(&prev).extend() {
|
||||
prev = current;
|
||||
if (self.filter_fn)(current) == true {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if of != prev {
|
||||
Some(prev)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn find_next_nonhidden(&mut self, of: &'a File) -> Option<&'a File> {
|
||||
let mut next = of;
|
||||
while let Some(current) = self.files.find_upper_bound(&next).extend() {
|
||||
next = current;
|
||||
if (self.filter_fn)(current) == true {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if of != next {
|
||||
Some(next)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn find_first_nonhidden(&mut self) -> Option<&'a File> {
|
||||
self.files.smallest().extend().map(|f| {
|
||||
let mut first = f;
|
||||
while let Some(current) = self.files.find_upper_bound(&first).extend() {
|
||||
first = current;
|
||||
if (self.filter_fn)(current) == true {
|
||||
break;
|
||||
}
|
||||
}
|
||||
first
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for FileIter<'a> {
|
||||
type Item = &'a File;
|
||||
|
||||
fn next(&mut self) -> Option<&'a File> {
|
||||
// if self.done || self.n > self.files.len() {
|
||||
// self.done = true;
|
||||
// return None;
|
||||
// }
|
||||
|
||||
if !self.done && self.current.is_none() {
|
||||
self.current = self.find_first_nonhidden();
|
||||
}
|
||||
|
||||
self.current.take().map(|f| {
|
||||
self.find_next_nonhidden(f)
|
||||
.map(|f| self.current = Some(f))
|
||||
.or_else(|| {
|
||||
self.done = true;
|
||||
None
|
||||
});
|
||||
f
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for FileIter<'a> {
|
||||
fn next_back(&mut self) -> Option<&'a File> {
|
||||
// dbg!(&self.current);
|
||||
// self.current
|
||||
// .clone()
|
||||
// .as_ref()
|
||||
// .and_then(|f| unsafe {
|
||||
// std::mem::transmute::<_, Option<&File>>(self.files.find_less(f))
|
||||
// .and_then(|f: &File| {
|
||||
// self.current = Some(f.clone());
|
||||
// Some(f)
|
||||
// })
|
||||
// .filter(|f| (self.filter_fn)(f))
|
||||
// .or_else(|| self.next_back())
|
||||
// })
|
||||
|
||||
self.current.and_then(|f| {
|
||||
self.find_prev_nonhidden(f)
|
||||
.extend()
|
||||
.map(|f| self.current = Some(f))
|
||||
.and_then(|_| self.current)
|
||||
// .or_else(|| { self.current = None; None });
|
||||
// self.current
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FileIterMut<'a> {
|
||||
files: VecLikeMut<'a, File>,
|
||||
pos: usize,
|
||||
filter_fn: Box<dyn Fn(&File) -> bool>,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a> FileIterMut<'a> {
|
||||
pub fn new(files: &'b mut SplaySet<File>, filter_fn: Box<dyn Fn(&File) -> bool>) -> Self {
|
||||
FileIterMut {
|
||||
files: files.as_vec_like_mut(),
|
||||
pos: 0,
|
||||
filter_fn,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_raw_pos(mut self, pos: usize) -> Self {
|
||||
self.pos = pos;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn seek_back(mut self, n: usize) -> Self {
|
||||
if n > 0 {
|
||||
self.nth_back(n - 1);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn unfiltered(mut self) -> Self {
|
||||
self.filter_fn = Box::new(|_| true);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for FileIterMut<'a> {
|
||||
type Item = &'a mut File;
|
||||
|
||||
fn next(&mut self) -> Option<&'a mut File> {
|
||||
let file = self.files.get_mut(self.pos).map(|f| {
|
||||
let f = f as *mut _;
|
||||
let f = unsafe { &mut *f };
|
||||
f
|
||||
});
|
||||
self.pos += 1;
|
||||
|
||||
match file {
|
||||
Some(file) => match (self.filter_fn)(file) {
|
||||
false => self.next(),
|
||||
true => Some(file),
|
||||
},
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for FileIterMut<'a> {
|
||||
fn next_back(&mut self) -> Option<&'a mut File> {
|
||||
if self.pos == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.pos -= 1;
|
||||
|
||||
let file = self.files.get_mut(self.pos).map(|f| {
|
||||
let f = f as *mut _;
|
||||
let f = unsafe { &mut *f };
|
||||
f
|
||||
});
|
||||
|
||||
match file {
|
||||
Some(file) => match (self.filter_fn)(file) {
|
||||
false => self.next_back(),
|
||||
true => Some(file),
|
||||
},
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait LifeTimeExtended {
|
||||
fn extend<'a>(self) -> Option<&'a File>;
|
||||
}
|
||||
|
||||
impl LifeTimeExtended for Option<&File> {
|
||||
fn extend<'a>(self) -> Option<&'a File> {
|
||||
self.and_then(|f| unsafe {
|
||||
let f = f as *const File;
|
||||
Some(&*f)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// pub struct FileIter<'a> {
|
||||
// files: &'a mut SplaySet<File>,
|
||||
// current: File,
|
||||
// filter_fn: Box<dyn Fn(&File) -> bool>,
|
||||
// done: bool,
|
||||
// n: usize,
|
||||
// }
|
||||
|
||||
// impl<'a> FileIter<'a> {
|
||||
// pub fn new(files: &'a mut SplaySet<File>, filter_fn: Box<dyn Fn(&File) -> bool>) -> Self {
|
||||
// let mut first = files.smallest().cloned().unwrap();
|
||||
|
||||
// while let Some(current) = files.find_upper_bound(&first) {
|
||||
// if (filter_fn)(current) == true {
|
||||
// break;
|
||||
// } else {
|
||||
// first = current.clone();
|
||||
// }
|
||||
// }
|
||||
|
||||
// FileIter {
|
||||
// files: files,
|
||||
// current: first,
|
||||
// filter_fn,
|
||||
// done: false,
|
||||
// n: 0
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn start_from(mut self, file: &File) -> Self {
|
||||
// let mut first = file.clone();
|
||||
|
||||
// while let Some(current) = self.files.find_less(&first) {
|
||||
// if (self.filter_fn)(current) == true {
|
||||
// first = current.clone();
|
||||
// break;
|
||||
// } else {
|
||||
// first = current.clone();
|
||||
// }
|
||||
// }
|
||||
// dbg!("STARTING FROM");
|
||||
// dbg!(&file);
|
||||
// self.current = first;
|
||||
// self
|
||||
// }
|
||||
|
||||
// pub fn seek_back(mut self, n: usize) -> Self {
|
||||
// if n > 0 {
|
||||
// dbg!(n);
|
||||
// dbg!(&self.current);
|
||||
// self.nth_back(n-1);
|
||||
// dbg!(&self.current);
|
||||
// }
|
||||
// self
|
||||
// }
|
||||
|
||||
// fn find_prev_nonhidden(&mut self) {
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<'a> Iterator for FileIter<'a> {
|
||||
// type Item=&'a File;
|
||||
|
||||
// fn next(&mut self) -> Option<&'a File> {
|
||||
// //dbg!(&self.current);
|
||||
// self.n+=1;
|
||||
// if self.done || self.n > self.files.len() {
|
||||
// self.done = true;
|
||||
// return None;
|
||||
// }
|
||||
|
||||
// self.files.find_upper_bound(&self.current)
|
||||
// .extend()
|
||||
// .and_then(|f| {
|
||||
// self.current = f.clone();
|
||||
// Some(f)
|
||||
// })
|
||||
// .filter(|f| (self.filter_fn)(f))
|
||||
// .or_else(|| self.next())
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<'a> DoubleEndedIterator for FileIter<'a> {
|
||||
// fn next_back(&mut self) -> Option<&'a File> {
|
||||
// // dbg!(&self.current);
|
||||
// // self.current
|
||||
// // .clone()
|
||||
// // .as_ref()
|
||||
// // .and_then(|f| unsafe {
|
||||
// // std::mem::transmute::<_, Option<&File>>(self.files.find_less(f))
|
||||
// // .and_then(|f: &File| {
|
||||
// // self.current = Some(f.clone());
|
||||
// // Some(f)
|
||||
// // })
|
||||
// // .filter(|f| (self.filter_fn)(f))
|
||||
// // .or_else(|| self.next_back())
|
||||
// // })
|
||||
|
||||
// self.files.find_less(&self.current)
|
||||
// .extend()
|
||||
// .and_then(|f| {
|
||||
// self.current = f.clone();
|
||||
// dbg!(&self.current.name);
|
||||
// if (self.filter_fn)(f) == true {
|
||||
// Some(f)
|
||||
// } else {
|
||||
// self.next_back()
|
||||
// }
|
||||
// })
|
||||
// .or_else(|| {
|
||||
// self.current = self.files.smallest().unwrap().clone();
|
||||
// None
|
||||
// })
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub struct FileIterMut<'a> {
|
||||
// files: VecLikeMut<'a, File>,
|
||||
// pos: usize,
|
||||
// filter_fn: Box<dyn Fn(&File) -> bool>,
|
||||
// }
|
||||
|
||||
// impl<'a, 'b: 'a> FileIterMut<'a> {
|
||||
// pub fn new(files: &'b mut SplaySet<File>, filter_fn: Box<dyn Fn(&File) -> bool>) -> Self {
|
||||
// FileIterMut {
|
||||
// files: files.as_vec_like_mut(),
|
||||
// pos: 0,
|
||||
// filter_fn
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn set_raw_pos(mut self, pos: usize) -> Self {
|
||||
// self.pos = pos;
|
||||
// self
|
||||
// }
|
||||
|
||||
// pub fn seek_back(mut self, n: usize) -> Self {
|
||||
// if n > 0 {
|
||||
// self.nth_back(n-1);
|
||||
// }
|
||||
// self
|
||||
// }
|
||||
|
||||
// pub fn unfiltered(mut self) -> Self {
|
||||
// self.filter_fn = Box::new(|_| true);
|
||||
// self
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<'a> Iterator for FileIterMut<'a> {
|
||||
// type Item=&'a mut File;
|
||||
|
||||
// fn next(&mut self) -> Option<&'a mut File> {
|
||||
// let file = self.files.get_mut(self.pos)
|
||||
// .map(|f| {
|
||||
// let f = f as *mut _;
|
||||
// let f = unsafe {
|
||||
// &mut *f
|
||||
// };
|
||||
// f
|
||||
// });
|
||||
// self.pos += 1;
|
||||
|
||||
// match file {
|
||||
// Some(file) => {
|
||||
// match (self.filter_fn)(file) {
|
||||
// false => self.next(),
|
||||
// true => Some(file)
|
||||
// }
|
||||
// }
|
||||
// None => None
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<'a> DoubleEndedIterator for FileIterMut<'a> {
|
||||
// fn next_back(&mut self) -> Option<&'a mut File> {
|
||||
// if self.pos == 0 {
|
||||
// return None;
|
||||
// }
|
||||
|
||||
// self.pos -= 1;
|
||||
|
||||
// let file = self.files.get_mut(self.pos)
|
||||
// .map(|f| {
|
||||
// let f = f as *mut _;
|
||||
// let f = unsafe {
|
||||
// &mut *f
|
||||
// };
|
||||
// f
|
||||
// });
|
||||
|
||||
// match file {
|
||||
// Some(file) => {
|
||||
// match (self.filter_fn)(file) {
|
||||
// false => self.next_back(),
|
||||
// true => Some(file)
|
||||
// }
|
||||
// }
|
||||
// None => None
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// trait LifeTimeExtended {
|
||||
// fn extend<'a>(self) -> Option<&'a File>;
|
||||
// }
|
||||
|
||||
// impl LifeTimeExtended for Option<&File> {
|
||||
// fn extend<'a>(self) -> Option<&'a File> {
|
||||
// self.and_then(|f| {
|
||||
// unsafe {
|
||||
// let f = f as *const File;
|
||||
// Some(&*f)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
Loading…
x
Reference in New Issue
Block a user