-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #33 from gsvgit/BlockResizeArray
Block resize array basic implementation
- Loading branch information
Showing
4 changed files
with
96 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
tests/FSharpx.Collections.Experimental.Tests/BlockResizeArrayTest.fs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters