-- | Atomic binary formats. module Data.Repa.Convert.Format.Binary ( Format (..) , Word8be (..), Int8be (..) , Word16be (..), Int16be (..) , Word32be (..), Int32be (..) , Word64be (..), Int64be (..) , Float32be (..) , Float64be (..)) where import Data.Repa.Convert.Internal.Format import Data.Repa.Convert.Internal.Packable import Data.Bits import Data.Int as V import Data.Word as V import qualified Foreign.Storable as S import qualified Foreign.Marshal.Alloc as S import qualified Foreign.Ptr as S import qualified Control.Monad.Primitive as Prim import GHC.Exts import Prelude hiding (fail) #include "repa-convert.h" ------------------------------------------------------------------------------------------- Word8be -- | Big-endian 8-bit unsigned word. data Word8be = Word8be deriving (Eq, Show) instance Format Word8be where type Value Word8be = Word8 fieldCount _ = 1 minSize _ = 1 fixedSize _ = Just 1 packedSize _ _ = Just 1 {-# INLINE minSize #-} {-# INLINE fieldCount #-} {-# INLINE fixedSize #-} {-# INLINE packedSize #-} instance Packable Word8be where packer _ x dst _fails k = do S.poke (Ptr dst) (fromIntegral x :: Word8) let !(Ptr dst') = S.plusPtr (Ptr dst) 1 k dst' {-# INLINE packer #-} instance Unpackable Word8be where unpacker _ start _end _stop _fail eat = do x <- S.peek (pw8 start) eat (plusAddr# start 1#) (fromIntegral x) {-# INLINE unpacker #-} w8 :: Integral a => a -> Word8 w8 = fromIntegral {-# INLINE w8 #-} ------------------------------------------------------------------------------------------- Int8be -- | Big-endian 8-bit signed integer. data Int8be = Int8be deriving (Eq, Show) instance Format Int8be where type Value Int8be = V.Int8 fieldCount _ = 1 minSize _ = 1 fixedSize _ = Just 1 packedSize _ _ = Just 1 {-# INLINE minSize #-} {-# INLINE fieldCount #-} {-# INLINE fixedSize #-} {-# INLINE packedSize #-} instance Packable Int8be where packer Int8be x buf k = packer Word8be (w8 x) buf k {-# INLINE packer #-} instance Unpackable Int8be where unpacker Int8be start end stop fail eat = unpacker Word8be start end stop fail $ \addr v -> eat addr (i8 v) {-# INLINE unpacker #-} i8 :: Integral a => a -> Int8 i8 = fromIntegral {-# INLINE i8 #-} ------------------------------------------------------------------------------------------ Word16be -- | Big-endian 32-bit unsigned word. data Word16be = Word16be deriving (Eq, Show) instance Format Word16be where type Value Word16be = V.Word16 fieldCount _ = 1 minSize _ = 2 fixedSize _ = Just 2 packedSize _ _ = Just 2 {-# INLINE minSize #-} {-# INLINE fieldCount #-} {-# INLINE fixedSize #-} {-# INLINE packedSize #-} instance Packable Word16be where packer Word16be x dst _fails k = do S.poke (Ptr dst) (w8 ((w16 x .&. 0x0ff00) `shiftR` 8)) S.pokeByteOff (Ptr dst) 1 (w8 ((w16 x .&. 0x000ff))) let !(Ptr dst') = S.plusPtr (Ptr dst) 2 k dst' {-# INLINE packer #-} instance Unpackable Word16be where unpacker Word16be start _end _stop _fail eat = do x0 :: Word8 <- S.peek (pw8 start) x1 :: Word8 <- S.peekByteOff (pw8 start) 1 eat (plusAddr# start 2#) (w16 ((w16 x0 `shiftL` 8) .|. w16 x1)) {-# INLINE unpacker #-} w16 :: Integral a => a -> Word16 w16 = fromIntegral {-# INLINE w16 #-} ------------------------------------------------------------------------------------------- Int16be --- | Big-endian 16-bit signed integer. data Int16be = Int16be deriving (Eq, Show) instance Format Int16be where type Value Int16be = V.Int16 fieldCount _ = 1 minSize _ = 2 fixedSize _ = Just 2 packedSize _ _ = Just 2 {-# INLINE minSize #-} {-# INLINE fieldCount #-} {-# INLINE fixedSize #-} {-# INLINE packedSize #-} instance Packable Int16be where packer Int16be x buf k = packer Word16be (w16 x) buf k {-# INLINE packer #-} instance Unpackable Int16be where unpacker Int16be start end stop fail eat = unpacker Word16be start end stop fail $ \addr v -> eat addr (i16 v) {-# INLINE unpacker #-} i16 :: Integral a => a -> Int16 i16 = fromIntegral {-# INLINE i16 #-} ------------------------------------------------------------------------------------------ Word32be -- | Big-endian 32-bit unsigned word. data Word32be = Word32be deriving (Eq, Show) instance Format Word32be where type Value Word32be = V.Word32 fieldCount _ = 1 minSize _ = 4 fixedSize _ = Just 4 packedSize _ _ = Just 4 {-# INLINE minSize #-} {-# INLINE fieldCount #-} {-# INLINE fixedSize #-} {-# INLINE packedSize #-} instance Packable Word32be where packer Word32be x dst _fails k = do S.poke (Ptr dst) (w8 ((w32 x .&. 0x0ff000000) `shiftR` 24)) S.pokeByteOff (Ptr dst) 1 (w8 ((w32 x .&. 0x000ff0000) `shiftR` 16)) S.pokeByteOff (Ptr dst) 2 (w8 ((w32 x .&. 0x00000ff00) `shiftR` 8)) S.pokeByteOff (Ptr dst) 3 (w8 ((w32 x .&. 0x0000000ff))) let !(Ptr dst') = S.plusPtr (Ptr dst) 4 k dst' {-# INLINE packer #-} instance Unpackable Word32be where unpacker Word32be start _end _fail _stop eat = do x0 :: Word8 <- S.peek (pw8 start) x1 :: Word8 <- S.peekByteOff (pw8 start) 1 x2 :: Word8 <- S.peekByteOff (pw8 start) 2 x3 :: Word8 <- S.peekByteOff (pw8 start) 3 eat (plusAddr# start 4#) (w32 ( (w32 x0 `shiftL` 24) .|. (w32 x1 `shiftL` 16) .|. (w32 x2 `shiftL` 8) .|. (w32 x3))) {-# INLINE unpacker #-} w32 :: Integral a => a -> Word32 w32 = fromIntegral {-# INLINE w32 #-} ------------------------------------------------------------------------------------------- Int32be -- | Big-endian 32-bit signed integer. data Int32be = Int32be deriving (Eq, Show) instance Format Int32be where type Value Int32be = V.Int32 fieldCount _ = 1 minSize _ = 4 fixedSize _ = Just 4 packedSize _ _ = Just 4 {-# INLINE minSize #-} {-# INLINE fieldCount #-} {-# INLINE fixedSize #-} {-# INLINE packedSize #-} instance Packable Int32be where packer Int32be x buf k = packer Word32be (w32 x) buf k {-# INLINE packer #-} instance Unpackable Int32be where unpacker Int32be start end stop fail eat = unpacker Word32be start end stop fail $ \addr v -> eat addr (i32 v) {-# INLINE unpacker #-} i32 :: Integral a => a -> Int32 i32 = fromIntegral {-# INLINE i32 #-} ------------------------------------------------------------------------------------------ Word64be -- | Big-endian 64-bit unsigned word. data Word64be = Word64be deriving (Eq, Show) instance Format Word64be where type Value Word64be = V.Word64 fieldCount _ = 1 minSize _ = 8 fixedSize _ = Just 8 packedSize _ _ = Just 8 {-# INLINE minSize #-} {-# INLINE fieldCount #-} {-# INLINE fixedSize #-} {-# INLINE packedSize #-} instance Packable Word64be where packer Word64be x dst _fails k = do S.poke (Ptr dst) (w8 ((w64 x .&. 0x0ff00000000000000) `shiftR` 56)) S.pokeByteOff (Ptr dst) 1 (w8 ((w64 x .&. 0x000ff000000000000) `shiftR` 48)) S.pokeByteOff (Ptr dst) 2 (w8 ((w64 x .&. 0x00000ff0000000000) `shiftR` 40)) S.pokeByteOff (Ptr dst) 3 (w8 ((w64 x .&. 0x0000000ff00000000) `shiftR` 32)) S.pokeByteOff (Ptr dst) 4 (w8 ((w64 x .&. 0x000000000ff000000) `shiftR` 24)) S.pokeByteOff (Ptr dst) 5 (w8 ((w64 x .&. 0x00000000000ff0000) `shiftR` 16)) S.pokeByteOff (Ptr dst) 6 (w8 ((w64 x .&. 0x0000000000000ff00) `shiftR` 8)) S.pokeByteOff (Ptr dst) 7 (w8 ((w64 x .&. 0x000000000000000ff) )) let !(Ptr dst') = S.plusPtr (Ptr dst) 8 k dst' {-# INLINE packer #-} instance Unpackable Word64be where unpacker Word64be start _end _fail _stop eat = do x0 :: Word8 <- S.peek (pw8 start) x1 :: Word8 <- S.peekByteOff (pw8 start) 1 x2 :: Word8 <- S.peekByteOff (pw8 start) 2 x3 :: Word8 <- S.peekByteOff (pw8 start) 3 x4 :: Word8 <- S.peekByteOff (pw8 start) 4 x5 :: Word8 <- S.peekByteOff (pw8 start) 5 x6 :: Word8 <- S.peekByteOff (pw8 start) 6 x7 :: Word8 <- S.peekByteOff (pw8 start) 7 eat (plusAddr# start 8#) (w64 ( (w64 x0 `shiftL` 56) .|. (w64 x1 `shiftL` 48) .|. (w64 x2 `shiftL` 40) .|. (w64 x3 `shiftL` 32) .|. (w64 x4 `shiftL` 24) .|. (w64 x5 `shiftL` 16) .|. (w64 x6 `shiftL` 8) .|. (w64 x7 ))) {-# INLINE unpacker #-} w64 :: Integral a => a -> Word64 w64 = fromIntegral {-# INLINE w64 #-} ------------------------------------------------------------------------------------------- Int64be -- | Big-endian 64-bit signed integer. data Int64be = Int64be deriving (Eq, Show) instance Format Int64be where type Value Int64be = V.Int64 fieldCount _ = 1 minSize _ = 8 fixedSize _ = Just 8 packedSize _ _ = Just 8 {-# INLINE minSize #-} {-# INLINE fieldCount #-} {-# INLINE fixedSize #-} {-# INLINE packedSize #-} instance Packable Int64be where packer Int64be x buf k = packer Word64be (w64 x) buf k {-# INLINE packer #-} instance Unpackable Int64be where unpacker Int64be start end stop fail eat = unpacker Word64be start end stop fail $ \addr v -> eat addr (i64 v) {-# INLINE unpacker #-} i64 :: Integral a => a -> Int64 i64 = fromIntegral {-# INLINE i64 #-} ----------------------------------------------------------------------------------------- Float32be -- | Big-endian 32-bit IEEE 754 float. data Float32be = Float32be deriving (Eq, Show) instance Format Float32be where type Value Float32be = Float fieldCount _ = 1 minSize _ = 4 fixedSize _ = Just 4 packedSize _ _ = Just 4 {-# INLINE minSize #-} {-# INLINE fieldCount #-} {-# INLINE fixedSize #-} {-# INLINE packedSize #-} instance Packable Float32be where packer Float32be x buf k = packer Word32be (floatToWord32 x) buf k {-# INLINE packer #-} instance Unpackable Float32be where unpacker Float32be start end stop fail eat = unpacker Word32be start end stop fail $ \addr v -> eat addr (word32ToFloat v) {-# INLINE unpacker #-} -- | Bitwise cast of `Float` to `Word32`. -- -- The resulting `Word32` contains the binary representation of the -- `Float`, rather than the integral part of its value. -- floatToWord32 :: Float -> Word32 floatToWord32 d = Prim.unsafeInlineIO $ S.alloca $ \buf -> do S.poke (S.castPtr buf) d S.peek buf {-# INLINE floatToWord32 #-} -- | Inverse of `doubleToFloat32` word32ToFloat :: Word32 -> Float word32ToFloat w = Prim.unsafeInlineIO $ S.alloca $ \buf -> do S.poke (S.castPtr buf) w S.peek buf {-# INLINE word32ToFloat #-} ----------------------------------------------------------------------------------------- Float64be -- | Big-endian 64-bit IEEE 754 float. data Float64be = Float64be deriving (Eq, Show) instance Format Float64be where type Value Float64be = Double fieldCount _ = 1 minSize _ = 8 fixedSize _ = Just 8 packedSize _ _ = Just 8 {-# INLINE minSize #-} {-# INLINE fieldCount #-} {-# INLINE fixedSize #-} {-# INLINE packedSize #-} instance Packable Float64be where packer Float64be x start fails eat = packer Word64be (doubleToWord64 x) start fails eat {-# INLINE packer #-} instance Unpackable Float64be where unpacker Float64be start end stop fail eat = unpacker Word64be start end stop fail $ \addr v -> eat addr (word64ToDouble v) {-# INLINE unpacker #-} -- | Bitwise cast of `Double` to `Word64`. -- -- The resulting `Word64` contains the binary representation of the -- `Double`, rather than the integral part of its value. -- doubleToWord64 :: Double -> Word64 doubleToWord64 d = Prim.unsafeInlineIO $ S.alloca $ \buf -> do S.poke (S.castPtr buf) d S.peek buf {-# INLINE doubleToWord64 #-} -- | Inverse of `doubleToWord64` word64ToDouble :: Word64 -> Double word64ToDouble w = Prim.unsafeInlineIO $ S.alloca $ \buf -> do S.poke (S.castPtr buf) w S.peek buf {-# INLINE word64ToDouble #-} --------------------------------------------------------------------------------------------------- pw8 :: Addr# -> Ptr Word8 pw8 addr = Ptr addr {-# INLINE pw8 #-}