diff --git a/crates/yglnk-core/src/ht.rs b/crates/yglnk-core/src/ht.rs index 79a729c..0a7f202 100644 --- a/crates/yglnk-core/src/ht.rs +++ b/crates/yglnk-core/src/ht.rs @@ -30,6 +30,13 @@ pub struct HashTableIter<'a> { chains: &'a [u8], } +#[derive(Clone, Copy, Debug)] +pub struct HashTableValue { + pub typ: u32, + pub lhs: u64, + pub rhs: u64, +} + impl HashTableHeader { pub fn parse(data: &[u8]) -> Option { if data.len() < 20 { @@ -68,6 +75,19 @@ pub fn hash_trf(h: u64, items: usize, div: usize) -> usize { div * usize::try_from(h % u64::try_from(items / div).unwrap()).unwrap() } +impl HashTableValue { + pub fn parse(entry: &[u8]) -> Option { + if entry.len() < 32 { + return None; + } + Some(Self { + typ: u32::from_be_bytes(entry[12..16].try_into().unwrap()), + lhs: u64::from_be_bytes(entry[16..24].try_into().unwrap()), + rhs: u64::from_be_bytes(entry[24..32].try_into().unwrap()), + }) + } +} + impl<'a> HashTableRef<'a> { /// `location` should be the offset where the hash table is present (in units of 16 bytes) pub fn parse(data: &'a [u8], location: u32) -> Option { @@ -92,7 +112,7 @@ impl<'a> HashTableRef<'a> { } /// NOTE: the key is truncated after the first null byte - pub fn lookup(&self, key: &[u8]) -> Option<(u32, u64, u64)> { + pub fn lookup(&self, key: &[u8]) -> Option { let key = trunc_key_at0(key); let (h, blmask) = self.settings.translate_key(key); @@ -118,11 +138,7 @@ impl<'a> HashTableRef<'a> { let e_name = trunc_key_at0(self.strtab.get(e_name_ix..)?); if e_name == key { - return Some(( - u32::from_be_bytes(sel[12..16].try_into().unwrap()), - u64::from_be_bytes(sel[16..24].try_into().unwrap()), - u64::from_be_bytes(sel[24..32].try_into().unwrap()), - )); + return HashTableValue::parse(sel); } } @@ -143,7 +159,7 @@ impl<'a> HashTableRef<'a> { } impl<'a> Iterator for HashTableIter<'a> { - type Item = (u64, &'a [u8], u32, u64, u64); + type Item = (u64, &'a [u8], HashTableValue); fn next(&mut self) -> Option { if self.chains.len() < 32 { @@ -156,9 +172,7 @@ impl<'a> Iterator for HashTableIter<'a> { Some(( u64::from_be_bytes(i[0..8].try_into().unwrap()), e_name, - u32::from_be_bytes(i[12..16].try_into().unwrap()), - u64::from_be_bytes(i[16..24].try_into().unwrap()), - u64::from_be_bytes(i[24..32].try_into().unwrap()), + HashTableValue::parse(i).unwrap(), )) } } diff --git a/crates/yglnk-ls/src/main.rs b/crates/yglnk-ls/src/main.rs index 5bb2033..d869a37 100644 --- a/crates/yglnk-ls/src/main.rs +++ b/crates/yglnk-ls/src/main.rs @@ -24,6 +24,9 @@ enum Command { /// list hash table Hash, + /// resolve a key via hash table + HashLookup { key: String }, + /// list 2D "hilbert curve" table X2dhc, } @@ -78,17 +81,30 @@ fn main() { let ht = yglnk_core::HashTableRef::parse(data, cli.location) .expect("unable to parse table header"); println!("hash\tL\tR\tname\t\ttyp"); - for (hash, name, typ, val_l, val_r) in ht.iter() { + for (hash, name, value) in ht.iter() { println!( "{:016x}\t{:016x}\t{:016x}\t{}\t{}", hash, - val_l, - val_r, + value.lhs, + value.rhs, name_to_txt(name), - typ_to_txt(typ) + typ_to_txt(value.typ) ); } } + Command::HashLookup { key } => { + let ht = yglnk_core::HashTableRef::parse(data, cli.location) + .expect("unable to parse table header"); + match ht.lookup(key.as_bytes()) { + None => println!("(none)"), + Some(value) => println!( + "typ={} L={:016x} R={:016x}", + typ_to_txt(value.typ), + value.lhs, + value.rhs + ), + } + } Command::X2dhc => unimplemented!(), } }