2016-09-25 59 views
3

我想寫以下功能:複製GHC的ByteArray#到PTR

memcpyByteArrayToPtr :: 
    ByteArray# --^source 
    -> Int --^start 
    -> Int --^length 
    -> Ptr a --^destination 
    -> IO() 

行爲應該是內部使用memcpyByteArray#的內容複製到Ptr。我有兩種技術可以做這樣的事情,但是我很難推斷他們的安全性。

第一個發現在memory包中。有一個輔助功能withPtr定義爲:

data Bytes = Bytes (MutableByteArray# RealWorld) 

withPtr :: Bytes -> (Ptr p -> IO a) -> IO a 
withPtr [email protected](Bytes mba) f = do 
    a <- f (Ptr (byteArrayContents# (unsafeCoerce# mba))) 
    touchBytes b 
    return a 

但是,我敢肯定,這僅僅是安全的,因爲構建Bytes的唯一途徑是通過調用newAlignedPinnedByteArray#一個聰明的構造函數。 An answer given to a similar questiondocs for byteArrayContents#表明只有在處理固定的ByteArray#時纔是安全的。在我的情況下,我正在處理,即textuses internally,並且它們沒有固定,所以我認爲這將是不安全的。

我偶然發現的第二種可能性是text本身。在Data.Text.Array source code的底部,有一個FFI功能memcpyI

foreign import ccall unsafe "_hs_text_memcpy" memcpyI 
    :: MutableByteArray# s -> CSize -> ByteArray# -> CSize -> CSize -> IO() 

這是由下面的C代碼的支持:

void _hs_text_memcpy(void *dest, size_t doff, const void *src, size_t soff, size_t n) 
{ 
    memcpy(dest + (doff<<1), src + (soff<<1), n<<1); 
} 

由於它的text的一部分,我相信這是安全的,它看起來很危險,因爲它是從未固定的ByteArray#獲取內存位置,這是byteArrayContents#文檔警告的內容。我認爲沒關係,因爲ffi呼叫被標記爲不安全,我認爲這阻止GC在ffi呼叫期間移動ByteArray#

這就是我所做的研究。到目前爲止,我最好的猜測是我可以複製text中已完成的工作。最大的區別是,我不會傳入MutableByteArray#ByteArray#作爲兩個指針,而是通過ByteArray#Ptr a(或者可能是Addr#,我不確定您通常使用哪些ffi)。

我建議安全嗎?有沒有更好的方法可以讓我避免使用ffi? base中有沒有這樣做?隨時糾正我做出的任何不正確的假設,並感謝您的任何建議或指導。

+1

'copyByteArrayToAddr#:: ByteArray# - > Int# - > Addr# - > Int# - > State#s - > State#s'看起來很有希望。雖然文檔似乎缺少了一些單詞,但它的有效性有點不明確。 「複製ByteArray的範圍。ByteArray必須包含指定的範圍,但不會被選中。 Addr#不能指向ByteArray被固定),但是這也沒有被選中。「 – dfeuer

+2

啊,這只是一個Haddock問題。源代碼說:」Addr#不能指向MutableByteArray#(例如,如果MutableByteArray# 「 – dfeuer

+0

非常好,看起來它應該是安全的,如果你想將你的評論轉換爲答案,我會接受它,如果不是,我會將它轉換成並且接受它 –

回答

6
copyByteArrayToAddr# :: ByteArray# -> Int# -> Addr# -> Int# -> State# s -> State# s 

看起來像是正確的primop。您只需確保不要嘗試將其複製到佔用的內存中。所以,你應該是安全與

copyByteArrayToPtr :: ByteArray# -> Int -> Ptr a -> Int -> ST s() 
copyByteArrayToPtr ba (I# x) (Ptr p) (I# y) = ST $ \ s -> 
    (# copyByteArrayToAddr# ba x p y s,() #) 

不幸的是,該文件給了我不知道什麼每個Int#應該是說,但我想你能明白這一點通過試驗和段錯誤。

+2

從它在'Data.ByteString.Short.Internal'中的使用,我能夠辨別第一個'Int#'是開始索引,第二個是長度,文檔真的應該改進。 –