{-# LANGUAGE CPP, BangPatterns #-} #if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-} #endif -- | Copyright : (c) 2010-2011 Simon Meier -- License : BSD3-style (see LICENSE) -- -- Maintainer : Simon Meier -- Portability : GHC -- module Data.ByteString.Builder.Prim.Binary ( -- ** Binary encodings int8 , word8 -- *** Big-endian , int16BE , int32BE , int64BE , word16BE , word32BE , word64BE , floatBE , doubleBE -- *** Little-endian , int16LE , int32LE , int64LE , word16LE , word32LE , word64LE , floatLE , doubleLE -- *** Non-portable, host-dependent , intHost , int16Host , int32Host , int64Host , wordHost , word16Host , word32Host , word64Host , floatHost , doubleHost ) where import Data.ByteString.Builder.Prim.Internal import Data.ByteString.Builder.Prim.Internal.UncheckedShifts import Data.ByteString.Builder.Prim.Internal.Floating import Foreign #include "MachDeps.h" ------------------------------------------------------------------------------ -- Binary encoding ------------------------------------------------------------------------------ -- Word encodings ----------------- -- | Encoding single unsigned bytes as-is. -- {-# INLINE word8 #-} word8 :: FixedPrim Word8 word8 = storableToF -- -- We rely on the fromIntegral to do the right masking for us. -- The inlining here is critical, and can be worth 4x performance -- -- | Encoding 'Word16's in big endian format. {-# INLINE word16BE #-} word16BE :: FixedPrim Word16 #ifdef WORDS_BIGENDIAN word16BE = word16Host #else word16BE = fixedPrim 2 $ \w p -> do poke p (fromIntegral (shiftr_w16 w 8) :: Word8) poke (p `plusPtr` 1) (fromIntegral (w) :: Word8) #endif -- | Encoding 'Word16's in little endian format. {-# INLINE word16LE #-} word16LE :: FixedPrim Word16 #ifdef WORDS_BIGENDIAN word16LE = fixedPrim 2 $ \w p -> do poke p (fromIntegral (w) :: Word8) poke (p `plusPtr` 1) (fromIntegral (shiftr_w16 w 8) :: Word8) #else word16LE = word16Host #endif -- | Encoding 'Word32's in big endian format. {-# INLINE word32BE #-} word32BE :: FixedPrim Word32 #ifdef WORDS_BIGENDIAN word32BE = word32Host #else word32BE = fixedPrim 4 $ \w p -> do poke p (fromIntegral (shiftr_w32 w 24) :: Word8) poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 w 16) :: Word8) poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 w 8) :: Word8) poke (p `plusPtr` 3) (fromIntegral (w) :: Word8) #endif -- | Encoding 'Word32's in little endian format. {-# INLINE word32LE #-} word32LE :: FixedPrim Word32 #ifdef WORDS_BIGENDIAN word32LE = fixedPrim 4 $ \w p -> do poke p (fromIntegral (w) :: Word8) poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 w 8) :: Word8) poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 w 16) :: Word8) poke (p `plusPtr` 3) (fromIntegral (shiftr_w32 w 24) :: Word8) #else word32LE = word32Host #endif -- on a little endian machine: -- word32LE w32 = fixedPrim 4 (\w p -> poke (castPtr p) w32) -- | Encoding 'Word64's in big endian format. {-# INLINE word64BE #-} word64BE :: FixedPrim Word64 #ifdef WORDS_BIGENDIAN word64BE = word64Host #else #if WORD_SIZE_IN_BITS < 64 -- -- To avoid expensive 64 bit shifts on 32 bit machines, we cast to -- Word32, and write that -- word64BE = fixedPrim 8 $ \w p -> do let a = fromIntegral (shiftr_w64 w 32) :: Word32 b = fromIntegral w :: Word32 poke p (fromIntegral (shiftr_w32 a 24) :: Word8) poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 a 16) :: Word8) poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 a 8) :: Word8) poke (p `plusPtr` 3) (fromIntegral (a) :: Word8) poke (p `plusPtr` 4) (fromIntegral (shiftr_w32 b 24) :: Word8) poke (p `plusPtr` 5) (fromIntegral (shiftr_w32 b 16) :: Word8) poke (p `plusPtr` 6) (fromIntegral (shiftr_w32 b 8) :: Word8) poke (p `plusPtr` 7) (fromIntegral (b) :: Word8) #else word64BE = fixedPrim 8 $ \w p -> do poke p (fromIntegral (shiftr_w64 w 56) :: Word8) poke (p `plusPtr` 1) (fromIntegral (shiftr_w64 w 48) :: Word8) poke (p `plusPtr` 2) (fromIntegral (shiftr_w64 w 40) :: Word8) poke (p `plusPtr` 3) (fromIntegral (shiftr_w64 w 32) :: Word8) poke (p `plusPtr` 4) (fromIntegral (shiftr_w64 w 24) :: Word8) poke (p `plusPtr` 5) (fromIntegral (shiftr_w64 w 16) :: Word8) poke (p `plusPtr` 6) (fromIntegral (shiftr_w64 w 8) :: Word8) poke (p `plusPtr` 7) (fromIntegral (w) :: Word8) #endif #endif -- | Encoding 'Word64's in little endian format. {-# INLINE word64LE #-} word64LE :: FixedPrim Word64 #ifdef WORDS_BIGENDIAN #if WORD_SIZE_IN_BITS < 64 word64LE = fixedPrim 8 $ \w p -> do let b = fromIntegral (shiftr_w64 w 32) :: Word32 a = fromIntegral w :: Word32 poke (p) (fromIntegral (a) :: Word8) poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 a 8) :: Word8) poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 a 16) :: Word8) poke (p `plusPtr` 3) (fromIntegral (shiftr_w32 a 24) :: Word8) poke (p `plusPtr` 4) (fromIntegral (b) :: Word8) poke (p `plusPtr` 5) (fromIntegral (shiftr_w32 b 8) :: Word8) poke (p `plusPtr` 6) (fromIntegral (shiftr_w32 b 16) :: Word8) poke (p `plusPtr` 7) (fromIntegral (shiftr_w32 b 24) :: Word8) #else word64LE = fixedPrim 8 $ \w p -> do poke p (fromIntegral (w) :: Word8) poke (p `plusPtr` 1) (fromIntegral (shiftr_w64 w 8) :: Word8) poke (p `plusPtr` 2) (fromIntegral (shiftr_w64 w 16) :: Word8) poke (p `plusPtr` 3) (fromIntegral (shiftr_w64 w 24) :: Word8) poke (p `plusPtr` 4) (fromIntegral (shiftr_w64 w 32) :: Word8) poke (p `plusPtr` 5) (fromIntegral (shiftr_w64 w 40) :: Word8) poke (p `plusPtr` 6) (fromIntegral (shiftr_w64 w 48) :: Word8) poke (p `plusPtr` 7) (fromIntegral (shiftr_w64 w 56) :: Word8) #endif #else word64LE = word64Host #endif -- | Encode a single native machine 'Word'. The 'Word's is encoded in host order, -- host endian form, for the machine you are on. On a 64 bit machine the 'Word' -- is an 8 byte value, on a 32 bit machine, 4 bytes. Values encoded this way -- are not portable to different endian or word sized machines, without -- conversion. -- {-# INLINE wordHost #-} wordHost :: FixedPrim Word wordHost = storableToF -- | Encoding 'Word16's in native host order and host endianness. {-# INLINE word16Host #-} word16Host :: FixedPrim Word16 word16Host = storableToF -- | Encoding 'Word32's in native host order and host endianness. {-# INLINE word32Host #-} word32Host :: FixedPrim Word32 word32Host = storableToF -- | Encoding 'Word64's in native host order and host endianness. {-# INLINE word64Host #-} word64Host :: FixedPrim Word64 word64Host = storableToF ------------------------------------------------------------------------------ -- Int encodings ------------------------------------------------------------------------------ -- -- We rely on 'fromIntegral' to do a loss-less conversion to the corresponding -- 'Word' type -- ------------------------------------------------------------------------------ -- | Encoding single signed bytes as-is. -- {-# INLINE int8 #-} int8 :: FixedPrim Int8 int8 = fromIntegral >$< word8 -- | Encoding 'Int16's in big endian format. {-# INLINE int16BE #-} int16BE :: FixedPrim Int16 int16BE = fromIntegral >$< word16BE -- | Encoding 'Int16's in little endian format. {-# INLINE int16LE #-} int16LE :: FixedPrim Int16 int16LE = fromIntegral >$< word16LE -- | Encoding 'Int32's in big endian format. {-# INLINE int32BE #-} int32BE :: FixedPrim Int32 int32BE = fromIntegral >$< word32BE -- | Encoding 'Int32's in little endian format. {-# INLINE int32LE #-} int32LE :: FixedPrim Int32 int32LE = fromIntegral >$< word32LE -- | Encoding 'Int64's in big endian format. {-# INLINE int64BE #-} int64BE :: FixedPrim Int64 int64BE = fromIntegral >$< word64BE -- | Encoding 'Int64's in little endian format. {-# INLINE int64LE #-} int64LE :: FixedPrim Int64 int64LE = fromIntegral >$< word64LE -- TODO: Ensure that they are safe on architectures where an unaligned write is -- an error. -- | Encode a single native machine 'Int'. The 'Int's is encoded in host order, -- host endian form, for the machine you are on. On a 64 bit machine the 'Int' -- is an 8 byte value, on a 32 bit machine, 4 bytes. Values encoded this way -- are not portable to different endian or integer sized machines, without -- conversion. -- {-# INLINE intHost #-} intHost :: FixedPrim Int intHost = storableToF -- | Encoding 'Int16's in native host order and host endianness. {-# INLINE int16Host #-} int16Host :: FixedPrim Int16 int16Host = storableToF -- | Encoding 'Int32's in native host order and host endianness. {-# INLINE int32Host #-} int32Host :: FixedPrim Int32 int32Host = storableToF -- | Encoding 'Int64's in native host order and host endianness. {-# INLINE int64Host #-} int64Host :: FixedPrim Int64 int64Host = storableToF -- IEEE Floating Point Numbers ------------------------------ -- | Encode a 'Float' in big endian format. {-# INLINE floatBE #-} floatBE :: FixedPrim Float floatBE = encodeFloatViaWord32F word32BE -- | Encode a 'Float' in little endian format. {-# INLINE floatLE #-} floatLE :: FixedPrim Float floatLE = encodeFloatViaWord32F word32LE -- | Encode a 'Double' in big endian format. {-# INLINE doubleBE #-} doubleBE :: FixedPrim Double doubleBE = encodeDoubleViaWord64F word64BE -- | Encode a 'Double' in little endian format. {-# INLINE doubleLE #-} doubleLE :: FixedPrim Double doubleLE = encodeDoubleViaWord64F word64LE -- | Encode a 'Float' in native host order and host endianness. Values written -- this way are not portable to different endian machines, without conversion. -- {-# INLINE floatHost #-} floatHost :: FixedPrim Float floatHost = storableToF -- | Encode a 'Double' in native host order and host endianness. {-# INLINE doubleHost #-} doubleHost :: FixedPrim Double doubleHost = storableToF