src/vs/base/common/buffer.ts
499 LOC · 469 covered · 30 uncovered · 133 ranges · 13454 concepts · 58 introducers · 6883 tests
File neighbourhood
The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.
Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file
In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.
Graph controls are ready.
Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.
/*---------------------------------------------------------------------------------------------
buffer.ts ×42
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Lazy } from './lazy.js';
import * as streams from './stream.js';
interface NodeBuffer {
allocUnsafe(size: number): Uint8Array;
isBuffer(obj: unknown): obj is NodeBuffer;
from(arrayBuffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint8Array;
from(data: string): Uint8Array;
}
declare const Buffer: NodeBuffer;
const hasBuffer = (typeof Buffer !== 'undefined');
const indexOfTable = new Lazy(() => new Uint8Array(256));
let textEncoder: { encode: (input: string) => Uint8Array } | null;
let textDecoder: { decode: (input: Uint8Array) => string } | null;
export class VSBuffer {
/**
* When running in a nodejs context, the backing store for the returned `VSBuffer` instance
* might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
*/
static alloc(byteLength: number): VSBuffer {
return new VSBuffer(Buffer.allocUnsafe(byteLength));
} else {
return new VSBuffer(new Uint8Array(byteLength));
}
/**
* When running in a nodejs context, if `actual` is not a nodejs Buffer, the backing store for
* the returned `VSBuffer` instance might use a nodejs Buffer allocated from node's Buffer pool,
* which is not transferrable.
*/
static wrap(actual: Uint8Array): VSBuffer {
// https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length
buffer.ts ×1
// Create a zero-copy Buffer wrapper around the ArrayBuffer pointed to by the Uint8Array
actual = Buffer.from(actual.buffer, actual.byteOffset, actual.byteLength);
}
}
/**
* When running in a nodejs context, the backing store for the returned `VSBuffer` instance
* might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
*/
static fromString(source: string, options?: { dontUseNodeBuffer?: boolean }): VSBuffer {
if (!dontUseNodeBuffer && hasBuffer) {
return new VSBuffer(Buffer.from(source));
} else {
if (!textEncoder) {
textEncoder = new TextEncoder();
}
return new VSBuffer(textEncoder.encode(source));
}
/**
* When running in a nodejs context, the backing store for the returned `VSBuffer` instance
* might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
*/
static fromByteArray(source: number[]): VSBuffer {
for (let i = 0, len = source.length; i < len; i++) {
result.buffer[i] = source[i];
}
return result;
}
/**
* When running in a nodejs context, the backing store for the returned `VSBuffer` instance
* might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
*/
static concat(buffers: VSBuffer[], totalLength?: number): VSBuffer {
for (let i = 0, len = buffers.length; i < len; i++) {
}
const ret = VSBuffer.alloc(totalLength);
let offset = 0;
for (let i = 0, len = buffers.length; i < len; i++) {
ret.set(element, offset);
offset += element.byteLength;
}
return ret;
}
static isNativeBuffer(buffer: unknown): boolean {
}
readonly buffer: Uint8Array;
readonly byteLength: number;
private constructor(buffer: Uint8Array) {
this.byteLength = this.buffer.byteLength;
}
/**
* When running in a nodejs context, the backing store for the returned `VSBuffer` instance
* might use a nodejs Buffer allocated from node's Buffer pool, which is not transferrable.
*/
clone(): VSBuffer {
result.set(this);
return result;
}
toString(): string {
return this.buffer.toString();
} else {
if (!textDecoder) {
textDecoder = new TextDecoder(undefined, { ignoreBOM: true });
}
return textDecoder.decode(this.buffer);
}
slice(start?: number, end?: number): VSBuffer {
// creates shallow copy and NodeBuffer#slice doesn't. The use of subarray
// ensures the same, performance, behaviour.
return new VSBuffer(this.buffer.subarray(start, end));
}
set(array: VSBuffer, offset?: number): void;
set(array: Uint8Array, offset?: number): void;
set(array: ArrayBuffer, offset?: number): void;
set(array: ArrayBufferView, offset?: number): void;
set(array: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView, offset?: number): void;
set(array: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView, offset?: number): void {
this.buffer.set(array.buffer, offset);
} else if (array instanceof Uint8Array) {
} else if (array instanceof ArrayBuffer) {
this.buffer.set(new Uint8Array(array), offset);
this.buffer.set(new Uint8Array(array.buffer, array.byteOffset, array.byteLength), offset);
throw new Error(`Unknown argument 'array'`);
}
readUInt32BE(offset: number): number {
}
writeUInt32BE(value: number, offset: number): void {
}
readUInt32LE(offset: number): number {
}
writeUInt32LE(value: number, offset: number): void {
}
readUInt8(offset: number): number {
}
writeUInt8(value: number, offset: number): void {
}
indexOf(subarray: VSBuffer | Uint8Array, offset = 0) {
return binaryIndexOf(this.buffer, subarray instanceof VSBuffer ? subarray.buffer : subarray, offset);
buffer.ts ×2
}
equals(other: VSBuffer): boolean {
return true;
}
if (this.byteLength !== other.byteLength) {
return false;
}
return this.buffer.every((value, index) => value === other.buffer[index]);
}
/**
* Like String.indexOf, but works on Uint8Arrays.
* Uses the boyer-moore-horspool algorithm to be reasonably speedy.
*/
export function binaryIndexOf(haystack: Uint8Array, needle: Uint8Array, offset = 0): number {
const haystackLen = haystack.byteLength;
if (needleLen === 0) {
}
if (needleLen === 1) {
}
if (needleLen > haystackLen - offset) {
return -1;
}
// find index of the subarray using boyer-moore-horspool algorithm
const table = indexOfTable.value;
table.fill(needle.length);
for (let i = 0; i < needle.length; i++) {
table[needle[i]] = needle.length - i - 1;
}
let i = offset + needle.length - 1;
let j = i;
let result = -1;
while (i < haystackLen) {
if (haystack[i] === needle[j]) {
if (j === 0) {
result = i;
break;
}
i--;
j--;
} else {
i += Math.max(needle.length - j, table[haystack[i]]);
j = needle.length - 1;
}
}
return result;
}
export function readUInt16LE(source: Uint8Array, offset: number): number {
((source[offset + 0] << 0) >>> 0) |
((source[offset + 1] << 8) >>> 0)
);
}
export function writeUInt16LE(destination: Uint8Array, value: number, offset: number): void {
value = value >>> 8;
destination[offset + 1] = (value & 0b11111111);
}
export function readUInt32BE(source: Uint8Array, offset: number): number {
source[offset] * 2 ** 24
+ source[offset + 1] * 2 ** 16
+ source[offset + 2] * 2 ** 8
+ source[offset + 3]
);
}
export function writeUInt32BE(destination: Uint8Array, value: number, offset: number): void {
value = value >>> 8;
destination[offset + 2] = value;
value = value >>> 8;
destination[offset + 1] = value;
value = value >>> 8;
destination[offset] = value;
}
export function readUInt32LE(source: Uint8Array, offset: number): number {
((source[offset + 0] << 0) >>> 0) |
((source[offset + 1] << 8) >>> 0) |
((source[offset + 2] << 16) >>> 0) |
((source[offset + 3] << 24) >>> 0)
);
}
export function writeUInt32LE(destination: Uint8Array, value: number, offset: number): void {
value = value >>> 8;
destination[offset + 1] = (value & 0b11111111);
value = value >>> 8;
destination[offset + 2] = (value & 0b11111111);
value = value >>> 8;
destination[offset + 3] = (value & 0b11111111);
}
export function readUInt8(source: Uint8Array, offset: number): number {
}
export function writeUInt8(destination: Uint8Array, value: number, offset: number): void {
}
export interface VSBufferReadable extends streams.Readable<VSBuffer> { }
export interface VSBufferReadableStream extends streams.ReadableStream<VSBuffer> { }
export interface VSBufferWriteableStream extends streams.WriteableStream<VSBuffer> { }
export interface VSBufferReadableBufferedStream extends streams.ReadableBufferedStream<VSBuffer> { }
export function readableToBuffer(readable: VSBufferReadable): VSBuffer {
return streams.consumeReadable<VSBuffer>(readable, chunks => VSBuffer.concat(chunks));
buffer.ts ×1
}
export function bufferToReadable(buffer: VSBuffer): VSBufferReadable {
}
export function streamToBuffer(stream: streams.ReadableStream<VSBuffer>): Promise<VSBuffer> {
return streams.consumeStream<VSBuffer>(stream, chunks => VSBuffer.concat(chunks));
buffer.ts ×1
}
export async function bufferedStreamToBuffer(bufferedStream: streams.ReadableBufferedStream<VSBuffer>): Promise<VSBuffer> {
buffer.ts ×1
if (bufferedStream.ended) {
return VSBuffer.concat(bufferedStream.buffer);
}
return VSBuffer.concat([
// Include already read chunks...
...bufferedStream.buffer,
// ...and all additional chunks
await streamToBuffer(bufferedStream.stream)
]);
}
export function bufferToStream(buffer: VSBuffer): streams.ReadableStream<VSBuffer> {
}
export function streamToBufferReadableStream(stream: streams.ReadableStreamEvents<Uint8Array | string>): streams.ReadableStream<VSBuffer> {
return streams.transform<Uint8Array | string, VSBuffer>(stream, { data: data => typeof data === 'string' ? VSBuffer.fromString(data) : VSBuffer.wrap(data) }, chunks => VSBuffer.concat(chunks));
buffer.ts ×1
}
export function newWriteableBufferStream(options?: streams.WriteableStreamOptions): streams.WriteableStream<VSBuffer> {
return streams.newWriteableStream<VSBuffer>(chunks => VSBuffer.concat(chunks), options);
buffer.ts ×1
}
export function prefixedBufferReadable(prefix: VSBuffer, readable: VSBufferReadable): VSBufferReadable {
return streams.prefixedReadable(prefix, readable, chunks => VSBuffer.concat(chunks));
}
export function prefixedBufferStream(prefix: VSBuffer, stream: VSBufferReadableStream): VSBufferReadableStream {
return streams.prefixedStream(prefix, stream, chunks => VSBuffer.concat(chunks));
}
/** Decodes base64 to a uint8 array. URL-encoded and unpadded base64 is allowed. */
export function decodeBase64(encoded: string) {
let remainder = 0;
let bufi = 0;
// The simpler way to do this is `Uint8Array.from(atob(str), c => c.charCodeAt(0))`,
// but that's about 10-20x slower than this function in current Chromium versions.
const buffer = new Uint8Array(Math.floor(encoded.length / 4 * 3));
const append = (value: number) => {
switch (remainder) {
case 3:
buffer[bufi++] = building | value;
remainder = 0;
break;
case 2:
buffer[bufi++] = building | (value >>> 2);
building = value << 6;
remainder = 3;
break;
case 1:
buffer[bufi++] = building | (value >>> 4);
building = value << 4;
remainder = 2;
break;
default:
building = value << 2;
remainder = 1;
}
};
for (let i = 0; i < encoded.length; i++) {
const code = encoded.charCodeAt(i);
// See https://datatracker.ietf.org/doc/html/rfc4648#section-4
// This branchy code is about 3x faster than an indexOf on a base64 char string.
if (code >= 65 && code <= 90) {
append(code - 97 + 26); // a-z starts ranges from char code 97 to 122, starting at byte 26
buffer.ts ×2
} else if (code >= 48 && code <= 57) {
append(code - 48 + 52); // 0-9 starts ranges from char code 48 to 58, starting at byte 52
buffer.ts ×1
}
const unpadded = bufi;
while (remainder > 0) {
}
// slice is needed to account for overestimation due to padding
return VSBuffer.wrap(buffer).slice(0, unpadded);
}
const base64Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const base64UrlSafeAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
/** Encodes a buffer to a base64 string. */
export function encodeBase64({ buffer }: VSBuffer, padded = true, urlSafe = false) {
let output = '';
const remainder = buffer.byteLength % 3;
let i = 0;
for (; i < buffer.byteLength - remainder; i += 3) {
const b = buffer[i + 1];
const c = buffer[i + 2];
output += dictionary[a >>> 2];
output += dictionary[(a << 4 | b >>> 4) & 0b111111];
output += dictionary[(b << 2 | c >>> 6) & 0b111111];
output += dictionary[c & 0b111111];
}
if (remainder === 1) {
output += dictionary[a >>> 2];
output += dictionary[(a << 4) & 0b111111];
if (padded) { output += '=='; }
const b = buffer[i + 1];
output += dictionary[a >>> 2];
output += dictionary[(a << 4 | b >>> 4) & 0b111111];
output += dictionary[(b << 2) & 0b111111];
if (padded) { output += '='; }
}
return output;
}
const hexChars = '0123456789abcdef';
export function encodeHex({ buffer }: VSBuffer): string {
for (let i = 0; i < buffer.length; i++) {
const byte = buffer[i];
result += hexChars[byte >>> 4];
result += hexChars[byte & 0x0f];
}
return result;
}
export function decodeHex(hex: string): VSBuffer {
throw new SyntaxError('Hex string must have an even length');
}
for (let i = 0; i < hex.length;) {
out[i >> 1] = (decodeHexChar(hex, i++) << 4) | decodeHexChar(hex, i++);
}
}
const s = str.charCodeAt(position);
if (s >= 48 && s <= 57) { // '0'-'9'
}