Skip to content

Commit

Permalink
Improve text mapper performance
Browse files Browse the repository at this point in the history
  • Loading branch information
shiro committed Dec 4, 2023
1 parent 4dac5a2 commit f45be3b
Showing 1 changed file with 70 additions and 5 deletions.
75 changes: 70 additions & 5 deletions src/mapper/text_mapper.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use nom::Slice;
use crate::*;
use crate::mapper::RuntimeKeyAction;
use crate::mapper::mapping_functions::*;
Expand All @@ -6,7 +7,7 @@ use crate::subscriber::{SubscribeEvent, Subscriber};
use crate::xkb::XKBTransformer;
use crate::xkb_transformer_registry::{TransformerParams, XKB_TRANSFORMER_REGISTRY};

type Mappings = HashMap<String, Vec<RuntimeKeyAction>>;
type Mappings = SuffixTree<Vec<RuntimeKeyAction>>;


#[derive(Default)]
Expand Down Expand Up @@ -34,6 +35,66 @@ fn _map(from: &KeyClickActionWithMods, to: Vec<ParsedKeyAction>) -> Vec<RuntimeK
seq
}

#[derive(Default)]
struct SuffixTree<Value> {
root: HashMap<char, SuffixTreeNode<Value>>,
}

impl<Value> SuffixTree<Value> {
pub fn new() -> Self { Self { root: HashMap::new() } }

pub fn insert(&mut self, key: String, value: Value) {
self.root.entry(key.chars().last().unwrap()).or_default().insert(&key[0..key.len() - 1], value);
}

pub fn get(&self, key: &String) -> Option<&Value> {
self.root.get(&key.chars().last().unwrap()).and_then(|x| x.get(&key[0..key.len() - 1]))
}
}

impl<Value: Clone> Clone for SuffixTree<Value> {
fn clone(&self) -> Self { Self { root: self.root.clone() } }
}

struct SuffixTreeNode<Value> {
value: Option<Value>,
children: HashMap<char, SuffixTreeNode<Value>>,
}

impl<Value> Default for SuffixTreeNode<Value> {
fn default() -> Self { Self { value: None, children: HashMap::new() } }
}

impl<Value> SuffixTreeNode<Value> {
pub fn new() -> Self {
Self { value: None, children: HashMap::new() }
}

pub fn insert(&mut self, key: &str, value: Value) {
if let Some(ch) = key.chars().last() {
self.children.entry(ch).or_default().insert(key.slice(0..key.len() - 1), value);
} else {
self.value = Some(value);
}
}

pub fn get(&self, key: &str) -> Option<&Value> {
if let Some(ch) = key.chars().last() {
self.children.get(&ch).and_then(|x| x.get(key.slice(0..key.len() - 1)))
} else {
self.value.as_ref()
}
}
}

impl<Value: Clone> Clone for SuffixTreeNode<Value> {
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
children: self.children.clone(),
}
}
}

#[derive(Default)]
struct Inner {
Expand Down Expand Up @@ -73,7 +134,8 @@ impl Inner {

if let Some(key) = key {
state.window.push(key.chars().next().unwrap());
if state.window.len() > 5 {
// TODO set window size dynamically
if state.window.len() > 32 {
state.window.remove(0);
}

Expand Down Expand Up @@ -110,7 +172,7 @@ impl Inner {
}
RuntimeKeyAction::ReleaseRestoreModifiers(from_flags, to_flags, to_type) => {
let new_events = release_restore_modifiers(
&state.modifiers, from_flags, to_flags, to_type,
&state.modifiers, &from_flags, &to_flags, &to_type,
);
// events.append(&mut new_events);
for ev in new_events {
Expand Down Expand Up @@ -195,8 +257,11 @@ impl TextMapper {
})
}


pub fn map(&mut self, from: String, to: String) -> PyResult<()> {
if from.len() > 32 {
return Err(PyRuntimeError::new_err("'from' side cannot be longer than 32 character"));
}

let from_seq: Vec<KeyClickActionWithMods> = parse_key_sequence(&from, Some(&self.transformer))
.map_err(|err| PyRuntimeError::new_err(format!(
"mapping error on the 'from' side:\n{}",
Expand All @@ -210,7 +275,7 @@ impl TextMapper {
}
})
.collect::<Option<Vec<_>>>()
.unwrap();
.ok_or_else(|| PyRuntimeError::new_err("invalid key sequence"))?;

let to = parse_key_sequence(&to, Some(&self.transformer))
.map_err(|err| PyRuntimeError::new_err(format!(
Expand Down

0 comments on commit f45be3b

Please sign in to comment.