110 lines
3.5 KiB
HTML
110 lines
3.5 KiB
HTML
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<style type="text/css">
|
|
pre {
|
|
font-family: monospace;
|
|
display: block;
|
|
white-space: pre;
|
|
font-size: 2em;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<script type="text/javascript">
|
|
|
|
const MIN = 0;
|
|
const MAX = 0xFFFFFFFF;
|
|
|
|
function zeropad(a, n) {
|
|
return "0".repeat(n - a.length) + a;
|
|
}
|
|
|
|
// const encodeNumber = n => zeropad((n >>> 0).toString(16), 8);
|
|
|
|
function encodeNumber(n) {
|
|
const a = (n & 0xFFFF0000) >>> 16;
|
|
const b = (n & 0xFFFF) >>> 0;
|
|
//return zeropad(a.toString(16), 4) + zeropad(b.toString(16), 4);
|
|
return String.fromCharCode(a, b);
|
|
}
|
|
|
|
function decodeNumber(s) {
|
|
const a = s.charCodeAt(0);
|
|
const b = s.charCodeAt(1);
|
|
//return `${a.toString(16)} ${b}`;
|
|
return ((a << 16) | b) >>> 0;
|
|
}
|
|
|
|
function formatArg(a) {
|
|
if (typeof a === "string") {
|
|
return `"${a}"`;
|
|
}
|
|
if (Array.isArray(a)) {
|
|
return `[${a.map(formatArg)}]`;
|
|
}
|
|
return a+"";
|
|
}
|
|
function cmp(a, b) {
|
|
let value;
|
|
try {
|
|
const result = indexedDB.cmp(encodeNumber(a), encodeNumber(b));
|
|
if (result < 0) {
|
|
value = "a < b";
|
|
} else if (result === 0) {
|
|
value = "a = b";
|
|
} else if (result > 0) {
|
|
value = "a > b";
|
|
}
|
|
} catch(err) {
|
|
value = err.message;
|
|
}
|
|
return `cmp(${formatArg(a)} as ${formatArg(encodeNumber(a))},\n ${formatArg(b)} as ${formatArg(encodeNumber(b))}): ${value}`;
|
|
}
|
|
|
|
try {
|
|
const tests = [
|
|
// see https://stackoverflow.com/questions/28413947/space-efficient-way-to-encode-numbers-as-sortable-strings
|
|
// need to encode numbers with base 256 and zero padded at start
|
|
// should still fit in 8 bytes then?
|
|
(cmp) => cmp(9, 100000),
|
|
(cmp) => cmp(1, 2),
|
|
(cmp) => cmp(MIN, 1),
|
|
(cmp) => cmp(MIN, MIN),
|
|
(cmp) => cmp(MIN, MAX),
|
|
(cmp) => cmp(MAX >>> 1, MAX),
|
|
(cmp) => cmp(0x7fffffff, 0xffff7fff),
|
|
(cmp) => cmp(MAX, MAX),
|
|
(cmp) => cmp(MAX - 1, MAX),
|
|
];
|
|
|
|
for (const fn of tests) {
|
|
const txt = document.createTextNode(fn(cmp));
|
|
const p = document.createElement("pre");
|
|
p.appendChild(txt);
|
|
document.body.appendChild(p);
|
|
}
|
|
} catch(err) {
|
|
alert(err.message);
|
|
}
|
|
|
|
let prev;
|
|
for (let i = MIN; i <= MAX; i += 100) {
|
|
if (decodeNumber(encodeNumber(i)) !== i) {
|
|
document.write(`<p>${i} decodes back to ${decodeNumber(encodeNumber(i))}</p>`);
|
|
break;
|
|
}
|
|
if (typeof prev === "number") {
|
|
if (indexedDB.cmp(encodeNumber(prev), encodeNumber(i)) >= 0) {
|
|
document.write(`<p>${i} <= ${prev}</p>`);
|
|
break;
|
|
}
|
|
}
|
|
prev = i;
|
|
}
|
|
document.write(`<p>check from ${MIN} to ${prev}</p>`);
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|