Skip to content

Commit

Permalink
fix #181: fix optimized matcher algorithm to query for all prefixes
Browse files Browse the repository at this point in the history
  • Loading branch information
hlorenzi committed Oct 7, 2023
1 parent f0e0b54 commit 3735e82
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 40 deletions.
79 changes: 42 additions & 37 deletions src/asm/defs/ruledef_map.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
use crate::*;


pub const RULEDEF_MAP_PREFIX_SIZE: usize = 4;
const MAX_PREFIX_SIZE: usize = 4;


pub type RuledefMapPrefix = [char; RULEDEF_MAP_PREFIX_SIZE];
pub type RuledefMapPrefix = [char; MAX_PREFIX_SIZE];


#[derive(Debug)]
pub struct RuledefMap
{
/// Instructions that start with a mnemonic
prefixed: std::collections::HashMap<RuledefMapPrefix, Vec<RuledefMapEntry>>,

/// All other instructions, e.g. the ones that start
/// with a parameter
unprefixed: Vec<RuledefMapEntry>,
/// Each rule is considered to have a prefix
/// consisting of the first few "exact" pattern-part characters,
/// stopping before parameter and subrule slots, and also
/// cut off by the constant maximum prefix size declared above.
prefixes_to_rules: std::collections::HashMap<RuledefMapPrefix, Vec<RuledefMapEntry>>,
}


Expand All @@ -32,8 +31,7 @@ impl RuledefMap
pub fn new() -> RuledefMap
{
RuledefMap {
prefixed: std::collections::HashMap::new(),
unprefixed: Vec::new(),
prefixes_to_rules: std::collections::HashMap::new(),
}
}

Expand Down Expand Up @@ -71,12 +69,12 @@ impl RuledefMap
rule_ref: util::ItemRef<asm::Rule>,
rule: &asm::Rule)
{
let mut prefix: RuledefMapPrefix = ['\0'; RULEDEF_MAP_PREFIX_SIZE];
let mut prefix: RuledefMapPrefix = ['\0'; MAX_PREFIX_SIZE];
let mut prefix_index = 0;

for part in &rule.pattern
{
if prefix_index >= RULEDEF_MAP_PREFIX_SIZE
if prefix_index >= MAX_PREFIX_SIZE
{
break;
}
Expand All @@ -96,30 +94,23 @@ impl RuledefMap
rule_ref,
};

if prefix_index > 0
{
self.prefixed
.entry(prefix)
.or_insert_with(|| Vec::new())
.push(entry);
}
else
{
self.unprefixed.push(entry);
}
self.prefixes_to_rules
.entry(prefix)
.or_insert_with(|| Vec::new())
.push(entry);
}


pub fn parse_prefix(
walker: &syntax::TokenWalker)
-> RuledefMapPrefix
{
let mut prefix: RuledefMapPrefix = ['\0'; RULEDEF_MAP_PREFIX_SIZE];
let mut prefix: RuledefMapPrefix = ['\0'; MAX_PREFIX_SIZE];
let mut prefix_index = 0;

let mut walker_index = 0;

while prefix_index < RULEDEF_MAP_PREFIX_SIZE
while prefix_index < MAX_PREFIX_SIZE
{
let token = walker.next_nth(walker_index);
walker_index += 1;
Expand All @@ -128,7 +119,7 @@ impl RuledefMap
{
for c in token.text().chars()
{
if prefix_index >= RULEDEF_MAP_PREFIX_SIZE
if prefix_index >= MAX_PREFIX_SIZE
{
break;
}
Expand All @@ -150,20 +141,34 @@ impl RuledefMap
pub fn query_prefixed(
&self,
prefix: RuledefMapPrefix)
-> &[RuledefMapEntry]
-> [&[RuledefMapEntry]; MAX_PREFIX_SIZE + 1]
{
match self.prefixed.get(&prefix)
// Try querying for every possible prefix,
// including the empty prefix,
// i.e. "abcde" will query for "", "a", "ab", "abc", and "abcd".
let mut results: [&[RuledefMapEntry]; MAX_PREFIX_SIZE + 1] =
[&[]; MAX_PREFIX_SIZE + 1];

for i in 0..(MAX_PREFIX_SIZE + 1)
{
Some(entries) => entries,
None => &[],
}
}
let mut subprefix = prefix;
for j in i..MAX_PREFIX_SIZE
{
subprefix[j] = '\0';
}

if let Some(entries) = self.prefixes_to_rules.get(&subprefix)
{
results[i] = entries;
}

pub fn query_unprefixed(
&self)
-> &[RuledefMapEntry]
{
&self.unprefixed
if i < MAX_PREFIX_SIZE &&
prefix[i] == '\0'
{
break;
}
}

results
}
}
5 changes: 2 additions & 3 deletions src/asm/matcher/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,10 +422,9 @@ fn match_with_ruledef_map<'tokens>(
let mut matches = WorkingMatches::new();

let prefix = asm::RuledefMap::parse_prefix(&walker);
let prefixed_entries = defs.ruledef_map.query_prefixed(prefix);
let unprefixed_entries = defs.ruledef_map.query_unprefixed();
let entries = defs.ruledef_map.query_prefixed(prefix);

for entry in prefixed_entries.iter().chain(unprefixed_entries)
for entry in entries.iter().flat_map(|e| e.iter())
{
let ruledef = defs.ruledefs.get(entry.ruledef_ref);
let rule = ruledef.get_rule(entry.rule_ref);
Expand Down
17 changes: 17 additions & 0 deletions tests/issue181/ok.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#subruledef SELECT
{
C => 0xc
}

#ruledef
{
A{sel:SELECT} => 0x1 @ sel
AB{sel:SELECT} => 0x2 @ sel
ABB{sel:SELECT} => 0x3 @ sel
ABBB{sel:SELECT} => 0x4 @ sel
}

AC ; = 0x1c
ABC ; = 0x2c
ABBC ; = 0x3c
ABBBC ; = 0x4c

0 comments on commit 3735e82

Please sign in to comment.