separated out utilities and started tightening visibility modifiers

This commit is contained in:
Yehowshua Immanuel 2022-08-08 19:45:14 -04:00
parent 9f2b349029
commit 0946d13e6e
6 changed files with 150 additions and 203 deletions

View file

@ -40,6 +40,8 @@ Here's a command to test on a malformed VCD:
# TODO
## Features
- [ ] be explicit with imports, remove exports as possible
once FastWave is known to be fairly stable.
- [ ] macro for getting line number when propagating errors
- [ ] search for any ok_or's
- [ ] search for any unwraps or any direct vectors indexing

View file

@ -1,18 +1,17 @@
use std::{fs::File};
use clap::Parser;
use std::fs::File;
pub mod test;
pub mod vcd;
use vcd::parse_vcd;
use std::mem::size_of_val;
#[derive(Parser)]
struct Cli {
/// The path to the file to read
#[clap(parse(from_os_str))]
path: std::path::PathBuf}
path: std::path::PathBuf,
}
fn main() -> std::io::Result<()> {
let args = Cli::parse();
@ -21,19 +20,9 @@ fn main() -> std::io::Result<()> {
let now = Instant::now();
let file = File::open(&args.path)?;
let vcd = parse_vcd(file).unwrap();
parse_vcd(file).unwrap();
let elapsed = now.elapsed();
println!("Elapsed: {:.2?}", elapsed);
vcd.print_longest_signal();
dbg!(size_of_val(&*vcd.timeline));
// unsafe {
// let sz = size_of_val(&*vcd.timeline);
// }
// println!("printing signal tree");
// vcd.print_scopes();
Ok(())
}
}

View file

@ -1,8 +1,11 @@
mod reader;
pub use reader::*;
use reader::*;
mod types;
pub use types::*;
pub(super) use types::*;
mod parse;
pub use parse::*;
pub(super) use parse::*;
mod utilities;
use utilities::*;

View file

@ -19,65 +19,6 @@ use scopes::*;
mod events;
use events::*;
use std::cmp::Ordering;
fn compare_strs(a: &str, b: &str) -> Ordering {
// choose the smaller of the two indices
let upper_bound = if a.len() > b.len() { b.len() } else { a.len() };
let a_as_bytes = a.as_bytes();
let b_as_bytes = b.as_bytes();
for i in 0..upper_bound {
let a_byte = a_as_bytes[i];
let b_byte = b_as_bytes[i];
if a_byte > b_byte {
return Ordering::Greater;
}
if b_byte > a_byte {
return Ordering::Less;
}
}
if a.len() > b.len() {
return Ordering::Greater;
}
if a.len() < b.len() {
return Ordering::Less;
}
return Ordering::Equal;
}
fn ordered_binary_lookup(map: &Vec<(String, SignalIdx)>, key: &str) -> Result<SignalIdx, String> {
let mut upper_idx = map.len() - 1;
let mut lower_idx = 0usize;
while lower_idx <= upper_idx {
let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
let (str_val, signal_idx) = map.get(mid_idx).unwrap();
let ordering = compare_strs(key, str_val.as_str());
match ordering {
Ordering::Less => {
upper_idx = mid_idx - 1;
}
Ordering::Equal => {
return Ok(*signal_idx);
}
Ordering::Greater => {
lower_idx = mid_idx + 1;
}
}
}
return Err(format!(
"Error near {}:{}. Unable to find key: `{key}` in the map.",
file!(),
line!()
));
}
pub fn parse_vcd(file: File) -> Result<VCD, String> {
let mut word_gen = WordReader::new(file);
@ -98,51 +39,6 @@ pub fn parse_vcd(file: File) -> Result<VCD, String> {
};
parse_scopes(&mut word_gen, &mut vcd, &mut signal_map)?;
// the signal map should not contain any empty string
for (k, v) in &signal_map {
if k.len() == 0 {
return Err(format!("Critical error near {}:{}. There should be no empty strings in vcd string -> SignalIdx hashmap.", file!(), line!()));
}
}
// now that we've parsed all scopes and filled the hashmap
// with signals, we convert hashmap to an ordered vector
let mut signal_map1: Vec<(String, SignalIdx)> = signal_map
.iter()
.map(|(string, idx)| (string.clone(), idx.clone()))
.collect();
signal_map1.sort_by(|a: &(String, SignalIdx), b: &(String, SignalIdx)| {
let a = &a.0;
let b = &b.0;
compare_strs(a, b)
});
for (k, v) in &signal_map1 {
let signal_idx = ordered_binary_lookup(&signal_map1, k.as_str())?;
assert!(*v == signal_idx);
}
// let now = std::time::Instant::now();
// for (k, v) in &signal_map1 {
// let signal_idx = ordered_binary_lookup(&signal_map1, k.as_str())?;
// assert!(*v == signal_idx);
// }
// let ordered_binary_search_elapsed = now.elapsed();
// println!(
// "ordered_binary_search_elapsed: {:.2?}",
// ordered_binary_search_elapsed
// );
// let now = std::time::Instant::now();
// for (k, v) in &signal_map1 {
// // let signal_idx = ordered_binary_lookup(&signal_map1, k.as_str())?;
// let signal_idx = signal_map.get(k).unwrap();
// assert!(*v == *signal_idx);
// }
// let hashmap_search_elapsed = now.elapsed();
// println!("hashmap_search_elapsed: {:.2?}", hashmap_search_elapsed);
parse_events(&mut word_gen, &mut vcd, &mut signal_map)?;
Ok(vcd)

View file

@ -1,84 +1,5 @@
//! part of the vcd parser that handles parsing the signal tree and
//! building the resulting signal tree
use core::time;
use super::*;
#[derive(Debug)]
pub(super) enum BinaryParserErrTypes {
XValue,
ZValue,
UValue,
OtherValue(char),
TooLong,
}
// We build a quick and not so dirty bit string parser.
fn base2_str_to_byte(word: &[u8]) -> Result<u8, BinaryParserErrTypes> {
let mut val = 0u8;
// shouldn't have more than 8 chars in str
let len = word.len();
if len > 8 {
return Err(BinaryParserErrTypes::TooLong);
}
let bit_lut = [
0b0000_0001u8,
0b0000_0010u8,
0b0000_0100u8,
0b0000_1000u8,
0b0001_0000u8,
0b0010_0000u8,
0b0100_0000u8,
0b1000_0000u8,
];
for (idx, chr) in word.iter().rev().enumerate() {
match chr {
b'1' => val = bit_lut[idx] | val,
b'0' => {}
b'x' | b'X' => return Err(BinaryParserErrTypes::XValue),
b'z' | b'Z' => return Err(BinaryParserErrTypes::ZValue),
b'u' | b'U' => return Err(BinaryParserErrTypes::UValue),
_ => return Err(BinaryParserErrTypes::OtherValue(*chr as char)),
}
}
Ok(val)
}
fn binary_str_to_vec_u8(binary_str: &str) -> Result<Vec<u8>, BinaryParserErrTypes> {
let mut vec_u8: Vec<u8> = Vec::new();
let binary_str_as_bytes = binary_str.as_bytes();
let mut tail_idx = binary_str_as_bytes.len();
// clamp head if provided binary str is less than 8 long
let mut head_idx = if tail_idx >= 8 {
binary_str_as_bytes.len() - 8
} else {
0
};
while tail_idx > 0 {
let curr_b_val = &binary_str_as_bytes[head_idx..tail_idx];
let val_u8 = base2_str_to_byte(curr_b_val)?;
vec_u8.push(val_u8);
if head_idx < 8 {
head_idx = 0
} else {
head_idx = head_idx - 8;
}
if tail_idx < 8 {
tail_idx = 0
} else {
tail_idx = tail_idx - 8;
}
}
Ok(vec_u8)
}
pub(super) fn parse_events<'a>(
word_reader: &mut WordReader,
vcd: &'a mut VCD,
@ -284,7 +205,6 @@ pub(super) fn parse_events<'a>(
"0" => {
// lookup signal idx
let hash = &word[1..];
let (f, l) = (file!(), line!());
let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
format!(
"Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",

137
src/vcd/utilities.rs Normal file
View file

@ -0,0 +1,137 @@
use super::*;
use std::cmp::Ordering;
#[derive(Debug)]
pub(super) enum BinaryParserErrTypes {
XValue,
ZValue,
UValue,
OtherValue(char),
TooLong,
}
// We build a quick and not so dirty bit string parser.
pub(super) fn base2_str_to_byte(word: &[u8]) -> Result<u8, BinaryParserErrTypes> {
let mut val = 0u8;
// shouldn't have more than 8 chars in str
let len = word.len();
if len > 8 {
return Err(BinaryParserErrTypes::TooLong);
}
let bit_lut = [
0b0000_0001u8,
0b0000_0010u8,
0b0000_0100u8,
0b0000_1000u8,
0b0001_0000u8,
0b0010_0000u8,
0b0100_0000u8,
0b1000_0000u8,
];
for (idx, chr) in word.iter().rev().enumerate() {
match chr {
b'1' => val = bit_lut[idx] | val,
b'0' => {}
b'x' | b'X' => return Err(BinaryParserErrTypes::XValue),
b'z' | b'Z' => return Err(BinaryParserErrTypes::ZValue),
b'u' | b'U' => return Err(BinaryParserErrTypes::UValue),
_ => return Err(BinaryParserErrTypes::OtherValue(*chr as char)),
}
}
Ok(val)
}
pub(super) fn binary_str_to_vec_u8(binary_str: &str) -> Result<Vec<u8>, BinaryParserErrTypes> {
let mut vec_u8: Vec<u8> = Vec::new();
let binary_str_as_bytes = binary_str.as_bytes();
let mut tail_idx = binary_str_as_bytes.len();
// clamp head if provided binary str is less than 8 long
let mut head_idx = if tail_idx >= 8 {
binary_str_as_bytes.len() - 8
} else {
0
};
while tail_idx > 0 {
let curr_b_val = &binary_str_as_bytes[head_idx..tail_idx];
let val_u8 = base2_str_to_byte(curr_b_val)?;
vec_u8.push(val_u8);
if head_idx < 8 {
head_idx = 0
} else {
head_idx = head_idx - 8;
}
if tail_idx < 8 {
tail_idx = 0
} else {
tail_idx = tail_idx - 8;
}
}
Ok(vec_u8)
}
// TODO : modify ordered_binary_lookup to support VCD timeline lookup
// and return time in signature
fn compare_strs(a: &str, b: &str) -> Ordering {
// choose the smaller of the two indices
let upper_bound = if a.len() > b.len() { b.len() } else { a.len() };
let a_as_bytes = a.as_bytes();
let b_as_bytes = b.as_bytes();
for i in 0..upper_bound {
let a_byte = a_as_bytes[i];
let b_byte = b_as_bytes[i];
if a_byte > b_byte {
return Ordering::Greater;
}
if b_byte > a_byte {
return Ordering::Less;
}
}
if a.len() > b.len() {
return Ordering::Greater;
}
if a.len() < b.len() {
return Ordering::Less;
}
return Ordering::Equal;
}
fn ordered_binary_lookup(map: &Vec<(String, SignalIdx)>, key: &str) -> Result<SignalIdx, String> {
let mut upper_idx = map.len() - 1;
let mut lower_idx = 0usize;
while lower_idx <= upper_idx {
let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
let (str_val, signal_idx) = map.get(mid_idx).unwrap();
let ordering = compare_strs(key, str_val.as_str());
match ordering {
Ordering::Less => {
upper_idx = mid_idx - 1;
}
Ordering::Equal => {
return Ok(*signal_idx);
}
Ordering::Greater => {
lower_idx = mid_idx + 1;
}
}
}
return Err(format!(
"Error near {}:{}. Unable to find key: `{key}` in the map.",
file!(),
line!()
));
}