UNPKG

@jsonjoy.com/json-type

Version:

High-performance JSON Pointer implementation

199 lines 9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CapacityEstimatorCodegen = void 0; const codegen_1 = require("@jsonjoy.com/codegen"); const JsExpression_1 = require("@jsonjoy.com/codegen/lib/util/JsExpression"); const normalizeAccessor_1 = require("@jsonjoy.com/codegen/lib/util/normalizeAccessor"); const json_size_1 = require("@jsonjoy.com/util/lib/json-size"); const type_1 = require("../../type"); const discriminator_1 = require("../discriminator"); const util_1 = require("../util"); const AbstractCodege_1 = require("../AbstractCodege"); const value_1 = require("../../value"); class IncrementSizeStep { constructor(inc) { this.inc = inc; } } class CapacityEstimatorCodegen extends AbstractCodege_1.AbstractCodegen { constructor(type, name) { super(); this.type = type; this.codegen = new codegen_1.Codegen({ name: 'approxSize' + (name ? '_' + name : ''), args: ['r0'], prologue: /* js */ `var size = 0;`, epilogue: /* js */ `return size;`, linkable: { Value: value_1.Value, get: CapacityEstimatorCodegen.get, }, processSteps: (steps) => { const stepsJoined = []; for (let i = 0; i < steps.length; i++) { const step = steps[i]; if (step instanceof codegen_1.CodegenStepExecJs) stepsJoined.push(step); else if (step instanceof IncrementSizeStep) { stepsJoined.push(new codegen_1.CodegenStepExecJs(/* js */ `size += ${step.inc};`)); } } return stepsJoined; }, }); this.codegen.linkDependency(json_size_1.maxEncodingCapacity, 'maxEncodingCapacity'); } inc(amount) { this.codegen.js(/* js */ `size += ${amount};`); } onAny(path, r, type) { const codegen = this.codegen; const rv = codegen.var(r.use()); codegen.link('Value'); codegen.link('get'); codegen.if( /* js */ `${rv} instanceof Value`, () => { const rType = codegen.var(/* js */ `${rv}.type`); const rData = codegen.var(/* js */ `${rv}.data`); codegen.if( /* js */ `${rType}`, () => { codegen.js(/* js */ `size += get(${rType})(${rData});`); }, () => { codegen.js(/* js */ `size += maxEncodingCapacity(${rData});`); }); }, () => { codegen.js(/* js */ `size += maxEncodingCapacity(${rv});`); }); } onCon(path, r, type) { this.inc((0, json_size_1.maxEncodingCapacity)(type.literal())); } onBool(path, r, type) { this.inc(5 /* MaxEncodingOverhead.Boolean */); } onNum(path, r, type) { this.inc(22 /* MaxEncodingOverhead.Number */); } onStr(path, r, type) { this.inc(5 /* MaxEncodingOverhead.String */); this.codegen.js(/* js */ `size += ${5 /* MaxEncodingOverhead.StringLengthMultiplier */} * ${r.use()}.length;`); } onBin(path, r, type) { this.inc(41 /* MaxEncodingOverhead.Binary */); this.codegen.js(/* js */ `size += ${2 /* MaxEncodingOverhead.BinaryLengthMultiplier */} * ${r.use()}.length;`); } onArr(path, r, type) { const codegen = this.codegen; this.inc(5 /* MaxEncodingOverhead.Array */); const rLen = codegen.var(/* js */ `${r.use()}.length`); codegen.js(/* js */ `size += ${1 /* MaxEncodingOverhead.ArrayElement */} * ${rLen}`); const { _head = [], _type, _tail = [] } = type; const headLength = _head.length; const tailLength = _tail.length; if (_type) { const isConstantSizeType = _type instanceof type_1.ConType || _type instanceof type_1.BoolType || _type instanceof type_1.NumType; if (isConstantSizeType) { const elementSize = _type instanceof type_1.ConType ? (0, json_size_1.maxEncodingCapacity)(_type.literal()) : _type instanceof type_1.BoolType ? 5 /* MaxEncodingOverhead.Boolean */ : 22 /* MaxEncodingOverhead.Number */; codegen.js(/* js */ `size += (${rLen} - ${headLength + tailLength}) * ${elementSize};`); } else { const rv = codegen.var(r.use()); const ri = codegen.getRegister(); codegen.js(/* js */ `for(var ${ri} = ${headLength}; ${ri} < ${rLen} - ${tailLength}; ${ri}++) {`); this.onNode([...path, { r: ri }], new JsExpression_1.JsExpression(() => /* js */ `${rv}[${ri}]`), _type); codegen.js(/* js */ `}`); } } if (headLength > 0) { const rr = codegen.var(r.use()); for (let i = 0; i < headLength; i++) this.onNode([...path, i], new JsExpression_1.JsExpression(() => /* js */ `${rr}[${i}]`), _head[i]); } if (tailLength > 0) { const rr = codegen.var(r.use()); for (let i = 0; i < tailLength; i++) this.onNode([...path, { r: `${rLen} - ${tailLength - i}` }], new JsExpression_1.JsExpression(() => /* js */ `${rr}[${rLen} - ${tailLength - i}]`), _tail[i]); } } onObj(path, r, type) { const codegen = this.codegen; const rv = codegen.var(r.use()); const encodeUnknownFields = !!type.schema.encodeUnknownKeys; if (encodeUnknownFields) { codegen.js(/* js */ `size += maxEncodingCapacity(${rv});`); return; } this.inc(5 /* MaxEncodingOverhead.Object */); const fields = type.keys; for (const field of fields) { const accessor = (0, normalizeAccessor_1.normalizeAccessor)(field.key); const fieldExpression = new JsExpression_1.JsExpression(() => `${rv}${accessor}`); const isOptional = field instanceof type_1.KeyOptType; if (isOptional) { codegen.if(/* js */ `${JSON.stringify(field.key)} in ${rv}`, () => { this.inc(2 /* MaxEncodingOverhead.ObjectElement */); this.inc((0, json_size_1.maxEncodingCapacity)(field.key)); this.onNode([...path, field.key], fieldExpression, field.val); }); } else { this.inc(2 /* MaxEncodingOverhead.ObjectElement */); this.inc((0, json_size_1.maxEncodingCapacity)(field.key)); this.onNode([...path, field.key], fieldExpression, field.val); } } } onKey(path, r, type) { this.onNode([...path, type.key], r, type.val); } onMap(path, r, type) { const codegen = this.codegen; this.inc(5 /* MaxEncodingOverhead.Object */); const rv = codegen.var(r.use()); const rKeys = codegen.var(/* js */ `Object.keys(${rv})`); const rKey = codegen.var(); const rLen = codegen.var(/* js */ `${rKeys}.length`); codegen.js(/* js */ `size += ${2 /* MaxEncodingOverhead.ObjectElement */} * ${rLen}`); const valueType = type._value; const ri = codegen.var('0'); codegen.js(/* js */ `for (; ${ri} < ${rLen}; ${ri}++) {`); codegen.js(/* js */ `${rKey} = ${rKeys}[${ri}];`); codegen.js( /* js */ `size += ${5 /* MaxEncodingOverhead.String */} + ${5 /* MaxEncodingOverhead.StringLengthMultiplier */} * ${rKey}.length;`); this.onNode([...path, { r: rKey }], new JsExpression_1.JsExpression(() => /* js */ `${rv}[${rKey}]`), valueType); codegen.js(/* js */ `}`); } onRef(path, r, type) { const system = type.getSystem(); const alias = system.resolve(type.ref()); const estimator = CapacityEstimatorCodegen.get(alias.type); const d = this.codegen.linkDependency(estimator); this.codegen.js(/* js */ `size += ${d}(${r.use()});`); } onOr(path, r, type) { const codegen = this.codegen; const discriminator = discriminator_1.DiscriminatorCodegen.get(type); const d = codegen.linkDependency(discriminator); const types = type.types; codegen.switch( /* js */ `${d}(${r.use()})`, types.map((childType, index) => [ index, () => { this.onNode(path, r, childType); }, ])); } } exports.CapacityEstimatorCodegen = CapacityEstimatorCodegen; CapacityEstimatorCodegen.get = (0, util_1.lazyKeyedFactory)((type, name) => { const codegen = new CapacityEstimatorCodegen(type, name); const r = codegen.codegen.options.args[0]; const expression = new JsExpression_1.JsExpression(() => r); codegen.onNode([], expression, type); return codegen.compile(); }); //# sourceMappingURL=CapacityEstimatorCodegen.js.map