Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# pointer member accessor

Is there any way of accessing the members of a NativePtr struct and assigning a value to them, much in the same way that you can in C# in the below example?

(From MSDN)

CoOrds* p = &home; p -> x = 25;

Currently I'm making use of NativePtr.write, however I'm unsure whether this is the best/correct solution.

Thanks.

like image 475
Ian Auty Avatar asked Nov 18 '16 20:11

Ian Auty


1 Answers

The way you described is the clearest way of doing this, presuming that you must deal with the structs in this manner. For completeness' sake, here's that method (with the implementation details of the packing omitted):

open FSharp.NativeInterop

[<StructLayout(...)>]
type myStructure =
    struct
        val mutable a : int
        val mutable b : byte
    end

let changeA pointer newA =
    let mutable structure = NativePtr.read pointer
    structure.a <- newA
    NativePtr.write pointer structure

However, because you must know the exact offsets of each of the elements, you could also use this information to write directly to that field. F# does not provide a way of doing this using named identifiers, and its strict typing of the nativeptr<'T> type means that you cannot simply cast to the relevant pointer type. The NativePtr.set offset ptr function adds sizeof<'T> * offset, so this is also no use in this case.

Let's say the type myStructure has the Packed attribute, for simplicity. The offsets are then 0 for a, and 4 for b. Throwing all caution to the wind, and completely abandoning the realm of managed memory, we could do:

let changeB pointer newB =
    let bPtr =
        NativePtr.toNativeInt pointer
        |> (+) 4n
        |> NativePtr.ofNativeInt<byte>
    NativePtr.write bPtr newB

or even:

let changeMember pointer offset (value : 'T) =
    let pointer' =
        NativePtr.toNativeInt pointer
        |> (+) (nativeint offset)
        |> NativePtr.ofNativeInt<'T>
    NativePtr.write pointer' value

I leave it an open question as to what the best method of dealing with these situations is, if they must be dealt with at all. I am inclined to go with the first, clearest method at the expense of additional memory use. The last, arbitrary offset method is to be avoided at all costs - if you must deal with adding raw offsets, it is much much better to wrap them in a more easily verifiable function like the second method, so the caller need not calculate the offset itself.

like image 167
Jake Lishman Avatar answered Nov 18 '22 08:11

Jake Lishman