Skip to content

Instantly share code, notes, and snippets.

@cloudRoutine
Created November 22, 2015 15:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cloudRoutine/30d4dbb8472b10301c03 to your computer and use it in GitHub Desktop.
Save cloudRoutine/30d4dbb8472b10301c03 to your computer and use it in GitHub Desktop.
Blit Parsing On Stack Allocated Array
open System.Reflection
open System.Reflection.Emit
open System.Runtime.InteropServices
open System
[<AutoOpen>]
module ByteUtils =
type Bit =
| One
| Zero
override this.ToString() =
match this with
| One -> "1"
| Zero -> "0"
let bitToByte = function
| One -> byte(1)
| Zero -> byte(0)
let bitMasks =
Array.zeroCreate 8
|> Array.mapi ( fun i _ -> byte(pown 2 i), i )
|> Array.rev
let private mask inputByte (bitMask, bitPosition) =
if (inputByte &&& bitMask) >>> bitPosition = byte(0) then Zero
else One
let byteToBitArray inputByte =
bitMasks |> Array.map (mask inputByte)
let bytesToBits (bytes:byte[]) =
bytes |> Array.collect byteToBitArray
let bitsToUInt (bits:Bit[]) =
let positions = Array.zip bits (Array.rev [|0..Array.length bits - 1|])
Array.fold (fun acc (bit, index) ->
match bit with
| Zero -> acc
| One -> acc + (pown 2 index)) 0 positions
let sizeofType objType = Marshal.SizeOf objType
type BlitParser<'T> = delegate of byte[] * int * int * int -> 'T[]
let makeUnsafeArrayBlitParser<'T when 'T: unmanaged> () : BlitParser<'T> =
let d = new DynamicMethod ( "BlitParseArray" + ( typeof<'T> |> string ) ,
typeof<'T[]> ,
[| typeof<byte[]>; typeof<int>; typeof<int>; typeof<int> |] ,
Assembly.GetExecutingAssembly().ManifestModule )
// ___( byte[] array, int count, int offset, int length )
let gen = d.GetILGenerator()
// T[] result
gen.DeclareLocal( typeof<'T[]> ) |> ignore
// IntPtr resultPtr
gen.DeclareLocal( typeof<IntPtr>, true ) |> ignore
// result = new T[count]
gen.Emit( OpCodes.Ldarg_1 )
gen.Emit( OpCodes.Newarr, typeof<'T> )
gen.Emit( OpCodes.Stloc_0 )
// fixed ( IntPtr resultPtr = result )
gen.Emit( OpCodes.Ldloc_0 )
gen.Emit( OpCodes.Ldc_I4_0 )
gen.Emit( OpCodes.Ldelema, typeof<'T> )
gen.Emit( OpCodes.Stloc_1 )
// Marshal.Copy( array, offset, (IntPtr)resultPtr, length )
gen.Emit( OpCodes.Ldarg_0 )
gen.Emit( OpCodes.Ldarg_2 )
gen.Emit( OpCodes.Ldloc_1 )
gen.Emit( OpCodes.Conv_I )
gen.Emit( OpCodes.Ldarg_3 )
let marshalCopy = typeof<Marshal>.GetMethod( "Copy", [| typeof<byte[]>; typeof<int>; typeof<IntPtr>; typeof<int> |])
gen.EmitCall( OpCodes.Call, marshalCopy, null)
// return result
gen.Emit( OpCodes.Ldloc_0 )
gen.Emit( OpCodes.Ret )
d.CreateDelegate( typeof<BlitParser<'T>> ) :?> BlitParser<'T>
let blit<'T when 'T: unmanaged > (byteArray: byte[]) : 'T [] =
let size = sizeofType typeof<'T>
let count = byteArray.Length / size
let offset = 0
let length = byteArray.Length
let args = (byteArray, count, offset, length)
let func = makeUnsafeArrayBlitParser()
func.Invoke args
let byteArrayToObjects<'T when 'T: unmanaged > (byteArray: byte[]) networkOrder : 'T [] =
blit byteArray |> (if networkOrder then Array.rev else id)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment