我正在编写一个非常注重性能的程序,并且一直在使用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#中的某些内容进行大小写掉入并跳入循环的中间吗?如果您能为我做到这一点,我想我可以自己找出其余的人。
最佳答案
这是在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)