@@ -210,6 +210,200 @@ namespace collections {
210
210
}
211
211
}
212
212
213
+ export class SortedSet < T > {
214
+ private _comparer : ( a : T , b : T ) => number ;
215
+ private _values : T [ ] = [ ] ;
216
+ private _order : number [ ] | undefined ;
217
+ private _version = 0 ;
218
+ private _copyOnWrite = false ;
219
+
220
+ constructor ( comparer : ( ( a : T , b : T ) => number ) | SortOptions < T > , iterable ?: Iterable < T > ) {
221
+ this . _comparer = typeof comparer === "object" ? comparer . comparer : comparer ;
222
+ this . _order = typeof comparer === "object" && comparer . sort === "insertion" ? [ ] : undefined ;
223
+ if ( iterable ) {
224
+ const iterator = getIterator ( iterable ) ;
225
+ try {
226
+ for ( let i = nextResult ( iterator ) ; i ; i = nextResult ( iterator ) ) {
227
+ const value = i . value ;
228
+ this . add ( value ) ;
229
+ }
230
+ }
231
+ finally {
232
+ closeIterator ( iterator ) ;
233
+ }
234
+ }
235
+ }
236
+
237
+ public get size ( ) {
238
+ return this . _values . length ;
239
+ }
240
+
241
+ public get comparer ( ) {
242
+ return this . _comparer ;
243
+ }
244
+
245
+ public get [ Symbol . toStringTag ] ( ) {
246
+ return "SortedSet" ;
247
+ }
248
+
249
+ public has ( key : T ) {
250
+ return ts . binarySearch ( this . _values , key , ts . identity , this . _comparer ) >= 0 ;
251
+ }
252
+
253
+ public add ( value : T ) {
254
+ const index = ts . binarySearch ( this . _values , value , ts . identity , this . _comparer ) ;
255
+ if ( index >= 0 ) {
256
+ this . _values [ index ] = value ;
257
+ }
258
+ else {
259
+ this . writePreamble ( ) ;
260
+ insertAt ( this . _values , ~ index , value ) ;
261
+ if ( this . _order ) insertAt ( this . _order , ~ index , this . _version ) ;
262
+ this . writePostScript ( ) ;
263
+ }
264
+ return this ;
265
+ }
266
+
267
+ public delete ( value : T ) {
268
+ const index = ts . binarySearch ( this . _values , value , ts . identity , this . _comparer ) ;
269
+ if ( index >= 0 ) {
270
+ this . writePreamble ( ) ;
271
+ ts . orderedRemoveItemAt ( this . _values , index ) ;
272
+ if ( this . _order ) ts . orderedRemoveItemAt ( this . _order , index ) ;
273
+ this . writePostScript ( ) ;
274
+ return true ;
275
+ }
276
+ return false ;
277
+ }
278
+
279
+ public clear ( ) {
280
+ if ( this . size > 0 ) {
281
+ this . writePreamble ( ) ;
282
+ this . _values . length = 0 ;
283
+ if ( this . _order ) this . _order . length = 0 ;
284
+ this . writePostScript ( ) ;
285
+ }
286
+ }
287
+
288
+ public forEach ( callback : ( value : T , key : T , collection : this) => void , thisArg ?: any ) {
289
+ const values = this . _values ;
290
+ const indices = this . getIterationOrder ( ) ;
291
+ const version = this . _version ;
292
+ this . _copyOnWrite = true ;
293
+ try {
294
+ if ( indices ) {
295
+ for ( const i of indices ) {
296
+ callback . call ( thisArg , values [ i ] , values [ i ] , this ) ;
297
+ }
298
+ }
299
+ else {
300
+ for ( const value of values ) {
301
+ callback . call ( thisArg , value , value , this ) ;
302
+ }
303
+ }
304
+ }
305
+ finally {
306
+ if ( version === this . _version ) {
307
+ this . _copyOnWrite = false ;
308
+ }
309
+ }
310
+ }
311
+
312
+ public * keys ( ) {
313
+ const values = this . _values ;
314
+ const indices = this . getIterationOrder ( ) ;
315
+ const version = this . _version ;
316
+ this . _copyOnWrite = true ;
317
+ try {
318
+ if ( indices ) {
319
+ for ( const i of indices ) {
320
+ yield values [ i ] ;
321
+ }
322
+ }
323
+ else {
324
+ yield * values ;
325
+ }
326
+ }
327
+ finally {
328
+ if ( version === this . _version ) {
329
+ this . _copyOnWrite = false ;
330
+ }
331
+ }
332
+ }
333
+
334
+ public * values ( ) {
335
+ const values = this . _values ;
336
+ const indices = this . getIterationOrder ( ) ;
337
+ const version = this . _version ;
338
+ this . _copyOnWrite = true ;
339
+ try {
340
+ if ( indices ) {
341
+ for ( const i of indices ) {
342
+ yield values [ i ] ;
343
+ }
344
+ }
345
+ else {
346
+ yield * values ;
347
+ }
348
+ }
349
+ finally {
350
+ if ( version === this . _version ) {
351
+ this . _copyOnWrite = false ;
352
+ }
353
+ }
354
+ }
355
+
356
+ public * entries ( ) {
357
+ const values = this . _values ;
358
+ const indices = this . getIterationOrder ( ) ;
359
+ const version = this . _version ;
360
+ this . _copyOnWrite = true ;
361
+ try {
362
+ if ( indices ) {
363
+ for ( const i of indices ) {
364
+ yield [ values [ i ] , values [ i ] ] as [ T , T ] ;
365
+ }
366
+ }
367
+ else {
368
+ for ( const value of values ) {
369
+ yield [ value , value ] as [ T , T ] ;
370
+ }
371
+ }
372
+ }
373
+ finally {
374
+ if ( version === this . _version ) {
375
+ this . _copyOnWrite = false ;
376
+ }
377
+ }
378
+ }
379
+
380
+ public [ Symbol . iterator ] ( ) {
381
+ return this . values ( ) ;
382
+ }
383
+
384
+ private writePreamble ( ) {
385
+ if ( this . _copyOnWrite ) {
386
+ this . _values = this . _values . slice ( ) ;
387
+ if ( this . _order ) this . _order = this . _order . slice ( ) ;
388
+ this . _copyOnWrite = false ;
389
+ }
390
+ }
391
+
392
+ private writePostScript ( ) {
393
+ this . _version ++ ;
394
+ }
395
+
396
+ private getIterationOrder ( ) {
397
+ if ( this . _order ) {
398
+ const order = this . _order ;
399
+ return this . _order
400
+ . map ( ( _ , i ) => i )
401
+ . sort ( ( x , y ) => order [ x ] - order [ y ] ) ;
402
+ }
403
+ return undefined ;
404
+ }
405
+ }
406
+
213
407
export function insertAt < T > ( array : T [ ] , index : number , value : T ) : void {
214
408
if ( index === 0 ) {
215
409
array . unshift ( value ) ;
0 commit comments