Skip to content

Commit

Permalink
refactor(bytes): move to single-export files (denoland#2955)
Browse files Browse the repository at this point in the history
  • Loading branch information
iuioiua committed Nov 29, 2022
1 parent 8e46f59 commit e1117a8
Show file tree
Hide file tree
Showing 31 changed files with 596 additions and 587 deletions.
26 changes: 26 additions & 0 deletions bytes/concat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

/** Concatenate the given arrays into a new Uint8Array.
*
* ```ts
* import { concat } from "https://deno.land/std@$STD_VERSION/bytes/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: Uint8Array[]): Uint8Array {
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;
}
36 changes: 36 additions & 0 deletions bytes/concat_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { assert, assertEquals } from "../testing/asserts.ts";
import { concat } from "./concat.ts";

Deno.test("[bytes] concat", () => {
const encoder = new TextEncoder();
const u1 = encoder.encode("Hello ");
const u2 = encoder.encode("World");
const joined = concat(u1, u2);
assertEquals(new TextDecoder().decode(joined), "Hello World");
assert(u1 !== joined);
assert(u2 !== joined);
});

Deno.test("[bytes] concat empty arrays", () => {
const u1 = new Uint8Array();
const u2 = new Uint8Array();
const joined = concat(u1, u2);
assertEquals(joined.byteLength, 0);
assert(u1 !== joined);
assert(u2 !== joined);
});

Deno.test("[bytes] concat multiple arrays", () => {
const encoder = new TextEncoder();
const u1 = encoder.encode("Hello ");
const u2 = encoder.encode("W");
const u3 = encoder.encode("o");
const u4 = encoder.encode("r");
const u5 = encoder.encode("l");
const u6 = encoder.encode("d");
const joined = concat(u1, u2, u3, u4, u5, u6);
assertEquals(new TextDecoder().decode(joined), "Hello World");
assert(u1 !== joined);
assert(u2 !== joined);
});
38 changes: 38 additions & 0 deletions bytes/copy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

/** 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 "https://deno.land/std@$STD_VERSION/bytes/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 "https://deno.land/std@$STD_VERSION/bytes/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: Uint8Array, dst: Uint8Array, off = 0): number {
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;
}
37 changes: 37 additions & 0 deletions bytes/copy_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { assert, assertEquals } from "../testing/asserts.ts";
import { copy } from "./copy.ts";

Deno.test("[bytes] copy", function () {
const dst = new Uint8Array(4);

dst.fill(0);
let src = Uint8Array.of(1, 2);
let len = copy(src, dst, 0);
assert(len === 2);
assertEquals(dst, Uint8Array.of(1, 2, 0, 0));

dst.fill(0);
src = Uint8Array.of(1, 2);
len = copy(src, dst, 1);
assert(len === 2);
assertEquals(dst, Uint8Array.of(0, 1, 2, 0));

dst.fill(0);
src = Uint8Array.of(1, 2, 3, 4, 5);
len = copy(src, dst);
assert(len === 4);
assertEquals(dst, Uint8Array.of(1, 2, 3, 4));

dst.fill(0);
src = Uint8Array.of(1, 2);
len = copy(src, dst, 100);
assert(len === 0);
assertEquals(dst, Uint8Array.of(0, 0, 0, 0));

dst.fill(0);
src = Uint8Array.of(3, 4);
len = copy(src, dst, -2);
assert(len === 2);
assertEquals(dst, Uint8Array.of(3, 4, 0, 0));
});
25 changes: 25 additions & 0 deletions bytes/ends_with.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

/** 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 "https://deno.land/std@$STD_VERSION/bytes/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: Uint8Array, suffix: Uint8Array): boolean {
for (
let srci = source.length - 1, sfxi = suffix.length - 1;
sfxi >= 0;
srci--, sfxi--
) {
if (source[srci] !== suffix[sfxi]) return false;
}
return true;
}
13 changes: 13 additions & 0 deletions bytes/ends_with_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

import { assert } from "../testing/asserts.ts";
import { endsWith } from "./ends_with.ts";

Deno.test("[bytes] endsWith", () => {
const v = endsWith(new Uint8Array([0, 1, 2]), new Uint8Array([1, 2]));
const v2 = endsWith(new Uint8Array([0, 1, 2]), new Uint8Array([0, 1]));
const v3 = endsWith(new Uint8Array([0, 1, 2]), new Uint8Array([0, 1, 2, 3]));
assert(v);
assert(!v2);
assert(!v3);
});
4 changes: 2 additions & 2 deletions bytes/equals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @param a first array to check equality
* @param b second array to check equality
*/
export function equalsNaive(a: Uint8Array, b: Uint8Array): boolean {
function equalsNaive(a: Uint8Array, b: Uint8Array): boolean {
if (a.length !== b.length) return false;
for (let i = 0; i < b.length; i++) {
if (a[i] !== b[i]) return false;
Expand All @@ -19,7 +19,7 @@ export function equalsNaive(a: Uint8Array, b: Uint8Array): boolean {
* @param a first array to check equality
* @param b second array to check equality
*/
export function equals32Bit(a: Uint8Array, b: Uint8Array): boolean {
function equals32Bit(a: Uint8Array, b: Uint8Array): boolean {
if (a.length !== b.length) return false;
const len = a.length;
const compressable = Math.floor(len / 4);
Expand Down
35 changes: 0 additions & 35 deletions bytes/equals_bench.ts

This file was deleted.

34 changes: 34 additions & 0 deletions bytes/equals_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { equals } from "./equals.ts";
import { assert } from "../testing/asserts.ts";

Deno.test("[bytes] equals", () => {
const v = equals(new Uint8Array([0, 1, 2, 3]), new Uint8Array([0, 1, 2, 3]));
const v2 = equals(new Uint8Array([0, 1, 2, 2]), new Uint8Array([0, 1, 2, 3]));
const v3 = equals(new Uint8Array([0, 1, 2, 3]), new Uint8Array([0, 1, 2]));
assert(v);
assert(!v2);
assert(!v3);
});

Deno.test("[bytes] equals randomized testing", () => {
// run tests before and after cutoff
for (let len = 995; len <= 1005; len++) {
const arr1 = crypto.getRandomValues(new Uint8Array(len));
const arr2 = crypto.getRandomValues(new Uint8Array(len));
const arr3 = arr1.slice(0);
// the chance of arr1 equaling arr2 is basically 0
// but introduce an inequality at the end just in case
arr2[arr2.length - 1] = arr1[arr1.length - 1] ^ 1;
// arr3 is arr1 but with an inequality in the very last element
// this is to test the equality check when length isn't a multiple of 4
arr3[arr3.length - 1] ^= 1;
// arrays with same underlying ArrayBuffer should be equal
assert(equals(arr1, arr1));
// equal arrays with different underlying ArrayBuffers should be equal
assert(equals(arr1, arr1.slice(0)));
// inequal arrays should be inequal
assert(!equals(arr1, arr2));
assert(!equals(arr1, arr3));
}
});
27 changes: 27 additions & 0 deletions bytes/includes_needle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

import { indexOfNeedle } from "./index_of_needle.ts";

/** 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 "https://deno.land/std@$STD_VERSION/bytes/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: Uint8Array,
needle: Uint8Array,
start = 0,
): boolean {
return indexOfNeedle(source, needle, start) !== -1;
}
15 changes: 15 additions & 0 deletions bytes/includes_needle_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { includesNeedle } from "./includes_needle.ts";
import { assert } from "../testing/asserts.ts";

Deno.test("[bytes] includesNeedle", () => {
const encoder = new TextEncoder();
const source = encoder.encode("deno.land");
const pattern = encoder.encode("deno");

assert(includesNeedle(source, pattern));
assert(includesNeedle(new Uint8Array([0, 1, 2, 3]), new Uint8Array([2, 3])));

assert(includesNeedle(source, pattern, -10));
assert(!includesNeedle(source, pattern, -1));
});
49 changes: 49 additions & 0 deletions bytes/index_of_needle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

/** 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 "https://deno.land/std@$STD_VERSION/bytes/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: Uint8Array,
needle: Uint8Array,
start = 0,
): number {
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;
}
Loading

0 comments on commit e1117a8

Please sign in to comment.