blob: 145036a800de51d272b9281448017152c21356b7 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
type TypedArray =
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array;
export class ArrayUtils {
static equal<T>(
a: T[] | TypedArray,
b: T[] | TypedArray,
predicate: (a: T | number, b: T | number) => boolean = (a, b) => a === b,
): boolean {
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (!predicate(a[i], b[i])) {
return false;
}
}
return true;
}
static searchSubarray<T>(
array: T[] | TypedArray,
subarray: T[] | TypedArray,
): number | undefined {
for (let i = 0; i + subarray.length <= array.length; ++i) {
let match = true;
for (let j = 0; j < subarray.length; ++j) {
if (array[i + j] !== subarray[j]) {
match = false;
break;
}
}
if (match) {
return i;
}
}
return undefined;
}
static binarySearchFirstGreaterOrEqual<T>(
values: T[] | TypedArray,
target: T,
): number | undefined {
if (values.length === 0) {
return undefined;
}
let low = 0;
let high = values.length - 1;
let result: number | undefined = undefined;
while (low <= high) {
const mid = (low + high) >> 1;
if (values[mid] < target) {
low = mid + 1;
} else if (values[mid] > target) {
if (result === undefined || result > mid) {
result = mid;
}
high = mid - 1;
} else {
result = mid;
high = mid - 1;
}
}
return result;
}
static binarySearchFirstGreater<T>(
values: T[] | TypedArray,
target: T,
): number | undefined {
if (values.length === 0) {
return undefined;
}
let low = 0;
let high = values.length - 1;
let result: number | undefined = undefined;
while (low <= high) {
const mid = (low + high) >> 1;
if (values[mid] < target) {
low = mid + 1;
} else if (values[mid] > target) {
if (result === undefined || result > mid) {
result = mid;
}
high = mid - 1;
} else {
low = mid + 1;
}
}
return result;
}
static toUintLittleEndian(
buffer: Uint8Array,
start: number,
end: number,
): bigint {
let result = 0n;
for (let i = end - 1; i >= start; --i) {
result *= 256n;
result += BigInt(buffer[i]);
}
return result;
}
static toIntLittleEndian(
buffer: Uint8Array,
start: number,
end: number,
): bigint {
const numOfBits = BigInt(Math.max(0, 8 * (end - start)));
if (numOfBits <= 0n) {
return 0n;
}
let result = ArrayUtils.toUintLittleEndian(buffer, start, end);
const maxSignedValue = 2n ** (numOfBits - 1n) - 1n;
if (result > maxSignedValue) {
const valuesRange = 2n ** numOfBits;
result -= valuesRange;
}
return result;
}
}