Skip to content

Commit 656db0f

Browse files
authored
perf: runtime function type checking overhead (#62)
<!-- ps-id: fd3afb3d-774f-4fe5-8171-afc0c54be315 -->
1 parent 251133b commit 656db0f

File tree

2 files changed

+61
-19
lines changed

2 files changed

+61
-19
lines changed

scripts/perf.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ async function runBenchmarks() {
1414
time: 1000,
1515
});
1616

17+
// Test data for TreeInterpreter benchmarks
18+
const simpleData = { foo: { bar: 'baz' } };
19+
const arrayData = { items: Array.from({ length: 100 }, (_, i) => ({ id: i, name: `item${i}`, price: i * 10 })) };
20+
const nestedData = { level1: { level2: { level3: { level4: { value: 42 } } } } };
21+
1722
// Baseline parsing benchmarks
1823
bench
1924
.add('Parser#single_expr', () => {
@@ -44,6 +49,41 @@ async function runBenchmarks() {
4449
})
4550
.add('Lexer#function_calls', () => {
4651
jmespath.compile('sort_by(items, &price).name');
52+
})
53+
// TreeInterpreter evaluation benchmarks
54+
.add('Eval#simple_field', () => {
55+
jmespath.search(simpleData, 'foo.bar');
56+
})
57+
.add('Eval#array_projection', () => {
58+
jmespath.search(arrayData, 'items[*].name');
59+
})
60+
.add('Eval#filter_projection', () => {
61+
jmespath.search(arrayData, 'items[?price > `500`].name');
62+
})
63+
.add('Eval#function_call', () => {
64+
jmespath.search(arrayData, 'length(items)');
65+
})
66+
.add('Eval#nested_access', () => {
67+
jmespath.search(nestedData, 'level1.level2.level3.level4.value');
68+
})
69+
.add('Eval#slice_operation', () => {
70+
jmespath.search(arrayData, 'items[10:20]');
71+
})
72+
// Runtime function call benchmarks
73+
.add('Runtime#length_function', () => {
74+
jmespath.search(arrayData, 'length(items)');
75+
})
76+
.add('Runtime#max_function', () => {
77+
jmespath.search(arrayData, 'max(items[*].price)');
78+
})
79+
.add('Runtime#sort_by_function', () => {
80+
jmespath.search(arrayData, 'sort_by(items, &price)');
81+
})
82+
.add('Runtime#map_function', () => {
83+
jmespath.search(arrayData, 'map(&name, items)');
84+
})
85+
.add('Runtime#contains_function', () => {
86+
jmespath.search(arrayData, 'contains(items[*].name, `"item50"`)');
4787
});
4888

4989
await bench.run();

src/Runtime.ts

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -201,26 +201,28 @@ export class Runtime {
201201
return false;
202202
}
203203
private getTypeName(obj: JSONValue | ExpressionNode): InputArgument | undefined {
204-
switch (Object.prototype.toString.call(obj)) {
205-
case '[object String]':
206-
return InputArgument.TYPE_STRING;
207-
case '[object Number]':
208-
return InputArgument.TYPE_NUMBER;
209-
case '[object Array]':
210-
return InputArgument.TYPE_ARRAY;
211-
case '[object Boolean]':
212-
return InputArgument.TYPE_BOOLEAN;
213-
case '[object Null]':
214-
return InputArgument.TYPE_NULL;
215-
case '[object Object]':
216-
if ((obj as ObjectDict).expref) {
217-
return InputArgument.TYPE_EXPREF;
218-
}
219-
return InputArgument.TYPE_OBJECT;
220-
221-
default:
222-
return;
204+
if (obj === null) {
205+
return InputArgument.TYPE_NULL;
206+
}
207+
if (typeof obj === 'string') {
208+
return InputArgument.TYPE_STRING;
209+
}
210+
if (typeof obj === 'number') {
211+
return InputArgument.TYPE_NUMBER;
212+
}
213+
if (typeof obj === 'boolean') {
214+
return InputArgument.TYPE_BOOLEAN;
215+
}
216+
if (Array.isArray(obj)) {
217+
return InputArgument.TYPE_ARRAY;
218+
}
219+
if (typeof obj === 'object') {
220+
if ((obj as ObjectDict).expref) {
221+
return InputArgument.TYPE_EXPREF;
222+
}
223+
return InputArgument.TYPE_OBJECT;
223224
}
225+
return;
224226
}
225227

226228
createKeyFunction(exprefNode: ExpressionNode, allowedTypes: InputArgument[]): (x: JSONValue) => JSONValue {

0 commit comments

Comments
 (0)