From a644699eb56832c917ebab3f3977e11d191c87ea Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Fri, 3 Feb 2023 09:52:52 +0000 Subject: [PATCH] Extend ArrayUtils Provide only two binary search functions: - Add binarySearchFirstGreaterOrEqual() - Add binarySearchFirstGreater() Note: other binary search variations can be built later on top of these functions. Bug: b/256564627 Test: npm run test:unit Change-Id: Icbd308923fe4b79dae29fb69176fa7276f5dd7cd --- tools/winscope/src/common/array_utils.ts | 39 +++++++++- tools/winscope/src/common/array_utils_test.ts | 77 +++++++++++++------ 2 files changed, 89 insertions(+), 27 deletions(-) diff --git a/tools/winscope/src/common/array_utils.ts b/tools/winscope/src/common/array_utils.ts index ac39a5a3a..3a0250f96 100644 --- a/tools/winscope/src/common/array_utils.ts +++ b/tools/winscope/src/common/array_utils.ts @@ -61,7 +61,10 @@ class ArrayUtils { return undefined; } - static binarySearchLowerOrEqual(values: T[] | TypedArray, target: T): number | undefined { + static binarySearchFirstGreaterOrEqual( + values: T[] | TypedArray, + target: T + ): number | undefined { if (values.length === 0) { return undefined; } @@ -75,11 +78,11 @@ class ArrayUtils { const mid = (low + high) >> 1; if (values[mid] < target) { - if (result === undefined || result < mid) { - result = mid; - } low = mid + 1; } else if (values[mid] > target) { + if (result === undefined || result > mid) { + result = mid; + } high = mid - 1; } else { result = mid; @@ -90,6 +93,34 @@ class ArrayUtils { return result; } + static binarySearchFirstGreater(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) { diff --git a/tools/winscope/src/common/array_utils_test.ts b/tools/winscope/src/common/array_utils_test.ts index e2bf97729..611a4e9c5 100644 --- a/tools/winscope/src/common/array_utils_test.ts +++ b/tools/winscope/src/common/array_utils_test.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import {ArrayUtils} from './array_utils'; describe('ArrayUtils', () => { @@ -55,35 +56,65 @@ describe('ArrayUtils', () => { expect(ArrayUtils.searchSubarray([0, 1, 2], [2, 3])).toEqual(undefined); }); - it('binarySearchLowerOrEqual', () => { + it('binarySearchFirstGreaterOrEqual', () => { // no match - expect(ArrayUtils.binarySearchLowerOrEqual([], 5)).toBeUndefined(); - expect(ArrayUtils.binarySearchLowerOrEqual([6], 5)).toBeUndefined(); - expect(ArrayUtils.binarySearchLowerOrEqual([6, 7], 5)).toBeUndefined(); - expect(ArrayUtils.binarySearchLowerOrEqual([6, 7, 8], 5)).toBeUndefined(); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([], 9)).toBeUndefined(); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([8], 9)).toBeUndefined(); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([7, 8], 9)).toBeUndefined(); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([6, 7, 8], 9)).toBeUndefined(); - // match (lower) - expect(ArrayUtils.binarySearchLowerOrEqual([4], 5)).toEqual(0); - expect(ArrayUtils.binarySearchLowerOrEqual([3, 4], 5)).toEqual(1); - expect(ArrayUtils.binarySearchLowerOrEqual([2, 3, 4], 5)).toEqual(2); - expect(ArrayUtils.binarySearchLowerOrEqual([2, 3, 4, 6], 5)).toEqual(2); - expect(ArrayUtils.binarySearchLowerOrEqual([2, 3, 4, 6, 7], 5)).toEqual(2); + // match (greater) + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([6], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([6, 7], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([4, 6], 5)).toEqual(1); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([4, 6, 7, 8], 5)).toEqual(1); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([3, 4, 6, 7, 8], 5)).toEqual(2); // match (equal) - expect(ArrayUtils.binarySearchLowerOrEqual([5], 5)).toEqual(0); - expect(ArrayUtils.binarySearchLowerOrEqual([5, 6], 5)).toEqual(0); - expect(ArrayUtils.binarySearchLowerOrEqual([4, 5], 5)).toEqual(1); - expect(ArrayUtils.binarySearchLowerOrEqual([3, 4, 5], 5)).toEqual(2); - expect(ArrayUtils.binarySearchLowerOrEqual([3, 4, 5, 6], 5)).toEqual(2); - expect(ArrayUtils.binarySearchLowerOrEqual([3, 4, 5, 6, 7], 5)).toEqual(2); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([5], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([5, 6], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([4, 5], 5)).toEqual(1); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([3, 4, 5], 5)).toEqual(2); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([3, 4, 5, 6], 5)).toEqual(2); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([3, 4, 5, 6, 7], 5)).toEqual(2); // match (equal with repeated values) - expect(ArrayUtils.binarySearchLowerOrEqual([5, 5], 5)).toEqual(0); - expect(ArrayUtils.binarySearchLowerOrEqual([5, 5, 5], 5)).toEqual(0); - expect(ArrayUtils.binarySearchLowerOrEqual([5, 5, 5, 5], 5)).toEqual(0); - expect(ArrayUtils.binarySearchLowerOrEqual([4, 5, 5, 6], 5)).toEqual(1); - expect(ArrayUtils.binarySearchLowerOrEqual([4, 4, 5, 5, 5, 6], 5)).toEqual(2); - expect(ArrayUtils.binarySearchLowerOrEqual([4, 4, 4, 5, 5, 5, 5, 6], 5)).toEqual(3); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([5, 5], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([5, 5, 5], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([5, 5, 5, 5], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([4, 5, 5, 6], 5)).toEqual(1); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([4, 4, 5, 5, 5, 6], 5)).toEqual(2); + expect(ArrayUtils.binarySearchFirstGreaterOrEqual([4, 4, 4, 5, 5, 5, 5, 6], 5)).toEqual(3); + }); + + it('binarySearchFirstGreater', () => { + // no match + expect(ArrayUtils.binarySearchFirstGreater([], 9)).toBeUndefined(); + expect(ArrayUtils.binarySearchFirstGreater([8], 9)).toBeUndefined(); + expect(ArrayUtils.binarySearchFirstGreater([7, 8], 9)).toBeUndefined(); + expect(ArrayUtils.binarySearchFirstGreater([6, 7, 8], 9)).toBeUndefined(); + + // match + expect(ArrayUtils.binarySearchFirstGreater([6], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreater([6, 7], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreater([4, 6], 5)).toEqual(1); + expect(ArrayUtils.binarySearchFirstGreater([4, 6, 7, 8], 5)).toEqual(1); + expect(ArrayUtils.binarySearchFirstGreater([3, 4, 6, 7, 8], 5)).toEqual(2); + + // match (ignore equal) + expect(ArrayUtils.binarySearchFirstGreater([5], 5)).toEqual(undefined); + expect(ArrayUtils.binarySearchFirstGreater([5, 6], 5)).toEqual(1); + expect(ArrayUtils.binarySearchFirstGreater([4, 5, 6], 5)).toEqual(2); + expect(ArrayUtils.binarySearchFirstGreater([3, 4, 5, 6], 5)).toEqual(3); + expect(ArrayUtils.binarySearchFirstGreater([3, 4, 5, 6, 7], 5)).toEqual(3); + + // match (with repeated values) + expect(ArrayUtils.binarySearchFirstGreater([6, 6], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreater([6, 6, 6], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreater([6, 6, 6, 6], 5)).toEqual(0); + expect(ArrayUtils.binarySearchFirstGreater([5, 6, 6, 7], 5)).toEqual(1); + expect(ArrayUtils.binarySearchFirstGreater([5, 5, 6, 6, 6, 7], 5)).toEqual(2); + expect(ArrayUtils.binarySearchFirstGreater([5, 5, 5, 6, 6, 6, 6, 7], 5)).toEqual(3); }); it('toUintLittleEndian', () => {