1 {-# LANGUAGE DeriveDataTypeable, CPP, BangPatterns, RankNTypes,
    2              ForeignFunctionInterface, MagicHash, UnboxedTuples,
    3              UnliftedFFITypes #-}
    4 {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
    5 #if __GLASGOW_HASKELL__ >= 703
    6 {-# LANGUAGE Unsafe #-}
    7 #endif
    8 {-# OPTIONS_HADDOCK hide #-}
    9 
   10 -- |
   11 -- Module      : Data.ByteString.Short.Internal
   12 -- Copyright   : (c) Duncan Coutts 2012-2013
   13 -- License     : BSD-style
   14 --
   15 -- Maintainer  : duncan@community.haskell.org
   16 -- Stability   : stable
   17 -- Portability : ghc only
   18 -- 
   19 -- Internal representation of ShortByteString
   20 --
   21 module Data.ByteString.Short.Internal (
   22 
   23     -- * The @ShortByteString@ type and representation
   24     ShortByteString(..),
   25 
   26     -- * Conversions
   27     toShort,
   28     fromShort,
   29     pack,
   30     unpack,
   31 
   32     -- * Other operations
   33     empty, null, length, index, unsafeIndex,
   34 
   35     -- * Low level operations
   36     createFromPtr, copyToPtr
   37   ) where
   38 
   39 import Data.ByteString.Internal (ByteString(..), accursedUnutterablePerformIO)
   40 
   41 import Data.Typeable    (Typeable)
   42 import Data.Data        (Data(..), mkNoRepType)
   43 #if MIN_VERSION_base(4,9,0)
   44 import Data.Semigroup   (Semigroup((<>)))
   45 #endif
   46 import Data.Monoid      (Monoid(..))
   47 import Data.String      (IsString(..))
   48 import Control.DeepSeq  (NFData(..))
   49 import qualified Data.List as List (length)
   50 #if MIN_VERSION_base(4,7,0)
   51 import Foreign.C.Types  (CSize(..), CInt(..))
   52 #elif MIN_VERSION_base(4,4,0)
   53 import Foreign.C.Types  (CSize(..), CInt(..), CLong(..))
   54 #else
   55 import Foreign.C.Types  (CSize, CInt, CLong)
   56 #endif
   57 import Foreign.Ptr
   58 import Foreign.ForeignPtr (touchForeignPtr)
   59 #if MIN_VERSION_base(4,5,0)
   60 import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
   61 #else
   62 import Foreign.ForeignPtr (unsafeForeignPtrToPtr)
   63 #endif
   64 
   65 #if MIN_VERSION_base(4,5,0)
   66 import qualified GHC.Exts
   67 #endif
   68 import GHC.Exts ( Int(I#), Int#, Ptr(Ptr), Addr#, Char(C#)
   69                 , State#, RealWorld
   70                 , ByteArray#, MutableByteArray#
   71                 , newByteArray#
   72 #if MIN_VERSION_base(4,6,0)
   73                 , newPinnedByteArray#
   74                 , byteArrayContents#
   75                 , unsafeCoerce#
   76 #endif
   77 #if MIN_VERSION_base(4,3,0)
   78                 , sizeofByteArray#
   79 #endif
   80                 , indexWord8Array#, indexCharArray#
   81                 , writeWord8Array#, writeCharArray#
   82                 , unsafeFreezeByteArray# )
   83 import GHC.IO
   84 #if MIN_VERSION_base(4,6,0)
   85 import GHC.ForeignPtr (ForeignPtr(ForeignPtr), ForeignPtrContents(PlainPtr))
   86 #else
   87 import GHC.ForeignPtr (mallocPlainForeignPtrBytes)
   88 #endif
   89 import GHC.ST         (ST(ST), runST)
   90 import GHC.Word
   91 
   92 import Prelude ( Eq(..), Ord(..), Ordering(..), Read(..), Show(..)
   93                , ($), error, (++)
   94                , Bool(..), (&&), otherwise
   95                , (+), (-), fromIntegral
   96                , return )
   97 
   98 
   99 -- | A compact representation of a 'Word8' vector.
  100 --
  101 -- It has a lower memory overhead than a 'ByteString' and and does not
  102 -- contribute to heap fragmentation. It can be converted to or from a
  103 -- 'ByteString' (at the cost of copying the string data). It supports very few
  104 -- other operations.
  105 --
  106 -- It is suitable for use as an internal representation for code that needs
  107 -- to keep many short strings in memory, but it /should not/ be used as an
  108 -- interchange type. That is, it should not generally be used in public APIs.
  109 -- The 'ByteString' type is usually more suitable for use in interfaces; it is
  110 -- more flexible and it supports a wide range of operations.
  111 --
  112 data ShortByteString = SBS ByteArray#
  113 #if !(MIN_VERSION_base(4,3,0))
  114            {-# UNPACK #-} !Int  -- ^ Prior to ghc-7.0.x, 'ByteArray#'s reported
  115                                 -- their length rounded up to the nearest word.
  116                                 -- This means we have to store the true length
  117                                 -- separately, wasting a word.
  118 #define LEN(x) (x)
  119 #else
  120 #define _len   /* empty */
  121 #define LEN(x) /* empty */
  122 #endif
  123     deriving Typeable
  124 
  125 -- The ByteArray# representation is always word sized and aligned but with a
  126 -- known byte length. Our representation choice for ShortByteString is to leave
  127 -- the 0--3 trailing bytes undefined. This means we can use word-sized writes,
  128 -- but we have to be careful with reads, see equateBytes and compareBytes below.
  129 
  130 
  131 instance Eq ShortByteString where
  132     (==)    = equateBytes
  133 
  134 instance Ord ShortByteString where
  135     compare = compareBytes
  136 
  137 #if MIN_VERSION_base(4,9,0)
  138 instance Semigroup ShortByteString where
  139     (<>)    = append
  140 #endif
  141 
  142 instance Monoid ShortByteString where
  143     mempty  = empty
  144 #if MIN_VERSION_base(4,9,0)
  145     mappend = (<>)
  146 #else
  147     mappend = append
  148 #endif
  149     mconcat = concat
  150 
  151 instance NFData ShortByteString where
  152     rnf (SBS {}) = ()
  153 
  154 instance Show ShortByteString where
  155     showsPrec p ps r = showsPrec p (unpackChars ps) r
  156 
  157 instance Read ShortByteString where
  158     readsPrec p str = [ (packChars x, y) | (x, y) <- readsPrec p str ]
  159 
  160 instance IsString ShortByteString where
  161     fromString = packChars
  162 
  163 instance Data ShortByteString where
  164   gfoldl f z txt = z packBytes `f` (unpackBytes txt)
  165   toConstr _     = error "Data.ByteString.Short.ShortByteString.toConstr"
  166   gunfold _ _    = error "Data.ByteString.Short.ShortByteString.gunfold"
  167   dataTypeOf _   = mkNoRepType "Data.ByteString.Short.ShortByteString"
  168 
  169 ------------------------------------------------------------------------
  170 -- Simple operations
  171 
  172 -- | /O(1)/. The empty 'ShortByteString'.
  173 empty :: ShortByteString
  174 empty = create 0 (\_ -> return ())
  175 
  176 -- | /O(1)/ The length of a 'ShortByteString'.
  177 length :: ShortByteString -> Int
  178 #if MIN_VERSION_base(4,3,0)
  179 length (SBS barr#) = I# (sizeofByteArray# barr#)
  180 #else
  181 length (SBS _ len) = len
  182 #endif
  183 
  184 -- | /O(1)/ Test whether a 'ShortByteString' is empty.
  185 null :: ShortByteString -> Bool
  186 null sbs = length sbs == 0
  187 
  188 -- | /O(1)/ 'ShortByteString' index (subscript) operator, starting from 0. 
  189 index :: ShortByteString -> Int -> Word8
  190 index sbs i
  191   | i >= 0 && i < length sbs = unsafeIndex sbs i
  192   | otherwise                = indexError sbs i
  193 
  194 unsafeIndex :: ShortByteString -> Int -> Word8
  195 unsafeIndex sbs = indexWord8Array (asBA sbs)
  196 
  197 indexError :: ShortByteString -> Int -> a
  198 indexError sbs i =
  199   error $ "Data.ByteString.Short.index: error in array index; " ++ show i
  200        ++ " not in range [0.." ++ show (length sbs) ++ ")"
  201 
  202 
  203 ------------------------------------------------------------------------
  204 -- Internal utils
  205 
  206 asBA :: ShortByteString -> BA
  207 asBA (SBS ba# _len) = BA# ba#
  208 
  209 create :: Int -> (forall s. MBA s -> ST s ()) -> ShortByteString
  210 create len fill =
  211     runST (do
  212       mba <- newByteArray len
  213       fill mba
  214       BA# ba# <- unsafeFreezeByteArray mba
  215       return (SBS ba# LEN(len)))
  216 {-# INLINE create #-}
  217 
  218 ------------------------------------------------------------------------
  219 -- Conversion to and from ByteString
  220 
  221 -- | /O(n)/. Convert a 'ByteString' into a 'ShortByteString'.
  222 --
  223 -- This makes a copy, so does not retain the input string.
  224 --
  225 toShort :: ByteString -> ShortByteString
  226 toShort !bs = unsafeDupablePerformIO (toShortIO bs)
  227 
  228 toShortIO :: ByteString -> IO ShortByteString
  229 toShortIO (PS fptr off len) = do
  230     mba <- stToIO (newByteArray len)
  231     let ptr = unsafeForeignPtrToPtr fptr
  232     stToIO (copyAddrToByteArray (ptr `plusPtr` off) mba 0 len)
  233     touchForeignPtr fptr
  234     BA# ba# <- stToIO (unsafeFreezeByteArray mba)
  235     return (SBS ba# LEN(len))
  236 
  237 
  238 -- | /O(n)/. Convert a 'ShortByteString' into a 'ByteString'.
  239 --
  240 fromShort :: ShortByteString -> ByteString
  241 fromShort !sbs = unsafeDupablePerformIO (fromShortIO sbs)
  242 
  243 fromShortIO :: ShortByteString -> IO ByteString
  244 fromShortIO sbs = do
  245 #if MIN_VERSION_base(4,6,0)
  246     let len = length sbs
  247     mba@(MBA# mba#) <- stToIO (newPinnedByteArray len)
  248     stToIO (copyByteArray (asBA sbs) 0 mba 0 len)
  249     let fp = ForeignPtr (byteArrayContents# (unsafeCoerce# mba#))
  250                         (PlainPtr mba#)
  251     return (PS fp 0 len)
  252 #else
  253     -- Before base 4.6 ForeignPtrContents is not exported from GHC.ForeignPtr
  254     -- so we cannot get direct access to the mbarr#
  255     let len = length sbs
  256     fptr <- mallocPlainForeignPtrBytes len
  257     let ptr = unsafeForeignPtrToPtr fptr
  258     stToIO (copyByteArrayToAddr (asBA sbs) 0 ptr len)
  259     touchForeignPtr fptr
  260     return (PS fptr 0 len)
  261 #endif
  262 
  263 
  264 ------------------------------------------------------------------------
  265 -- Packing and unpacking from lists
  266 
  267 -- | /O(n)/. Convert a list into a 'ShortByteString'
  268 pack :: [Word8] -> ShortByteString
  269 pack = packBytes
  270 
  271 -- | /O(n)/. Convert a 'ShortByteString' into a list.
  272 unpack :: ShortByteString -> [Word8]
  273 unpack = unpackBytes
  274 
  275 packChars :: [Char] -> ShortByteString
  276 packChars cs = packLenChars (List.length cs) cs
  277 
  278 packBytes :: [Word8] -> ShortByteString
  279 packBytes cs = packLenBytes (List.length cs) cs
  280 
  281 packLenChars :: Int -> [Char] -> ShortByteString
  282 packLenChars len cs0 =
  283     create len (\mba -> go mba 0 cs0)
  284   where
  285     go :: MBA s -> Int -> [Char] -> ST s ()
  286     go !_   !_ []     = return ()
  287     go !mba !i (c:cs) = do
  288       writeCharArray mba i c
  289       go mba (i+1) cs
  290 
  291 packLenBytes :: Int -> [Word8] -> ShortByteString
  292 packLenBytes len ws0 =
  293     create len (\mba -> go mba 0 ws0)
  294   where
  295     go :: MBA s -> Int -> [Word8] -> ST s ()
  296     go !_   !_ []     = return ()
  297     go !mba !i (w:ws) = do
  298       writeWord8Array mba i w
  299       go mba (i+1) ws
  300 
  301 -- Unpacking bytestrings into lists effeciently is a tradeoff: on the one hand
  302 -- we would like to write a tight loop that just blats the list into memory, on
  303 -- the other hand we want it to be unpacked lazily so we don't end up with a
  304 -- massive list data structure in memory.
  305 --
  306 -- Our strategy is to combine both: we will unpack lazily in reasonable sized
  307 -- chunks, where each chunk is unpacked strictly.
  308 --
  309 -- unpackChars does the lazy loop, while unpackAppendBytes and
  310 -- unpackAppendChars do the chunks strictly.
  311 
  312 unpackChars :: ShortByteString -> [Char]
  313 unpackChars bs = unpackAppendCharsLazy bs []
  314 
  315 unpackBytes :: ShortByteString -> [Word8]
  316 unpackBytes bs = unpackAppendBytesLazy bs []
  317 
  318 -- Why 100 bytes you ask? Because on a 64bit machine the list we allocate
  319 -- takes just shy of 4k which seems like a reasonable amount.
  320 -- (5 words per list element, 8 bytes per word, 100 elements = 4000 bytes)
  321 
  322 unpackAppendCharsLazy :: ShortByteString -> [Char] -> [Char]
  323 unpackAppendCharsLazy sbs cs0 =
  324     go 0 (length sbs) cs0
  325   where
  326     sz = 100
  327 
  328     go off len cs
  329       | len <= sz = unpackAppendCharsStrict sbs off len cs
  330       | otherwise = unpackAppendCharsStrict sbs off sz  remainder
  331                       where remainder = go (off+sz) (len-sz) cs
  332 
  333 unpackAppendBytesLazy :: ShortByteString -> [Word8] -> [Word8]
  334 unpackAppendBytesLazy sbs ws0 =
  335     go 0 (length sbs) ws0
  336   where
  337     sz = 100
  338 
  339     go off len ws
  340       | len <= sz = unpackAppendBytesStrict sbs off len ws
  341       | otherwise = unpackAppendBytesStrict sbs off sz  remainder
  342                       where remainder = go (off+sz) (len-sz) ws
  343 
  344 -- For these unpack functions, since we're unpacking the whole list strictly we
  345 -- build up the result list in an accumulator. This means we have to build up
  346 -- the list starting at the end. So our traversal starts at the end of the
  347 -- buffer and loops down until we hit the sentinal:
  348 
  349 unpackAppendCharsStrict :: ShortByteString -> Int -> Int -> [Char] -> [Char]
  350 unpackAppendCharsStrict !sbs off len cs =
  351     go (off-1) (off-1 + len) cs
  352   where
  353     go !sentinal !i !acc
  354       | i == sentinal = acc
  355       | otherwise     = let !c = indexCharArray (asBA sbs) i
  356                         in go sentinal (i-1) (c:acc)
  357 
  358 unpackAppendBytesStrict :: ShortByteString -> Int -> Int -> [Word8] -> [Word8]
  359 unpackAppendBytesStrict !sbs off len ws =
  360     go (off-1) (off-1 + len) ws
  361   where
  362     go !sentinal !i !acc
  363       | i == sentinal = acc
  364       | otherwise     = let !w = indexWord8Array (asBA sbs) i
  365                          in go sentinal (i-1) (w:acc)
  366 
  367 
  368 ------------------------------------------------------------------------
  369 -- Eq and Ord implementations
  370 
  371 equateBytes :: ShortByteString -> ShortByteString -> Bool
  372 equateBytes sbs1 sbs2 =
  373     let !len1 = length sbs1
  374         !len2 = length sbs2
  375      in len1 == len2
  376      && 0 == accursedUnutterablePerformIO
  377                (memcmp_ByteArray (asBA sbs1) (asBA sbs2) len1)
  378 
  379 compareBytes :: ShortByteString -> ShortByteString -> Ordering
  380 compareBytes sbs1 sbs2 =
  381     let !len1 = length sbs1
  382         !len2 = length sbs2
  383         !len  = min len1 len2
  384      in case accursedUnutterablePerformIO
  385                (memcmp_ByteArray (asBA sbs1) (asBA sbs2) len) of
  386           i | i    < 0    -> LT
  387             | i    > 0    -> GT
  388             | len2 > len1 -> LT
  389             | len2 < len1 -> GT
  390             | otherwise   -> EQ
  391 
  392 
  393 ------------------------------------------------------------------------
  394 -- Appending and concatenation
  395 
  396 append :: ShortByteString -> ShortByteString -> ShortByteString
  397 append src1 src2 =
  398   let !len1 = length src1
  399       !len2 = length src2
  400    in create (len1 + len2) $ \dst -> do
  401         copyByteArray (asBA src1) 0 dst 0    len1
  402         copyByteArray (asBA src2) 0 dst len1 len2
  403 
  404 concat :: [ShortByteString] -> ShortByteString
  405 concat sbss =
  406     create (totalLen 0 sbss) (\dst -> copy dst 0 sbss)
  407   where
  408     totalLen !acc []          = acc
  409     totalLen !acc (sbs: sbss) = totalLen (acc + length sbs) sbss
  410 
  411     copy :: MBA s -> Int -> [ShortByteString] -> ST s ()
  412     copy !_   !_   []                           = return ()
  413     copy !dst !off (src : sbss) = do
  414       let !len = length src
  415       copyByteArray (asBA src) 0 dst off len
  416       copy dst (off + len) sbss
  417 
  418 
  419 ------------------------------------------------------------------------
  420 -- Exported low level operations
  421 
  422 copyToPtr :: ShortByteString  -- ^ source data
  423           -> Int              -- ^ offset into source
  424           -> Ptr a            -- ^ destination
  425           -> Int              -- ^ number of bytes to copy
  426           -> IO ()
  427 copyToPtr src off dst len =
  428     stToIO $
  429       copyByteArrayToAddr (asBA src) off dst len
  430 
  431 createFromPtr :: Ptr a   -- ^ source data
  432               -> Int     -- ^ number of bytes to copy
  433               -> IO ShortByteString
  434 createFromPtr !ptr len =
  435     stToIO $ do
  436       mba <- newByteArray len
  437       copyAddrToByteArray ptr mba 0 len
  438       BA# ba# <- unsafeFreezeByteArray mba
  439       return (SBS ba# LEN(len))
  440 
  441 
  442 ------------------------------------------------------------------------
  443 -- Primop wrappers
  444 
  445 data BA    = BA# ByteArray#
  446 data MBA s = MBA# (MutableByteArray# s)
  447 
  448 indexCharArray :: BA -> Int -> Char
  449 indexCharArray (BA# ba#) (I# i#) = C# (indexCharArray# ba# i#)
  450 
  451 indexWord8Array :: BA -> Int -> Word8
  452 indexWord8Array (BA# ba#) (I# i#) = W8# (indexWord8Array# ba# i#)
  453 
  454 newByteArray :: Int -> ST s (MBA s)
  455 newByteArray (I# len#) =
  456     ST $ \s -> case newByteArray# len# s of
  457                  (# s, mba# #) -> (# s, MBA# mba# #)
  458 
  459 #if MIN_VERSION_base(4,6,0)
  460 newPinnedByteArray :: Int -> ST s (MBA s)
  461 newPinnedByteArray (I# len#) =
  462     ST $ \s -> case newPinnedByteArray# len# s of
  463                  (# s, mba# #) -> (# s, MBA# mba# #)
  464 #endif
  465 
  466 unsafeFreezeByteArray :: MBA s -> ST s BA
  467 unsafeFreezeByteArray (MBA# mba#) =
  468     ST $ \s -> case unsafeFreezeByteArray# mba# s of
  469                  (# s, ba# #) -> (# s, BA# ba# #)
  470 
  471 writeCharArray :: MBA s -> Int -> Char -> ST s ()
  472 writeCharArray (MBA# mba#) (I# i#) (C# c#) =
  473   ST $ \s -> case writeCharArray# mba# i# c# s of
  474                s -> (# s, () #)
  475 
  476 writeWord8Array :: MBA s -> Int -> Word8 -> ST s ()
  477 writeWord8Array (MBA# mba#) (I# i#) (W8# w#) =
  478   ST $ \s -> case writeWord8Array# mba# i# w# s of
  479                s -> (# s, () #)
  480 
  481 copyAddrToByteArray :: Ptr a -> MBA RealWorld -> Int -> Int -> ST RealWorld ()
  482 copyAddrToByteArray (Ptr src#) (MBA# dst#) (I# dst_off#) (I# len#) =
  483     ST $ \s -> case copyAddrToByteArray# src# dst# dst_off# len# s of
  484                  s -> (# s, () #)
  485 
  486 copyByteArrayToAddr :: BA -> Int -> Ptr a -> Int -> ST RealWorld ()
  487 copyByteArrayToAddr (BA# src#) (I# src_off#) (Ptr dst#) (I# len#) =
  488     ST $ \s -> case copyByteArrayToAddr# src# src_off# dst# len# s of
  489                  s -> (# s, () #)
  490 
  491 copyByteArray :: BA -> Int -> MBA s -> Int -> Int -> ST s ()
  492 copyByteArray (BA# src#) (I# src_off#) (MBA# dst#) (I# dst_off#) (I# len#) =
  493     ST $ \s -> case copyByteArray# src# src_off# dst# dst_off# len# s of
  494                  s -> (# s, () #)
  495 
  496 
  497 ------------------------------------------------------------------------
  498 -- FFI imports
  499 
  500 memcmp_ByteArray :: BA -> BA -> Int -> IO CInt
  501 memcmp_ByteArray (BA# ba1#) (BA# ba2#) len =
  502   c_memcmp_ByteArray ba1# ba2# (fromIntegral len)
  503 
  504 foreign import ccall unsafe "string.h memcmp"
  505   c_memcmp_ByteArray :: ByteArray# -> ByteArray# -> CSize -> IO CInt
  506 
  507 
  508 ------------------------------------------------------------------------
  509 -- Primop replacements
  510 
  511 copyAddrToByteArray# :: Addr#
  512                      -> MutableByteArray# RealWorld -> Int#
  513                      -> Int#
  514                      -> State# RealWorld -> State# RealWorld
  515 
  516 copyByteArrayToAddr# :: ByteArray# -> Int#
  517                      -> Addr#
  518                      -> Int#
  519                      -> State# RealWorld -> State# RealWorld
  520 
  521 copyByteArray#       :: ByteArray# -> Int#
  522                      -> MutableByteArray# s -> Int#
  523                      -> Int#
  524                      -> State# s -> State# s
  525 
  526 #if MIN_VERSION_base(4,7,0)
  527 
  528 -- These exist as real primops in ghc-7.8, and for before that we use
  529 -- FFI to C memcpy.
  530 copyAddrToByteArray# = GHC.Exts.copyAddrToByteArray#
  531 copyByteArrayToAddr# = GHC.Exts.copyByteArrayToAddr#
  532 
  533 #else
  534 
  535 copyAddrToByteArray# src dst dst_off len s =
  536   unIO_ (memcpy_AddrToByteArray dst (clong dst_off) src 0 (csize len)) s
  537 
  538 copyAddrToByteArray0 :: Addr# -> MutableByteArray# s -> Int#
  539                      -> State# RealWorld -> State# RealWorld
  540 copyAddrToByteArray0 src dst len s =
  541   unIO_ (memcpy_AddrToByteArray0 dst src (csize len)) s
  542 
  543 {-# INLINE [0] copyAddrToByteArray# #-}
  544 {-# RULES "copyAddrToByteArray# dst_off=0"
  545       forall src dst len s.
  546           copyAddrToByteArray# src dst 0# len s
  547         = copyAddrToByteArray0 src dst    len s  #-}
  548 
  549 foreign import ccall unsafe "fpstring.h fps_memcpy_offsets"
  550   memcpy_AddrToByteArray :: MutableByteArray# s -> CLong -> Addr# -> CLong -> CSize -> IO ()
  551 
  552 foreign import ccall unsafe "string.h memcpy"
  553   memcpy_AddrToByteArray0 :: MutableByteArray# s -> Addr# -> CSize -> IO ()
  554 
  555 
  556 copyByteArrayToAddr# src src_off dst len s =
  557   unIO_ (memcpy_ByteArrayToAddr dst 0 src (clong src_off) (csize len)) s
  558 
  559 copyByteArrayToAddr0 :: ByteArray# -> Addr# -> Int#
  560                      -> State# RealWorld -> State# RealWorld
  561 copyByteArrayToAddr0 src dst len s =
  562   unIO_ (memcpy_ByteArrayToAddr0 dst src (csize len)) s
  563 
  564 {-# INLINE [0] copyByteArrayToAddr# #-}
  565 {-# RULES "copyByteArrayToAddr# src_off=0"
  566       forall src dst len s.
  567           copyByteArrayToAddr# src 0# dst len s
  568         = copyByteArrayToAddr0 src    dst len s  #-}
  569 
  570 foreign import ccall unsafe "fpstring.h fps_memcpy_offsets"
  571   memcpy_ByteArrayToAddr :: Addr# -> CLong -> ByteArray# -> CLong -> CSize -> IO ()
  572 
  573 foreign import ccall unsafe "string.h memcpy"
  574   memcpy_ByteArrayToAddr0 :: Addr# -> ByteArray# -> CSize -> IO ()
  575 
  576 
  577 unIO_ :: IO () -> State# RealWorld -> State# RealWorld
  578 unIO_ io s = case unIO io s of (# s, _ #) -> s
  579 
  580 clong :: Int# -> CLong
  581 clong i# = fromIntegral (I# i#)
  582 
  583 csize :: Int# -> CSize
  584 csize i# = fromIntegral (I# i#)
  585 #endif
  586 
  587 #if MIN_VERSION_base(4,5,0)
  588 copyByteArray# = GHC.Exts.copyByteArray#
  589 #else
  590 copyByteArray# src src_off dst dst_off len s =
  591     unST_ (unsafeIOToST
  592       (memcpy_ByteArray dst (clong dst_off) src (clong src_off) (csize len))) s
  593   where
  594     unST (ST st) = st
  595     unST_ st s = case unST st s of (# s, _ #) -> s
  596 
  597 foreign import ccall unsafe "fpstring.h fps_memcpy_offsets"
  598   memcpy_ByteArray :: MutableByteArray# s -> CLong
  599                    -> ByteArray# -> CLong -> CSize -> IO ()
  600 #endif
  601