2 {-# OPTIONS_GHC -O -funbox-strict-fields #-}
3 -- We always optimise this, otherwise performance of a non-optimised
4 -- compiler is severely affected
7 -- (c) The University of Glasgow 2002-2006
9 -- Binary I/O library, with special tweaks for GHC
11 -- Based on the nhc98 Binary library, which is copyright
12 -- (c) Malcolm Wallace and Colin Runciman, University of York, 1998.
13 -- Under the terms of the license for that software, we must tell you
14 -- where you can obtain the original version of the Binary library, namely
15 -- http://www.cs.york.ac.uk/fp/nhc98/
22 openBinIO, openBinIO_,
39 -- for writing instances:
47 #ifdef __GLASGOW_HASKELL__
54 UserData(..), getUserData, setUserData,
55 newReadState, newWriteState,
56 putDictionary, getDictionary, putFS,
59 #include "HsVersions.h"
61 -- The *host* architecture version:
62 #include "../includes/MachDeps.h"
64 import {-# SOURCE #-} Name (Name)
75 import Data.Char ( ord, chr )
77 import Control.Monad ( when )
78 import System.IO as IO
79 import System.IO.Unsafe ( unsafeInterleaveIO )
80 import System.IO.Error ( mkIOError, eofErrorType )
81 import GHC.Real ( Ratio(..) )
83 import GHC.Word ( Word8(..) )
85 #if __GLASGOW_HASKELL__ >= 611
86 import GHC.IO ( IO(..) )
88 import GHC.IOBase ( IO(..) )
91 type BinArray = ForeignPtr Word8
93 ---------------------------------------------------------------
95 ---------------------------------------------------------------
98 = BinMem { -- binary data stored in an unboxed array
99 bh_usr :: UserData, -- sigh, need parameterized modules :-)
100 _off_r :: !FastMutInt, -- the current offset
101 _sz_r :: !FastMutInt, -- size of the array (cached)
102 _arr_r :: !(IORef BinArray) -- the array (bounds: (0,size-1))
104 -- XXX: should really store a "high water mark" for dumping out
105 -- the binary data to a file.
107 | BinIO { -- binary data stored in a file
109 _off_r :: !FastMutInt, -- the current offset (cached)
110 _hdl :: !IO.Handle -- the file handle (must be seekable)
112 -- cache the file ptr in BinIO; using hTell is too expensive
113 -- to call repeatedly. If anyone else is modifying this Handle
114 -- at the same time, we'll be screwed.
116 getUserData :: BinHandle -> UserData
117 getUserData bh = bh_usr bh
119 setUserData :: BinHandle -> UserData -> BinHandle
120 setUserData bh us = bh { bh_usr = us }
123 ---------------------------------------------------------------
125 ---------------------------------------------------------------
127 newtype Bin a = BinPtr Int
128 deriving (Eq, Ord, Show, Bounded)
130 castBin :: Bin a -> Bin b
131 castBin (BinPtr i) = BinPtr i
133 ---------------------------------------------------------------
135 ---------------------------------------------------------------
138 put_ :: BinHandle -> a -> IO ()
139 put :: BinHandle -> a -> IO (Bin a)
140 get :: BinHandle -> IO a
142 -- define one of put_, put. Use of put_ is recommended because it
143 -- is more likely that tail-calls can kick in, and we rarely need the
144 -- position return value.
145 put_ bh a = do _ <- put bh a; return ()
146 put bh a = do p <- tellBin bh; put_ bh a; return p
148 putAt :: Binary a => BinHandle -> Bin a -> a -> IO ()
149 putAt bh p x = do seekBin bh p; put_ bh x; return ()
151 getAt :: Binary a => BinHandle -> Bin a -> IO a
152 getAt bh p = do seekBin bh p; get bh
154 openBinIO_ :: IO.Handle -> IO BinHandle
155 openBinIO_ h = openBinIO h
157 openBinIO :: IO.Handle -> IO BinHandle
161 return (BinIO noUserData r h)
163 openBinMem :: Int -> IO BinHandle
165 | size <= 0 = error "Data.Binary.openBinMem: size must be >= 0"
167 arr <- mallocForeignPtrBytes size
168 arr_r <- newIORef arr
169 ix_r <- newFastMutInt
170 writeFastMutInt ix_r 0
171 sz_r <- newFastMutInt
172 writeFastMutInt sz_r size
173 return (BinMem noUserData ix_r sz_r arr_r)
175 tellBin :: BinHandle -> IO (Bin a)
176 tellBin (BinIO _ r _) = do ix <- readFastMutInt r; return (BinPtr ix)
177 tellBin (BinMem _ r _ _) = do ix <- readFastMutInt r; return (BinPtr ix)
179 seekBin :: BinHandle -> Bin a -> IO ()
180 seekBin (BinIO _ ix_r h) (BinPtr p) = do
181 writeFastMutInt ix_r p
182 hSeek h AbsoluteSeek (fromIntegral p)
183 seekBin h@(BinMem _ ix_r sz_r _) (BinPtr p) = do
184 sz <- readFastMutInt sz_r
186 then do expandBin h p; writeFastMutInt ix_r p
187 else writeFastMutInt ix_r p
189 seekBy :: BinHandle -> Int -> IO ()
190 seekBy (BinIO _ ix_r h) off = do
191 ix <- readFastMutInt ix_r
193 writeFastMutInt ix_r ix'
194 hSeek h AbsoluteSeek (fromIntegral ix')
195 seekBy h@(BinMem _ ix_r sz_r _) off = do
196 sz <- readFastMutInt sz_r
197 ix <- readFastMutInt ix_r
200 then do expandBin h ix'; writeFastMutInt ix_r ix'
201 else writeFastMutInt ix_r ix'
203 isEOFBin :: BinHandle -> IO Bool
204 isEOFBin (BinMem _ ix_r sz_r _) = do
205 ix <- readFastMutInt ix_r
206 sz <- readFastMutInt sz_r
208 isEOFBin (BinIO _ _ h) = hIsEOF h
210 writeBinMem :: BinHandle -> FilePath -> IO ()
211 writeBinMem (BinIO _ _ _) _ = error "Data.Binary.writeBinMem: not a memory handle"
212 writeBinMem (BinMem _ ix_r _ arr_r) fn = do
213 h <- openBinaryFile fn WriteMode
214 arr <- readIORef arr_r
215 ix <- readFastMutInt ix_r
216 withForeignPtr arr $ \p -> hPutBuf h p ix
219 readBinMem :: FilePath -> IO BinHandle
220 -- Return a BinHandle with a totally undefined State
221 readBinMem filename = do
222 h <- openBinaryFile filename ReadMode
223 filesize' <- hFileSize h
224 let filesize = fromIntegral filesize'
225 arr <- mallocForeignPtrBytes (filesize*2)
226 count <- withForeignPtr arr $ \p -> hGetBuf h p filesize
227 when (count /= filesize) $
228 error ("Binary.readBinMem: only read " ++ show count ++ " bytes")
230 arr_r <- newIORef arr
231 ix_r <- newFastMutInt
232 writeFastMutInt ix_r 0
233 sz_r <- newFastMutInt
234 writeFastMutInt sz_r filesize
235 return (BinMem noUserData ix_r sz_r arr_r)
237 fingerprintBinMem :: BinHandle -> IO Fingerprint
238 fingerprintBinMem (BinIO _ _ _) = error "Binary.md5BinMem: not a memory handle"
239 fingerprintBinMem (BinMem _ ix_r _ arr_r) = do
240 arr <- readIORef arr_r
241 ix <- readFastMutInt ix_r
242 withForeignPtr arr $ \p -> fingerprintData p ix
244 -- expand the size of the array to include a specified offset
245 expandBin :: BinHandle -> Int -> IO ()
246 expandBin (BinMem _ _ sz_r arr_r) off = do
247 sz <- readFastMutInt sz_r
248 let sz' = head (dropWhile (<= off) (iterate (* 2) sz))
249 arr <- readIORef arr_r
250 arr' <- mallocForeignPtrBytes sz'
251 withForeignPtr arr $ \old ->
252 withForeignPtr arr' $ \new ->
254 writeFastMutInt sz_r sz'
255 writeIORef arr_r arr'
256 when False $ -- disabled
257 hPutStrLn stderr ("Binary: expanding to size: " ++ show sz')
259 expandBin (BinIO _ _ _) _ = return ()
260 -- no need to expand a file, we'll assume they expand by themselves.
262 -- -----------------------------------------------------------------------------
263 -- Low-level reading/writing of bytes
265 putWord8 :: BinHandle -> Word8 -> IO ()
266 putWord8 h@(BinMem _ ix_r sz_r arr_r) w = do
267 ix <- readFastMutInt ix_r
268 sz <- readFastMutInt sz_r
269 -- double the size of the array if it overflows
271 then do expandBin h ix
273 else do arr <- readIORef arr_r
274 withForeignPtr arr $ \p -> pokeByteOff p ix w
275 writeFastMutInt ix_r (ix+1)
277 putWord8 (BinIO _ ix_r h) w = do
278 ix <- readFastMutInt ix_r
279 hPutChar h (chr (fromIntegral w)) -- XXX not really correct
280 writeFastMutInt ix_r (ix+1)
283 getWord8 :: BinHandle -> IO Word8
284 getWord8 (BinMem _ ix_r sz_r arr_r) = do
285 ix <- readFastMutInt ix_r
286 sz <- readFastMutInt sz_r
288 ioError (mkIOError eofErrorType "Data.Binary.getWord8" Nothing Nothing)
289 arr <- readIORef arr_r
290 w <- withForeignPtr arr $ \p -> peekByteOff p ix
291 writeFastMutInt ix_r (ix+1)
293 getWord8 (BinIO _ ix_r h) = do
294 ix <- readFastMutInt ix_r
296 writeFastMutInt ix_r (ix+1)
297 return $! (fromIntegral (ord c)) -- XXX not really correct
299 putByte :: BinHandle -> Word8 -> IO ()
300 putByte bh w = put_ bh w
302 getByte :: BinHandle -> IO Word8
305 -- -----------------------------------------------------------------------------
306 -- Primitve Word writes
308 instance Binary Word8 where
312 instance Binary Word16 where
313 put_ h w = do -- XXX too slow.. inline putWord8?
314 putByte h (fromIntegral (w `shiftR` 8))
315 putByte h (fromIntegral (w .&. 0xff))
319 return $! ((fromIntegral w1 `shiftL` 8) .|. fromIntegral w2)
322 instance Binary Word32 where
324 putByte h (fromIntegral (w `shiftR` 24))
325 putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
326 putByte h (fromIntegral ((w `shiftR` 8) .&. 0xff))
327 putByte h (fromIntegral (w .&. 0xff))
333 return $! ((fromIntegral w1 `shiftL` 24) .|.
334 (fromIntegral w2 `shiftL` 16) .|.
335 (fromIntegral w3 `shiftL` 8) .|.
338 instance Binary Word64 where
340 putByte h (fromIntegral (w `shiftR` 56))
341 putByte h (fromIntegral ((w `shiftR` 48) .&. 0xff))
342 putByte h (fromIntegral ((w `shiftR` 40) .&. 0xff))
343 putByte h (fromIntegral ((w `shiftR` 32) .&. 0xff))
344 putByte h (fromIntegral ((w `shiftR` 24) .&. 0xff))
345 putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
346 putByte h (fromIntegral ((w `shiftR` 8) .&. 0xff))
347 putByte h (fromIntegral (w .&. 0xff))
357 return $! ((fromIntegral w1 `shiftL` 56) .|.
358 (fromIntegral w2 `shiftL` 48) .|.
359 (fromIntegral w3 `shiftL` 40) .|.
360 (fromIntegral w4 `shiftL` 32) .|.
361 (fromIntegral w5 `shiftL` 24) .|.
362 (fromIntegral w6 `shiftL` 16) .|.
363 (fromIntegral w7 `shiftL` 8) .|.
366 -- -----------------------------------------------------------------------------
367 -- Primitve Int writes
369 instance Binary Int8 where
370 put_ h w = put_ h (fromIntegral w :: Word8)
371 get h = do w <- get h; return $! (fromIntegral (w::Word8))
373 instance Binary Int16 where
374 put_ h w = put_ h (fromIntegral w :: Word16)
375 get h = do w <- get h; return $! (fromIntegral (w::Word16))
377 instance Binary Int32 where
378 put_ h w = put_ h (fromIntegral w :: Word32)
379 get h = do w <- get h; return $! (fromIntegral (w::Word32))
381 instance Binary Int64 where
382 put_ h w = put_ h (fromIntegral w :: Word64)
383 get h = do w <- get h; return $! (fromIntegral (w::Word64))
385 -- -----------------------------------------------------------------------------
386 -- Instances for standard types
388 instance Binary () where
389 put_ _ () = return ()
392 instance Binary Bool where
393 put_ bh b = putByte bh (fromIntegral (fromEnum b))
394 get bh = do x <- getWord8 bh; return $! (toEnum (fromIntegral x))
396 instance Binary Char where
397 put_ bh c = put_ bh (fromIntegral (ord c) :: Word32)
398 get bh = do x <- get bh; return $! (chr (fromIntegral (x :: Word32)))
400 instance Binary Int where
401 put_ bh i = put_ bh (fromIntegral i :: Int64)
404 return $! (fromIntegral (x :: Int64))
406 instance Binary a => Binary [a] where
410 then putByte bh (fromIntegral len :: Word8)
411 else do putByte bh 0xff; put_ bh (fromIntegral len :: Word32)
417 else return (fromIntegral b :: Word32)
418 let loop 0 = return []
419 loop n = do a <- get bh; as <- loop (n-1); return (a:as)
422 instance (Binary a, Binary b) => Binary (a,b) where
423 put_ bh (a,b) = do put_ bh a; put_ bh b
424 get bh = do a <- get bh
428 instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where
429 put_ bh (a,b,c) = do put_ bh a; put_ bh b; put_ bh c
430 get bh = do a <- get bh
435 instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where
436 put_ bh (a,b,c,d) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d
437 get bh = do a <- get bh
443 instance Binary a => Binary (Maybe a) where
444 put_ bh Nothing = putByte bh 0
445 put_ bh (Just a) = do putByte bh 1; put_ bh a
446 get bh = do h <- getWord8 bh
449 _ -> do x <- get bh; return (Just x)
451 instance (Binary a, Binary b) => Binary (Either a b) where
452 put_ bh (Left a) = do putByte bh 0; put_ bh a
453 put_ bh (Right b) = do putByte bh 1; put_ bh b
454 get bh = do h <- getWord8 bh
456 0 -> do a <- get bh ; return (Left a)
457 _ -> do b <- get bh ; return (Right b)
459 #if defined(__GLASGOW_HASKELL__) || 1
460 --to quote binary-0.3 on this code idea,
462 -- TODO This instance is not architecture portable. GMP stores numbers as
463 -- arrays of machine sized words, so the byte format is not portable across
464 -- architectures with different endianess and word size.
466 -- This makes it hard (impossible) to make an equivalent instance
467 -- with code that is compilable with non-GHC. Do we need any instance
468 -- Binary Integer, and if so, does it have to be blazing fast? Or can
469 -- we just change this instance to be portable like the rest of the
470 -- instances? (binary package has code to steal for that)
472 -- yes, we need Binary Integer and Binary Rational in basicTypes/Literal.lhs
474 instance Binary Integer where
475 -- XXX This is hideous
476 put_ bh i = put_ bh (show i)
477 get bh = do str <- get bh
479 [(i, "")] -> return i
480 _ -> fail ("Binary Integer: got " ++ show str)
483 put_ bh (S# i#) = do putByte bh 0; put_ bh (I# i#)
484 put_ bh (J# s# a#) = do
487 let sz# = sizeofByteArray# a# -- in *bytes*
488 put_ bh (I# sz#) -- in *bytes*
489 putByteArray bh a# sz#
494 0 -> do (I# i#) <- get bh
496 _ -> do (I# s#) <- get bh
498 (BA a#) <- getByteArray bh sz
502 -- As for the rest of this code, even though this module
503 -- exports it, it doesn't seem to be used anywhere else
506 putByteArray :: BinHandle -> ByteArray# -> Int# -> IO ()
507 putByteArray bh a s# = loop 0#
509 | n# ==# s# = return ()
511 putByte bh (indexByteArray a n#)
514 getByteArray :: BinHandle -> Int -> IO ByteArray
515 getByteArray bh (I# sz) = do
516 (MBA arr) <- newByteArray sz
518 | n ==# sz = return ()
521 writeByteArray arr n w
527 data ByteArray = BA ByteArray#
528 data MBA = MBA (MutableByteArray# RealWorld)
530 newByteArray :: Int# -> IO MBA
531 newByteArray sz = IO $ \s ->
532 case newByteArray# sz s of { (# s, arr #) ->
535 freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray
536 freezeByteArray arr = IO $ \s ->
537 case unsafeFreezeByteArray# arr s of { (# s, arr #) ->
540 writeByteArray :: MutableByteArray# RealWorld -> Int# -> Word8 -> IO ()
541 writeByteArray arr i (W8# w) = IO $ \s ->
542 case writeWord8Array# arr i w s of { s ->
545 indexByteArray :: ByteArray# -> Int# -> Word8
546 indexByteArray a# n# = W8# (indexWord8Array# a# n#)
548 instance (Integral a, Binary a) => Binary (Ratio a) where
549 put_ bh (a :% b) = do put_ bh a; put_ bh b
550 get bh = do a <- get bh; b <- get bh; return (a :% b)
553 instance Binary (Bin a) where
554 put_ bh (BinPtr i) = put_ bh (fromIntegral i :: Int32)
555 get bh = do i <- get bh; return (BinPtr (fromIntegral (i :: Int32)))
557 -- -----------------------------------------------------------------------------
558 -- Instances for Data.Typeable stuff
560 instance Binary TyCon where
562 let s = tyConString ty_con
568 instance Binary TypeRep where
569 put_ bh type_rep = do
570 let (ty_con, child_type_reps) = splitTyConApp type_rep
572 put_ bh child_type_reps
575 child_type_reps <- get bh
576 return (mkTyConApp ty_con child_type_reps)
578 -- -----------------------------------------------------------------------------
579 -- Lazy reading/writing
581 lazyPut :: Binary a => BinHandle -> a -> IO ()
583 -- output the obj with a ptr to skip over it:
585 put_ bh pre_a -- save a slot for the ptr
586 put_ bh a -- dump the object
587 q <- tellBin bh -- q = ptr to after object
588 putAt bh pre_a q -- fill in slot before a with ptr to q
589 seekBin bh q -- finally carry on writing at q
591 lazyGet :: Binary a => BinHandle -> IO a
593 p <- get bh -- a BinPtr
595 a <- unsafeInterleaveIO (getAt bh p_a)
596 seekBin bh p -- skip over the object for now
599 -- -----------------------------------------------------------------------------
601 -- -----------------------------------------------------------------------------
605 -- for *deserialising* only:
606 ud_dict :: Dictionary,
607 ud_symtab :: SymbolTable,
609 -- for *serialising* only:
610 ud_put_name :: BinHandle -> Name -> IO (),
611 ud_put_fs :: BinHandle -> FastString -> IO ()
614 newReadState :: Dictionary -> IO UserData
615 newReadState dict = do
616 return UserData { ud_dict = dict,
617 ud_symtab = undef "symtab",
618 ud_put_name = undef "put_name",
619 ud_put_fs = undef "put_fs"
622 newWriteState :: (BinHandle -> Name -> IO ())
623 -> (BinHandle -> FastString -> IO ())
625 newWriteState put_name put_fs = do
626 return UserData { ud_dict = undef "dict",
627 ud_symtab = undef "symtab",
628 ud_put_name = put_name,
633 noUserData = undef "UserData"
636 undef s = panic ("Binary.UserData: no " ++ s)
638 ---------------------------------------------------------
640 ---------------------------------------------------------
642 type Dictionary = Array Int FastString -- The dictionary
643 -- Should be 0-indexed
645 putDictionary :: BinHandle -> Int -> UniqFM (Int,FastString) -> IO ()
646 putDictionary bh sz dict = do
648 mapM_ (putFS bh) (elems (array (0,sz-1) (eltsUFM dict)))
650 getDictionary :: BinHandle -> IO Dictionary
651 getDictionary bh = do
653 elems <- sequence (take sz (repeat (getFS bh)))
654 return (listArray (0,sz-1) elems)
656 ---------------------------------------------------------
658 ---------------------------------------------------------
660 -- On disk, the symbol table is an array of IfaceExtName, when
661 -- reading it in we turn it into a SymbolTable.
663 type SymbolTable = Array Int Name
665 ---------------------------------------------------------
666 -- Reading and writing FastStrings
667 ---------------------------------------------------------
669 putFS :: BinHandle -> FastString -> IO ()
670 putFS bh (FastString _ l _ buf _) = do
672 withForeignPtr buf $ \ptr ->
674 go n | n == l = return ()
676 b <- peekElemOff ptr n
682 {- -- possible faster version, not quite there yet:
683 getFS bh@BinMem{} = do
685 arr <- readIORef (arr_r bh)
686 off <- readFastMutInt (off_r bh)
687 return $! (mkFastSubStringBA# arr off l)
689 getFS :: BinHandle -> IO FastString
692 fp <- mallocForeignPtrBytes l
693 withForeignPtr fp $ \ptr -> do
695 go n | n == l = mkFastStringForeignPtr ptr fp l
703 instance Binary FastString where
705 case getUserData bh of
706 UserData { ud_put_fs = put_fs } -> put_fs bh f
710 return $! (ud_dict (getUserData bh) ! (fromIntegral (j :: Word32)))
712 -- Here to avoid loop
714 instance Binary Fingerprint where
715 put_ h (Fingerprint w1 w2) = do put_ h w1; put_ h w2
716 get h = do w1 <- get h; w2 <- get h; return (Fingerprint w1 w2)
718 instance Binary FunctionOrData where
719 put_ bh IsFunction = putByte bh 0
720 put_ bh IsData = putByte bh 1
724 0 -> return IsFunction
726 _ -> panic "Binary FunctionOrData"