Files
start-sdk/lib/esm/deps/deno.land/std@0.140.0/bytes/mod.js
2023-02-27 10:38:56 -07:00

242 lines
7.4 KiB
JavaScript

// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.
/**
* Provides helper functions to manipulate `Uint8Array` byte slices that are not
* included on the `Uint8Array` prototype.
*
* @module
*/
/** Returns the index of the first occurrence of the needle array in the source
* array, or -1 if it is not present.
*
* A start index can be specified as the third argument that begins the search
* at that given index. The start index defaults to the start of the array.
*
* The complexity of this function is O(source.lenth * needle.length).
*
* ```ts
* import { indexOfNeedle } from "./mod.ts";
* const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]);
* const needle = new Uint8Array([1, 2]);
* console.log(indexOfNeedle(source, needle)); // 1
* console.log(indexOfNeedle(source, needle, 2)); // 3
* ```
*/
export function indexOfNeedle(source, needle, start = 0) {
if (start >= source.length) {
return -1;
}
if (start < 0) {
start = Math.max(0, source.length + start);
}
const s = needle[0];
for (let i = start; i < source.length; i++) {
if (source[i] !== s)
continue;
const pin = i;
let matched = 1;
let j = i;
while (matched < needle.length) {
j++;
if (source[j] !== needle[j - pin]) {
break;
}
matched++;
}
if (matched === needle.length) {
return pin;
}
}
return -1;
}
/** Returns the index of the last occurrence of the needle array in the source
* array, or -1 if it is not present.
*
* A start index can be specified as the third argument that begins the search
* at that given index. The start index defaults to the end of the array.
*
* The complexity of this function is O(source.lenth * needle.length).
*
* ```ts
* import { lastIndexOfNeedle } from "./mod.ts";
* const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]);
* const needle = new Uint8Array([1, 2]);
* console.log(lastIndexOfNeedle(source, needle)); // 5
* console.log(lastIndexOfNeedle(source, needle, 4)); // 3
* ```
*/
export function lastIndexOfNeedle(source, needle, start = source.length - 1) {
if (start < 0) {
return -1;
}
if (start >= source.length) {
start = source.length - 1;
}
const e = needle[needle.length - 1];
for (let i = start; i >= 0; i--) {
if (source[i] !== e)
continue;
const pin = i;
let matched = 1;
let j = i;
while (matched < needle.length) {
j--;
if (source[j] !== needle[needle.length - 1 - (pin - j)]) {
break;
}
matched++;
}
if (matched === needle.length) {
return pin - needle.length + 1;
}
}
return -1;
}
/** Returns true if the prefix array appears at the start of the source array,
* false otherwise.
*
* The complexity of this function is O(prefix.length).
*
* ```ts
* import { startsWith } from "./mod.ts";
* const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]);
* const prefix = new Uint8Array([0, 1, 2]);
* console.log(startsWith(source, prefix)); // true
* ```
*/
export function startsWith(source, prefix) {
for (let i = 0, max = prefix.length; i < max; i++) {
if (source[i] !== prefix[i])
return false;
}
return true;
}
/** Returns true if the suffix array appears at the end of the source array,
* false otherwise.
*
* The complexity of this function is O(suffix.length).
*
* ```ts
* import { endsWith } from "./mod.ts";
* const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]);
* const suffix = new Uint8Array([1, 2, 3]);
* console.log(endsWith(source, suffix)); // true
* ```
*/
export function endsWith(source, suffix) {
for (let srci = source.length - 1, sfxi = suffix.length - 1; sfxi >= 0; srci--, sfxi--) {
if (source[srci] !== suffix[sfxi])
return false;
}
return true;
}
/** Returns a new Uint8Array composed of `count` repetitions of the `source`
* array.
*
* If `count` is negative, a `RangeError` is thrown.
*
* ```ts
* import { repeat } from "./mod.ts";
* const source = new Uint8Array([0, 1, 2]);
* console.log(repeat(source, 3)); // [0, 1, 2, 0, 1, 2, 0, 1, 2]
* console.log(repeat(source, 0)); // []
* console.log(repeat(source, -1)); // RangeError
* ```
*/
export function repeat(source, count) {
if (count === 0) {
return new Uint8Array();
}
if (count < 0) {
throw new RangeError("bytes: negative repeat count");
}
else if ((source.length * count) / count !== source.length) {
throw new Error("bytes: repeat count causes overflow");
}
const int = Math.floor(count);
if (int !== count) {
throw new Error("bytes: repeat count must be an integer");
}
const nb = new Uint8Array(source.length * count);
let bp = copy(source, nb);
for (; bp < nb.length; bp *= 2) {
copy(nb.slice(0, bp), nb, bp);
}
return nb;
}
/** Concatenate the given arrays into a new Uint8Array.
*
* ```ts
* import { concat } from "./mod.ts";
* const a = new Uint8Array([0, 1, 2]);
* const b = new Uint8Array([3, 4, 5]);
* console.log(concat(a, b)); // [0, 1, 2, 3, 4, 5]
*/
export function concat(...buf) {
let length = 0;
for (const b of buf) {
length += b.length;
}
const output = new Uint8Array(length);
let index = 0;
for (const b of buf) {
output.set(b, index);
index += b.length;
}
return output;
}
/** Returns true if the source array contains the needle array, false otherwise.
*
* A start index can be specified as the third argument that begins the search
* at that given index. The start index defaults to the beginning of the array.
*
* The complexity of this function is O(source.length * needle.length).
*
* ```ts
* import { includesNeedle } from "./mod.ts";
* const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]);
* const needle = new Uint8Array([1, 2]);
* console.log(includesNeedle(source, needle)); // true
* console.log(includesNeedle(source, needle, 6)); // false
* ```
*/
export function includesNeedle(source, needle, start = 0) {
return indexOfNeedle(source, needle, start) !== -1;
}
/** Copy bytes from the `src` array to the `dst` array. Returns the number of
* bytes copied.
*
* If the `src` array is larger than what the `dst` array can hold, only the
* amount of bytes that fit in the `dst` array are copied.
*
* An offset can be specified as the third argument that begins the copy at
* that given index in the `dst` array. The offset defaults to the beginning of
* the array.
*
* ```ts
* import { copy } from "./mod.ts";
* const src = new Uint8Array([9, 8, 7]);
* const dst = new Uint8Array([0, 1, 2, 3, 4, 5]);
* console.log(copy(src, dst)); // 3
* console.log(dst); // [9, 8, 7, 3, 4, 5]
* ```
*
* ```ts
* import { copy } from "./mod.ts";
* const src = new Uint8Array([1, 1, 1, 1]);
* const dst = new Uint8Array([0, 0, 0, 0]);
* console.log(copy(src, dst, 1)); // 3
* console.log(dst); // [0, 1, 1, 1]
* ```
*/
export function copy(src, dst, off = 0) {
off = Math.max(0, Math.min(off, dst.byteLength));
const dstBytesAvailable = dst.byteLength - off;
if (src.byteLength > dstBytesAvailable) {
src = src.subarray(0, dstBytesAvailable);
}
dst.set(src, off);
return src.byteLength;
}
export { equals } from "./equals.js";