Last active
May 10, 2023 07:09
-
-
Save jack-pappas/9725445 to your computer and use it in GitHub Desktop.
Fixed-length arrays in F#
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 code posted in fsharp-opensource discussion: | |
// https://groups.google.com/forum/#!topic/fsharp-opensource/pI73-GkoxbY | |
namespace Blah | |
open System.Runtime.InteropServices | |
[<Struct>] | |
type vec3_t = | |
val mutable X : int | |
val mutable Y : int | |
val mutable Z : int | |
[<Struct>] | |
[<StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)>] | |
type md3Frame_t = | |
[<MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)>] | |
val mutable bounds : vec3_t[]; | |
val mutable localOrigin : vec3_t; | |
val mutable radius : float32; | |
[<DefaultValue>] | |
[<MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)>] | |
val name : string; |
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
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
namespace FixedSizeBuffers | |
{ | |
internal unsafe struct MyBuffer | |
{ | |
public fixed char fixedBuffer[128]; | |
} | |
internal unsafe class MyClass | |
{ | |
public MyBuffer myBuffer = default(MyBuffer); | |
} | |
internal class Program | |
{ | |
static void Main() | |
{ | |
MyClass myC = new MyClass(); | |
unsafe | |
{ | |
// Pin the buffer to a fixed location in memory. | |
fixed (char* charPtr = myC.myBuffer.fixedBuffer) | |
{ | |
*charPtr = 'A'; | |
} | |
} | |
} | |
} | |
} |
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
// This is an F# implementation which compiles to the same IL as C#'s "fixed buffers"; | |
// or rather, would compile -- this code requires the 'fixed' construct, which isn't yet supported in F#. | |
// Vote to add 'fixed' support in F# here: | |
// http://fslang.uservoice.com/forums/245727-f-language/suggestions/5663721-add-support-for-fixed | |
namespace MyProgram | |
open System.Runtime.CompilerServices | |
open System.Runtime.InteropServices | |
#nowarn "9" | |
[<Struct>] | |
[<StructLayout(LayoutKind.Sequential, Size = 0x100)>] | |
[<UnsafeValueType>] // Comment this out for more speed, less safety | |
type FixedBufferInternal = | |
val mutable FixedElementField : char | |
[<Struct>] | |
type MyBuffer = | |
[<FixedBuffer(typeof<char>, 0x80)>] | |
val mutable fixedBuffer : FixedBufferInternal | |
type MyClass () = | |
// This is the "fixed length array" | |
[<DefaultValue>] | |
val mutable myBuffer : MyBuffer | |
module Program = | |
open Microsoft.FSharp.NativeInterop | |
[<EntryPoint>] | |
let main argv = | |
let myC = MyClass () | |
// C# version uses 'fixed'; F# doesn't have fixed yet, and this code can't be approximated with GCHandle. | |
// 'charPtr' would have the type 'char*' or 'nativeptr<char>' | |
fixed charPtr = myC.myBuffer.fixedBuffer | |
// Use the functions in the NativePtr module to read/write the array elements. | |
NativePtr.set charPtr 0 'A' | |
NativePtr.set charPtr 1 'b' | |
// 'myC' is unpinned here when 'charPtr' goes out of scope | |
0 // Exit code |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Interesting examples!
FYI, your last example suggests the need for
fixed
, which is now supported (since F# 4.1): https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/fixed. Original proposal and implementation: https://github.com/fsharp/fslang-design/blob/master/FSharp-4.1/FS-1015-support-for-fixed.md.The syntax would be something like (not tried):