never executed always true always false
1 {-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples, FlexibleContexts #-}
2 -- | Efficient serialisation for GHCi Instruction arrays
3 --
4 -- Author: Ben Gamari
5 --
6 module GHCi.BinaryArray(putArray, getArray) where
7
8 import Prelude
9 import Foreign.Ptr
10 import Data.Binary
11 import Data.Binary.Put (putBuilder)
12 import qualified Data.Binary.Get.Internal as Binary
13 import qualified Data.ByteString.Builder as BB
14 import qualified Data.ByteString.Builder.Internal as BB
15 import qualified Data.Array.Base as A
16 import qualified Data.Array.IO.Internals as A
17 import qualified Data.Array.Unboxed as A
18 import GHC.Exts
19 import GHC.IO
20
21 -- | An efficient serialiser of 'A.UArray'.
22 putArray :: Binary i => A.UArray i a -> Put
23 putArray (A.UArray l u _ arr#) = do
24 put l
25 put u
26 putBuilder $ byteArrayBuilder arr#
27
28 byteArrayBuilder :: ByteArray# -> BB.Builder
29 byteArrayBuilder arr# = BB.builder $ go 0 (I# (sizeofByteArray# arr#))
30 where
31 go :: Int -> Int -> BB.BuildStep a -> BB.BuildStep a
32 go !inStart !inEnd k (BB.BufferRange outStart outEnd)
33 -- There is enough room in this output buffer to write all remaining array
34 -- contents
35 | inRemaining <= outRemaining = do
36 copyByteArrayToAddr arr# inStart outStart inRemaining
37 k (BB.BufferRange (outStart `plusPtr` inRemaining) outEnd)
38 -- There is only enough space for a fraction of the remaining contents
39 | otherwise = do
40 copyByteArrayToAddr arr# inStart outStart outRemaining
41 let !inStart' = inStart + outRemaining
42 return $! BB.bufferFull 1 outEnd (go inStart' inEnd k)
43 where
44 inRemaining = inEnd - inStart
45 outRemaining = outEnd `minusPtr` outStart
46
47 copyByteArrayToAddr :: ByteArray# -> Int -> Ptr a -> Int -> IO ()
48 copyByteArrayToAddr src# (I# src_off#) (Ptr dst#) (I# len#) =
49 IO $ \s -> case copyByteArrayToAddr# src# src_off# dst# len# s of
50 s' -> (# s', () #)
51
52 -- | An efficient deserialiser of 'A.UArray'.
53 getArray :: (Binary i, A.Ix i, A.MArray A.IOUArray a IO) => Get (A.UArray i a)
54 getArray = do
55 l <- get
56 u <- get
57 arr@(A.IOUArray (A.STUArray _ _ _ arr#)) <-
58 return $ unsafeDupablePerformIO $ A.newArray_ (l,u)
59 let go 0 _ = return ()
60 go !remaining !off = do
61 Binary.readNWith n $ \ptr ->
62 copyAddrToByteArray ptr arr# off n
63 go (remaining - n) (off + n)
64 where n = min chunkSize remaining
65 go (I# (sizeofMutableByteArray# arr#)) 0
66 return $! unsafeDupablePerformIO $ unsafeFreezeIOUArray arr
67 where
68 chunkSize = 10*1024
69
70 copyAddrToByteArray :: Ptr a -> MutableByteArray# RealWorld
71 -> Int -> Int -> IO ()
72 copyAddrToByteArray (Ptr src#) dst# (I# dst_off#) (I# len#) =
73 IO $ \s -> case copyAddrToByteArray# src# dst# dst_off# len# s of
74 s' -> (# s', () #)
75
76 -- this is inexplicably not exported in currently released array versions
77 unsafeFreezeIOUArray :: A.IOUArray ix e -> IO (A.UArray ix e)
78 unsafeFreezeIOUArray (A.IOUArray marr) = stToIO (A.unsafeFreezeSTUArray marr)