1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2018 The Android Open Source Project 2*6dbdd20aSAndroid Build Coastguard Worker// 3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*6dbdd20aSAndroid Build Coastguard Worker// 7*6dbdd20aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*6dbdd20aSAndroid Build Coastguard Worker// 9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License. 14*6dbdd20aSAndroid Build Coastguard Worker 15*6dbdd20aSAndroid Build Coastguard Workertype Numeric = number | bigint; 16*6dbdd20aSAndroid Build Coastguard Workertype Range = [number, number]; 17*6dbdd20aSAndroid Build Coastguard Worker 18*6dbdd20aSAndroid Build Coastguard Workerfunction searchImpl<T extends Numeric>( 19*6dbdd20aSAndroid Build Coastguard Worker haystack: ArrayLike<T>, 20*6dbdd20aSAndroid Build Coastguard Worker needle: T, 21*6dbdd20aSAndroid Build Coastguard Worker i: number, 22*6dbdd20aSAndroid Build Coastguard Worker j: number, 23*6dbdd20aSAndroid Build Coastguard Worker): number { 24*6dbdd20aSAndroid Build Coastguard Worker if (i === j) return -1; 25*6dbdd20aSAndroid Build Coastguard Worker if (i + 1 === j) { 26*6dbdd20aSAndroid Build Coastguard Worker return needle >= haystack[i] ? i : -1; 27*6dbdd20aSAndroid Build Coastguard Worker } 28*6dbdd20aSAndroid Build Coastguard Worker 29*6dbdd20aSAndroid Build Coastguard Worker const mid = Math.floor((j - i) / 2) + i; 30*6dbdd20aSAndroid Build Coastguard Worker const midValue = haystack[mid]; 31*6dbdd20aSAndroid Build Coastguard Worker if (needle < midValue) { 32*6dbdd20aSAndroid Build Coastguard Worker return searchImpl(haystack, needle, i, mid); 33*6dbdd20aSAndroid Build Coastguard Worker } else { 34*6dbdd20aSAndroid Build Coastguard Worker return searchImpl(haystack, needle, mid, j); 35*6dbdd20aSAndroid Build Coastguard Worker } 36*6dbdd20aSAndroid Build Coastguard Worker} 37*6dbdd20aSAndroid Build Coastguard Worker 38*6dbdd20aSAndroid Build Coastguard Workerfunction searchRangeImpl<T extends Numeric>( 39*6dbdd20aSAndroid Build Coastguard Worker haystack: ArrayLike<T>, 40*6dbdd20aSAndroid Build Coastguard Worker needle: T, 41*6dbdd20aSAndroid Build Coastguard Worker i: number, 42*6dbdd20aSAndroid Build Coastguard Worker j: number, 43*6dbdd20aSAndroid Build Coastguard Worker): Range { 44*6dbdd20aSAndroid Build Coastguard Worker if (i === j) return [i, j]; 45*6dbdd20aSAndroid Build Coastguard Worker if (i + 1 === j) { 46*6dbdd20aSAndroid Build Coastguard Worker if (haystack[i] <= needle) { 47*6dbdd20aSAndroid Build Coastguard Worker return [i, j]; 48*6dbdd20aSAndroid Build Coastguard Worker } else { 49*6dbdd20aSAndroid Build Coastguard Worker return [i, i]; 50*6dbdd20aSAndroid Build Coastguard Worker } 51*6dbdd20aSAndroid Build Coastguard Worker } 52*6dbdd20aSAndroid Build Coastguard Worker 53*6dbdd20aSAndroid Build Coastguard Worker const mid = Math.floor((j - i) / 2) + i; 54*6dbdd20aSAndroid Build Coastguard Worker const midValue = haystack[mid]; 55*6dbdd20aSAndroid Build Coastguard Worker 56*6dbdd20aSAndroid Build Coastguard Worker if (needle < midValue) { 57*6dbdd20aSAndroid Build Coastguard Worker return searchRangeImpl(haystack, needle, i, mid); 58*6dbdd20aSAndroid Build Coastguard Worker } else if (needle > midValue) { 59*6dbdd20aSAndroid Build Coastguard Worker return searchRangeImpl(haystack, needle, mid, j); 60*6dbdd20aSAndroid Build Coastguard Worker } else { 61*6dbdd20aSAndroid Build Coastguard Worker while (haystack[i] !== needle) i++; 62*6dbdd20aSAndroid Build Coastguard Worker while (haystack[j - 1] !== needle) j--; 63*6dbdd20aSAndroid Build Coastguard Worker return [i, j]; 64*6dbdd20aSAndroid Build Coastguard Worker } 65*6dbdd20aSAndroid Build Coastguard Worker} 66*6dbdd20aSAndroid Build Coastguard Worker 67*6dbdd20aSAndroid Build Coastguard Worker// Given a sorted array of numeric values |haystack| and a |needle|, return the 68*6dbdd20aSAndroid Build Coastguard Worker// index of the last element of |haystack| which is less than or equal to 69*6dbdd20aSAndroid Build Coastguard Worker// |needle|, or -1 if all elements of |haystack| are greater than |needle|. 70*6dbdd20aSAndroid Build Coastguard Workerexport function search<T extends Numeric>( 71*6dbdd20aSAndroid Build Coastguard Worker haystack: ArrayLike<T>, 72*6dbdd20aSAndroid Build Coastguard Worker needle: T, 73*6dbdd20aSAndroid Build Coastguard Worker): number { 74*6dbdd20aSAndroid Build Coastguard Worker return searchImpl(haystack, needle, 0, haystack.length); 75*6dbdd20aSAndroid Build Coastguard Worker} 76*6dbdd20aSAndroid Build Coastguard Worker 77*6dbdd20aSAndroid Build Coastguard Worker// Given a sorted array of numeric values (|haystack|) return the half open 78*6dbdd20aSAndroid Build Coastguard Worker// range [i, j) of indices where |haystack| is equal to needle. 79*6dbdd20aSAndroid Build Coastguard Workerexport function searchEq<T extends Numeric>( 80*6dbdd20aSAndroid Build Coastguard Worker haystack: ArrayLike<T>, 81*6dbdd20aSAndroid Build Coastguard Worker needle: T, 82*6dbdd20aSAndroid Build Coastguard Worker optRange?: Range, 83*6dbdd20aSAndroid Build Coastguard Worker): Range { 84*6dbdd20aSAndroid Build Coastguard Worker const range = searchRange(haystack, needle, optRange); 85*6dbdd20aSAndroid Build Coastguard Worker const [i, j] = range; 86*6dbdd20aSAndroid Build Coastguard Worker if (haystack[i] === needle) return range; 87*6dbdd20aSAndroid Build Coastguard Worker return [j, j]; 88*6dbdd20aSAndroid Build Coastguard Worker} 89*6dbdd20aSAndroid Build Coastguard Worker 90*6dbdd20aSAndroid Build Coastguard Worker// Given a sorted array of numeric values (|haystack|) and a |needle| return the 91*6dbdd20aSAndroid Build Coastguard Worker// smallest half open range [i, j) of indexes which contains |needle|. 92*6dbdd20aSAndroid Build Coastguard Workerexport function searchRange<T extends Numeric>( 93*6dbdd20aSAndroid Build Coastguard Worker haystack: ArrayLike<T>, 94*6dbdd20aSAndroid Build Coastguard Worker needle: T, 95*6dbdd20aSAndroid Build Coastguard Worker optRange?: Range, 96*6dbdd20aSAndroid Build Coastguard Worker): Range { 97*6dbdd20aSAndroid Build Coastguard Worker const [left, right] = optRange ? optRange : [0, haystack.length]; 98*6dbdd20aSAndroid Build Coastguard Worker return searchRangeImpl(haystack, needle, left, right); 99*6dbdd20aSAndroid Build Coastguard Worker} 100*6dbdd20aSAndroid Build Coastguard Worker 101*6dbdd20aSAndroid Build Coastguard Worker// Given a sorted array of numeric values (|haystack|) and a |needle| return a 102*6dbdd20aSAndroid Build Coastguard Worker// pair of indexes [i, j] such that: 103*6dbdd20aSAndroid Build Coastguard Worker// If there is at least one element in |haystack| smaller than |needle| 104*6dbdd20aSAndroid Build Coastguard Worker// i is the index of the largest such number otherwise -1; 105*6dbdd20aSAndroid Build Coastguard Worker// If there is at least one element in |haystack| larger than |needle| 106*6dbdd20aSAndroid Build Coastguard Worker// j is the index of the smallest such element otherwise -1. 107*6dbdd20aSAndroid Build Coastguard Worker// 108*6dbdd20aSAndroid Build Coastguard Worker// So we try to get the indexes of the two data points around needle 109*6dbdd20aSAndroid Build Coastguard Worker// or -1 if there is no such datapoint. 110*6dbdd20aSAndroid Build Coastguard Workerexport function searchSegment<T extends Numeric>( 111*6dbdd20aSAndroid Build Coastguard Worker haystack: ArrayLike<T>, 112*6dbdd20aSAndroid Build Coastguard Worker needle: T, 113*6dbdd20aSAndroid Build Coastguard Worker): Range { 114*6dbdd20aSAndroid Build Coastguard Worker if (!haystack.length) return [-1, -1]; 115*6dbdd20aSAndroid Build Coastguard Worker 116*6dbdd20aSAndroid Build Coastguard Worker const left = search(haystack, needle); 117*6dbdd20aSAndroid Build Coastguard Worker if (left === -1) { 118*6dbdd20aSAndroid Build Coastguard Worker return [left, 0]; 119*6dbdd20aSAndroid Build Coastguard Worker } else if (left + 1 === haystack.length) { 120*6dbdd20aSAndroid Build Coastguard Worker return [left, -1]; 121*6dbdd20aSAndroid Build Coastguard Worker } else { 122*6dbdd20aSAndroid Build Coastguard Worker return [left, left + 1]; 123*6dbdd20aSAndroid Build Coastguard Worker } 124*6dbdd20aSAndroid Build Coastguard Worker} 125