1+ /// <reference path="./harness.ts" />
2+ namespace Collections {
3+ import compareValues = ts . compareValues ;
4+ import binarySearch = ts . binarySearch ;
5+ import removeAt = ts . orderedRemoveItemAt ;
6+
7+ const caseInsensitiveComparisonCollator = typeof Intl === "object" ? new Intl . Collator ( /*locales*/ undefined , { usage : "sort" , sensitivity : "accent" } ) : undefined ;
8+ const caseSensitiveComparisonCollator = typeof Intl === "object" ? new Intl . Collator ( /*locales*/ undefined , { usage : "sort" , sensitivity : "variant" } ) : undefined ;
9+
10+ export function compareStrings ( a : string | undefined , b : string | undefined , ignoreCase ?: boolean ) {
11+ if ( a === b ) return 0 ;
12+ if ( a === undefined ) return - 1 ;
13+ if ( b === undefined ) return + 1 ;
14+ const collator = ignoreCase ? caseInsensitiveComparisonCollator : caseSensitiveComparisonCollator ;
15+ if ( collator ) {
16+ return collator . compare ( a , b ) ;
17+ }
18+ else if ( ignoreCase ) {
19+ a = a . toUpperCase ( ) ;
20+ b = b . toUpperCase ( ) ;
21+ }
22+ return a < b ? - 1 : a > b ? + 1 : 0 ;
23+ }
24+
25+ export namespace compareStrings {
26+ export function caseSensitive ( a : string | undefined , b : string | undefined ) {
27+ return compareStrings ( a , b , /*ignoreCase*/ false ) ;
28+ }
29+
30+ export function caseInsensitive ( a : string | undefined , b : string | undefined ) {
31+ return compareStrings ( a , b , /*ignoreCase*/ true ) ;
32+ }
33+ }
34+
35+ function insertAt < T > ( array : T [ ] , index : number , value : T ) {
36+ if ( index === 0 ) {
37+ array . unshift ( value ) ;
38+ }
39+ else if ( index === array . length ) {
40+ array . push ( value ) ;
41+ }
42+ else {
43+ for ( let i = array . length ; i > index ; i -- ) {
44+ array [ i ] = array [ i - 1 ] ;
45+ }
46+ array [ index ] = value ;
47+ }
48+ }
49+
50+ /**
51+ * A collection of key/value pairs sorted by key.
52+ */
53+ export class KeyedCollection < K , V > {
54+ private _comparer : ( a : K , b : K ) => number ;
55+ private _keys : K [ ] = [ ] ;
56+ private _values : V [ ] = [ ] ;
57+ private _order : number [ ] = [ ] ;
58+ private _version = 0 ;
59+ private _copyOnWrite = false ;
60+
61+ constructor ( comparer : ( a : K , b : K ) => number = compareValues ) {
62+ this . _comparer = comparer ;
63+ }
64+
65+ public get size ( ) {
66+ return this . _keys . length ;
67+ }
68+
69+ public has ( key : K ) {
70+ return binarySearch ( this . _keys , key , this . _comparer ) >= 0 ;
71+ }
72+
73+ public get ( key : K ) {
74+ const index = binarySearch ( this . _keys , key , this . _comparer ) ;
75+ return index >= 0 ? this . _values [ index ] : undefined ;
76+ }
77+
78+ public set ( key : K , value : V ) {
79+ const index = binarySearch ( this . _keys , key , this . _comparer ) ;
80+ if ( index >= 0 ) {
81+ this . _values [ index ] = value ;
82+ }
83+ else {
84+ this . writePreamble ( ) ;
85+ insertAt ( this . _keys , ~ index , key ) ;
86+ insertAt ( this . _values , ~ index , value ) ;
87+ insertAt ( this . _order , ~ index , this . _version ) ;
88+ this . _version ++ ;
89+ }
90+ return this ;
91+ }
92+
93+ public delete ( key : K ) {
94+ const index = binarySearch ( this . _keys , key , this . _comparer ) ;
95+ if ( index >= 0 ) {
96+ this . writePreamble ( ) ;
97+ removeAt ( this . _keys , index ) ;
98+ removeAt ( this . _values , index ) ;
99+ removeAt ( this . _order , index ) ;
100+ this . _version ++ ;
101+ return true ;
102+ }
103+ return false ;
104+ }
105+
106+ public clear ( ) {
107+ if ( this . size > 0 ) {
108+ this . writePreamble ( ) ;
109+ this . _keys . length = 0 ;
110+ this . _values . length = 0 ;
111+ this . _order . length = 0 ;
112+ this . _version = 0 ;
113+ }
114+ }
115+
116+ public forEach ( callback : ( value : V , key : K , collection : this) => void ) {
117+ const keys = this . _keys ;
118+ const values = this . _values ;
119+ const order = this . getInsertionOrder ( ) ;
120+ const version = this . _version ;
121+ this . _copyOnWrite = true ;
122+ for ( let i = 0 ; i < order . length ; i ++ ) {
123+ callback ( values [ order [ i ] ] , keys [ order [ i ] ] , this ) ;
124+ }
125+ if ( version === this . _version ) {
126+ this . _copyOnWrite = false ;
127+ }
128+ }
129+
130+ private writePreamble ( ) {
131+ if ( this . _copyOnWrite ) {
132+ this . _keys = this . _keys . slice ( ) ;
133+ this . _values = this . _values . slice ( ) ;
134+ this . _order = this . _order . slice ( ) ;
135+ this . _copyOnWrite = false ;
136+ }
137+ }
138+
139+ private getInsertionOrder ( ) {
140+ return this . _order
141+ . map ( ( _ , i ) => i )
142+ . sort ( ( x , y ) => compareValues ( this . _order [ x ] , this . _order [ y ] ) ) ;
143+ }
144+ }
145+
146+ const undefinedSentinel = { } ;
147+
148+ /**
149+ * A collection of metadata that supports inheritance.
150+ */
151+ export class Metadata {
152+ private _parent : Metadata | undefined ;
153+ private _map : { [ key : string ] : any } ;
154+ private _version = 0 ;
155+ private _size = - 1 ;
156+ private _parentVersion : number | undefined ;
157+
158+ constructor ( parent ?: Metadata ) {
159+ this . _parent = parent ;
160+ this . _map = Object . create ( parent ? parent . _map : null ) ; // tslint:disable-line:no-null-keyword
161+ }
162+
163+ public get size ( ) : number {
164+ if ( this . _size === - 1 || ( this . _parent && this . _parent . _version !== this . _parentVersion ) ) {
165+ let size = 0 ;
166+ for ( const _ in this . _map ) size ++ ;
167+ this . _size = size ;
168+ if ( this . _parent ) {
169+ this . _parentVersion = this . _parent . _version ;
170+ }
171+ }
172+ return this . _size ;
173+ }
174+
175+ public has ( key : string ) : boolean {
176+ return this . _map [ key ] !== undefined ;
177+ }
178+
179+ public get ( key : string ) : any {
180+ const value = this . _map [ key ] ;
181+ return value === undefinedSentinel ? undefined : value ;
182+ }
183+
184+ public set ( key : string , value : any ) : this {
185+ this . _map [ key ] = value === undefined ? undefinedSentinel : value ;
186+ this . _size = - 1 ;
187+ this . _version ++ ;
188+ return this ;
189+ }
190+
191+ public delete ( key : string ) : boolean {
192+ if ( this . _map [ key ] !== undefined ) {
193+ delete this . _map [ key ] ;
194+ this . _size = - 1 ;
195+ this . _version ++ ;
196+ return true ;
197+ }
198+ return false ;
199+ }
200+
201+ public clear ( ) : void {
202+ this . _map = Object . create ( this . _parent ? this . _parent . _map : null ) ; // tslint:disable-line:no-null-keyword
203+ this . _size = - 1 ;
204+ this . _version ++ ;
205+ }
206+
207+ public forEach ( callback : ( value : any , key : string , map : this) => void ) {
208+ for ( const key in this . _map ) {
209+ callback ( this . _map [ key ] , key , this ) ;
210+ }
211+ }
212+ }
213+ }
0 commit comments