UNPKG

@shumai/shumai

Version:

A fast, network-connected, differentiable tensor library for TypeScript (and JavaScript). Built with bun + flashlight for software engineers and researchers alike.

154 lines (146 loc) 3.69 kB
import { createReadStream } from 'node:fs' /** * * An extremely fast JavaScript native (bun) line reader for use with * arbitrary files. This is included as a utility for manual data pre-processing. * * @example * * ```javascript * for await (let line of sm.io.readlines('myfile.txt')) { * console.log(line.split(',')[0]) * } * ``` * * @param filename - The file to open and asynchronously read from * @param utfLabel - The label of the encoder * @param buffer_len - The size of the buffer to read into before flushing to the user * @returns A generator of each line in the file */ export async function* readlines(filename: string, utfLabel: Encoding = 'utf-8', buffer_len = 16) { const stream = Bun.file(filename).stream() const reader = stream.getReader() const td = new TextDecoder(utfLabel) let overflow = null let buffer = [] function flush_buffer() { const flushed = [] for (const b of buffer) { flushed.push(td.decode(b)) } buffer = [] return flushed } function add_to_buffer(b) { buffer.push(b) if (buffer.length >= buffer_len) { return flush_buffer() } return [] } while (true) { const b = await reader.read() if (!b.value) { break } const value = b.value let i = -1 let last_nl = 0 while ((i = value.indexOf('\n'.charCodeAt(0), i + 1)) >= 0) { const next_line = value.slice(last_nl, i) if (overflow && overflow.length) { const merge = new Uint8Array(overflow.length + next_line.length) merge.set(overflow) merge.set(next_line, overflow.length) for (const d of add_to_buffer(merge)) { yield d } overflow = null } else { for (const d of add_to_buffer(next_line)) { yield d } } if (i >= 0) { last_nl = i + 1 } } if (last_nl != value.length) { overflow = value.slice(last_nl, value.length) } } if (overflow) { for (const d of add_to_buffer(overflow)) { yield d } } for (const d of flush_buffer()) { yield d } } export function readlinesCallback( filename: string, callback, finishCallback?, utfLabel: Encoding = 'utf-8', buffer_len = 16 ) { const stdin = createReadStream(filename) const td = new TextDecoder(utfLabel) let overflow = null let buffer = [] function flush_buffer() { const flushed = [] for (const b of buffer) { flushed.push(td.decode(b)) } buffer = [] return flushed } function add_to_buffer(b) { buffer.push(b) if (buffer.length >= buffer_len) { return flush_buffer() } return [] } stdin.on('data', (value: Uint8Array) => { let i = -1 let last_nl = 0 while ((i = value.indexOf('\n'.charCodeAt(0), i + 1)) >= 0) { const next_line = value.slice(last_nl, i) if (overflow && overflow.length) { const merge = new Uint8Array(overflow.length + next_line.length) merge.set(overflow) merge.set(next_line, overflow.length) for (const d of add_to_buffer(merge)) { callback(d) } overflow = null } else { for (const d of add_to_buffer(next_line)) { callback(d) } } if (i >= 0) { last_nl = i + 1 } } if (last_nl != value.length) { overflow = value.slice(last_nl, value.length) } }) stdin.on('close', () => { if (overflow) { for (const d of add_to_buffer(overflow)) { callback(d) } } for (const d of flush_buffer()) { callback(d) } if (finishCallback) { finishCallback() } }) }