Iosevka/font-src/gen/caching/index.mjs

104 lines
2.6 KiB
JavaScript

import fs from "fs";
import zlib from "zlib";
import { encode, decode } from "@msgpack/msgpack";
const Edition = 23;
const MAX_AGE = 16;
class GfEntry {
constructor(age, value) {
this.age = age;
this.value = value;
}
}
class Cache {
constructor(freshAgeKey) {
this.freshAgeKey = freshAgeKey;
this.historyAgeKeys = [];
this.gf = new Map();
this.diff = new Set();
}
loadRep(version, rep) {
if (!rep || rep.version !== version + "@" + Edition) return;
this.historyAgeKeys = rep.ageKeys.slice(0, MAX_AGE);
const ageKeySet = new Set(this.historyAgeKeys);
for (const [k, e] of Object.entries(rep.gf)) {
if (ageKeySet.has(e.age)) this.gf.set(k, new GfEntry(e.age, e.value));
}
}
toRep(version, diffOnly) {
let gfRep = {};
for (const [k, e] of this.gf) {
if (!diffOnly || this.diff.has(k)) {
gfRep[k] = { age: e.age, value: e.value };
}
}
const mergedAgeKeys =
this.historyAgeKeys[0] === this.freshAgeKey
? this.historyAgeKeys
: [this.freshAgeKey, ...this.historyAgeKeys];
return {
version: version + "@" + Edition,
ageKeys: mergedAgeKeys,
gf: gfRep
};
}
isEmpty() {
return this.gf.size == 0;
}
isUpdated() {
return this.diff.size != 0;
}
// Geometry flattening conversion cache
getGF(k) {
const entry = this.gf.get(k);
if (!entry) return undefined;
else return entry.value;
}
refreshGF(k) {
const entry = this.gf.get(k);
if (!entry) return;
if (entry.age != this.freshAgeKey) {
this.diff.add(k);
entry.age = this.freshAgeKey;
}
}
saveGF(k, v) {
this.gf.set(k, new GfEntry(this.freshAgeKey, v));
this.diff.add(k);
}
merge(other) {
for (const [k, e] of other.gf) {
this.gf.set(k, e);
}
}
}
export async function load(path, version, freshAgeKey) {
let cache = new Cache(freshAgeKey);
if (path && fs.existsSync(path)) {
try {
const buf = zlib.gunzipSync(await fs.promises.readFile(path));
cache.loadRep(version, decode(buf));
} catch (e) {
console.error("Error loading cache. Treat as empty.");
console.error(e);
}
}
return cache;
}
export async function save(path, version, cache, diffOnly) {
if (path) {
const buf = encode(cache.toRep(version, diffOnly));
const bufZip = zlib.gzipSync(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength));
await fs.promises.writeFile(path, bufZip);
}
}
export async function merge(base, diff, version, freshAgeKey) {
const cacheDiff = await load(diff, version, freshAgeKey);
if (!cacheDiff.isEmpty()) {
const cacheBase = await load(base, version, freshAgeKey);
cacheBase.merge(cacheDiff);
await save(base, version, cacheBase, false);
}
if (fs.existsSync(diff)) await fs.promises.rm(diff);
}