deno.land / x / deno@v1.28.2 / runtime / js / 13_buffer.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// This code has been ported almost directly from Go's src/bytes/buffer.go// Copyright 2009 The Go Authors. All rights reserved. BSD license.// https://github.com/golang/go/blob/master/LICENSE"use strict";
((window) => { const { assert } = window.__bootstrap.infra; const { TypedArrayPrototypeSubarray, TypedArrayPrototypeSlice, TypedArrayPrototypeSet, MathFloor, MathMin, PromiseResolve, Uint8Array, Error, } = window.__bootstrap.primordials;
// MIN_READ is the minimum ArrayBuffer size passed to a read call by // buffer.ReadFrom. As long as the Buffer has at least MIN_READ bytes beyond // what is required to hold the contents of r, readFrom() will not grow the // underlying buffer. const MIN_READ = 32 * 1024; const MAX_SIZE = 2 ** 32 - 2;
// `off` is the offset into `dst` where it will at which to begin writing values // from `src`. // Returns the number of bytes copied. function copyBytes(src, dst, off = 0) { const r = dst.byteLength - off; if (src.byteLength > r) { src = TypedArrayPrototypeSubarray(src, 0, r); } TypedArrayPrototypeSet(dst, src, off); return src.byteLength; }
class Buffer { #buf = null; // contents are the bytes buf[off : len(buf)] #off = 0; // read at buf[off], write at buf[buf.byteLength]
constructor(ab) { if (ab == null) { this.#buf = new Uint8Array(0); return; }
this.#buf = new Uint8Array(ab); }
bytes(options = { copy: true }) { if (options.copy === false) { return TypedArrayPrototypeSubarray(this.#buf, this.#off); } return TypedArrayPrototypeSlice(this.#buf, this.#off); }
empty() { return this.#buf.byteLength <= this.#off; }
get length() { return this.#buf.byteLength - this.#off; }
get capacity() { return this.#buf.buffer.byteLength; }
truncate(n) { if (n === 0) { this.reset(); return; } if (n < 0 || n > this.length) { throw Error("bytes.Buffer: truncation out of range"); } this.#reslice(this.#off + n); }
reset() { this.#reslice(0); this.#off = 0; }
#tryGrowByReslice(n) { const l = this.#buf.byteLength; if (n <= this.capacity - l) { this.#reslice(l + n); return l; } return -1; }
#reslice(len) { assert(len <= this.#buf.buffer.byteLength); this.#buf = new Uint8Array(this.#buf.buffer, 0, len); }
readSync(p) { if (this.empty()) { // Buffer is empty, reset to recover space. this.reset(); if (p.byteLength === 0) { // this edge case is tested in 'bufferReadEmptyAtEOF' test return 0; } return null; } const nread = copyBytes( TypedArrayPrototypeSubarray(this.#buf, this.#off), p, ); this.#off += nread; return nread; }
read(p) { const rr = this.readSync(p); return PromiseResolve(rr); }
writeSync(p) { const m = this.#grow(p.byteLength); return copyBytes(p, this.#buf, m); }
write(p) { const n = this.writeSync(p); return PromiseResolve(n); }
#grow(n) { const m = this.length; // If buffer is empty, reset to recover space. if (m === 0 && this.#off !== 0) { this.reset(); } // Fast: Try to grow by means of a reslice. const i = this.#tryGrowByReslice(n); if (i >= 0) { return i; } const c = this.capacity; if (n <= MathFloor(c / 2) - m) { // We can slide things down instead of allocating a new // ArrayBuffer. We only need m+n <= c to slide, but // we instead let capacity get twice as large so we // don't spend all our time copying. copyBytes(TypedArrayPrototypeSubarray(this.#buf, this.#off), this.#buf); } else if (c + n > MAX_SIZE) { throw new Error("The buffer cannot be grown beyond the maximum size."); } else { // Not enough space anywhere, we need to allocate. const buf = new Uint8Array(MathMin(2 * c + n, MAX_SIZE)); copyBytes(TypedArrayPrototypeSubarray(this.#buf, this.#off), buf); this.#buf = buf; } // Restore this.#off and len(this.#buf). this.#off = 0; this.#reslice(MathMin(m + n, MAX_SIZE)); return m; }
grow(n) { if (n < 0) { throw Error("Buffer.grow: negative count"); } const m = this.#grow(n); this.#reslice(m); }
async readFrom(r) { let n = 0; const tmp = new Uint8Array(MIN_READ); while (true) { const shouldGrow = this.capacity - this.length < MIN_READ; // read into tmp buffer if there's not enough room // otherwise read directly into the internal buffer const buf = shouldGrow ? tmp : new Uint8Array(this.#buf.buffer, this.length);
const nread = await r.read(buf); if (nread === null) { return n; }
// write will grow if needed if (shouldGrow) { this.writeSync(TypedArrayPrototypeSubarray(buf, 0, nread)); } else this.#reslice(this.length + nread);
n += nread; } }
readFromSync(r) { let n = 0; const tmp = new Uint8Array(MIN_READ); while (true) { const shouldGrow = this.capacity - this.length < MIN_READ; // read into tmp buffer if there's not enough room // otherwise read directly into the internal buffer const buf = shouldGrow ? tmp : new Uint8Array(this.#buf.buffer, this.length);
const nread = r.readSync(buf); if (nread === null) { return n; }
// write will grow if needed if (shouldGrow) { this.writeSync(TypedArrayPrototypeSubarray(buf, 0, nread)); } else this.#reslice(this.length + nread);
n += nread; } } }
async function readAll(r) { const buf = new Buffer(); await buf.readFrom(r); return buf.bytes(); }
function readAllSync(r) { const buf = new Buffer(); buf.readFromSync(r); return buf.bytes(); }
async function writeAll(w, arr) { let nwritten = 0; while (nwritten < arr.length) { nwritten += await w.write(TypedArrayPrototypeSubarray(arr, nwritten)); } }
function writeAllSync(w, arr) { let nwritten = 0; while (nwritten < arr.length) { nwritten += w.writeSync(TypedArrayPrototypeSubarray(arr, nwritten)); } }
window.__bootstrap.buffer = { writeAll, writeAllSync, readAll, readAllSync, Buffer, };})(this);
Version Info