0

一部のコードのプロファイリングでは、約 65% の時間で次のコードの内部にいることがわかりました。

それが行うことは、Data.Binary.Get モナドを使用して、ターミネータを探してバイト文字列をウォークスルーすることです。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
4

2 に答える 2

1

バグ修正

ここにバグがあるようです。0x00 シーケンスではなく 0xff が検出される前にバイト ストリームの最後に到達すると、例外が発生します。関数の修正版は次のとおりです。

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
于 2010-03-20T20:02:09.257 に答える
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
于 2010-03-21T16:03:51.780 に答える