From 50a47348a7a040d1bcaf0a12a38cca049dc207f7 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 5 Oct 2019 16:24:42 -0400 Subject: [PATCH] Optimize internal data structure used by the Deinflector class --- ext/bg/js/deinflector.js | 73 ++++++++++++++++++++++++++-------------- ext/bg/js/translator.js | 17 ++-------- 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/ext/bg/js/deinflector.js b/ext/bg/js/deinflector.js index ad77895c..ce4b2961 100644 --- a/ext/bg/js/deinflector.js +++ b/ext/bg/js/deinflector.js @@ -19,51 +19,74 @@ class Deinflector { constructor(reasons) { - this.reasons = reasons; + this.reasons = Deinflector.normalizeReasons(reasons); } deinflect(source) { const results = [{ source, term: source, - rules: [], + rules: 0, definitions: [], reasons: [] }]; for (let i = 0; i < results.length; ++i) { - const entry = results[i]; - - for (const reason in this.reasons) { - for (const variant of this.reasons[reason]) { - let accept = entry.rules.length === 0; - if (!accept) { - for (const rule of entry.rules) { - if (variant.rulesIn.includes(rule)) { - accept = true; - break; - } - } - } - - if (!accept || !entry.term.endsWith(variant.kanaIn)) { - continue; - } - - const term = entry.term.slice(0, -variant.kanaIn.length) + variant.kanaOut; - if (term.length === 0) { + const {rules, term, reasons} = results[i]; + for (const [reason, variants] of this.reasons) { + for (const [kanaIn, kanaOut, rulesIn, rulesOut] of variants) { + if ( + (rules !== 0 && (rules & rulesIn) === 0) || + !term.endsWith(kanaIn) || + (term.length - kanaIn.length + kanaOut.length) <= 0 + ) { continue; } results.push({ source, - term, - rules: variant.rulesOut, + term: term.slice(0, -kanaIn.length) + kanaOut, + rules: rulesOut, definitions: [], - reasons: [reason, ...entry.reasons] + reasons: [reason, ...reasons] }); } } } return results; } + + static normalizeReasons(reasons) { + const normalizedReasons = []; + for (const reason in reasons) { + const variants = []; + for (const {kanaIn, kanaOut, rulesIn, rulesOut} of reasons[reason]) { + variants.push([ + kanaIn, + kanaOut, + Deinflector.rulesToRuleFlags(rulesIn), + Deinflector.rulesToRuleFlags(rulesOut) + ]); + } + normalizedReasons.push([reason, variants]); + } + return normalizedReasons; + } + + static rulesToRuleFlags(rules) { + const ruleTypes = Deinflector.ruleTypes; + let value = 0; + for (const rule of rules) { + value |= ruleTypes[rule]; + } + return value; + } } + +Deinflector.ruleTypes = { + 'v1': 0b0000001, // Verb ichidan + 'v5': 0b0000010, // Verb godan + 'vs': 0b0000100, // Verb suru + 'vk': 0b0001000, // Verb kuru + 'adj-i': 0b0010000, // Adjective i + 'iru': 0b0100000, // Intermediate -iru endings for progressive or perfect tense +}; diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 65d746ea..601ee30c 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -238,8 +238,10 @@ class Translator { const definitions = await this.database.findTermsBulk(uniqueDeinflectionTerms, titles); for (const definition of definitions) { + const definitionRules = Deinflector.rulesToRuleFlags(definition.rules); for (const deinflection of uniqueDeinflectionArrays[definition.index]) { - if (Translator.definitionContainsAnyRule(definition, deinflection.rules)) { + const deinflectionRules = deinflection.rules; + if (deinflectionRules === 0 || (definitionRules & deinflectionRules) !== 0) { deinflection.definitions.push(definition); } } @@ -248,19 +250,6 @@ class Translator { return deinflections.filter(e => e.definitions.length > 0); } - static definitionContainsAnyRule(definition, rules) { - if (rules.length === 0) { - return true; - } - const definitionRules = definition.rules; - for (const rule of rules) { - if (definitionRules.includes(rule)) { - return true; - } - } - return false; - } - getDeinflections(text) { const deinflections = [];