1*90c8c64dSAndroid Build Coastguard Worker/* 2*90c8c64dSAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project 3*90c8c64dSAndroid Build Coastguard Worker * 4*90c8c64dSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*90c8c64dSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*90c8c64dSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*90c8c64dSAndroid Build Coastguard Worker * 8*90c8c64dSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*90c8c64dSAndroid Build Coastguard Worker * 10*90c8c64dSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*90c8c64dSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*90c8c64dSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*90c8c64dSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*90c8c64dSAndroid Build Coastguard Worker * limitations under the License. 15*90c8c64dSAndroid Build Coastguard Worker */ 16*90c8c64dSAndroid Build Coastguard Workertype TypedArray = 17*90c8c64dSAndroid Build Coastguard Worker | Int8Array 18*90c8c64dSAndroid Build Coastguard Worker | Uint8Array 19*90c8c64dSAndroid Build Coastguard Worker | Uint8ClampedArray 20*90c8c64dSAndroid Build Coastguard Worker | Int16Array 21*90c8c64dSAndroid Build Coastguard Worker | Uint16Array 22*90c8c64dSAndroid Build Coastguard Worker | Int32Array 23*90c8c64dSAndroid Build Coastguard Worker | Uint32Array 24*90c8c64dSAndroid Build Coastguard Worker | Float32Array 25*90c8c64dSAndroid Build Coastguard Worker | Float64Array; 26*90c8c64dSAndroid Build Coastguard Worker 27*90c8c64dSAndroid Build Coastguard Workerexport class ArrayUtils { 28*90c8c64dSAndroid Build Coastguard Worker static equal<T>( 29*90c8c64dSAndroid Build Coastguard Worker a: T[] | TypedArray, 30*90c8c64dSAndroid Build Coastguard Worker b: T[] | TypedArray, 31*90c8c64dSAndroid Build Coastguard Worker predicate: (a: T | number, b: T | number) => boolean = (a, b) => a === b, 32*90c8c64dSAndroid Build Coastguard Worker ): boolean { 33*90c8c64dSAndroid Build Coastguard Worker if (a.length !== b.length) { 34*90c8c64dSAndroid Build Coastguard Worker return false; 35*90c8c64dSAndroid Build Coastguard Worker } 36*90c8c64dSAndroid Build Coastguard Worker 37*90c8c64dSAndroid Build Coastguard Worker for (let i = 0; i < a.length; i++) { 38*90c8c64dSAndroid Build Coastguard Worker if (!predicate(a[i], b[i])) { 39*90c8c64dSAndroid Build Coastguard Worker return false; 40*90c8c64dSAndroid Build Coastguard Worker } 41*90c8c64dSAndroid Build Coastguard Worker } 42*90c8c64dSAndroid Build Coastguard Worker 43*90c8c64dSAndroid Build Coastguard Worker return true; 44*90c8c64dSAndroid Build Coastguard Worker } 45*90c8c64dSAndroid Build Coastguard Worker 46*90c8c64dSAndroid Build Coastguard Worker static searchSubarray<T>( 47*90c8c64dSAndroid Build Coastguard Worker array: T[] | TypedArray, 48*90c8c64dSAndroid Build Coastguard Worker subarray: T[] | TypedArray, 49*90c8c64dSAndroid Build Coastguard Worker ): number | undefined { 50*90c8c64dSAndroid Build Coastguard Worker for (let i = 0; i + subarray.length <= array.length; ++i) { 51*90c8c64dSAndroid Build Coastguard Worker let match = true; 52*90c8c64dSAndroid Build Coastguard Worker 53*90c8c64dSAndroid Build Coastguard Worker for (let j = 0; j < subarray.length; ++j) { 54*90c8c64dSAndroid Build Coastguard Worker if (array[i + j] !== subarray[j]) { 55*90c8c64dSAndroid Build Coastguard Worker match = false; 56*90c8c64dSAndroid Build Coastguard Worker break; 57*90c8c64dSAndroid Build Coastguard Worker } 58*90c8c64dSAndroid Build Coastguard Worker } 59*90c8c64dSAndroid Build Coastguard Worker 60*90c8c64dSAndroid Build Coastguard Worker if (match) { 61*90c8c64dSAndroid Build Coastguard Worker return i; 62*90c8c64dSAndroid Build Coastguard Worker } 63*90c8c64dSAndroid Build Coastguard Worker } 64*90c8c64dSAndroid Build Coastguard Worker 65*90c8c64dSAndroid Build Coastguard Worker return undefined; 66*90c8c64dSAndroid Build Coastguard Worker } 67*90c8c64dSAndroid Build Coastguard Worker 68*90c8c64dSAndroid Build Coastguard Worker static binarySearchFirstGreaterOrEqual<T>( 69*90c8c64dSAndroid Build Coastguard Worker values: T[] | TypedArray, 70*90c8c64dSAndroid Build Coastguard Worker target: T, 71*90c8c64dSAndroid Build Coastguard Worker ): number | undefined { 72*90c8c64dSAndroid Build Coastguard Worker if (values.length === 0) { 73*90c8c64dSAndroid Build Coastguard Worker return undefined; 74*90c8c64dSAndroid Build Coastguard Worker } 75*90c8c64dSAndroid Build Coastguard Worker 76*90c8c64dSAndroid Build Coastguard Worker let low = 0; 77*90c8c64dSAndroid Build Coastguard Worker let high = values.length - 1; 78*90c8c64dSAndroid Build Coastguard Worker 79*90c8c64dSAndroid Build Coastguard Worker let result: number | undefined = undefined; 80*90c8c64dSAndroid Build Coastguard Worker 81*90c8c64dSAndroid Build Coastguard Worker while (low <= high) { 82*90c8c64dSAndroid Build Coastguard Worker const mid = (low + high) >> 1; 83*90c8c64dSAndroid Build Coastguard Worker 84*90c8c64dSAndroid Build Coastguard Worker if (values[mid] < target) { 85*90c8c64dSAndroid Build Coastguard Worker low = mid + 1; 86*90c8c64dSAndroid Build Coastguard Worker } else if (values[mid] > target) { 87*90c8c64dSAndroid Build Coastguard Worker if (result === undefined || result > mid) { 88*90c8c64dSAndroid Build Coastguard Worker result = mid; 89*90c8c64dSAndroid Build Coastguard Worker } 90*90c8c64dSAndroid Build Coastguard Worker high = mid - 1; 91*90c8c64dSAndroid Build Coastguard Worker } else { 92*90c8c64dSAndroid Build Coastguard Worker result = mid; 93*90c8c64dSAndroid Build Coastguard Worker high = mid - 1; 94*90c8c64dSAndroid Build Coastguard Worker } 95*90c8c64dSAndroid Build Coastguard Worker } 96*90c8c64dSAndroid Build Coastguard Worker 97*90c8c64dSAndroid Build Coastguard Worker return result; 98*90c8c64dSAndroid Build Coastguard Worker } 99*90c8c64dSAndroid Build Coastguard Worker 100*90c8c64dSAndroid Build Coastguard Worker static binarySearchFirstGreater<T>( 101*90c8c64dSAndroid Build Coastguard Worker values: T[] | TypedArray, 102*90c8c64dSAndroid Build Coastguard Worker target: T, 103*90c8c64dSAndroid Build Coastguard Worker ): number | undefined { 104*90c8c64dSAndroid Build Coastguard Worker if (values.length === 0) { 105*90c8c64dSAndroid Build Coastguard Worker return undefined; 106*90c8c64dSAndroid Build Coastguard Worker } 107*90c8c64dSAndroid Build Coastguard Worker 108*90c8c64dSAndroid Build Coastguard Worker let low = 0; 109*90c8c64dSAndroid Build Coastguard Worker let high = values.length - 1; 110*90c8c64dSAndroid Build Coastguard Worker 111*90c8c64dSAndroid Build Coastguard Worker let result: number | undefined = undefined; 112*90c8c64dSAndroid Build Coastguard Worker 113*90c8c64dSAndroid Build Coastguard Worker while (low <= high) { 114*90c8c64dSAndroid Build Coastguard Worker const mid = (low + high) >> 1; 115*90c8c64dSAndroid Build Coastguard Worker 116*90c8c64dSAndroid Build Coastguard Worker if (values[mid] < target) { 117*90c8c64dSAndroid Build Coastguard Worker low = mid + 1; 118*90c8c64dSAndroid Build Coastguard Worker } else if (values[mid] > target) { 119*90c8c64dSAndroid Build Coastguard Worker if (result === undefined || result > mid) { 120*90c8c64dSAndroid Build Coastguard Worker result = mid; 121*90c8c64dSAndroid Build Coastguard Worker } 122*90c8c64dSAndroid Build Coastguard Worker high = mid - 1; 123*90c8c64dSAndroid Build Coastguard Worker } else { 124*90c8c64dSAndroid Build Coastguard Worker low = mid + 1; 125*90c8c64dSAndroid Build Coastguard Worker } 126*90c8c64dSAndroid Build Coastguard Worker } 127*90c8c64dSAndroid Build Coastguard Worker 128*90c8c64dSAndroid Build Coastguard Worker return result; 129*90c8c64dSAndroid Build Coastguard Worker } 130*90c8c64dSAndroid Build Coastguard Worker 131*90c8c64dSAndroid Build Coastguard Worker static toUintLittleEndian( 132*90c8c64dSAndroid Build Coastguard Worker buffer: Uint8Array, 133*90c8c64dSAndroid Build Coastguard Worker start: number, 134*90c8c64dSAndroid Build Coastguard Worker end: number, 135*90c8c64dSAndroid Build Coastguard Worker ): bigint { 136*90c8c64dSAndroid Build Coastguard Worker let result = 0n; 137*90c8c64dSAndroid Build Coastguard Worker for (let i = end - 1; i >= start; --i) { 138*90c8c64dSAndroid Build Coastguard Worker result *= 256n; 139*90c8c64dSAndroid Build Coastguard Worker result += BigInt(buffer[i]); 140*90c8c64dSAndroid Build Coastguard Worker } 141*90c8c64dSAndroid Build Coastguard Worker return result; 142*90c8c64dSAndroid Build Coastguard Worker } 143*90c8c64dSAndroid Build Coastguard Worker 144*90c8c64dSAndroid Build Coastguard Worker static toIntLittleEndian( 145*90c8c64dSAndroid Build Coastguard Worker buffer: Uint8Array, 146*90c8c64dSAndroid Build Coastguard Worker start: number, 147*90c8c64dSAndroid Build Coastguard Worker end: number, 148*90c8c64dSAndroid Build Coastguard Worker ): bigint { 149*90c8c64dSAndroid Build Coastguard Worker const numOfBits = BigInt(Math.max(0, 8 * (end - start))); 150*90c8c64dSAndroid Build Coastguard Worker if (numOfBits <= 0n) { 151*90c8c64dSAndroid Build Coastguard Worker return 0n; 152*90c8c64dSAndroid Build Coastguard Worker } 153*90c8c64dSAndroid Build Coastguard Worker 154*90c8c64dSAndroid Build Coastguard Worker let result = ArrayUtils.toUintLittleEndian(buffer, start, end); 155*90c8c64dSAndroid Build Coastguard Worker const maxSignedValue = 2n ** (numOfBits - 1n) - 1n; 156*90c8c64dSAndroid Build Coastguard Worker if (result > maxSignedValue) { 157*90c8c64dSAndroid Build Coastguard Worker const valuesRange = 2n ** numOfBits; 158*90c8c64dSAndroid Build Coastguard Worker result -= valuesRange; 159*90c8c64dSAndroid Build Coastguard Worker } 160*90c8c64dSAndroid Build Coastguard Worker 161*90c8c64dSAndroid Build Coastguard Worker return result; 162*90c8c64dSAndroid Build Coastguard Worker } 163*90c8c64dSAndroid Build Coastguard Worker} 164