Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 51 additions & 86 deletions src/fsharp/block.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ type blockbuilder<'T> = ImmutableArray<'T>.Builder
module BlockBuilder =

let create size : blockbuilder<'T> =
if size = 0 then
ImmutableArray.CreateBuilder()
else
ImmutableArray.CreateBuilder(size)
ImmutableArray.CreateBuilder(size)

[<RequireQualifiedAccess>]
module Block =

[<GeneralizableValue>]
let empty<'T> = ImmutableArray<'T>.Empty
Comment thread
TIHan marked this conversation as resolved.
Resolved

let init n (f: int -> 'T) : block<_> =
Expand All @@ -30,7 +28,7 @@ module Block =
let builder = ImmutableArray.CreateBuilder(n)
for i = 0 to n - 1 do
builder.Add(f i)
builder.ToImmutable()
builder.MoveToImmutable()

let iter f (arr: block<'T>) =
for i = 0 to arr.Length - 1 do
Expand All @@ -56,23 +54,23 @@ module Block =

let map (mapper: 'T -> 'U) (arr: block<'T>) : block<_> =
match arr.Length with
| 0 -> block.Empty
| 0 -> ImmutableArray.Empty
| 1 -> ImmutableArray.Create(mapper arr.[0])
| _ ->
let builder = ImmutableArray.CreateBuilder(arr.Length)
for i = 0 to arr.Length - 1 do
builder.Add(mapper arr.[i])
builder.ToImmutable()
builder.MoveToImmutable()

let mapi (mapper: int -> 'T -> 'U) (arr: block<'T>) : block<_> =
match arr.Length with
| 0 -> block.Empty
| 0 -> ImmutableArray.Empty
| 1 -> ImmutableArray.Create(mapper 0 arr.[0])
| _ ->
let builder = ImmutableArray.CreateBuilder(arr.Length)
for i = 0 to arr.Length - 1 do
builder.Add(mapper i arr.[i])
builder.ToImmutable()
builder.MoveToImmutable()

let map2 (mapper: 'T1 -> 'T2 -> 'T) (arr1: block<'T1>) (arr2: block<'T2>) : block<_> =
if arr1.Length <> arr2.Length then
Expand All @@ -85,7 +83,7 @@ module Block =
let builder = ImmutableArray.CreateBuilder(n)
for i = 0 to n - 1 do
builder.Add(mapper arr1.[i] arr2.[i])
builder.ToImmutable()
builder.MoveToImmutable()

let mapi2 (mapper: int -> 'T1 -> 'T2 -> 'T) (arr1: block<'T1>) (arr2: block<'T2>) : block<_> =
if arr1.Length <> arr2.Length then
Expand All @@ -98,85 +96,55 @@ module Block =
let builder = ImmutableArray.CreateBuilder(n)
for i = 0 to n - 1 do
builder.Add(mapper i arr1.[i] arr2.[i])
builder.ToImmutable()

let concat (arr: block<block<'T>>) : block<'T> =
if arr.IsEmpty then
empty
elif arr.Length = 1 then
arr.[0]
elif arr.Length = 2 then
arr.[0].AddRange(arr.[1])
else
let mutable arr2 = arr.[0]
for i = 1 to arr.Length - 1 do
arr2 <- arr2.AddRange(arr.[i])
arr2
builder.MoveToImmutable()

let concat (arrs: block<block<'T>>) : block<'T> =
match arrs.Length with
| 0 -> ImmutableArray.Empty
| 1 -> arrs.[0]
| 2 -> arrs.[0].AddRange(arrs.[1])
| _ ->
let mutable acc = 0
for h in arrs do
acc <- acc + h.Length

let builder = ImmutableArray.CreateBuilder(acc)
for i = 0 to arrs.Length - 1 do
builder.AddRange(arrs.[i])
builder.MoveToImmutable()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing capacity <- count or ToImmutable here, as capacity could be anything.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine. acc is the total length of the final array.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I completely missed the the length summing loop, yep it's fine!


let forall predicate (arr: block<'T>) =
Comment thread
TIHan marked this conversation as resolved.
Resolved
match arr.Length with
| 0 -> true
| 1 -> predicate arr.[0]
| n ->
let mutable result = true
let mutable i = 0
while result && i < n do
result <- predicate arr.[i]
i <- i + 1
result
let len = arr.Length
let rec loop i = i >= len || (predicate arr.[i] && loop (i+1))
loop 0

let forall2 predicate (arr1: block<'T1>) (arr2: block<'T2>) =
if arr1.Length <> arr2.Length then
invalidOp "Block lengths do not match."

match arr1.Length with
| 0 -> true
| 1 -> predicate arr1.[0] arr2.[0]
| n ->
let mutable result = true
let mutable i = 0
while result && i < n do
result <- predicate arr1.[i] arr2.[i]
i <- i + 1
result
let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(predicate)
let len1 = arr1.Length
let rec loop i = i >= len1 || (f.Invoke(arr1.[i], arr2.[i]) && loop (i+1))
loop 0

let tryFind predicate (arr: block<'T>) =
match arr.Length with
| 0 -> None
| 1 -> if predicate arr.[0] then Some arr.[0] else None
| n ->
let mutable result = None
let mutable i = 0
while result.IsNone && i < n do
if predicate arr.[i] then
result <- Some arr.[i]
i <- i + 1
result
let rec loop i =
if i >= arr.Length then None else
if predicate arr.[i] then Some arr.[i] else loop (i+1)
loop 0

let tryFindIndex predicate (arr: block<'T>) =
match arr.Length with
| 0 -> None
| 1 -> if predicate arr.[0] then Some 0 else None
| n ->
let mutable result = None
let mutable i = 0
while result.IsNone && i < n do
if predicate arr.[i] then
result <- Some i
i <- i + 1
result
let len = arr.Length
let rec go n = if n >= len then None elif predicate arr.[n] then Some n else go (n+1)
go 0

let tryPick chooser (arr: block<'T>) =
match arr.Length with
| 0 -> None
| 1 -> chooser arr.[0]
| n ->
let mutable result = None
let mutable i = 0
while result.IsNone && i < n do
result <- chooser arr.[i]
i <- i + 1
result
let rec loop i =
if i >= arr.Length then None else
match chooser arr.[i] with
| None -> loop(i+1)
| res -> res
loop 0

let ofSeq (xs: 'T seq) =
ImmutableArray.CreateRange(xs)
Expand All @@ -192,25 +160,22 @@ module Block =
for i = 0 to arr.Length - 1 do
if predicate arr.[i] then
builder.Add(arr.[i])
builder.ToImmutable()
builder.Capacity <- builder.Count
builder.MoveToImmutable()

let exists predicate (arr: block<'T>) =
let n = arr.Length
let mutable result = false
let mutable i = 0
while not result && i < n do
if predicate arr.[i] then
result <- true
i <- i + 1
result
let len = arr.Length
let rec loop i = i < len && (predicate arr.[i] || loop (i+1))
len > 0 && loop 0

let choose (chooser: 'T -> 'U option) (arr: block<'T>) : block<'U> =
let builder = ImmutableArray.CreateBuilder(arr.Length)
for i = 0 to arr.Length - 1 do
let result = chooser arr.[i]
if result.IsSome then
builder.Add(result.Value)
builder.ToImmutable()
builder.Capacity <- builder.Count

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't know the length it doesn't matter too much if you do ToImmutable. You'll do a copy by changing capacity anyway.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the capacity will only copy if the count is different.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough :)

builder.MoveToImmutable()

let isEmpty (arr: block<_>) = arr.Length = 0

Expand Down
1 change: 1 addition & 0 deletions src/fsharp/block.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module BlockBuilder =
[<RequireQualifiedAccess>]
module Block =

[<GeneralizableValue>]
val empty<'T> : block<'T>

val init : n: int -> f: (int -> 'T) -> block<'T>
Expand Down