Rename DirEntryVec to SlotVec

This commit is contained in:
LI Qing
2023-04-18 18:09:57 +08:00
committed by Tate, Hongliang Tian
parent 0fc707d38c
commit 0abe40e0f8
6 changed files with 139 additions and 96 deletions

View File

@ -2,9 +2,10 @@ use alloc::string::String;
use core::any::Any; use core::any::Any;
use core::time::Duration; use core::time::Duration;
use jinux_frame::vm::VmFrame; use jinux_frame::vm::VmFrame;
use jinux_util::slot_vec::SlotVec;
use crate::fs::utils::{ use crate::fs::utils::{
DirEntryVec, DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata, DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata,
}; };
use crate::prelude::*; use crate::prelude::*;
@ -14,7 +15,7 @@ pub struct ProcDir<D: DirOps> {
inner: D, inner: D,
this: Weak<ProcDir<D>>, this: Weak<ProcDir<D>>,
parent: Option<Weak<dyn Inode>>, parent: Option<Weak<dyn Inode>>,
cached_children: RwLock<DirEntryVec<(String, Arc<dyn Inode>)>>, cached_children: RwLock<SlotVec<(String, Arc<dyn Inode>)>>,
info: ProcInodeInfo, info: ProcInodeInfo,
} }
@ -38,7 +39,7 @@ impl<D: DirOps> ProcDir<D> {
inner: dir, inner: dir,
this: weak_self.clone(), this: weak_self.clone(),
parent, parent,
cached_children: RwLock::new(DirEntryVec::new()), cached_children: RwLock::new(SlotVec::new()),
info, info,
}) })
} }
@ -51,7 +52,7 @@ impl<D: DirOps> ProcDir<D> {
self.parent.as_ref().and_then(|p| p.upgrade()) self.parent.as_ref().and_then(|p| p.upgrade())
} }
pub fn cached_children(&self) -> &RwLock<DirEntryVec<(String, Arc<dyn Inode>)>> { pub fn cached_children(&self) -> &RwLock<SlotVec<(String, Arc<dyn Inode>)>> {
&self.cached_children &self.cached_children
} }
} }
@ -127,7 +128,7 @@ impl<D: DirOps + 'static> Inode for ProcDir<D> {
self.inner.populate_children(self.this.clone()); self.inner.populate_children(self.this.clone());
let cached_children = self.cached_children.read(); let cached_children = self.cached_children.read();
for (idx, (name, child)) in cached_children for (idx, (name, child)) in cached_children
.idxes_and_entries() .idxes_and_items()
.map(|(idx, (name, child))| (idx + 2, (name, child))) .map(|(idx, (name, child))| (idx + 2, (name, child)))
{ {
if idx < *offset { if idx < *offset {

View File

@ -5,12 +5,12 @@ use core::any::Any;
use core::sync::atomic::{AtomicUsize, Ordering}; use core::sync::atomic::{AtomicUsize, Ordering};
use core::time::Duration; use core::time::Duration;
use jinux_frame::vm::VmFrame; use jinux_frame::vm::VmFrame;
use jinux_util::slot_vec::SlotVec;
use spin::{RwLock, RwLockWriteGuard}; use spin::{RwLock, RwLockWriteGuard};
use super::*; use super::*;
use crate::fs::utils::{ use crate::fs::utils::{
DirEntryVec, DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, SuperBlock,
Metadata, SuperBlock,
}; };
pub struct RamFS { pub struct RamFS {
@ -164,7 +164,7 @@ impl Inner {
} }
struct DirEntry { struct DirEntry {
children: DirEntryVec<(Str256, Arc<RamInode>)>, children: SlotVec<(Str256, Arc<RamInode>)>,
this: Weak<RamInode>, this: Weak<RamInode>,
parent: Weak<RamInode>, parent: Weak<RamInode>,
} }
@ -172,7 +172,7 @@ struct DirEntry {
impl DirEntry { impl DirEntry {
fn new() -> Self { fn new() -> Self {
Self { Self {
children: DirEntryVec::new(), children: SlotVec::new(),
this: Weak::default(), this: Weak::default(),
parent: Weak::default(), parent: Weak::default(),
} }
@ -205,13 +205,13 @@ impl DirEntry {
Some((1, self.parent.upgrade().unwrap())) Some((1, self.parent.upgrade().unwrap()))
} else { } else {
self.children self.children
.idxes_and_entries() .idxes_and_items()
.find(|(_, (child, _))| child == &Str256::from(name)) .find(|(_, (child, _))| child == &Str256::from(name))
.map(|(idx, (_, inode))| (idx + 2, inode.clone())) .map(|(idx, (_, inode))| (idx + 2, inode.clone()))
} }
} }
fn append_entry(&mut self, name: &str, inode: Arc<RamInode>) { fn append_entry(&mut self, name: &str, inode: Arc<RamInode>) -> usize {
self.children.put((Str256::from(name), inode)) self.children.put((Str256::from(name), inode))
} }
@ -255,7 +255,7 @@ impl DirEntry {
// Read the normal child entries. // Read the normal child entries.
for (offset, (name, child)) in self for (offset, (name, child)) in self
.children .children
.idxes_and_entries() .idxes_and_items()
.map(|(offset, (name, child))| (offset + 2, (name, child))) .map(|(offset, (name, child))| (offset + 2, (name, child)))
{ {
if offset < *idx { if offset < *idx {

View File

@ -1,87 +1,7 @@
use super::Inode; use super::Inode;
use crate::prelude::*; use crate::prelude::*;
/// DirEntryVec is used to store the entries of a directory. use jinux_util::slot_vec::SlotVec;
/// It can guarantee that the index of one dir entry remains unchanged during
/// adding or deleting other dir entries of it.
pub struct DirEntryVec<T> {
// The slots to store dir entries.
slots: Vec<Option<T>>,
// The number of occupied slots.
// The i-th slot is occupied if `self.slots[i].is_some()`.
num_occupied: usize,
}
impl<T> DirEntryVec<T> {
/// New an empty vec.
pub fn new() -> Self {
Self {
slots: Vec::new(),
num_occupied: 0,
}
}
/// Returns `true` if the vec contains no entries.
pub fn is_empty(&self) -> bool {
self.num_occupied == 0
}
/// Put a dir entry into the vec.
/// it may be put into an existing empty slot or the back of the vec.
pub fn put(&mut self, entry: T) {
if self.num_occupied == self.slots.len() {
self.slots.push(Some(entry));
} else {
let idx = self.slots.iter().position(|x| x.is_none()).unwrap();
self.slots[idx] = Some(entry);
}
self.num_occupied += 1;
}
/// Removes and returns the entry at position `idx`.
/// Returns `None` if `idx` is out of bounds or the entry has been removed.
pub fn remove(&mut self, idx: usize) -> Option<T> {
if idx >= self.slots.len() {
return None;
}
let mut del_entry = None;
core::mem::swap(&mut del_entry, &mut self.slots[idx]);
if del_entry.is_some() {
debug_assert!(self.num_occupied > 0);
self.num_occupied -= 1;
}
del_entry
}
/// Put and returns the entry at position `idx`.
/// Returns `None` if `idx` is out of bounds or the entry has been removed.
pub fn put_at(&mut self, idx: usize, entry: T) -> Option<T> {
if idx >= self.slots.len() {
return None;
}
let mut sub_entry = Some(entry);
core::mem::swap(&mut sub_entry, &mut self.slots[idx]);
if sub_entry.is_none() {
self.num_occupied += 1;
}
sub_entry
}
/// Creates an iterator which gives both of the index and the dir entry.
/// The index may not be continuous.
pub fn idxes_and_entries(&self) -> impl Iterator<Item = (usize, &'_ T)> {
self.slots
.iter()
.enumerate()
.filter(|(_, x)| x.is_some())
.map(|(idx, x)| (idx, x.as_ref().unwrap()))
}
/// Creates an iterator which gives the dir entry.
pub fn iter(&self) -> impl Iterator<Item = &'_ T> {
self.slots.iter().filter_map(|x| x.as_ref())
}
}
pub trait DirEntryVecExt { pub trait DirEntryVecExt {
/// If the entry is not found by `name`, use `f` to get the inode, then put the entry into vec. /// If the entry is not found by `name`, use `f` to get the inode, then put the entry into vec.
@ -92,7 +12,7 @@ pub trait DirEntryVecExt {
fn remove_entry_by_name(&mut self, name: &str) -> Option<(String, Arc<dyn Inode>)>; fn remove_entry_by_name(&mut self, name: &str) -> Option<(String, Arc<dyn Inode>)>;
} }
impl DirEntryVecExt for DirEntryVec<(String, Arc<dyn Inode>)> { impl DirEntryVecExt for SlotVec<(String, Arc<dyn Inode>)> {
fn put_entry_if_not_found(&mut self, name: &str, f: impl Fn() -> Arc<dyn Inode>) { fn put_entry_if_not_found(&mut self, name: &str, f: impl Fn() -> Arc<dyn Inode>) {
if self if self
.iter() .iter()
@ -106,7 +26,7 @@ impl DirEntryVecExt for DirEntryVec<(String, Arc<dyn Inode>)> {
fn remove_entry_by_name(&mut self, name: &str) -> Option<(String, Arc<dyn Inode>)> { fn remove_entry_by_name(&mut self, name: &str) -> Option<(String, Arc<dyn Inode>)> {
let idx = self let idx = self
.idxes_and_entries() .idxes_and_items()
.find(|(_, (child_name, _))| child_name == name) .find(|(_, (child_name, _))| child_name == name)
.map(|(idx, _)| idx); .map(|(idx, _)| idx);
if let Some(idx) = idx { if let Some(idx) = idx {

View File

@ -5,7 +5,7 @@ pub use channel::{Channel, Consumer, Producer};
pub use creation_flags::CreationFlags; pub use creation_flags::CreationFlags;
pub use dentry_cache::Dentry; pub use dentry_cache::Dentry;
pub use dirent_visitor::DirentVisitor; pub use dirent_visitor::DirentVisitor;
pub use direntry_vec::{DirEntryVec, DirEntryVecExt}; pub use direntry_vec::DirEntryVecExt;
pub use fcntl::FcntlCmd; pub use fcntl::FcntlCmd;
pub use file_creation_mask::FileCreationMask; pub use file_creation_mask::FileCreationMask;
pub use fs::{FileSystem, FsFlags, SuperBlock}; pub use fs::{FileSystem, FsFlags, SuperBlock};

View File

@ -2,5 +2,8 @@
#![no_std] #![no_std]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
extern crate alloc;
pub mod frame_ptr; pub mod frame_ptr;
pub mod slot_vec;
pub mod union_read_ptr; pub mod union_read_ptr;

View File

@ -0,0 +1,119 @@
use alloc::vec::Vec;
/// SlotVec is the variant of Vector.
/// It guarantees that the index of one item remains unchanged during adding
/// or deleting other items of the vector.
pub struct SlotVec<T> {
// The slots to store items.
slots: Vec<Option<T>>,
// The number of occupied slots.
// The i-th slot is occupied if `self.slots[i].is_some()`.
num_occupied: usize,
}
impl<T> SlotVec<T> {
/// New an empty vector.
pub fn new() -> Self {
Self {
slots: Vec::new(),
num_occupied: 0,
}
}
/// Return `true` if the vector contains no items.
pub fn is_empty(&self) -> bool {
self.num_occupied == 0
}
/// Return the number of items.
pub fn len(&self) -> usize {
self.num_occupied
}
/// Return the number of slots.
pub fn slots_len(&self) -> usize {
self.slots.len()
}
/// Get the item at position `idx`.
///
/// Return `None` if `idx` is out of bounds or the item is not exist.
pub fn get(&self, idx: usize) -> Option<&T> {
if idx >= self.slots.len() {
return None;
}
self.slots[idx].as_ref()
}
/// Put an item into the vector.
/// It may be put into any existing empty slots or the back of the vector.
///
/// Return the index of the inserted item.
pub fn put(&mut self, entry: T) -> usize {
let idx = if self.num_occupied == self.slots.len() {
self.slots.push(Some(entry));
self.slots.len() - 1
} else {
let idx = self.slots.iter().position(|x| x.is_none()).unwrap();
self.slots[idx] = Some(entry);
idx
};
self.num_occupied += 1;
idx
}
/// Put and return the item at position `idx`.
///
/// Return `None` if the item is not exist.
pub fn put_at(&mut self, idx: usize, item: T) -> Option<T> {
if idx >= self.slots.len() {
self.slots.resize_with(idx + 1, Default::default);
}
let mut sub_item = Some(item);
core::mem::swap(&mut sub_item, &mut self.slots[idx]);
if sub_item.is_none() {
self.num_occupied += 1;
}
sub_item
}
/// Remove and return the item at position `idx`.
///
/// Return `None` if `idx` is out of bounds or the item has been removed.
pub fn remove(&mut self, idx: usize) -> Option<T> {
if idx >= self.slots.len() {
return None;
}
let mut del_item = None;
core::mem::swap(&mut del_item, &mut self.slots[idx]);
if del_item.is_some() {
debug_assert!(self.num_occupied > 0);
self.num_occupied -= 1;
}
del_item
}
/// Create an iterator which gives both of the index and the item.
/// The index may not be continuous.
pub fn idxes_and_items(&self) -> impl Iterator<Item = (usize, &'_ T)> {
self.slots
.iter()
.enumerate()
.filter(|(_, x)| x.is_some())
.map(|(idx, x)| (idx, x.as_ref().unwrap()))
}
/// Create an iterator which just gives the item.
pub fn iter(&self) -> impl Iterator<Item = &'_ T> {
self.slots.iter().filter_map(|x| x.as_ref())
}
}
impl<T: Clone> Clone for SlotVec<T> {
fn clone(&self) -> Self {
Self {
slots: self.slots.clone(),
num_occupied: self.num_occupied.clone(),
}
}
}