将Word32函数应用于ByteString

时间:2016-02-24 19:36:14

标签: haskell

我有一个ByteString b,其长度为4 * n(整数n),并希望在map上使用f::Word32->Word32函数b(以便f应用于“b[0..3]”,“b[4..7]”等。如何以高效(优雅)的方式完成这项工作?

2 个答案:

答案 0 :(得分:4)

鉴于B.takeB.drop都是ByteString操作,您可以非常有效地 chunk up O(1)

import Data.ByteString (ByteString)
import qualified Data.ByteString as B

chunk :: Int -> ByteString -> [ByteString]
chunk k = takeWhile (not . B.null) . map (B.take k) . iterate (B.drop k) 

然后:

\> :set -XOverloadedStrings
\> chunk 4 "abcdefghijkl"
["abcd","efgh","ijkl"]

剩下的就是将列表转换为所需类型的转换,以及最后一次调用B.concat

可以使用位移和左侧折叠来实现fromByteString

import Data.Bits (Bits, shiftL, (.|.))

fromByteString :: (Num a, Bits a) => ByteString -> a
fromByteString = B.foldl go 0
    where go acc i = (acc  `shiftL` 8) .|. (fromIntegral i)

然后:

\> map fromByteString $ chunk 4 "abcdefghijkl" :: [Word32]
[1633837924,1701209960,1768581996]

答案 1 :(得分:4)

一种hackish但有效的方法是convert to a storable vector(不需要副本!),映射,并转换回来:

import Data.Vector.Storable.ByteString
import qualified Data.Vector.Storable as VS
import qualified Data.ByteString as BS

mapBSChunks :: (VS.Storable a, VS.Storable b)
              => (a->b) -> BS.ByteString -> BS.ByteString
mapBSChunks f = vectorToByteString . VS.map f . byteStringToVector

根据Michael's comment,您可以在本地轻松定义这些hackish转换函数:

bytestringToVector bs = runST
   ( V.unsafeThaw (toByteVector bs) >>= V.unsafeFreeze . M.unsafeCast )
vectorToByteString v = runST
   ( V.unsafeThaw v >>= fmap fromByteVector . V.unsafeFreeze . M.unsafeCast )

虽然我依赖于一个库提供这个,特别是,因为不安全的演员有点可疑。

相关问题