{-# OPTIONS -O2 #-} -- -- Translated from the OCaml version. -- import Control.Monad import Data.Char import Data.Array.IO import Data.Array.Base import Data.Bits import Data.Word import System import System.CPUTime import System.IO import Text.Printf iter :: Int iter = 10 main = do f <- getArgs >>= return . head (arr,l) <- slurp f t0 <- getCPUTime (arr',l') <- replicateM iter (drop0xx arr (l*8)) >>= return . head t1 <- getCPUTime printf "%.3f" $ (fromInteger (t1 - t0) :: Float) / (fromInteger 10 ^ 12 :: Float) dump f arr' (1 + (snd . bounds) arr') -------------------------------------------------------------------------------------------- drop0xx = drop0xx' 0 0 0 [] --1 drop0xx' :: Int -> Int -> Int -> [Int] -> Buffer -> Int -> IO (Buffer,Int) drop0xx' inoff reg shifts acc str len --2 | inoff `seq` reg `seq` shifts `seq` acc `seq` str `seq` len `seq` False = undefined --3 | inoff' > len = makeResult (reverse acc) reg shifts --4 | otherwise = do --5 triple <- getTriple str inoff --6 if triple >= 4 --7 then let reg' = (reg `shiftL` 3) .|. triple --8 in if shifts == 7 --9 then drop0xx' inoff' 0 0 (reg':acc) str len --10 else drop0xx' inoff' reg' (shifts+1) acc str len --11 else drop0xx' inoff' reg shifts acc str len --12 where inoff' = inoff + 3 --13 getTriple :: Buffer -> Int -> IO Int getTriple str inoff | str `seq` inoff `seq` False = undefined --14 getTriple str inoff = do --15 b0 <- str `unsafeRead` bitind >>= return . fromIntegral --16 b1 <- str `unsafeRead` (bitind+1) >>= return . fromIntegral --17 return $! (if bitoff < 6 --18 then b0 `shiftR` (5-bitoff) --19 else (b0 `shiftL` (bitoff-5)) .|. (b1 `shiftR` (13-bitoff))) --20 .&. 7 where bitoff = inoff .&. 7 --21 bitind = inoff `shiftR` 3 --22 makeResult :: [Int] -> Int -> Int -> IO (Buffer,Int) makeResult list0 endpiece shifts = do --23 arr <- newArray_ (0,triplebytesize + endpiecesize-1) :: IO Buffer --24 let packList (triple:rest) ind = do --25 unsafeWrite arr ind $ fromIntegral $ (triple `shiftR` 16) .&. 255 --26 unsafeWrite arr (ind+1) $ fromIntegral $ (triple `shiftR` 8) .&. 255 --27 unsafeWrite arr (ind+2) $ fromIntegral $ triple .&. 255 --28 packList rest (ind+3) --29 packList [] ind = --30 let c1 = endpiece `shiftL` ((shifts*3 - 8) .&. 255) --31 s0 = shifts * 3 - 8 --32 in case endpiecesize of --33 0 -> return () --34 1 -> do unsafeWrite arr ind $ fromIntegral $ --35 endpiece `shiftL` (s0 .&. 255) --36 2 -> do unsafeWrite arr ind $ fromIntegral $ --37 endpiece `shiftL` (s0 .&. 255) --38 unsafeWrite arr (ind+1) $ fromIntegral $ --39 endpiece `shiftL` ((s0-8) .&. 255) --40 packList list0 0 --41 return (arr, triplebytesize * 8 + shifts * 3) --42 where endpiecesize = getNeededBytes shifts --43 triplebytesize = 3 * length list0 --44 getNeededBytes shifts | shifts < 3 = 0 --45 | shifts < 6 = 1 --46 | otherwise = 2 --47 ------------------------------------------------------------------------ type Buffer = IOUArray Int Word8 slurp :: FilePath -> IO (Buffer, Int) slurp f = do h <- openBinaryFile f ReadMode l <- hFileSize h arr <- newArray_ (0,fromIntegral l-1) :: IO Buffer hGetArray h arr (fromIntegral l) hClose h return (arr,fromIntegral l) dump :: FilePath -> Buffer -> Int -> IO () dump f arr l = do h <- openBinaryFile (f ++ ".haskell") WriteMode hPutArray h arr l hClose h