From 7b396929fde0e82249b5539881f58789dbeccdbc Mon Sep 17 00:00:00 2001 From: jiyinyiyong Date: Mon, 11 Oct 2021 12:37:42 +0800 Subject: [PATCH] add index number in keyword in js for fast comparing; tag 0.5.0-a5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- package.json | 2 +- ts-src/calcit-data.ts | 21 +++++++++-- ts-src/calcit.procs.ts | 9 +++-- ts-src/js-cirru.ts | 8 +--- ts-src/js-record.ts | 83 ++++++++++++++++++------------------------ 7 files changed, 63 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c468d2e7..4600c0b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,7 +39,7 @@ dependencies = [ [[package]] name = "calcit_runner" -version = "0.5.0-a4" +version = "0.5.0-a5" dependencies = [ "cirru_edn", "cirru_parser", diff --git a/Cargo.toml b/Cargo.toml index ff42392c..2b0d5dd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "calcit_runner" -version = "0.5.0-a4" +version = "0.5.0-a5" authors = ["jiyinyiyong "] edition = "2018" license = "MIT" diff --git a/package.json b/package.json index d787292e..3d34d02b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@calcit/procs", - "version": "0.5.0-a4", + "version": "0.5.0-a5", "main": "./lib/calcit.procs.js", "devDependencies": { "@types/node": "^16.9.6", diff --git a/ts-src/calcit-data.ts b/ts-src/calcit-data.ts index f604e4f0..46df753f 100644 --- a/ts-src/calcit-data.ts +++ b/ts-src/calcit-data.ts @@ -13,16 +13,31 @@ import { CalcitTuple } from "./js-tuple"; // we have to inject cache in a dirty way in some cases const calcit_dirty_hash_key = "_calcit_cached_hash"; +let keywordIdx = 0; + export class CalcitKeyword { value: string; cachedHash: Hash; + // use keyword for fast comparing + idx: number; constructor(x: string) { this.value = x; + this.idx = keywordIdx; + keywordIdx++; this.cachedHash = null; } toString() { return `:${this.value}`; } + cmp(other: CalcitKeyword): number { + if (this.idx < other.idx) { + return -1; + } else if (this.idx > other.idx) { + return 1; + } else { + return 0; + } + } } export class CalcitSymbol { @@ -121,9 +136,9 @@ export function findInFields(xs: Array, y: CalcitKeyword): number while (upper - lower > 1) { let pos = (lower + upper) >> 1; let v = xs[pos]; - if (y.value < v.value) { + if (y.idx < v.idx) { upper = pos - 1; - } else if (y.value > v.value) { + } else if (y.idx > v.idx) { lower = pos + 1; } else { return pos; @@ -202,7 +217,7 @@ let hashFunction = (x: CalcitValue): Hash => { } if (x instanceof CalcitKeyword) { - let h = mergeValueHash(defaultHash_keyword, x.value); + let h = mergeValueHash(defaultHash_keyword, x.idx); x.cachedHash = h; return h; } diff --git a/ts-src/calcit.procs.ts b/ts-src/calcit.procs.ts index d5e2054f..27046df3 100644 --- a/ts-src/calcit.procs.ts +++ b/ts-src/calcit.procs.ts @@ -1,5 +1,5 @@ // CALCIT VERSION -export const calcit_version = "0.5.0-a4"; +export const calcit_version = "0.5.0-a5"; import { overwriteComparator, initTernaryTreeMap } from "@calcit/ternary-tree"; import { parse, ICirruNode } from "@cirru/parser.ts"; @@ -950,7 +950,7 @@ export let turn_keyword = (x: CalcitValue): CalcitKeyword => { throw new Error("Unexpected data for keyword"); }; -export let turn_symbol = (x: CalcitValue): CalcitKeyword => { +export let turn_symbol = (x: CalcitValue): CalcitSymbol => { if (typeof x === "string") { return new CalcitSymbol(x); } @@ -1325,6 +1325,7 @@ let rawCompare = (x: any, y: any): number => { }; export let _$n_compare = (a: CalcitValue, b: CalcitValue): number => { + if (a === b) return 0; let ta = typeAsInt(a); let tb = typeAsInt(b); if (ta === tb) { @@ -1335,9 +1336,9 @@ export let _$n_compare = (a: CalcitValue, b: CalcitValue): number => { return rawCompare(a, b); case PseudoTypeIndex.number: return rawCompare(a, b); - case PseudoTypeIndex.symbol: - return rawCompare(a, b); case PseudoTypeIndex.keyword: + return (a as CalcitKeyword).cmp(b as CalcitKeyword); + case PseudoTypeIndex.symbol: return rawCompare(a, b); case PseudoTypeIndex.string: return rawCompare(a, b); diff --git a/ts-src/js-cirru.ts b/ts-src/js-cirru.ts index 2d176290..fa075bf7 100644 --- a/ts-src/js-cirru.ts +++ b/ts-src/js-cirru.ts @@ -165,13 +165,7 @@ export let extract_cirru_edn = (x: CirruEdnFormat): CalcitValue => { } }); entries.sort((a, b) => { - if (a[0] < b[0]) { - return -1; - } else if (a[0] > b[0]) { - return 1; - } else { - return 0; - } + return a[0].cmp(b[0]); }); let fields: Array = []; let values: Array = []; diff --git a/ts-src/js-record.ts b/ts-src/js-record.ts index f92456a2..96ab5309 100644 --- a/ts-src/js-record.ts +++ b/ts-src/js-record.ts @@ -65,9 +65,9 @@ export class CalcitRecord { export let new_record = (name: CalcitValue, ...fields: Array): CalcitValue => { let fieldNames = fields.map(castKwd).sort((x, y) => { - if (x.value < y.value) { + if (x.idx < y.idx) { return -1; - } else if (x.value > y.value) { + } else if (x.idx > y.idx) { return 1; } else { throw new Error(`Unexpected duplication in record fields: ${x.toString()}`); @@ -76,16 +76,6 @@ export let new_record = (name: CalcitValue, ...fields: Array): Calc return new CalcitRecord(castKwd(name), fieldNames); }; -let fieldPairOrder = (a: [string, CalcitValue], b: [string, CalcitValue]) => { - if (a[0] < b[0]) { - return -1; - } else if (a[0] > b[0]) { - return 1; - } else { - return 0; - } -}; - export let fieldsEqual = (xs: Array, ys: Array): boolean => { if (xs === ys) { return true; // special case, referential equal @@ -146,46 +136,44 @@ export let _$n_record_$o_get_name = (x: CalcitRecord): CalcitKeyword => { }; export let _$n_record_$o_from_map = (proto: CalcitValue, data: CalcitValue): CalcitValue => { - if (proto instanceof CalcitRecord) { - if (data instanceof CalcitRecord) { - if (fieldsEqual(proto.fields, data.fields)) { - return new CalcitRecord(proto.name, proto.fields, data.values); - } else { - let values: Array = []; - for (let field of proto.fields) { - let idx = findInFields(data.fields, field); - if (idx < 0) { - throw new Error(`Cannot find field ${field} among ${data.fields}`); - } - values.push(data.values[idx]); - } - return new CalcitRecord(proto.name, proto.fields, values); - } - } else if (data instanceof CalcitMap) { - let pairs: Array<[string, CalcitValue]> = []; - for (let [k, v] of data.pairs()) { - pairs.push([getStringName(k), v]); - } - // mutable sort - pairs.sort(fieldPairOrder); + if (!(proto instanceof CalcitRecord)) throw new Error("Expected prototype to be record"); + if (data instanceof CalcitRecord) { + if (fieldsEqual(proto.fields, data.fields)) { + return new CalcitRecord(proto.name, proto.fields, data.values); + } else { let values: Array = []; - outerLoop: for (let field of proto.fields) { - for (let idx = 0; idx < pairs.length; idx++) { - let pair = pairs[idx]; - if (pair[0] === field.value) { - values.push(pair[1]); - continue outerLoop; // dirty code for performance - } + for (let field of proto.fields) { + let idx = findInFields(data.fields, field); + if (idx < 0) { + throw new Error(`Cannot find field ${field} among ${data.fields}`); } - throw new Error(`Cannot find field ${field} among ${pairs}`); + values.push(data.values[idx]); } return new CalcitRecord(proto.name, proto.fields, values); - } else { - throw new Error("Expected record or data for making a record"); } + } else if (data instanceof CalcitMap) { + let pairs: Array<[CalcitKeyword, CalcitValue]> = []; + for (let [k, v] of data.pairs()) { + pairs.push([castKwd(k), v]); + } + // mutable sort + pairs.sort((pair1, pair2) => pair1[0].cmp(pair2[0])); + + let values: Array = []; + outerLoop: for (let field of proto.fields) { + for (let idx = 0; idx < pairs.length; idx++) { + let pair = pairs[idx]; + if (pair[0] === field) { + values.push(pair[1]); + continue outerLoop; // dirty code for performance + } + } + throw new Error(`Cannot find field ${field} among ${pairs}`); + } + return new CalcitRecord(proto.name, proto.fields, values); } else { - throw new Error("Expected prototype to be record"); + throw new Error("Expected record or data for making a record"); } }; @@ -230,13 +218,14 @@ export function _$n_record_$o_extend_as(obj: CalcitValue, new_name: CalcitValue, new_fields.push(k); new_values.push(obj.values[i]); } else { - if (field.value < k.value) { + let ordering = field.cmp(k); + if (ordering === -1) { new_fields.push(field); new_values.push(new_value); new_fields.push(k); new_values.push(obj.values[i]); - } else if (field.value > k.value) { + } else if (ordering === 1) { new_fields.push(k); new_values.push(obj.values[i]); } else {