我正在编写一个性能非常强的程序并且一直在使用C,但是有人告诉我函数式编程有多酷,所以我决定用F#重写它。
无论如何,我在F#中复制算法的特定功能是Duff's device。它不是典型的迭代,而是展开循环,因此它可以每次迭代复制8个字节,而不是只复制一个。
void copy_memory( char* to, char* from, size_t count ) {
size_t n = (count+7)/8;
switch( count%8 ) {
case 0: do{ *to++ = *from++;
case 7: *to++ = *from++;
case 6: *to++ = *from++;
case 5: *to++ = *from++;
case 4: *to++ = *from++;
case 3: *to++ = *from++;
case 2: *to++ = *from++;
case 1: *to++ = *from++;
}while(--n>0);
}
}
这利用了案例漏洞和跳转到C循环中间的能力,据我所知,这是F#似乎缺失的功能。
我在MSDN上阅读了一些内容,并认为F#的match
功能是我可以接近C switch
的最接近的功能。所以,我开始编写这段代码
open System.Reflection
let copyMemory (pTo : Pointer) (pFrom : Pointer) length =
let n = (length + 7) / 8
match n % 8 with
| 0 ->
然后我无法弄清楚该怎么做。它不会让我在这里开始循环并在另一种情况下结束它。
F#中有什么东西我可以用来做一个案例直播并跳到循环的中间吗?如果你能为我做到这一点,我想我可以自己弄清楚其余部分。
答案 0 :(得分:7)
这是在F#中调整记忆的惯用方法: - )
#nowarn "9" //stop telling me I'm going to break something
open Microsoft.FSharp.NativeInterop
let inline (~+) ptr = NativePtr.add ptr 1
let rec copyMemory src dest = function
| 0 -> ()
| n ->
NativePtr.read src |> NativePtr.write dest
copyMemory +src +dest (n - 1)
但这可能更符合Duff的精神
let inline (+>) s d =
NativePtr.read !s |> NativePtr.write !d
s:= NativePtr.add !s 1
d:= NativePtr.add !d 1
let copyMemory src dst count =
let n = ref ((count + 7) / 8)
let s, d = ref src, ref dst
let
rec case_0() = s +> d; case_7()
and case_7() = s +> d; case_6()
and case_6() = s +> d; case_5()
and case_5() = s +> d; case_4()
and case_4() = s +> d; case_3()
and case_3() = s +> d; case_2()
and case_2() = s +> d; case_1()
and case_1() = s +> d; decr n; if !n > 0 then case_0()
match count % 8 with
| 7 -> case_7() | 6 -> case_6()
| 5 -> case_5() | 4 -> case_4()
| 3 -> case_3() | 2 -> case_2()
| 1 -> case_1() | _ -> case_0()
但严重
System.Buffer.BlockCopy(src, 0, dest, 0, count)
答案 1 :(得分:2)
F#中没有标签。但是,你可以用另一种方式展开循环。
let copy (dst : nativeptr<byte>) (src : nativeptr<byte>) count =
let mutable s = src
let mutable d = dst
for n in 1 .. count / 8 do
NativePtr.read s |> NativePtr.write d
s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1)
d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1)
NativePtr.read s |> NativePtr.write d
s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1)
d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1)
NativePtr.read s |> NativePtr.write d
s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1)
d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1)
NativePtr.read s |> NativePtr.write d
s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1)
d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1)
NativePtr.read s |> NativePtr.write d
s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1)
d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1)
NativePtr.read s |> NativePtr.write d
s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1)
d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1)
NativePtr.read s |> NativePtr.write d
s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1)
d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1)
NativePtr.read s |> NativePtr.write d
s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1)
d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1)
for n in 1 .. count % 8 do
NativePtr.read s |> NativePtr.write d
s <- NativePtr.ofNativeInt(NativePtr.toNativeInt s + nativeint 1)
d <- NativePtr.ofNativeInt(NativePtr.toNativeInt d + nativeint 1)
在相关的说明中,NativePtr.add
将在nativeptr上调用sizeof,因此我将其转换为上面的nativeint。