{-# OPTIONS -cpp -fglasgow-exts #-} module BinArray ( BinArray , newBinArray , sizeBinArray , zeroBinArray , readWord8 , writeWord8 , readWord32 , writeWord32 , copy , getBinArrayRawBuffer -- :: BinArray -> MutableByteArray# RealWorld ) where import GHC.Base import GHC.IOBase import GHC.Word --import GHC.Int -- This is a hack to prevent the profiling version from -- being *significantly* slower than the unprofiling version. #ifdef PROFILING #define IOSCC(label) (\ fn -> IO $ \ s -> {-# SCC label #-} case fn of { IO m -> m s }) #else #define IOSCC(label) id #endif data BinArray = BinArray Int# -- size in *bytes* (MutableByteArray# RealWorld) -- byte array, padded to 32 bits sized getBinArrayRawBuffer :: BinArray -> MutableByteArray# RealWorld getBinArrayRawBuffer (BinArray _ arr) = arr newBinArray :: Int -> IO BinArray newBinArray (I# sz) = IO $ \ s_in -> case newByteArray# size s_in of { (# s, arr #) -> (# s, BinArray sz arr #) } where (I# size) = ((I# sz + 3) `div` 4) * 4 sizeBinArray :: BinArray -> Int sizeBinArray (BinArray sz _) = I# sz zeroBinArray :: BinArray -> IO () zeroBinArray arr@(BinArray sz _) = sequence_ [ writeWord8 arr i 0x0 | i <- take (I# sz) [0..] ] -- TODO: this copy needs reworked, to use the FFI. -- | copy a BinArray onto another BinArray. -- Requires that the target be the same size, or bigger. copy :: BinArray -> BinArray -> IO () copy ba1@(BinArray i1 _) ba2@(BinArray i2 _) | i1 <=# i2 && ((I# i1) `mod` 4) == 0 && ((I# i2) `mod` 4) == 0 = IOSCC("copy") $ do let loop i t | t == 0 = return () | otherwise = do v <- unsafeReadWord32 ba1 (I# i) unsafeWriteWord32 ba2 (I# i) v loop (i +# 1#) (t - 1) loop 0# ((I# i1) `div` (4 :: Int)) | otherwise = error "BinArray.copy: BinArray's need to be the same size (or bigger) for copy, and power of 4" readWord8 :: BinArray -> Int -> IO Word8 readWord8 ba@(BinArray i1 _) (I# i) | i <# i1 = unsafeReadWord8 ba (I# i) | otherwise = fail "Bad index value in readWord8" {-# INLINE unsafeReadWord8 #-} unsafeReadWord8 :: BinArray -> Int -> IO Word8 unsafeReadWord8 (BinArray _ arr) (I# i) = IO $ \ s_in -> case readWord8Array# arr i s_in of { (# s, v #) -> (# s, W8# v #) } writeWord8 :: BinArray -> Int -> Word8 -> IO () writeWord8 ba@(BinArray i1 _) (I# i) v | i <# i1 = unsafeWriteWord8 ba (I# i) v | otherwise = fail "Bad index value in writeWord8" {-# INLINE unsafeWriteWord8 #-} unsafeWriteWord8 :: BinArray -> Int -> Word8 -> IO () unsafeWriteWord8 (BinArray _ arr) (I# i) (W8# v) = IO $ \ s_in -> case writeWord8Array# arr i v s_in of { s -> (# s, () #) } -- | The addressing is done by Word32 blocks, not the byte address. readWord32 :: BinArray -> Int -> IO Word32 readWord32 ba@(BinArray i1 _) (I# i) | (i *# 4#) <# i1 = unsafeReadWord32 ba (I# i) | otherwise = fail "Bad index value in readWord32" {-# INLINE unsafeReadWord32 #-} unsafeReadWord32 :: BinArray -> Int -> IO Word32 unsafeReadWord32 (BinArray _ arr) (I# i) = IO $ \ s_in -> case readWord32Array# arr i s_in of { (# s, v #) -> (# s, W32# v #) } -- | The addressing is done by Word32 blocks, not the byte address. writeWord32 :: BinArray -> Int -> Word32 -> IO () writeWord32 ba@(BinArray i1 _) (I# i) v | (i *# 4#) <# i1 = unsafeWriteWord32 ba (I# i) v | otherwise = fail "Bad index value in writeWord32" {-# INLINE unsafeWriteWord32 #-} unsafeWriteWord32 :: BinArray -> Int -> Word32 -> IO () unsafeWriteWord32 (BinArray _ arr) (I# i) (W32# v) = IO $ \ s_in -> case writeWord32Array# arr i v s_in of { s -> (# s, () #) }