{-# LANGUAGE CPP, MonoPatBinds #-} -- | -- Module : Blaze.ByteString.Builder.Word -- Copyright : (c) 2010 Jasper Van der Jeugt & Simon Meier -- -- Original serialization code from 'Data.Binary.Builder': -- (c) Lennart Kolmodin, Ross Patterson -- -- License : BSD3-style (see LICENSE) -- -- Maintainer : Simon Meier -- Stability : experimental -- Portability : tested on GHC only -- -- 'Write's and 'Builder's for serializing words. -- -- Note that for serializing a three tuple @(x,y,z)@ of bytes (or other word -- values) you should use the expression -- -- > fromWrite $ writeWord8 x `mappend` writeWord8 y `mappend` writeWord z -- -- instead of -- -- > fromWord8 x `mappend` fromWord8 y `mappend` fromWord z -- -- The first expression will result in a single atomic write of three bytes, -- while the second expression will check for each byte, if there is free space -- left in the output buffer. Coalescing these checks can improve performance -- quite a bit, as long as you use it sensibly. -- #if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__) #include "MachDeps.h" #endif module Blaze.ByteString.Builder.Word ( -- * Writing words to a buffer writeWord8 -- ** Big-endian writes , writeWord16be -- :: Word16 -> Write , writeWord32be -- :: Word32 -> Write , writeWord64be -- :: Word64 -> Write -- ** Little-endian writes , writeWord16le -- :: Word16 -> Write , writeWord32le -- :: Word32 -> Write , writeWord64le -- :: Word64 -> Write -- ** Host-endian writes , writeWordhost -- :: Word -> Write , writeWord16host -- :: Word16 -> Write , writeWord32host -- :: Word32 -> Write , writeWord64host -- :: Word64 -> Write -- * Creating builders from words -- | We provide serialization functions both for singleton words as well as -- for lists of words. Using these list serialization functions is /much/ faster -- than using @mconcat . map fromWord/@, as the list serialization -- functions use a tighter inner loop. , fromWord8 , fromWord8s -- ** Big-endian serialization , fromWord16be -- :: Word16 -> Builder , fromWord32be -- :: Word32 -> Builder , fromWord64be -- :: Word64 -> Builder , fromWord32sbe -- :: [Word32] -> Builder , fromWord16sbe -- :: [Word16] -> Builder , fromWord64sbe -- :: [Word64] -> Builder -- ** Little-endian serialization , fromWord16le -- :: Word16 -> Builder , fromWord32le -- :: Word32 -> Builder , fromWord64le -- :: Word64 -> Builder , fromWord16sle -- :: [Word16] -> Builder , fromWord32sle -- :: [Word32] -> Builder , fromWord64sle -- :: [Word64] -> Builder -- ** Host-endian serialization , fromWordhost -- :: Word -> Builder , fromWord16host -- :: Word16 -> Builder , fromWord32host -- :: Word32 -> Builder , fromWord64host -- :: Word64 -> Builder , fromWordshost -- :: [Word] -> Builder , fromWord16shost -- :: [Word16] -> Builder , fromWord32shost -- :: [Word32] -> Builder , fromWord64shost -- :: [Word64] -> Builder ) where import Blaze.ByteString.Builder.Internal import Blaze.ByteString.Builder.Internal.UncheckedShifts import Foreign #if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__) import GHC.Word (Word32(..),Word16(..),Word64(..)) #else import Data.Word #endif ------------------------------------------------------------------------------ -- Word writes -------------- -- -- Based upon the 'putWordX' functions from "Data.Binary.Builder" from the -- 'binary' package. -- ------------------------------------------------------------------------------ -- | Write a single byte. -- writeWord8 :: Word8 -> Write writeWord8 x = exactWrite 1 (\pf -> poke pf x) {-# INLINE writeWord8 #-} -- -- We rely on the fromIntegral to do the right masking for us. -- The inlining here is critical, and can be worth 4x performance -- -- | Write a 'Word16' in big endian format. writeWord16be :: Word16 -> Write writeWord16be w = exactWrite 2 $ \p -> do poke p (fromIntegral (shiftr_w16 w 8) :: Word8) poke (p `plusPtr` 1) (fromIntegral (w) :: Word8) {-# INLINE writeWord16be #-} -- | Write a 'Word16' in little endian format. writeWord16le :: Word16 -> Write writeWord16le w = exactWrite 2 $ \p -> do poke p (fromIntegral (w) :: Word8) poke (p `plusPtr` 1) (fromIntegral (shiftr_w16 w 8) :: Word8) {-# INLINE writeWord16le #-} -- writeWord16le w16 = exactWrite 2 (\p -> poke (castPtr p) w16) -- | Write a 'Word32' in big endian format. writeWord32be :: Word32 -> Write writeWord32be w = exactWrite 4 $ \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) {-# INLINE writeWord32be #-} -- | Write a 'Word32' in little endian format. writeWord32le :: Word32 -> Write writeWord32le w = exactWrite 4 $ \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) {-# INLINE writeWord32le #-} -- on a little endian machine: -- writeWord32le w32 = exactWrite 4 (\p -> poke (castPtr p) w32) -- | Write a 'Word64' in big endian format. writeWord64be :: Word64 -> Write #if WORD_SIZE_IN_BITS < 64 -- -- To avoid expensive 64 bit shifts on 32 bit machines, we cast to -- Word32, and write that -- writeWord64be w = let a = fromIntegral (shiftr_w64 w 32) :: Word32 b = fromIntegral w :: Word32 in exactWrite 8 $ \p -> do 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 writeWord64be w = exactWrite 8 $ \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 {-# INLINE writeWord64be #-} -- | Write a 'Word64' in little endian format. writeWord64le :: Word64 -> Write #if WORD_SIZE_IN_BITS < 64 writeWord64le w = let b = fromIntegral (shiftr_w64 w 32) :: Word32 a = fromIntegral w :: Word32 in exactWrite 8 $ \p -> do 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 writeWord64le w = exactWrite 8 $ \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 {-# INLINE writeWord64le #-} -- on a little endian machine: -- writeWord64le w64 = exactWrite 8 (\p -> poke (castPtr p) w64) ------------------------------------------------------------------------ -- Unaligned, word size ops -- | Write a single native machine 'Word'. The 'Word' is written in host order, -- host endian form, for the machine you're on. On a 64 bit machine the 'Word' -- is an 8 byte value, on a 32 bit machine, 4 bytes. Values written this way -- are not portable to different endian or word sized machines, without -- conversion. -- writeWordhost :: Word -> Write writeWordhost w = exactWrite (sizeOf (undefined :: Word)) (\p -> poke (castPtr p) w) {-# INLINE writeWordhost #-} -- | Write a 'Word16' in native host order and host endianness. writeWord16host :: Word16 -> Write writeWord16host w16 = exactWrite (sizeOf (undefined :: Word16)) (\p -> poke (castPtr p) w16) {-# INLINE writeWord16host #-} -- | Write a 'Word32' in native host order and host endianness. writeWord32host :: Word32 -> Write writeWord32host w32 = exactWrite (sizeOf (undefined :: Word32)) (\p -> poke (castPtr p) w32) {-# INLINE writeWord32host #-} -- | Write a 'Word64' in native host order and host endianness. writeWord64host :: Word64 -> Write writeWord64host w = exactWrite (sizeOf (undefined :: Word64)) (\p -> poke (castPtr p) w) {-# INLINE writeWord64host #-} ------------------------------------------------------------------------------ -- Builders corresponding to the word writes ------------------------------------------------------------------------------ -- Single bytes ------------------------------------------------------------------------------ -- | Serialize a single byte. -- fromWord8 :: Word8 -> Builder fromWord8 = fromWriteSingleton writeWord8 -- | Serialize a list of bytes. -- fromWord8s :: [Word8] -> Builder fromWord8s = fromWriteList writeWord8 -- Word16 ------------------------------------------------------------------------------ -- | Serialize a 'Word16' in big endian format. fromWord16be :: Word16 -> Builder fromWord16be = fromWriteSingleton writeWord16be {-# INLINE fromWord16be #-} -- | Serialize a list of 'Word16's in big endian format. fromWord16sbe :: [Word16] -> Builder fromWord16sbe = fromWriteList writeWord16be {-# INLINE fromWord16sbe #-} -- | Serialize a 'Word16' in little endian format. fromWord16le :: Word16 -> Builder fromWord16le = fromWriteSingleton writeWord16le {-# INLINE fromWord16le #-} -- | Serialize a list of 'Word16's in little endian format. fromWord16sle :: [Word16] -> Builder fromWord16sle = fromWriteList writeWord16le {-# INLINE fromWord16sle #-} -- Word32 ----------------------------------------------------------------------------- -- | Serialize a 'Word32' in big endian format. fromWord32be :: Word32 -> Builder fromWord32be = fromWriteSingleton writeWord32be {-# INLINE fromWord32be #-} -- | Serialize a list of 'Word32's in big endian format. fromWord32sbe :: [Word32] -> Builder fromWord32sbe = fromWriteList writeWord32be {-# INLINE fromWord32sbe #-} -- | Serialize a 'Word32' in little endian format. fromWord32le :: Word32 -> Builder fromWord32le = fromWriteSingleton writeWord32le {-# INLINE fromWord32le #-} -- | Serialize a list of 'Word32's in little endian format. fromWord32sle :: [Word32] -> Builder fromWord32sle = fromWriteList writeWord32le {-# INLINE fromWord32sle #-} -- | Serialize a 'Word64' in big endian format. fromWord64be :: Word64 -> Builder fromWord64be = fromWriteSingleton writeWord64be {-# INLINE fromWord64be #-} -- | Serialize a list of 'Word64's in big endian format. fromWord64sbe :: [Word64] -> Builder fromWord64sbe = fromWriteList writeWord64be {-# INLINE fromWord64sbe #-} -- | Serialize a 'Word64' in little endian format. fromWord64le :: Word64 -> Builder fromWord64le = fromWriteSingleton writeWord64le {-# INLINE fromWord64le #-} -- | Serialize a list of 'Word64's in little endian format. fromWord64sle :: [Word64] -> Builder fromWord64sle = fromWriteList writeWord64le {-# INLINE fromWord64sle #-} ------------------------------------------------------------------------ -- Unaligned, word size ops -- | Serialize a single native machine 'Word'. The 'Word' is serialized in host -- order, host endian form, for the machine you're on. On a 64 bit machine the -- 'Word' is an 8 byte value, on a 32 bit machine, 4 bytes. Values written this -- way are not portable to different endian or word sized machines, without -- conversion. -- fromWordhost :: Word -> Builder fromWordhost = fromWriteSingleton writeWordhost {-# INLINE fromWordhost #-} -- | Serialize a list of 'Word's. -- See 'fromWordhost' for usage considerations. fromWordshost :: [Word] -> Builder fromWordshost = fromWriteList writeWordhost {-# INLINE fromWordshost #-} -- | Write a 'Word16' in native host order and host endianness. fromWord16host :: Word16 -> Builder fromWord16host = fromWriteSingleton writeWord16host {-# INLINE fromWord16host #-} -- | Write a list of 'Word16's in native host order and host endianness. fromWord16shost :: [Word16] -> Builder fromWord16shost = fromWriteList writeWord16host {-# INLINE fromWord16shost #-} -- | Write a 'Word32' in native host order and host endianness. fromWord32host :: Word32 -> Builder fromWord32host = fromWriteSingleton writeWord32host {-# INLINE fromWord32host #-} -- | Write a list of 'Word32's in native host order and host endianness. fromWord32shost :: [Word32] -> Builder fromWord32shost = fromWriteList writeWord32host {-# INLINE fromWord32shost #-} -- | Write a 'Word64' in native host order and host endianness. fromWord64host :: Word64 -> Builder fromWord64host = fromWriteSingleton writeWord64host {-# INLINE fromWord64host #-} -- | Write a list of 'Word64's in native host order and host endianness. fromWord64shost :: [Word64] -> Builder fromWord64shost = fromWriteList writeWord64host {-# INLINE fromWord64shost #-}