如何在 Haskell 中有效地字节交换二进制数据

发布于 2025-01-11 03:32:47 字数 600 浏览 0 评论 0原文

下面的 byteswap 可以满足我的要求,但我担心它对于较大的二进制数据块来说效率低下。有没有高效的库函数或者我可以使用的东西?

{-# LANGUAGE OverloadedStrings #-}

import qualified Data.ByteString as B (ByteString, length, append, cons, foldl)

byteswap :: B.ByteString -> B.ByteString
byteswap = let
  swapper (collector, result) byte = let
    updated = B.cons byte collector
    in if 3 < B.length updated then ("", B.append result updated) else (updated, result)
  in snd . B.foldl swapper ("", "")

main = print $ byteswap "1234abcdXYZ"

打印 4321dcba

byteswap below does what I want, but I fear it is inefficient for larger chunks of binary data. Is there an efficient library function or something I can use?

{-# LANGUAGE OverloadedStrings #-}

import qualified Data.ByteString as B (ByteString, length, append, cons, foldl)

byteswap :: B.ByteString -> B.ByteString
byteswap = let
  swapper (collector, result) byte = let
    updated = B.cons byte collector
    in if 3 < B.length updated then ("", B.append result updated) else (updated, result)
  in snd . B.foldl swapper ("", "")

main = print $ byteswap "1234abcdXYZ"

Prints 4321dcba.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

樱&纷飞 2025-01-18 03:32:47

代码中最慢的部分是 append ,它与您生成的字节串的大小成线性关系,因此您的程序将至少花费二次时间。

相反,您可以使用列表作为中间结构(理想情况下会被融合)并一次性打包整个结果:

byteswap :: B.ByteString -> B.ByteString
byteswap xs = B.pack
  [ B.index xs $ i * 4 + j
  | i <- [0 .. B.length xs `quot` 4 - 1]
  , j <- [3,2,1,0]
  ]

这可以在我的机器上 3 秒内完成 1000 万字节。

您可以通过使用不安全的内部字节串函数来加速它:

byteswap :: B.ByteString -> B.ByteString
byteswap xs = unsafePackLenBytes (B.length xs `quot` 4 * 4)
  [ unsafeIndex xs $ i * 4 + j
  | i <- [0 .. B.length xs `quot` 4 - 1]
  , j <- [3,2,1,0]
  ]

并使用 我的 unsafePackLenBytes 融合补丁 我在 6 毫秒内交换了 1000 万字节。

The slow part of your code is append which is linear in the size of the bytestring that you are generating, hence your program will take at least quadratic time.

Instead you can use a list as intermediate structure (which ideally would get fused away) and pack the whole result in one go:

byteswap :: B.ByteString -> B.ByteString
byteswap xs = B.pack
  [ B.index xs $ i * 4 + j
  | i <- [0 .. B.length xs `quot` 4 - 1]
  , j <- [3,2,1,0]
  ]

This can do 10 million bytes in 3 seconds on my machine.

You can speed it up by using unsafe internal bytestring functions:

byteswap :: B.ByteString -> B.ByteString
byteswap xs = unsafePackLenBytes (B.length xs `quot` 4 * 4)
  [ unsafeIndex xs $ i * 4 + j
  | i <- [0 .. B.length xs `quot` 4 - 1]
  , j <- [3,2,1,0]
  ]

And with my patch for fusion of unsafePackLenBytes I get 10 million bytes swapped in 6 ms.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文