Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 2x 2x 76x 76x 76x 76x 160x 160x 160x 160x 76x 2x 54x 54x 98x 98x 76x 76x 76x 76x 76x 76x 76x 76x 76x 76x 76x 76x 98x 12x 48x 12x 86x 26x 52x 26x 60x 60x 76x 76x 76x 76x 76x 22x 22x 22x 22x 22x 54x | import type {Path} from '@jsonjoy.com/json-pointer';
import {Codegen} from '@jsonjoy.com/codegen/lib/Codegen';
import type {MsgPackDecoder} from './MsgPackDecoder';
type Decoder = Pick<MsgPackDecoder, 'readObjHdr' | 'readStrHdr' | 'readArrHdr' | 'skipAny'>;
type Fn = (decoder: Decoder) => number;
const toUtf8 = (str: string) => {
const arr: number[] = [];
const length = str.length;
let curr = 0;
while (curr < length) {
let value = str.charCodeAt(curr++);
if ((value & 0xffffff80) === 0) {
arr.push(value);
continue;
} else Eif ((value & 0xfffff800) === 0) {
arr.push(((value >> 6) & 0x1f) | 0xc0);
} else {
Iif (value >= 0xd800 && value <= 0xdbff) {
Iif (curr < length) {
const extra = str.charCodeAt(curr);
Iif ((extra & 0xfc00) === 0xdc00) {
curr++;
value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;
}
}
}
if ((value & 0xffff0000) === 0) {
arr.push(((value >> 12) & 0x0f) | 0xe0);
arr.push(((value >> 6) & 0x3f) | 0x80);
} else {
arr.push(((value >> 18) & 0x07) | 0xf0);
arr.push(((value >> 12) & 0x3f) | 0x80);
arr.push(((value >> 6) & 0x3f) | 0x80);
}
}
arr.push((value & 0x3f) | 0x80);
}
return arr;
};
export const genShallowReader = (path: Path): Fn => {
const codegen = new Codegen<Fn>({
args: ['dec'],
name: 'readShallow',
prologue: 'var r = dec.reader;',
epilogue: 'return r.x;',
});
for (let i = 0; i < path.length; i++) {
const step = path[i];
switch (typeof step) {
case 'string': {
const rObj = codegen.getRegister();
const rIter = codegen.getRegister();
const rFound = codegen.getRegister();
codegen.js(/* js */ `var ${rObj} = dec.readObjHdr();`);
codegen.js(/* js */ `var ${rFound} = false;`);
codegen.js(`for(var ${rIter} = 0; ${rIter} < ${rObj}; ${rIter}++) {`);
const utf8Arr = toUtf8(step);
const length = utf8Arr.length;
const rKey = codegen.getRegister();
codegen.js(/* js */ `var ${rKey} = dec.readStrHdr();`);
codegen.js(/* js */ `if (${rKey} !== ${length}) { r.x += ${rKey}; dec.skipAny(); continue; };`);
while (utf8Arr.length > 0) {
if (utf8Arr.length >= 4) {
const word = utf8Arr.splice(0, 4);
const utf8Chunk = '0x' + word.map((x) => x.toString(16)).join('');
codegen.js(
`if (r.u32() !== ${utf8Chunk}) { ${
utf8Arr.length ? `r.x += ${utf8Arr.length}; ` : ''
}dec.skipAny(); continue; }`,
);
} else if (utf8Arr.length >= 2) {
const word = utf8Arr.splice(0, 2);
const utf8Chunk = '0x' + word.map((x) => x.toString(16)).join('');
codegen.js(
`if (r.u16() !== ${utf8Chunk}) { ${
utf8Arr.length ? `r.x += ${utf8Arr.length}; ` : ''
}dec.skipAny(); continue; }`,
);
} else {
const [octet] = utf8Arr.splice(0, 1);
codegen.js(
`if (r.u8() !== ${octet}) { ${
utf8Arr.length ? `r.x += ${utf8Arr.length}; ` : ''
}dec.skipAny(); continue; }`,
);
}
}
codegen.js(`${rFound} = true;`);
codegen.js(`break;`);
codegen.js(`}`);
codegen.js(`if (!${rFound}) throw new Error('KEY_NOT_FOUND');`);
break;
}
case 'number': {
const rObj = codegen.getRegister();
codegen.js(/* js */ `var ${rObj} = dec.readArrHdr();`);
codegen.js(/* js */ `if(${rObj} <= ${step}) throw new Error('INDEX_OUT_OF_BOUNDS');`);
for (let i = 0; i < step; i++) codegen.js(/* js */ `dec.skipAny();`);
break;
}
default: {
throw new Error('INVALID_PATH_STEP');
}
}
}
return codegen.compile();
};
|