all-package-names
Version:
Fast lookup and iteration over all NPM package names
69 lines • 2.68 kB
JavaScript
const DEFAULT_PAGE_SIZE = 16 * 1024;
const DEFAULT_CACHE_PAGES = 64;
/**
* Small paged reader for repeated random access against a file handle.
*
* Pages are cached in insertion order and the oldest page is evicted when the
* cache grows past `maxCachedPages`.
*/
export class PagedReader {
pageSize;
maxCachedPages;
cache = new Map();
handle;
constructor(handle, options = {}) {
this.handle = handle;
this.pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;
this.maxCachedPages = options.maxCachedPages ?? DEFAULT_CACHE_PAGES;
}
async read(offset, length) {
if (length <= 0) {
return Buffer.alloc(0);
}
const startPage = Math.floor(offset / this.pageSize);
const endPage = Math.floor((offset + length - 1) / this.pageSize);
const firstPageOffset = offset % this.pageSize;
if (startPage === endPage) {
const page = await this.readPage(startPage);
return page.subarray(firstPageOffset, firstPageOffset + length);
}
const buffer = Buffer.allocUnsafe(length);
let written = 0;
for (let pageNumber = startPage; pageNumber <= endPage; pageNumber += 1) {
const page = await this.readPage(pageNumber);
const sliceStart = pageNumber === startPage ? firstPageOffset : 0;
const remaining = length - written;
const sliceEnd = Math.min(page.length, sliceStart + remaining);
written += page.copy(buffer, written, sliceStart, sliceEnd);
}
return buffer;
}
async readByte(offset) {
if (offset < 0) {
return undefined;
}
const pageNumber = Math.floor(offset / this.pageSize);
const page = await this.readPage(pageNumber);
return page[offset % this.pageSize];
}
async readPage(pageNumber) {
const cached = this.cache.get(pageNumber);
if (cached !== undefined) {
this.cache.delete(pageNumber);
this.cache.set(pageNumber, cached);
return cached;
}
const buffer = Buffer.allocUnsafe(this.pageSize);
const { bytesRead } = await this.handle.read(buffer, 0, this.pageSize, pageNumber * this.pageSize);
const page = bytesRead === this.pageSize ? buffer : buffer.subarray(0, bytesRead);
this.cache.set(pageNumber, page);
if (this.cache.size > this.maxCachedPages) {
const first = this.cache.keys().next();
if (!first.done) {
this.cache.delete(first.value);
}
}
return page;
}
}
//# sourceMappingURL=paged-reader.js.map