Skip to content

Commit cda06dd

Browse files
committed
Add idiom replacement; I don't want to do too many of these as these don't enhance general performance for every case, but the reduce lift is simple
1 parent 2d1a8b1 commit cda06dd

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

bench/test.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ import { LogicEngine, AsyncLogicEngine } from '../index.js'
22
import fs from 'fs'
33
import { isDeepStrictEqual } from 'util'
44
import jl from 'json-logic-js'
5-
import rust from '@bestow/jsonlogic-rs'
65

76
const x = new LogicEngine()
87
const y = new AsyncLogicEngine()
9-
108
const compatible = []
119
const incompatible = []
1210
JSON.parse(fs.readFileSync('./tests.json').toString()).forEach((test) => {
@@ -33,7 +31,7 @@ console.log(
3331
compatible.length / (compatible.length + incompatible.length)
3432
)
3533

36-
x.optimizedMap = new WeakMap()
34+
// x.optimizedMap = new WeakMap()
3735

3836
// eslint-disable-next-line no-unused-vars
3937
const defined = [

optimizer.js

+24
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,27 @@ function getMethod (logic, engine, methodName, above) {
7777
}
7878
}
7979

80+
/**
81+
* Macro-type replacements to lift inefficient logic into more efficient forms.
82+
*/
83+
function checkIdioms (logic, engine, above) {
84+
if (logic.reduce && Array.isArray(logic.reduce)) {
85+
let [root, mapper, defaultValue] = logic.reduce
86+
if (mapper['+'] && mapper['+'].length === 2 && mapper['+'][0].var && mapper['+'][1].var) {
87+
const accumulatorFound = mapper['+'][0].var === 'accumulator' || mapper['+'][1].var === 'accumulator'
88+
const currentFound = mapper['+'][0].var === 'current' || mapper['+'][1].var === 'current'
89+
defaultValue = defaultValue || 0
90+
if (accumulatorFound && currentFound) return optimize({ '+': [{ '+': root }, defaultValue] }, engine, above)
91+
}
92+
if (mapper['*'] && mapper['*'].length === 2 && mapper['*'][0].var && mapper['*'][1].var) {
93+
const accumulatorFound = mapper['*'][0].var === 'accumulator' || mapper['*'][1].var === 'accumulator'
94+
const currentFound = mapper['*'][0].var === 'current' || mapper['*'][1].var === 'current'
95+
defaultValue = typeof defaultValue === 'undefined' ? 1 : defaultValue
96+
if (accumulatorFound && currentFound) return optimize({ '*': [{ '*': root }, defaultValue] }, engine, above)
97+
}
98+
}
99+
}
100+
80101
/**
81102
* Processes the logic for the engine once so that it doesn't need to be traversed again.
82103
* @param {*} logic
@@ -92,6 +113,9 @@ export function optimize (logic, engine, above = []) {
92113
};
93114

94115
if (logic && typeof logic === 'object') {
116+
const idiomEnhancement = checkIdioms(logic, engine, above)
117+
if (idiomEnhancement) return idiomEnhancement
118+
95119
const keys = Object.keys(logic)
96120
const methodName = keys[0]
97121

0 commit comments

Comments
 (0)