From 2f6171fc707267c7248063d28de623ca002eef26 Mon Sep 17 00:00:00 2001 From: raabh Date: Mon, 13 Mar 2023 15:47:39 +0100 Subject: [PATCH] removed BufReaderML --- src/bin/ddnnife.rs | 11 +++-- src/bin/dhone.rs | 13 +++--- src/ddnnf/anomalies/atomic_sets.rs | 11 ++--- src/ddnnf/anomalies/core.rs | 2 +- src/ddnnf/anomalies/false_optional.rs | 15 +------ src/ddnnf/anomalies/sat.rs | 2 +- src/ddnnf/config_creation.rs | 1 - src/parser.rs | 22 +++++----- src/parser/bufreader_for_big_files.rs | 59 --------------------------- 9 files changed, 31 insertions(+), 105 deletions(-) delete mode 100644 src/parser/bufreader_for_big_files.rs diff --git a/src/bin/ddnnife.rs b/src/bin/ddnnife.rs index 2c9ff77..a63139b 100644 --- a/src/bin/ddnnife.rs +++ b/src/bin/ddnnife.rs @@ -1,5 +1,3 @@ -//#![warn(clippy::all, clippy::pedantic)] - #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -18,7 +16,8 @@ use ddnnf_lib::ddnnf::Ddnnf; use ddnnf_lib::parser::{self as dparser, persisting::write_ddnnf}; #[derive(Parser)] -#[command(author, version, about, arg_required_else_help(true), help_template("\ +#[command(author, version, about, arg_required_else_help(true), +help_template("\ {before-help}{name} {version} {author-with-newline}{about-with-newline} {usage-heading} {usage} @@ -116,6 +115,7 @@ fn main() { ddnnf = dparser::build_ddnnf(ddnnf_path, cli.ommited_features) } + // print additional output, iff we are not in the stream mode if !cli.stream { let elapsed_time = time.elapsed().as_secs_f32(); println!( @@ -215,7 +215,7 @@ fn main() { let response = ddnnf.handle_stream_msg(&buffer); - if response.as_str() == "exit" { handle_out.write_all("ENDE \\ü/".as_bytes()).unwrap(); break; } + if response.as_str() == "exit" { handle_out.write_all("ENDE \\ü/\n".as_bytes()).unwrap(); break; } handle_out.write_all(format!("{}\n", response).as_bytes()).unwrap(); handle_out.flush().unwrap(); @@ -244,6 +244,8 @@ fn main() { } } +// Uses the supplied file path if there is any. +// If there is no prefix, we switch to the default fallback. fn build_file_path(maybe_prefix: Option>, fallback: &String, postfix: &str) -> String { let potential_path = maybe_prefix.unwrap(); let mut custom_file_path; @@ -257,6 +259,7 @@ fn build_file_path(maybe_prefix: Option>, fallback: &String, postfix custom_file_path } +// spawns a new thread that listens on stdin and delivers its request to the stream message handling fn spawn_stdin_channel() -> Receiver { let (tx, rx) = mpsc::channel::(); thread::spawn(move || { diff --git a/src/bin/dhone.rs b/src/bin/dhone.rs index 475f8f9..c4f8a68 100644 --- a/src/bin/dhone.rs +++ b/src/bin/dhone.rs @@ -2,13 +2,12 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use clap::Parser; -use ddnnf_lib::parser::bufreader_for_big_files::BufReaderMl; use rustc_hash::FxHashMap; use std::time::Instant; use std::fs::File; -use std::io::{BufWriter, Write}; +use std::io::{BufWriter, Write, BufRead, BufReader}; pub use ddnnf_lib::parser as dparser; pub use dparser::c2d_lexer; @@ -121,14 +120,16 @@ fn preprocess(path: &str) -> Vec { // generates a token stream from a file path fn get_token_stream(path: &str) -> Vec { - let buf_reader = BufReaderMl::open(path).expect("Unable to open file"); + let file = File::open(path).unwrap(); + let lines = BufReader::new(file) + .lines() + .map(|line| line.expect("Unable to read line")); // we do not know the capacity beforehand without applying semmantics but we know that the file will often be quite big let mut parsed_tokens: Vec = Vec::with_capacity(10000); - // opens the file with a BufReaderMl which is similar to a regular BufReader + // opens the file with a BufReader and // works off each line of the file data seperatly - for line in buf_reader { - let line = line.expect("Unable to read line"); + for line in lines { parsed_tokens.push(dparser::c2d_lexer::lex_line(line.as_ref()).unwrap().1); } diff --git a/src/ddnnf/anomalies/atomic_sets.rs b/src/ddnnf/anomalies/atomic_sets.rs index df2e061..54229a5 100644 --- a/src/ddnnf/anomalies/atomic_sets.rs +++ b/src/ddnnf/anomalies/atomic_sets.rs @@ -7,14 +7,15 @@ use crate::Ddnnf; use std::hash::Hash; +/// A quite basic union-find implementation that uses ranks and path compresion #[derive(Debug, Clone, PartialEq)] -pub struct UnionFind { +struct UnionFind { size: usize, parents: FxHashMap, rank: FxHashMap, } -pub trait UnionFindTrait { +trait UnionFindTrait { fn find(&mut self, node: N) -> N; fn equiv(&mut self, x: N, y: N) -> bool; fn union(&mut self, x: N, y: N); @@ -30,7 +31,7 @@ where T: Eq + Hash + Clone { impl UnionFind where T: Eq + Hash + Clone { - pub fn new() -> UnionFind { + fn new() -> UnionFind { let parents: FxHashMap = FxHashMap::default(); let rank: FxHashMap = FxHashMap::default(); @@ -40,10 +41,6 @@ where T: Eq + Hash + Clone { rank, } } - - pub fn entries(&self) -> Vec { - self.rank.clone().into_keys().collect() - } } impl UnionFindTrait for UnionFind diff --git a/src/ddnnf/anomalies/core.rs b/src/ddnnf/anomalies/core.rs index 85744f9..01fb771 100644 --- a/src/ddnnf/anomalies/core.rs +++ b/src/ddnnf/anomalies/core.rs @@ -3,7 +3,7 @@ use rustc_hash::FxHashSet; use crate::{Ddnnf}; impl Ddnnf { - /// Computes all core features + /// Computes all core features /// A feature is a core feature iff there exists only the positiv occurence of that feature pub(crate) fn get_core(&mut self) { self.core = (1..=self.number_of_variables as i32) diff --git a/src/ddnnf/anomalies/false_optional.rs b/src/ddnnf/anomalies/false_optional.rs index 16cf3b0..c661eb4 100644 --- a/src/ddnnf/anomalies/false_optional.rs +++ b/src/ddnnf/anomalies/false_optional.rs @@ -6,19 +6,6 @@ impl Ddnnf { /// the feature while simultanously excluding its parent #[allow(dead_code)] fn get_false_optional(&mut self) { - /*** - * Probleme: - * - Wie findet man den parent eines features? - * - Welches feature ist das root feature? - * - * Beziehung eines features zu parent: - * p => c (Damit das child ausgewählt werden kann muss der parent gewählt sein) - * - * F_FM and p and not c is unsatisfiable - * <=> #SAT(F_FM and p) == #SAT(F_FM and p and c) und f ist nicht mandatory - * Wie ermittelt man ob ein feature mandatory ist? - * -> SAT(F_FM and p and other child von p) - * - */ + // TODO } } \ No newline at end of file diff --git a/src/ddnnf/anomalies/sat.rs b/src/ddnnf/anomalies/sat.rs index 49ed702..98fe382 100644 --- a/src/ddnnf/anomalies/sat.rs +++ b/src/ddnnf/anomalies/sat.rs @@ -43,7 +43,7 @@ impl Ddnnf { } #[inline] - // CComputes if a node is sat + // Computes if a node is sat pub(crate) fn sat_node_default(&mut self, i: usize) { match &self.nodes[i].ntype { And { children } => { diff --git a/src/ddnnf/config_creation.rs b/src/ddnnf/config_creation.rs index f4ca633..5b54fc8 100644 --- a/src/ddnnf/config_creation.rs +++ b/src/ddnnf/config_creation.rs @@ -253,7 +253,6 @@ impl Ddnnf { } #[cfg(test)] -#[cfg_attr(coverage_nightly, no_coverage)] mod test { use std::{collections::HashSet}; diff --git a/src/parser.rs b/src/parser.rs index 8744511..c6273c5 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -18,9 +18,6 @@ use std::{ use rug::{Integer, Complete}; use rustc_hash::{FxHashMap, FxHashSet}; -pub mod bufreader_for_big_files; -use bufreader_for_big_files::BufReaderMl; - use crate::ddnnf::{Ddnnf, node::Node, node::NodeType}; use petgraph::graph::DiGraph; @@ -101,7 +98,7 @@ fn build_c2d_ddnnf(lines: Vec, variables: u32) -> Ddnnf { let mut literals: FxHashMap = FxHashMap::default(); let mut true_nodes = Vec::new(); - // opens the file with a BufReaderMl which is similar to a regular BufReader + // opens the file with a BufReader and // works off each line of the file data seperatly // skip the first line, because we already looked at the header for line in lines.into_iter().skip(1) { @@ -235,7 +232,7 @@ fn build_d4_ddnnf(lines: Vec, ommited_features: u32) -> Ddnnf { ddnnf_graph.add_edge(and_node, to, ()); }; - // opens the file with a BufReaderMl which is similar to a regular BufReader + // opens the file with a BufReader and // works off each line of the file data seperatly for line in lines { let next: D4Token = lex_line_d4(line.as_ref()).unwrap().1; @@ -507,16 +504,17 @@ fn calc_or_count( /// /// Panics for a path to a non existing file pub fn parse_queries_file(path: &str) -> Vec<(usize, Vec)> { - let buf_reader = BufReaderMl::open(path).expect("Unable to open file"); - let mut parsed_queries: Vec<(usize, Vec)> = Vec::new(); - - // opens the file with a BufReaderMl which is similar to a regular BufReader + // opens the file with a BufReader and // works off each line of the file data seperatly - for (line_number, line) in buf_reader.enumerate() { - let l = line.expect("Unable to read line"); + let file = File::open(path).unwrap(); + let lines = BufReader::new(file) + .lines() + .map(|line| line.expect("Unable to read line")); + let mut parsed_queries: Vec<(usize, Vec)> = Vec::new(); + for (line_number, line) in lines.enumerate() { // takes a line of the file and parses the i32 values - let res: Vec = l.as_ref().split_whitespace().into_iter() + let res: Vec = line.split_whitespace().into_iter() .map(|elem| elem.to_string().parse::() .unwrap_or_else(|_| panic!("Unable to parse {:?} into an i32 value while trying to parse the querie file at {:?}.\nCheck the help page with \"-h\" or \"--help\" for further information.\n", elem, path)) ).collect(); diff --git a/src/parser/bufreader_for_big_files.rs b/src/parser/bufreader_for_big_files.rs deleted file mode 100644 index e3e0f27..0000000 --- a/src/parser/bufreader_for_big_files.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::{ - fs::File, - io::{self, prelude::*}, - rc::Rc, -}; - -/// The BufReaderMl is a BufReader that reuses a String multiples times (once for each line) -/// We gain some performance using that approach -pub struct BufReaderMl { - reader: io::BufReader, - buf: Rc, -} - -/// Creates a new String which will hold the data of each line in a file -fn new() -> Rc { - Rc::new(String::with_capacity(1024)) // Tweakable capacity -} - -impl BufReaderMl { - /// Opens a file with a BufReader - pub fn open(path: impl AsRef) -> io::Result { - let file = File::open(path)?; - let reader = io::BufReader::new(file); - let buf = new(); - - Ok(Self { reader, buf }) - } -} - -/// Uses the declared String for each line and does not create a new String for each individual line -/// and increases the performance. -impl Iterator for BufReaderMl { - type Item = io::Result>; - - fn next(&mut self) -> Option { - let buf = match Rc::get_mut(&mut self.buf) { - // if the String holds information -> discard it so there is room for the next line - Some(buf) => { - buf.clear(); - buf - } - None => { - self.buf = new(); - Rc::make_mut(&mut self.buf) - } - }; - - self.reader - .read_line(buf) - .map(|u| { - if u == 0 { - None - } else { - Some(Rc::clone(&self.buf)) - } - }) - .transpose() - } -}