高效地将 Foreign.Ptr Word8(或 ByteString)转换为 UArray Int Word8
Efficiently convert Foreign.Ptr Word8 (or ByteString) to UArray Int Word8
我正在使用 Network.Pcap
(pcap) and plan to do some inspection using Net.PacketParsing
(network-house) 进行一些网络捕获。为此,看起来我必须将我的数据包解析放在
Pcap.Callback :: PktHdr -> Ptr Word8 -> IO ()
或
Pcap.CallbackBS :: PktHdr -> ByteString -> IO ().
并以 'Ptr Word8' 或 'ByteString' 的形式处理数据包。在数据包解析方面,我有:
Net.Packet.toInPack :: UArray Int Word8 -> InPacket
获取解析所需的 InPacket
类型。因此,留给我的是将 'Ptr' 或 'ByteString' 转换为 'UArray'-- 纯粹或在 IO 中。我想我可以将 ByteString
解压缩到 [Word8]
,然后从那里解压缩到 UArray
,但似乎必须有更好的方法。
我也担心我对图书馆的选择。我过去使用过 network-house 并且发现它非常好,但是它变老了并且使用了 UArray,它本身看起来有点过时。因此,欢迎提出更好的起点建议。
ByteString
和Ptr Word8
指向外部堆,而UArray
在GHC堆上,所以任何转换函数都必须复制数据。
我没有在库中找到任何直接转换函数,但幸运的是有一个 GHC 原语可以完全满足我们的需求,称为 copyAddrToByteArray#
。这使我们能够以最少的开销进行转换:
{-# language MagicHash, UnboxedTuples #-}
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import qualified Data.Array.Base as A
import GHC.Types
import GHC.Prim
import GHC.Magic (runRW#)
import GHC.ForeignPtr
import Data.Word
-- when using GHC 8.2.x or later:
byteStringToUArray :: B.ByteString -> A.UArray Int Word8
byteStringToUArray (B.PS (ForeignPtr addr _) (I# start) (I# len)) =
runRW# $ \s -> case newByteArray# len s of
(# s, marr #) -> case copyAddrToByteArray# (plusAddr# addr start) marr 0# len s of
s -> case unsafeFreezeByteArray# marr s of
(# _, arr #) -> A.UArray 0 (I# (len -# 1#)) (I# len) arr
{-# inline byteStringToUArray #-}
-- when using GHC 8.0.x:
byteStringToUArray :: B.ByteString -> A.UArray Int Word8
byteStringToUArray (B.PS (ForeignPtr addr _) (I# start) (I# len)) =
case (runRW# $ \s -> case newByteArray# len s of
(# s, marr #) -> case copyAddrToByteArray# (plusAddr# addr start) marr 0# len s of
s -> case unsafeFreezeByteArray# marr s of
(# s, arr #) -> (# s, A.UArray 0 (I# (len -# 1#)) (I# len) arr #)) of
(# _, res #) -> res
{-# inline byteStringToUArray #-}
但总的来说,你是对的,array
已经过时并且现在很少使用了。
我正在使用 Network.Pcap
(pcap) and plan to do some inspection using Net.PacketParsing
(network-house) 进行一些网络捕获。为此,看起来我必须将我的数据包解析放在
Pcap.Callback :: PktHdr -> Ptr Word8 -> IO ()
或
Pcap.CallbackBS :: PktHdr -> ByteString -> IO ().
并以 'Ptr Word8' 或 'ByteString' 的形式处理数据包。在数据包解析方面,我有:
Net.Packet.toInPack :: UArray Int Word8 -> InPacket
获取解析所需的 InPacket
类型。因此,留给我的是将 'Ptr' 或 'ByteString' 转换为 'UArray'-- 纯粹或在 IO 中。我想我可以将 ByteString
解压缩到 [Word8]
,然后从那里解压缩到 UArray
,但似乎必须有更好的方法。
我也担心我对图书馆的选择。我过去使用过 network-house 并且发现它非常好,但是它变老了并且使用了 UArray,它本身看起来有点过时。因此,欢迎提出更好的起点建议。
ByteString
和Ptr Word8
指向外部堆,而UArray
在GHC堆上,所以任何转换函数都必须复制数据。
我没有在库中找到任何直接转换函数,但幸运的是有一个 GHC 原语可以完全满足我们的需求,称为 copyAddrToByteArray#
。这使我们能够以最少的开销进行转换:
{-# language MagicHash, UnboxedTuples #-}
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import qualified Data.Array.Base as A
import GHC.Types
import GHC.Prim
import GHC.Magic (runRW#)
import GHC.ForeignPtr
import Data.Word
-- when using GHC 8.2.x or later:
byteStringToUArray :: B.ByteString -> A.UArray Int Word8
byteStringToUArray (B.PS (ForeignPtr addr _) (I# start) (I# len)) =
runRW# $ \s -> case newByteArray# len s of
(# s, marr #) -> case copyAddrToByteArray# (plusAddr# addr start) marr 0# len s of
s -> case unsafeFreezeByteArray# marr s of
(# _, arr #) -> A.UArray 0 (I# (len -# 1#)) (I# len) arr
{-# inline byteStringToUArray #-}
-- when using GHC 8.0.x:
byteStringToUArray :: B.ByteString -> A.UArray Int Word8
byteStringToUArray (B.PS (ForeignPtr addr _) (I# start) (I# len)) =
case (runRW# $ \s -> case newByteArray# len s of
(# s, marr #) -> case copyAddrToByteArray# (plusAddr# addr start) marr 0# len s of
s -> case unsafeFreezeByteArray# marr s of
(# s, arr #) -> (# s, A.UArray 0 (I# (len -# 1#)) (I# len) arr #)) of
(# _, res #) -> res
{-# inline byteStringToUArray #-}
但总的来说,你是对的,array
已经过时并且现在很少使用了。