将 GHC ByteArray# 复制到 Ptr
Copying GHC ByteArray# to Ptr
我正在尝试编写以下函数:
memcpyByteArrayToPtr ::
ByteArray# -- ^ source
-> Int -- ^ start
-> Int -- ^ length
-> Ptr a -- ^ destination
-> IO ()
行为应该是在内部使用 memcpy
将 ByteArray#
的内容复制到 Ptr
。我看到有两种技术可以做这样的事情,但我很难推断出它们的安全性。
第一个是在memory package. There is an auxiliary function 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 and the docs for byteArrayContents#
indicate that it is only safe when dealing with pinned ByteArray#
s. In my situation, I'm dealing with the ByteArray#
s that the text
library uses 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
中有什么东西可以做到这一点吗?请随时纠正我所做的任何错误假设,并感谢您的任何建议或指导。
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#
应该是什么意思,但我想你可以通过试验和段错误来弄明白。
我正在尝试编写以下函数:
memcpyByteArrayToPtr ::
ByteArray# -- ^ source
-> Int -- ^ start
-> Int -- ^ length
-> Ptr a -- ^ destination
-> IO ()
行为应该是在内部使用 memcpy
将 ByteArray#
的内容复制到 Ptr
。我看到有两种技术可以做这样的事情,但我很难推断出它们的安全性。
第一个是在memory package. There is an auxiliary function 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 and the docs for byteArrayContents#
indicate that it is only safe when dealing with pinned ByteArray#
s. In my situation, I'm dealing with the ByteArray#
s that the text
library uses 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
中有什么东西可以做到这一点吗?请随时纠正我所做的任何错误假设,并感谢您的任何建议或指导。
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#
应该是什么意思,但我想你可以通过试验和段错误来弄明白。