Skip to content

Commit

Permalink
Merge pull request #33 from gsvgit/BlockResizeArray
Browse files Browse the repository at this point in the history
Block resize array basic implementation
  • Loading branch information
forki committed May 25, 2015
2 parents ce3487f + d376fe8 commit 060d6b7
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/FSharpx.Collections.Experimental/BlockResizeArray.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
namespace FSharpx.Collections

// Resize array fith fixed size block memory allocation.
// Provide more optimal space usage for huge arrays than standard ResizeArray.
// Basic version created by Avdyukhin Dmitry <dimonbv@gmail.com>

type BlockResizeArray<'T> () =
let initArraysCount = 1
let mutable count = 0
let shift = 17
let blockSize = 1 <<< shift
let smallPart = blockSize - 1
let mutable arrays = Array.init initArraysCount (fun _ -> Array.zeroCreate blockSize)
let mutable cap = blockSize * arrays.Length
let mutable nextAllocate = cap
member this.Add (x : 'T) =
if count = nextAllocate then
if count = cap then
let oldArrays = arrays
arrays <- Array.zeroCreate (arrays.Length * 2)
for i = 0 to oldArrays.Length-1 do
arrays.[i] <- oldArrays.[i]
cap <- blockSize * arrays.Length
arrays.[count >>> shift] <- Array.zeroCreate blockSize
nextAllocate <- nextAllocate + blockSize
arrays.[count >>> shift].[count &&& smallPart] <- x
count <- count + 1

member this.Item i =
arrays.[i >>> shift].[i &&& smallPart]

member this.Set i value =
arrays.[i >>> shift].[i &&& smallPart] <- value

member this.DeleteBlock i = arrays.[i] <- null
member this.Count = count
member this.Shift = shift

member this.ToArray() =
let res = Array.zeroCreate count
for i = 0 to (count >>> shift) - 1 do
Array.blit arrays.[i] 0 res (i <<< shift) blockSize
if (count &&& smallPart) <> 0 then
let i = count >>> shift
Array.blit arrays.[i] 0 res (i <<< shift) (count &&& smallPart)
res
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
<Compile Include="SkewBinaryRandomAccessList.fs" />
<Compile Include="TimeSeries.fs" />
<Compile Include="CSharpCompat.fs" />
<Compile Include="BlockResizeArray.fs" />
<None Include="paket.template" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
module FSharpx.Collections.Experimental.Tests.BlockResizeArrayTest

open FSharpx.Collections
open NUnit.Framework
open FsUnit
open FSharpx.Collections.TimeMeasurement

let arraySize = 2048*2048*10
let testIters = 10
let x = 1000UL

[<Test>]
let ``allocation performance`` () =

averageTime testIters "ResizeArrayAlloc" (fun () ->
let a = new ResizeArray<uint64>()
for i in 0..arraySize do a.Add x )
averageTime testIters "BlockResizeArrayAlloc" (fun () ->
let a = new BlockResizeArray<uint64>()
for i in 0..arraySize do a.Add x )

[<Test>]
let ``random access performance`` () =
let rand = System.Random()
let access = [|for i in 0..arraySize-1 -> rand.Next(0, arraySize - 1)|]
let a = Array.init arraySize (fun _ -> x)
let ra = new ResizeArray<uint64>()
for i in 0..arraySize do ra.Add x
let bra = new BlockResizeArray<uint64>()
for i in 0..arraySize do bra.Add x
let b = ref 0UL
averageTime testIters "ResizeArray random access" (fun () -> for i in access do ra.[i] <- 0UL)
averageTime testIters "Array random access" (fun () -> for i in access do a.[i] <- 0UL)
averageTime testIters "BlockResizeArray random access" (fun () -> for i in access do bra.Set i 0UL)

[<Test>]
let ``sequential access performance`` () =
let rand = System.Random()
let access = [|0..arraySize-1|]
let a = Array.init arraySize (fun _ -> x)
let ra = new ResizeArray<uint64>()
for i in 0..arraySize do ra.Add x
let bra = new BlockResizeArray<uint64>()
for i in 0..arraySize do bra.Add x
let b = ref 0UL
averageTime testIters "ResizeArray sequential access" (fun () -> for i in access do ra.[i] <- 0UL)
averageTime testIters "Array sequential access" (fun () -> for i in access do a.[i] <- 0UL)
averageTime testIters "BlockResize sequential access" (fun () -> for i in access do bra.Set i 0UL)
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
<Compile Include="RealTimeQueueTest.fs" />
<Compile Include="RoseTreeTest.fs" />
<Compile Include="TimeSeriesTest.fs" />
<Compile Include="BlockResizeArrayTest.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\FSharpx.Collections.Experimental\FSharpx.Collections.Experimental.fsproj">
Expand Down

0 comments on commit 060d6b7

Please sign in to comment.