一些代码的分析表明,大约65%的时间我在以下代码中。
它的作用是使用Data.Binary.Get monad遍历一个字节串来寻找终结符。如果它检测到0xff,则检查下一个字节是否为0x00。如果是,则丢弃0x00并继续。如果它不是0x00,则它会丢弃两个字节,并且生成的字节列表将转换为字节字符串并返回。
任何明显的优化方法?我看不到它。
parseECS = f [] False
where
f acc ff = do
b <- getWord8
if ff
then if b == 0x00
then f (0xff:acc) False
else return $ L.pack (reverse acc)
else if b == 0xff
then f acc True
else f (b:acc) False
答案 0 :(得分:1)
似乎这里可能存在错误。如果在0xff之前到达字节流的末尾,而不是0x00序列,则会引发异常。这是您的功能的修改版本:
parseECS :: Get L.ByteString
parseECS = f [] False
where
f acc ff = do
noMore <- isEmpty
if noMore
then return $ L.pack (reverse acc)
else do
b <- getWord8
if ff
then
if b == 0x00
then f (0xff:acc) False
else return $ L.pack (reverse acc)
else
if b == 0xff
then f acc True
else f (b:acc) False
我没有做任何分析,但这个功能可能会更快。扭转长名单很昂贵。我不确定我是多么懒惰getRemainingLazyByteString
。如果它太严格,这可能不适合你。
parseECS2 :: Get L.ByteString
parseECS2 = do
wx <- liftM L.unpack $ getRemainingLazyByteString
return . L.pack . go $ wx
where
go [] = []
go (0xff:0x00:wx) = 0xff : go wx
go (0xff:_) = []
go (w:wx) = w : go wx
答案 1 :(得分:0)
如果问题是“反向”,您可以使用“lookAhead”扫描位置,然后返回并重建新字符串
parseECS2 :: Get L.ByteString
parseECS2 = do
let nextWord8 = do
noMore <- isEmpty
if noMore then return Nothing
else liftM Just getWord8
let scanChunk !n = do
b <- nextWord8
case b of
Just 0xff -> return (Right (n+1))
Just _ -> scanChunk (n+1)
Nothing -> return (Left n)
let readChunks = do
c <- lookAhead (scanChunk 0)
case c of
Left n -> getLazyByteString n >>= \blk -> return [blk]
Right n -> do
blk <- getLazyByteString n
b <- lookAhead nextWord8
case b of
Just 0x00 -> skip 1 >> liftM (blk:) readChunks
_ -> return [L.init blk]
liftM (foldr L.append L.empty) readChunks