向指针添加64位偏移量

Fra*_*ank 5 .net f# interop pointers native

在F#中,有NativePtr模块,但它似乎只为其'add/get/set函数支持32位偏移,就像System.IntPtr一样.

有没有办法在F#中为本机指针(nativeptr <'a>)添加64位偏移量?当然,我可以将所有地址转换为64位整数,执行正常的整数运算,然后将结果再次转换为nativeptr <'a>,但这会花费额外的add和imul指令.我真的希望AGU执行地址计算.

例如,在C#中使用unsafe,你可以做类似的事情

void* ptr = Marshal.AllocHGlobal(...).ToPointer();
int64 offset = ...;
T* newAddr = (T*)ptr + offset; // T has to be an unmanaged type
Run Code Online (Sandbox Code Playgroud)

实际上你不能,因为类型参数没有"非托管"约束,但至少你可以用非泛型方式进行通用指针运算.

在F#中,我们终于得到了非托管约束; 但是如何进行指针运算呢?

Tom*_*cek 3

我不是该领域的专家,但我查看了该模块的 F# 实现,我认为转换和返回NativePtr没有相关的性能开销。nativeptr<'a>nativeint

该实现使用内联 IL,并且内联 IL 代码不包含任何代码 - 它只是为了让 F# 编译器认为堆栈上的值具有不同的类型:

let inline ofNativeInt (x:nativeint)    = (# "" x : nativeptr<_> #)
let inline toNativeInt (x:nativeptr<_>) = (# "" x : nativeint    #)
Run Code Online (Sandbox Code Playgroud)

事实上,该NativePtr.add方法也使用了这两个方法——它将指针转换为nativeint32 位整数,然后相加(乘以类型的大小'a)。

所以,下面的函数应该没问题:

let inline addNativeInt (x:nativeptr<'a>) (n:nativeint) : nativeptr<'a> = 
   (NativePtr.toNativeInt x) + n |> NativePtr.ofNativeInt
Run Code Online (Sandbox Code Playgroud)

代码中使用的所有函数都应该内联,因此您最终只会得到一条添加指令(尽管我尚未验证这一点)。您甚至不必担心在代码中多次使用该函数(您可以nativeptr<'a>一直使用该函数并使用该函数进行添加)。

然而,对数据进行分区也可能是一种选择 - 据我所知,使用 F# 处理一些大型(>2GB)数据集的 MSR 团队正是使用了这种方法 - 他们将数据分区为 2GB 块(存储在数组中) 。

  • @Novox:您可以下载 Visual Studio 2008 的 F# 版本 - 它附带源代码(在“source”目录中)。这是一个非常有用的信息来源:-)。有趣的是 Reflector 无法处理这些代码! (2认同)