sclass LineCompSemiCached implements AutoCloseable { File f; // must be the raw text version RandomAccessFile raf; int[] literalOffsets; int[] pairs; Map files; S encoding = "UTF-8"; transient Lock lock = lock(); *() {} *(File f) { if (isGZipFile(f)) fail("Must not be gzipped: " + f2s(f)); init(f); } LineCompReader init(File f) { this.f = f; LineCompReader reader = new(f); literalOffsets = reader.literalOffsets; pairs = intPairsToIntArray(reader.pairs); files = mapValues toIntArray(reader.versions); ret reader; } void openFile { lock lock; if (raf == null) raf = randomAccessFileForReading(f); } S getLiteral(int i) { openFile(); int start = literalOffsets[i]; ret bytesToString(raf_readFilePart(raf, start, literalOffsets[i+1]-start), encoding); } public void close ctex { if (raf != null) raf.close(); } int nLiterals() { ret literalOffsets.length-1; } S getFile(S name) { int[] encoded = files.get(name); if (encoded == null) null; new StringBuilder buf; for (int idx : encoded) decode(idx, buf); ret str(buf); } Set files() { ret keys(files); } void decode(int idx, StringBuilder buf) { if (idx < nLiterals()) { if (empty(buf)) buf.append('\n'); buf.append(getLiteral(idx)); } else { int idx2 = (idx-nLiterals())*2; decode(pairs[idx2], buf); decode(pairs[idx2+1], buf); } } }