Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/util/vs/base/common/arraysFind.ts
13405 views
1
//!!! DO NOT modify, this file was COPIED from 'microsoft/vscode'
2
3
/*---------------------------------------------------------------------------------------------
4
* Copyright (c) Microsoft Corporation. All rights reserved.
5
* Licensed under the MIT License. See License.txt in the project root for license information.
6
*--------------------------------------------------------------------------------------------*/
7
8
import { Comparator } from './arrays';
9
10
export function findLast<T, R extends T>(array: readonly T[], predicate: (item: T, index: number) => item is R, fromIndex?: number): R | undefined;
11
export function findLast<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex?: number): T | undefined;
12
export function findLast<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex = array.length - 1): T | undefined {
13
const idx = findLastIdx(array, predicate, fromIndex);
14
if (idx === -1) {
15
return undefined;
16
}
17
return array[idx];
18
}
19
20
export function findLastIdx<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex = array.length - 1): number {
21
for (let i = fromIndex; i >= 0; i--) {
22
const element = array[i];
23
24
if (predicate(element, i)) {
25
return i;
26
}
27
}
28
29
return -1;
30
}
31
32
export function findFirst<T, R extends T>(array: readonly T[], predicate: (item: T, index: number) => item is R, fromIndex?: number): R | undefined;
33
export function findFirst<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex?: number): T | undefined;
34
export function findFirst<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex = 0): T | undefined {
35
const idx = findFirstIdx(array, predicate, fromIndex);
36
if (idx === -1) {
37
return undefined;
38
}
39
return array[idx];
40
}
41
42
export function findFirstIdx<T>(array: readonly T[], predicate: (item: T, index: number) => unknown, fromIndex = 0): number {
43
for (let i = fromIndex; i < array.length; i++) {
44
const element = array[i];
45
46
if (predicate(element, i)) {
47
return i;
48
}
49
}
50
51
return -1;
52
}
53
54
/**
55
* Finds the last item where predicate is true using binary search.
56
* `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!
57
*
58
* @returns `undefined` if no item matches, otherwise the last item that matches the predicate.
59
*/
60
export function findLastMonotonous<T>(array: readonly T[], predicate: (item: T) => boolean): T | undefined {
61
const idx = findLastIdxMonotonous(array, predicate);
62
return idx === -1 ? undefined : array[idx];
63
}
64
65
/**
66
* Finds the last item where predicate is true using binary search.
67
* `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!
68
*
69
* @returns `startIdx - 1` if predicate is false for all items, otherwise the index of the last item that matches the predicate.
70
*/
71
export function findLastIdxMonotonous<T>(array: readonly T[], predicate: (item: T) => boolean, startIdx = 0, endIdxEx = array.length): number {
72
let i = startIdx;
73
let j = endIdxEx;
74
while (i < j) {
75
const k = Math.floor((i + j) / 2);
76
if (predicate(array[k])) {
77
i = k + 1;
78
} else {
79
j = k;
80
}
81
}
82
return i - 1;
83
}
84
85
/**
86
* Finds the first item where predicate is true using binary search.
87
* `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[false, ..., false, true, ..., true]`!
88
*
89
* @returns `undefined` if no item matches, otherwise the first item that matches the predicate.
90
*/
91
export function findFirstMonotonous<T>(array: readonly T[], predicate: (item: T) => boolean): T | undefined {
92
const idx = findFirstIdxMonotonousOrArrLen(array, predicate);
93
return idx === array.length ? undefined : array[idx];
94
}
95
96
/**
97
* Finds the first item where predicate is true using binary search.
98
* `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[false, ..., false, true, ..., true]`!
99
*
100
* @returns `endIdxEx` if predicate is false for all items, otherwise the index of the first item that matches the predicate.
101
*/
102
export function findFirstIdxMonotonousOrArrLen<T>(array: readonly T[], predicate: (item: T) => boolean, startIdx = 0, endIdxEx = array.length): number {
103
let i = startIdx;
104
let j = endIdxEx;
105
while (i < j) {
106
const k = Math.floor((i + j) / 2);
107
if (predicate(array[k])) {
108
j = k;
109
} else {
110
i = k + 1;
111
}
112
}
113
return i;
114
}
115
116
export function findFirstIdxMonotonous<T>(array: readonly T[], predicate: (item: T) => boolean, startIdx = 0, endIdxEx = array.length): number {
117
const idx = findFirstIdxMonotonousOrArrLen(array, predicate, startIdx, endIdxEx);
118
return idx === array.length ? -1 : idx;
119
}
120
121
/**
122
* Use this when
123
* * You have a sorted array
124
* * You query this array with a monotonous predicate to find the last item that has a certain property.
125
* * You query this array multiple times with monotonous predicates that get weaker and weaker.
126
*/
127
export class MonotonousArray<T> {
128
public static assertInvariants = false;
129
130
private _findLastMonotonousLastIdx = 0;
131
private _prevFindLastPredicate: ((item: T) => boolean) | undefined;
132
133
constructor(private readonly _array: readonly T[]) {
134
}
135
136
/**
137
* The predicate must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!
138
* For subsequent calls, current predicate must be weaker than (or equal to) the previous predicate, i.e. more entries must be `true`.
139
*/
140
findLastMonotonous(predicate: (item: T) => boolean): T | undefined {
141
if (MonotonousArray.assertInvariants) {
142
if (this._prevFindLastPredicate) {
143
for (const item of this._array) {
144
if (this._prevFindLastPredicate(item) && !predicate(item)) {
145
throw new Error('MonotonousArray: current predicate must be weaker than (or equal to) the previous predicate.');
146
}
147
}
148
}
149
this._prevFindLastPredicate = predicate;
150
}
151
152
const idx = findLastIdxMonotonous(this._array, predicate, this._findLastMonotonousLastIdx);
153
this._findLastMonotonousLastIdx = idx + 1;
154
return idx === -1 ? undefined : this._array[idx];
155
}
156
}
157
158
/**
159
* Returns the first item that is equal to or greater than every other item.
160
*/
161
export function findFirstMax<T>(array: readonly T[], comparator: Comparator<T>): T | undefined {
162
if (array.length === 0) {
163
return undefined;
164
}
165
166
let max = array[0];
167
for (let i = 1; i < array.length; i++) {
168
const item = array[i];
169
if (comparator(item, max) > 0) {
170
max = item;
171
}
172
}
173
return max;
174
}
175
176
/**
177
* Returns the last item that is equal to or greater than every other item.
178
*/
179
export function findLastMax<T>(array: readonly T[], comparator: Comparator<T>): T | undefined {
180
if (array.length === 0) {
181
return undefined;
182
}
183
184
let max = array[0];
185
for (let i = 1; i < array.length; i++) {
186
const item = array[i];
187
if (comparator(item, max) >= 0) {
188
max = item;
189
}
190
}
191
return max;
192
}
193
194
/**
195
* Returns the first item that is equal to or less than every other item.
196
*/
197
export function findFirstMin<T>(array: readonly T[], comparator: Comparator<T>): T | undefined {
198
return findFirstMax(array, (a, b) => -comparator(a, b));
199
}
200
201
export function findMaxIdx<T>(array: readonly T[], comparator: Comparator<T>): number {
202
if (array.length === 0) {
203
return -1;
204
}
205
206
let maxIdx = 0;
207
for (let i = 1; i < array.length; i++) {
208
const item = array[i];
209
if (comparator(item, array[maxIdx]) > 0) {
210
maxIdx = i;
211
}
212
}
213
return maxIdx;
214
}
215
216
/**
217
* Returns the first mapped value of the array which is not undefined.
218
*/
219
export function mapFindFirst<T, R>(items: Iterable<T>, mapFn: (value: T) => R | undefined): R | undefined {
220
for (const value of items) {
221
const mapped = mapFn(value);
222
if (mapped !== undefined) {
223
return mapped;
224
}
225
}
226
227
return undefined;
228
}
229
230