Ho un ByteString b
con una lunghezza di forma 4 * n (con n intero) e si desidera utilizzare map
con una funzione di f::Word32->Word32
su b
(in modo che f
viene applicata a "b[0..3]
" , "b[4..7]
", ecc.). Come può essere fatto in modo efficiente (ed elegante)?applicare una funzione Word32 ad un ByteString
risposta
È possibile pezzo fino il ByteString
in modo molto efficiente, dato che B.take
e B.drop
sono entrambi O(1)
operazioni:
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)
poi:
\> :set -XOverloadedStrings
\> chunk 4 "abcdefghijkl"
["abcd","efgh","ijkl"]
il resto sarebbe quello di mappare sulla lista la conversione da e verso il tipo desiderato e una singola chiamata a B.concat
alla fine.
Una possibile fromByteString
potrebbero essere attuate mediante turni bit e piega a sinistra:
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)
quindi: (! Che non richiede una copia)
\> map fromByteString $ chunk 4 "abcdefghijkl" :: [Word32]
[1633837924,1701209960,1768581996]
Ohhh, sembra molto buono :)! Grazie mille!!! – dmw64
Non sono sicuro che 'ByteString.Conversion' fa la cosa giusta. Analizza i numeri come 'Char8' con attoparsec. – Zeta
Se l'obiettivo finale è qualcosa di tipo 'ByteString -> ByteString', il passaggio di riassemblaggio dai blocchi di 4 byte non terminerà le prestazioni? – Cactus
Un modo hacker ma efficiente è quello di convert to a storable vector , mappare sopra e riconvertire:
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
come da Michael's comment, si può facilmente definire le funzioni di conversione hacker a livello locale:
bytestringToVector bs = runST
(V.unsafeThaw (toByteVector bs) >>= V.unsafeFreeze . M.unsafeCast)
vectorToByteString v = runST
(V.unsafeThaw v >>= fmap fromByteVector . V.unsafeFreeze . M.unsafeCast)
anche se preferirei dipendo da una biblioteca per fornire questo, in particolare perché il casting non sicuro è un po 'di pesce.
* "A seconda di questa libreria dovrebbe essere visto come un modo per documentare e standardizzare un hack esistente, e non come una garanzia assoluta di comportamento corretto." * Dato che la libreria è del 2011 e non ha una versione in LTS di Stack, funziona ancora come previsto? – Zeta
Anch'io ho avuto i miei dubbi, ma sembra funzionare bene. Forse qualcuno dovrebbe trasferire tali conversioni in un pacchetto ben mantenuto. – leftaroundabout
Penso che Monotraversable's ['Data.ByteVector'] (http://hackage.haskell.org/package/mono-traversable-0.10.1/docs/Data-ByteVector.html) sia la cosa più visibile come questa - almeno se preso insieme a ['unssafeCast'] (http://hackage.haskell.org/package/vector-0.11.0.0/docs/src/Data-Vector-Storable-Mutable.html#unsafeCast) Forse è possibile eseguire operazioni monotraversibili con un poche altre funzioni come questa. – Michael
I tuoi dati sono binari o leggibili? Se il byte 4 byte '0x31343239' viene interpretato come '1429',' 9241' o binario 'Word32' 825,504,313? – Zeta