diff --git a/src/utility/bitmap.rs b/src/utility/bitmap.rs index 0892b31..5dbb7fe 100644 --- a/src/utility/bitmap.rs +++ b/src/utility/bitmap.rs @@ -4,18 +4,28 @@ pub const BITS_IN_WORD: usize = 32; use std::fs::File; use std::io::{Cursor, Write, Read}; -use crate::drivers::drv_disk::{self, DrvDisk}; -use crate::filesys::openfile::OpenFile; use crate::simulator::disk::SECTOR_SIZE; pub struct BitMap { - num_bits: usize, - num_words: usize, - map: Vec, + pub num_bits: usize, + pub num_words: usize, + pub map: Vec, } impl BitMap { + pub fn compute_map_size(n_item : usize, dst_n_item : &mut usize, dst_num_word : &mut usize){ + //on effectue un calcul sur n_item pour avoir un nombre de bits multiple de 32 + //On fait le choix d'arrondir vers le haut pour que la map puisse acceuillir la taille souhaitée + *dst_n_item = n_item - (n_item%32); + + if n_item%32 > 0 { + *dst_n_item += 32; + } + + *dst_num_word = *dst_n_item/32; + } + /// Initialize a bitmap with "nitems" bits, so that every bit is clear. /// it can be added somewhere on a list. /// @@ -23,19 +33,45 @@ impl BitMap { /// - **nitems** is the number of bits in the bitmap. ///---------------------------------------------------------------------- pub fn init_bitmap(n_items: usize) -> BitMap { + + let mut rounded_num_bits = 0; + let mut rounded_num_words = 0; + + BitMap::compute_map_size(n_items, &mut rounded_num_bits, &mut rounded_num_words); + BitMap{ - num_bits: n_items, - num_words: (n_items + SECTOR_SIZE as usize -1) / SECTOR_SIZE as usize, - map: vec![0,n_items as u32], + num_bits: rounded_num_bits, + num_words: rounded_num_words,//(n_items + SECTOR_SIZE as usize -1) / SECTOR_SIZE as usize, + map: vec![0u32 ; rounded_num_words], } } + + //values is not borrowed + pub fn init_bitmap_from(values: &mut Vec)-> BitMap { + let mut tmp: Vec = Vec::new(); + + for value in values.iter(){ + tmp.push(*value) + } + + BitMap{ + num_bits: values.len()*std::mem::size_of::()*8, + num_words: values.len(), + map: tmp + } + } + /// Set the "nth" bit in a bitmap. /// ### Parameters /// - **which** is the number of the bit to be set. pub fn mark(&mut self, which: usize) { assert!(which >= 0 && which < self.num_bits); - self.map[which / BITS_IN_WORD] |= 1 << (which % BITS_IN_WORD); + //self.map[which / BITS_IN_WORD] |= 1 << (which % BITS_IN_WORD); + let position_modulo = which%BITS_IN_WORD; + let left_shift = BITS_IN_WORD-position_modulo-1; + + self.map[which / BITS_IN_WORD] |= (1u32 << left_shift); } /// return true if the "nth" bit is set. @@ -44,7 +80,11 @@ impl BitMap { /// - **which** is the number of the bit to be tested. pub fn test(&self, which: usize) -> bool { assert!(which < self.num_bits); - (self.map[which / BITS_IN_WORD] & (1 << (which % BITS_IN_WORD))) != 0 + //(self.map[which / BITS_IN_WORD] & (1 << (which % BITS_IN_WORD))) != 0 + let position_modulo = which%BITS_IN_WORD; + let left_shift = BITS_IN_WORD-position_modulo-1; + + (self.map[which / BITS_IN_WORD] & (1u32 << left_shift)) != 0 } /// Return the number of the first bit which is clear. @@ -97,15 +137,18 @@ impl BitMap { println!(); } + /* ///Initialize the contents of a bitmap from a Nachos file. /// /// ### Parameters /// - **file** is the place to read the bitmap from - pub fn fetch_from(&mut self, file: &mut OpenFile, drv_disk: &mut DrvDisk) -> std::io::Result<&Vec> { - let mut num_bytes = self.num_words * std::mem::size_of::(); + pub fn fetch_from(&mut self, file_path: &str) -> std::io::Result<&Vec> { + // Ouvre le fichier en mode lecture seule + let mut file = File::open(file_path)?; + // Lit les octets du fichier dans un buffer let mut buffer = vec![0; self.num_words * std::mem::size_of::()]; - OpenFile::read(drv_disk, file, &mut buffer, num_bytes as i32); + file.read_exact(&mut buffer)?; // Convertit les octets en vecteur de u32 self.map = vec![0; self.num_words]; @@ -119,22 +162,218 @@ impl BitMap { Ok(&self.map) } + */ + + ///Initialize the contents of a bitmap from a Nachos file. + /// + /// ### Parameters + /// - **file** is the place to read the bitmap from + pub fn fetch_from(&mut self, file_path: &str){ + // Ouvre le fichier en mode lecture seule + let mut file = File::open(file_path).expect("BitMap::fetch_from , unable to open file in read only"); + + let mut buf_to_convert : Vec = Vec::new(); + + file.read_to_end(&mut buf_to_convert).expect("BitMap::fetch_from , unable to read from file"); + + let borne_max_exclue; + + //si le fichier contient plus de mots que la map ne peut en acceuillir, on lit de quoi remplir la map + if buf_to_convert.len() > self.num_bits/8 { + borne_max_exclue = self.num_words*4; + } + //sinon on lit ce que le fichier contient, en respectant l'alignement sur 4 octects ! + else { + borne_max_exclue = buf_to_convert.len() - (buf_to_convert.len()%4); + } + + let mut i = 0; + + // !! borne_max_exclue doit etre multiple de 4 !! + while i < borne_max_exclue { + + let a : u32 = buf_to_convert[i] as u32; + let b : u32 = buf_to_convert[i+1] as u32; + let c : u32 = buf_to_convert[i+2] as u32; + let d : u32 = buf_to_convert[i+3] as u32; + + self.map[i/4] = (a<<24) | (b<<16) | (c<<8) | (d); + + i += 4;//on passe aux 4 octets suivants + } + } /// Store the contents of a bitmap to a Nachos file. /// /// ### Paramenters /// - **file** is the place to write the bitmap to - pub fn write_back(&mut self, file: &mut OpenFile, drv_disk: &mut DrvDisk) -> std::io::Result<()> { - let mut num_bytes = self.num_words * std::mem::size_of::(); - + pub fn write_back(&mut self, file_path: &str) -> std::io::Result<()> { // Encapsule le vecteur dans un std::io::Cursor pour l'utiliser comme un std::io::Write let mut cursor = Cursor::new(Vec::::new()); for u32_val in self.map.as_mut_slice() { cursor.write_all(&u32_val.to_le_bytes())?; } - OpenFile::read_at(drv_disk, file, &mut cursor.into_inner(), num_bytes as i32, 0); + // Ouvre le fichier en mode écriture + let mut file = File::create(file_path)?; + // Écrit les données dans le fichier + file.write_all(&cursor.into_inner())?; + Ok(()) } + + + pub fn add_word(&mut self, word : u32){ + self.map.push(word); + self.num_words += 1; + self.num_bits += std::mem::size_of::()*8; + } + + pub fn add_words(&mut self, words : Vec){ + for word in words.iter(){ + self.add_word(*word); + } + } +} + + + +#[cfg(test)] +mod tests { + use std::io::{Seek, SeekFrom}; + use super::*; + + #[test] + fn test_fetch_from_file_smaller_than_map() { + //println!("\n\n TEST FETCH FROM\n"); + //On ecrit la séquence 0x AB CD EF 10 20 2E 3E 4F + let values : [u8 ; 8] = [0xAB, 0xCD, 0xEF, 0x10, 0x20, 0x2E, 0x3E, 0x4F]; + let values_for_test : [u32 ; 2] = [0xABCDEF10, 0x202E3E4F]; + + let mut f = File::options() + .read(true) + .write(true) + .create(true) + .open("test_fetch_bitmap") + .expect("Unable to create File"); + + f.write_all(&values[..]).expect("Unable to write data"); + + //creating and loading the bitmap + + let mut bit_map : BitMap = BitMap::init_bitmap(100); + + bit_map.fetch_from("test_fetch_bitmap"); + + assert!(bit_map.num_bits == 128); + assert!(bit_map.num_words == 4); + + for j in 0..bit_map.map.len(){ + if j<2 { + assert!(values_for_test[j] == bit_map.map[j]); + } + else { + assert!(bit_map.map[j] == 0u32); + } + } + //print for debug + /*for val in bit_map.map.iter(){ + println!("{:08X?}", *val) + }*/ + } + + + #[test] + fn test_fetch_from_map_smaller_than_file() { + //println!("\n\n TEST FETCH FROM\n"); + //On ecrit la séquence 0x AB CD EF 10 20 2E 3E 4F + let mut values : [u8 ; 8] = [0xFE, 0x59, 0xEF, 0x10, 0x20, 0x2E, 0x3E, 0x4F]; + + let mut f = File::options() + .read(true) + .write(true) + .create(true) + .open("test_fetch_bitmap_2") + .expect("Unable to create File"); + + f.write_all(&values[..]).expect("Unable to write data"); + + //creating and loading the bitmap + //1 bit donnera lieu via init_bit_map a une map de 32 bit soit 1 mot + let mut bit_map : BitMap = BitMap::init_bitmap(1); + + //println!("\nnombre de bit de la map {} \nnombre de mot {}\n", bit_map.num_bits, bit_map.num_words); + + bit_map.fetch_from("test_fetch_bitmap"); + + assert!(bit_map.num_bits == 32); + assert!(bit_map.num_words == 1); + assert!(bit_map.map[0] == 0xFE59EF10); + //println!("\n\n data loaded into map \n"); + + //print for debug + /*for val in bit_map.map.iter(){ + println!("{:08X?}", *val) + }*/ + } + + + #[test] + fn test_mark() { + + let mut bit_map : BitMap = BitMap::init_bitmap(128); + let index_to_set : [usize ; 16] = [0,5,10,15,18,25,28,31,45,70,74,88,99,101,102,127]; + + for val in index_to_set.iter(){ + bit_map.mark(*val); + } + + assert!(bit_map.num_bits == 128); + assert!(bit_map.num_words == 4); + + /*for i in bit_map.map.iter(){ + println!("\n{:#032b}", *i); + }*/ + + for i in 0..bit_map.num_bits { + + let word_index = i/32; + let mask_to_shift : u32 = 0x80000000;//un 1 au debut puis full 0 <=> 0x100000000000000000000000000000000 + let shift_value = i%32; + + if index_to_set.contains(&i) { + assert!( (bit_map.map[word_index] & (mask_to_shift>>shift_value)) != 0); + } + else{ + assert!( (bit_map.map[word_index] & (mask_to_shift>>shift_value)) == 0) ; + } + } + } + + + #[test] + fn test_test() { + + let mut bit_map : BitMap = BitMap::init_bitmap(128); + let index_to_set : [usize ; 16] = [0,5,10,15,18,25,28,31,45,70,74,88,99,101,102,127]; + + for val in index_to_set.iter(){ + bit_map.mark(*val); + } + + assert!(bit_map.num_bits == 128); + assert!(bit_map.num_words == 4); + + for i in 0..bit_map.num_bits { + + if index_to_set.contains(&i) { + assert!( bit_map.test(i) == true); + } + else{ + assert!( bit_map.test(i) == false) ; + } + } + } + } \ No newline at end of file