@@ -12,24 +12,31 @@ module SR =
12
12
let listsHadDifferentLengths = " The lists had different lengths."
13
13
let notEnoughElements = " The input sequence has an insufficient number of elements."
14
14
15
+ [<Emit( " new Array($0)" ) >]
16
+ let private allocate ( i : int ): ResizeArray < 'T > = jsNative
17
+
15
18
// [<Struct>]
16
- [<CustomEquality; CustomComparison>]
19
+ // [<CustomEquality; CustomComparison>]
17
20
[<CompiledName( " FSharpList" ) >]
18
- type ResizeList < 'T > =
19
- { Count: int ; Values: ResizeArray < 'T > }
21
+ type ResizeList < 'T >( count , values ) =
22
+ member _.Count : int = count
23
+ member _.Values : ResizeArray < 'T > = values
20
24
21
- member inline internal xs.Add ( x : 'T ) =
25
+ member internal xs.Add ( x : 'T ) =
22
26
let values =
23
27
if xs.Count = xs.Values.Count
24
28
then xs.Values
25
29
else xs.Values.GetRange( 0 , xs.Count)
26
30
values.Add( x)
27
- { Count = values.Count ; Values = values }
31
+ ResizeList < 'T >. NewList ( values)
28
32
29
- member inline internal xs.Reverse () =
30
- let values = xs.Values.GetRange( 0 , xs.Count)
31
- values.Reverse()
32
- { Count = values.Count; Values = values }
33
+ member internal xs.Reverse () =
34
+ let values = allocate xs.Count
35
+ let mutable j = 0
36
+ for i = xs.Count - 1 downto 0 do
37
+ values.[ j] <- xs.Values.[ i]
38
+ j <- j + 1
39
+ ResizeList< 'T>. NewList( values)
33
40
34
41
// This is a destructive internal optimization that
35
42
// can only be performed on newly constructed lists.
@@ -38,30 +45,31 @@ type ResizeList<'T> =
38
45
xs
39
46
40
47
static member inline Singleton ( x : 'T ) =
41
- let values = ResizeArray< 'T>()
42
- values.Add( x)
43
- { Count = 1 ; Values = values }
48
+ ResizeList< 'T>. NewList( ResizeArray [| x|])
44
49
45
50
static member inline NewList ( values : ResizeArray < 'T >) =
46
- { Count = values.Count; Values = values }
51
+ ResizeList( values.Count, values)
52
+
53
+ static member inline NewList ( count , values ) =
54
+ ResizeList( count, values)
47
55
48
- static member inline Empty =
49
- { Count = 0 ; Values = ResizeArray < 'T>() }
56
+ static member inline Empty : ResizeList < 'T > =
57
+ ResizeList < 'T>. NewList ( ResizeArray ())
50
58
51
59
static member inline Cons ( x : 'T , xs : 'T list ) = xs.Add( x)
52
60
53
61
member inline xs.IsEmpty = xs.Count <= 0
54
62
55
63
member inline xs.Length = xs.Count
56
64
57
- member inline xs.Head =
65
+ member xs.Head =
58
66
if xs.Count > 0
59
67
then xs.Values.[ xs.Count - 1 ]
60
68
else invalidArg " list" SR.inputListWasEmpty
61
69
62
- member inline xs.Tail =
70
+ member xs.Tail =
63
71
if xs.Count > 0
64
- then { Count = xs.Count - 1 ; Values = xs.Values }
72
+ then ResizeList < 'T >. NewList ( xs.Count - 1 , xs.Values)
65
73
else invalidArg " list" SR.inputListWasEmpty
66
74
67
75
member inline xs.Item with get ( index : int ) =
@@ -121,7 +129,7 @@ and 'T list = ResizeList<'T>
121
129
122
130
let inline indexNotFound () = raise ( System.Collections.Generic.KeyNotFoundException( SR.keyNotFoundAlt))
123
131
124
- let newList values = ResizeList.NewList ( values)
132
+ let newList values = ResizeList< 'T > . NewList ( values)
125
133
126
134
let empty () = ResizeList.Empty
127
135
@@ -174,22 +182,24 @@ let foldBack (folder: 'T -> 'acc -> 'acc) (xs: 'T list) (state: 'acc) =
174
182
let reverse ( xs : 'a list ) =
175
183
xs.Reverse()
176
184
177
- let inline reverseInPlace ( xs : 'a list ) =
178
- xs.ReverseInPlace()
185
+ let ofResizeArrayInPlace ( xs : ResizeArray < 'a >) =
186
+ xs.Reverse()
187
+ ResizeList.NewList xs
179
188
180
189
let toSeq ( xs : 'a list ): 'a seq =
181
190
xs :> System.Collections.Generic.IEnumerable< 'a>
182
191
183
192
let ofSeq ( xs : 'a seq ): 'a list =
184
193
// Seq.fold (fun acc x -> cons x acc) ResizeList.Empty xs
185
- // |> reverseInPlace
194
+ // |> ofResizeArrayInPlace
186
195
let values = ResizeArray( xs)
187
196
values.Reverse()
188
197
values |> newList
189
198
190
199
let concat ( lists : seq < 'a list >) =
191
- Seq.fold ( fold ( fun acc x -> cons x acc)) ResizeList.Empty lists
192
- |> reverseInPlace
200
+ ( ResizeArray(), lists)
201
+ ||> Seq.fold ( fold ( fun acc x -> acc.Add( x); acc))
202
+ |> ofResizeArrayInPlace
193
203
194
204
let fold2 f ( state : 'acc ) ( xs : 'a list ) ( ys : 'b list ) =
195
205
Seq.fold2 f state xs ys
@@ -200,9 +210,9 @@ let foldBack2 f (xs: 'a list) (ys: 'b list) (state: 'acc) =
200
210
let unfold ( gen : 'acc -> ( 'T * 'acc ) option ) ( state : 'acc ) =
201
211
let rec loop st acc =
202
212
match gen st with
203
- | None -> reverseInPlace acc
204
- | Some ( x, st) -> loop st ( cons x acc)
205
- loop state ResizeList.Empty
213
+ | None -> ofResizeArrayInPlace acc
214
+ | Some ( x, st) -> acc.Add ( x ); loop st acc
215
+ loop state ( ResizeArray ())
206
216
207
217
let scan f ( state : 'acc ) ( xs : 'a list ) =
208
218
Seq.scan f state xs |> ofSeq
@@ -211,21 +221,24 @@ let scanBack f (xs: 'a list) (state: 'acc) =
211
221
Seq.scanBack f xs state |> ofSeq
212
222
213
223
let append ( xs : 'a list ) ( ys : 'a list ) =
214
- // foldBack cons xs ys
215
- let mutable acc = ys
216
- for i = xs.Length - 1 downto 0 do
217
- acc <- cons xs.[ i] acc
218
- acc
224
+ let ylen = ys.Count
225
+ let values = allocate ( xs.Count + ys.Count)
226
+ for i = xs.Count - 1 downto 0 do
227
+ values.[ i + ylen] <- xs.Values.[ i]
228
+ for i = ys.Count - 1 downto 0 do
229
+ values.[ i] <- ys.Values.[ i]
230
+ ResizeList< 'a>. NewList( values)
219
231
220
232
let collect ( f : 'a -> 'b list ) ( xs : 'a list ) =
221
233
Seq.collect f xs |> ofSeq
222
234
223
235
let mapIndexed ( f : int -> 'a -> 'b ) ( xs : 'a list ) =
224
- let rec loop i acc =
225
- if i < xs.Length
226
- then loop ( i + 1 ) ( cons ( f i xs.[ i]) acc)
227
- else reverseInPlace acc
228
- loop 0 ResizeList.Empty
236
+ let values = allocate xs.Count
237
+ let mutable j = 0
238
+ for i = xs.Count - 1 downto 0 do
239
+ values.[ i] <- f j xs.Values.[ i]
240
+ j <- j + 1
241
+ ResizeList< 'b>. NewList( values)
229
242
230
243
let map ( f : 'a -> 'b ) ( xs : 'a list ) =
231
244
mapIndexed ( fun _i x -> f x) xs
@@ -243,11 +256,12 @@ let map3 f xs ys zs =
243
256
Seq.map3 f xs ys zs |> ofSeq
244
257
245
258
let mapFold ( f : 'S -> 'T -> 'R * 'S ) s xs =
246
- let folder ( nxs , fs ) x =
259
+ let folder ( nxs : ResizeArray < _ > , fs ) x =
247
260
let nx , fs = f fs x
248
- cons nx nxs, fs
249
- let nxs , s = fold folder ( ResizeList.Empty, s) xs
250
- reverseInPlace nxs, s
261
+ nxs.Add( nx)
262
+ nxs, fs
263
+ let nxs , s = fold folder ( ResizeArray(), s) xs
264
+ ofResizeArrayInPlace nxs, s
251
265
252
266
let mapFoldBack ( f : 'T -> 'S -> 'R * 'S ) xs s =
253
267
mapFold ( fun s v -> f v s) s ( reverse xs)
@@ -265,10 +279,10 @@ let iterateIndexed2 f xs ys =
265
279
fold2 ( fun i x y -> f i x y; i + 1 ) 0 xs ys |> ignore
266
280
267
281
let ofArrayWithTail ( xs : 'T []) ( tail : 'T list ) =
268
- let mutable res = tail
282
+ let values = tail.Values
269
283
for i = xs.Length - 1 downto 0 do
270
- res <- cons xs.[ i] res
271
- res
284
+ values.Add ( xs.[ i])
285
+ newList values
272
286
273
287
// let ofArray (xs: 'T[]) =
274
288
// ofArrayWithTail xs ResizeList.Empty
@@ -369,53 +383,26 @@ let tryItem index (xs: 'a list) =
369
383
else None
370
384
371
385
let filter f xs =
372
- fold ( fun acc x ->
386
+ ( ResizeArray(), xs)
387
+ ||> fold ( fun acc x ->
373
388
if f x
374
- then cons x acc
375
- else acc) ResizeList.Empty xs
376
- |> reverseInPlace
389
+ then acc.Add ( x ); acc
390
+ else acc)
391
+ |> ofResizeArrayInPlace
377
392
393
+ // TODO: Optimize this
378
394
let partition f xs =
379
395
fold ( fun ( lacc , racc ) x ->
380
396
if f x then cons x lacc, racc
381
397
else lacc, cons x racc) ( ResizeList.Empty, ResizeList.Empty) ( reverse xs)
382
398
383
- let tryItem n ( xs : 'T list ) =
384
- let rec loop i ( xs : 'T list ) =
385
- if xs.IsEmpty then None
386
- else
387
- if i = n then Some xs.Head
388
- else loop ( i + 1 ) xs.Tail
389
- loop 0 xs
390
-
391
- let item n ( xs : 'T list ) = xs.Item( n)
392
-
393
- let filter f ( xs : 'T list ) =
394
- let root = List.Empty
395
- let folder ( acc : 'T list ) x =
396
- if f x then acc.AppendConsNoTail x else acc
397
- let node = fold folder root xs
398
- node.SetConsTail List.Empty
399
- root.Tail
400
-
401
- let partition f ( xs : 'T list ) =
402
- let root1 , root2 = List.Empty, List.Empty
403
- let folder ( lacc : 'T list , racc : 'T list ) x =
404
- if f x
405
- then lacc.AppendConsNoTail x, racc
406
- else lacc, racc.AppendConsNoTail x
407
- let node1 , node2 = fold folder ( root1, root2) xs
408
- node1.SetConsTail List.Empty
409
- node2.SetConsTail List.Empty
410
- root1.Tail, root2.Tail
411
-
412
- let choose f ( xs : 'T list ) =
413
- let root = List.Empty
414
- let folder ( acc : 'T list ) x =
399
+ let choose f xs =
400
+ ( ResizeArray(), xs)
401
+ ||> fold ( fun acc x ->
415
402
match f x with
416
- | Some y -> cons y acc
417
- | None -> acc) ResizeList.Empty xs
418
- |> reverseInPlace
403
+ | Some y -> acc.Add ( y ); acc
404
+ | None -> acc)
405
+ |> ofResizeArrayInPlace
419
406
420
407
let contains ( value : 'T ) ( xs : 'T list ) ( [<Inject>] eq : System.Collections.Generic.IEqualityComparer < 'T >) =
421
408
tryFindIndex ( fun v -> eq.Equals ( value, v)) xs |> Option.isSome
@@ -427,10 +414,12 @@ let except (itemsToExclude: seq<'t>) (xs: 't list) ([<Inject>] eq: System.Collec
427
414
xs |> filter cached.Add
428
415
429
416
let initialize n f =
430
- let mutable res = ResizeList.Empty
431
- for i = 0 to n - 1 do
432
- res <- cons ( f i) res
433
- res |> reverseInPlace
417
+ let mutable j = 0
418
+ let values = allocate n
419
+ for i = n - 1 downto 0 do
420
+ values.[ i] <- f j
421
+ j <- j + 1
422
+ values |> newList
434
423
435
424
let replicate n x =
436
425
initialize n ( fun _ -> x)
@@ -458,6 +447,7 @@ let rec exists2 f xs ys =
458
447
| x, y when x = y -> f ( head xs) ( head ys) || exists2 f ( tail xs) ( tail ys)
459
448
| _ -> invalidArg " list2" SR.listsHadDifferentLengths
460
449
450
+ // TODO: Optimize this
461
451
let unzip xs =
462
452
foldBack ( fun ( x , y ) ( lacc , racc ) -> cons x lacc, cons y racc) xs ( ResizeList.Empty, ResizeList.Empty)
463
453
@@ -473,7 +463,7 @@ let zip3 xs ys zs =
473
463
let sortWith ( comparison : 'T -> 'T -> int ) ( xs : 'T list ): 'T list =
474
464
let values = ResizeArray( xs)
475
465
values.Sort( System.Comparison<_>( comparison)) // should be a stable sort in JS
476
- values |> newList |> reverseInPlace
466
+ values |> ofResizeArrayInPlace
477
467
478
468
let sort ( xs : 'T list ) ( [<Inject>] comparer : System.Collections.Generic.IComparer < 'T >): 'T list =
479
469
sortWith ( fun x y -> comparer.Compare( x, y)) xs
@@ -545,8 +535,11 @@ let getSlice (startIndex: int option) (endIndex: int option) (xs: 'T list) =
545
535
let startIndex = if startIndex < 0 then 0 else startIndex
546
536
let endIndex = if endIndex >= xs.Length then xs.Length - 1 else endIndex
547
537
// take (endIndex - startIndex + 1) (skip startIndex xs)
548
- let values = ResizeArray( endIndex - startIndex + 1 )
549
- for i = endIndex downto startIndex do values.Add( xs.[ i])
538
+ let values = allocate ( endIndex - startIndex + 1 )
539
+ let mutable j = 0
540
+ for i = endIndex downto startIndex do
541
+ values.[ j] <- xs.[ i]
542
+ j <- j + 1
550
543
values |> newList
551
544
552
545
let splitAt index ( xs : 'T list ) =
@@ -567,6 +560,7 @@ let exactlyOne (xs: 'T list) =
567
560
| 0 -> invalidArg " list" SR.inputSequenceEmpty
568
561
| _ -> invalidArg " list" SR.inputSequenceTooLong
569
562
563
+ // TODO: Optimize this
570
564
let groupBy ( projection : 'T -> 'Key ) ( xs : 'T list )( [<Inject>] eq : System.Collections.Generic.IEqualityComparer < 'Key >): ( 'Key * 'T list ) list =
571
565
let dict = System.Collections.Generic.Dictionary< 'Key, 'T list>( eq)
572
566
let mutable keys = ResizeList.Empty
@@ -579,7 +573,7 @@ let groupBy (projection: 'T -> 'Key) (xs: 'T list)([<Inject>] eq: System.Collect
579
573
dict.Add( key, cons v ResizeList.Empty)
580
574
keys <- cons key keys )
581
575
let mutable result = ResizeList.Empty
582
- keys |> iterate ( fun key -> result <- cons ( key, reverseInPlace dict.[ key]) result)
576
+ keys |> iterate ( fun key -> result <- cons ( key, dict.[ key]. ReverseInPlace () ) result)
583
577
result
584
578
585
579
let countBy ( projection : 'T -> 'Key ) ( xs : 'T list )( [<Inject>] eq : System.Collections.Generic.IEqualityComparer < 'Key >) =
0 commit comments