@jsonjoy.com/json-type
Version:
High-performance JSON Pointer implementation
199 lines • 9 kB
JavaScript
;
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