[英]Efficiently convert Foreign.Ptr Word8 (or ByteString) to UArray Int Word8
我正在使用Network.Pcap
( pcap )進行一些網絡捕獲,並計划使用Net.PacketParsing
( 網絡中心 )進行一些檢查。 為此,看起來我必須將我的數據包解析
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
,但似乎必須有更好的方法。
我也很關心我選擇的庫。 我過去曾經使用過網絡設備並發現它非常好,但它已經老了並且使用了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
已經過時,現在很少使用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.