use std::collections::HashMap; use crate::regex::byte_range::ByteRange; pub struct DecisionTree { instrs: Vec, ret_vals: Vec, } #[repr(u32)] #[derive(Copy, Clone)] enum Instr { JumpIfGe(u8, u8), Ret(u8), } impl DecisionTree { pub fn decide(&self, val: u8) -> T { let mut pc = 0; loop { match self.instrs[pc] { Instr::JumpIfGe(pivot, rela) => { if val >= pivot { pc += rela as usize; } else { pc += 1; } } Instr::Ret(idx) => return self.ret_vals[idx as usize].clone(), } } } } impl DecisionTree { fn add_retval(&mut self, searched_val: &T) -> u8 { for (i, val) in self.ret_vals.iter().enumerate() { if val == searched_val { return i as u8; } } self.ret_vals.push(searched_val.clone()); (self.ret_vals.len() - 1) as u8 } fn merge(mut self, other: Self) -> Self { for ins in other.instrs.into_iter() { match ins { Instr::JumpIfGe(_, _) => self.instrs.push(ins), Instr::Ret(i) => { let i = self.add_retval(&other.ret_vals[i as usize]); self.instrs.push(Instr::Ret(i)); } } } self } fn build_inner(ranges: &[(ByteRange, T)]) -> Self { assert!(!ranges.is_empty()); if ranges.len() == 1 { Self { instrs: vec![Instr::Ret(0)], ret_vals: vec![ranges[0].1.clone()], } } else { let pivot = ranges.len() / 2; let a = Self::build_inner(&ranges[..pivot]); let b = Self::build_inner(&ranges[pivot..]); let decider = Self { instrs: vec![Instr::JumpIfGe( ranges[pivot].0.lower_bound(), a.instrs.len() as u8 + 1, )], ret_vals: Vec::new(), }; decider.merge(a).merge(b) } } pub fn build(map: HashMap, default: T) -> Self { let mut ranges: Vec = map.keys().cloned().collect(); ranges.push(ByteRange::all()); let ranges = ByteRange::split_to_disjoint(ranges); for i in 0..ranges.len() - 1 { assert_eq!(ranges[i].upper_bound() + 1, ranges[i + 1].lower_bound()); } let ranges: Vec<(ByteRange, T)> = ranges .into_iter() .map(|r| { let maps_to = map .iter() .filter_map(|(x, t)| if x.overlaps(r) { Some(t.clone()) } else { None }) .next() .unwrap_or(default.clone()); (r, maps_to) }) .collect(); Self::build_inner(&ranges) } } impl Default for DecisionTree { fn default() -> Self { Self { instrs: Default::default(), ret_vals: Default::default(), } } }