Files
scriptc/tests/corpus/string-char-code-integer-loops.ts
T

83 lines
2.8 KiB
TypeScript

// charCodeAt at counted-loop counters and other proven integers: in-range
// reads, negative and past-the-end indices, non-ASCII and surrogate text,
// and counters near the 2^31 and 2^53 bounds. (4990-lone-surrogates covers
// lone surrogates.)
const texts = ["", "a", "plain ascii text", "caf\u00e9 cr\u00e8me", "emoji \ud83d\ude00 pair", "\u4e2d\u6587\u5b57"];
function codes(s: string): string {
let out = "";
for (let i = 0; i < s.length; i++) out += s.charCodeAt(i) + ",";
return out;
}
function inclusive(s: string): string {
let out = "";
for (let i = 0; i <= s.length; i++) out += s.charCodeAt(i) + ",";
return out;
}
function neighbours(s: string): string {
let out = "";
for (let i = 0; i < s.length; i++) out += `${s.charCodeAt(i - 1)}/${s.charCodeAt(i + 1)}/${s.charCodeAt(i * 2)},`;
return out;
}
function backwards(s: string): string {
let out = "";
for (let i = s.length - 1; i >= -2; i--) out += s.charCodeAt(i) + ",";
return out;
}
function hash(s: string): number {
let h = 0x811c9dc5 | 0;
for (let i = 0; i < s.length; i++) h = Math.imul(h ^ s.charCodeAt(i), 0x01000193);
return h >>> 0;
}
for (const s of texts) {
console.log(JSON.stringify(s), s.length, codes(s), inclusive(s), neighbours(s), backwards(s), hash(s));
}
// A counter that starts negative or at -0.
function fromStart(s: string, start: number): string {
let out = "";
for (let i = start; i < 3; i++) out += `${Object.is(i, -0) ? "-0" : i}:${s.charCodeAt(i)},`;
return out;
}
for (const start of [-3, -0, 0, 1]) console.log("start", start, fromStart("xyz", start), fromStart("", start));
// Counters far beyond any string length.
function wide(s: string, start: number): string {
let out = "";
let steps = 0;
for (let i = start; i < start + 4; i++) {
out += `${i}:${s.charCodeAt(i)}:${s.charCodeAt(i - start)},`;
if (++steps === 4) break;
}
return out;
}
for (const start of [2147483646, 4294967294, 9007199254740989]) console.log("wide", wide("abcd", start));
// Bounds derived from indexOf and length.
function afterSlash(path: string): number {
let sum = 0;
for (let i = path.indexOf("/") + 1; i < path.length; i++) sum += path.charCodeAt(i);
return sum;
}
function countDots(path: string): number {
const n = path.length;
let dots = 0;
for (let i = 0; i < n; i++) if (path.charCodeAt(i) === 46) dots++;
return dots;
}
for (const path of ["a/b.c", "/x/./y/../z", "no-slash", "", "\u00e9/\u00e8.\u00ea"]) {
console.log("path", JSON.stringify(path), afterSlash(path), countDots(path), path.indexOf("."), path.length);
}
// The receiver changes inside the loop.
function changing(seed: string): string {
let s = seed;
let out = "";
for (let i = 0; i < 6; i++) {
out += s.charCodeAt(i) + ",";
s = i % 2 === 0 ? s + "\u00df" : s.slice(1);
}
return out;
}
console.log("changing", changing("ab"), changing(""));