我正在尝试编写以下函数:
memcpyByteArrayToPtr ::
ByteArray# -- ^ source
-> Int -- ^ start
-> Int -- ^ length
-> Ptr a -- ^ destination
-> IO ()
行为应该是在内部使用memcpy
将ByteArray#
的内容复制到Ptr
。我做过这样的事情有两种技巧,但我很难推断他们的安全。
第一个在memory包中找到。辅助函数withPtr定义为:
data Bytes = Bytes (MutableByteArray# RealWorld)
withPtr :: Bytes -> (Ptr p -> IO a) -> IO a
withPtr b@(Bytes mba) f = do
a <- f (Ptr (byteArrayContents# (unsafeCoerce# mba)))
touchBytes b
return a
但是,我非常确定这只是安全的,因为构建Bytes
的唯一方法是使用调用newAlignedPinnedByteArray#
的智能构造函数。 An answer given to a similar question和docs for byteArrayContents#
表示在处理固定ByteArray#
时它是唯一安全的。在我的情况下,我正在处理ByteArray#
库uses internally的text
,而且它们没有固定,所以我认为这样会不安全。
我遇到的第二种可能性是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
中有什么东西可以做到这一点吗?请随意更正我所做的任何错误假设,并感谢您的任何建议或指导。
答案 0 :(得分:6)
copyByteArrayToPtr :: ByteArray# -> Int -> Ptr a -> Int -> ST s ()
copyByteArrayToPtr ba (I# x) (Ptr p) (I# y) = ST $ \ s ->
(# copyByteArrayToAddr# ba x p y s, () #)
看起来像正确的primop。您只需要确保不要尝试将其复制到它占用的内存中。
你可能应该安全Int#
不幸的是,文档并没有让我知道每个[56]
[85,66,73]
[57]
[8,16]
[25,96,22,17]
[83,61]
应该是什么意思,但我想你可以通过试验和段错误来解决这个问题。