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:
64 import {-# SOURCE #-} Name (Name)
77 import Data.Char ( ord, chr )
78 import Control.Monad ( when )
79 import System.IO as IO
80 import System.IO.Unsafe ( unsafeInterleaveIO )
81 import System.IO.Error ( mkIOError, eofErrorType )
82 import GHC.Real ( Ratio(..) )
84 import GHC.IOBase ( IO(..) )
85 import GHC.Word ( Word8(..) )
86 import System.IO ( openBinaryFile )
88 type BinArray = ForeignPtr Word8
90 ---------------------------------------------------------------
92 ---------------------------------------------------------------
95 = BinMem { -- binary data stored in an unboxed array
96 bh_usr :: UserData, -- sigh, need parameterized modules :-)
97 _off_r :: !FastMutInt, -- the current offset
98 _sz_r :: !FastMutInt, -- size of the array (cached)
99 _arr_r :: !(IORef BinArray) -- the array (bounds: (0,size-1))
101 -- XXX: should really store a "high water mark" for dumping out
102 -- the binary data to a file.
104 | BinIO { -- binary data stored in a file
106 _off_r :: !FastMutInt, -- the current offset (cached)
107 _hdl :: !IO.Handle -- the file handle (must be seekable)
109 -- cache the file ptr in BinIO; using hTell is too expensive
110 -- to call repeatedly. If anyone else is modifying this Handle
111 -- at the same time, we'll be screwed.
113 getUserData :: BinHandle -> UserData
114 getUserData bh = bh_usr bh
116 setUserData :: BinHandle -> UserData -> BinHandle
117 setUserData bh us = bh { bh_usr = us }
120 ---------------------------------------------------------------
122 ---------------------------------------------------------------
124 newtype Bin a = BinPtr Int
125 deriving (Eq, Ord, Show, Bounded)
127 castBin :: Bin a -> Bin b
128 castBin (BinPtr i) = BinPtr i
130 ---------------------------------------------------------------
132 ---------------------------------------------------------------
135 put_ :: BinHandle -> a -> IO ()
136 put :: BinHandle -> a -> IO (Bin a)
137 get :: BinHandle -> IO a
139 -- define one of put_, put. Use of put_ is recommended because it
140 -- is more likely that tail-calls can kick in, and we rarely need the
141 -- position return value.
142 put_ bh a = do put bh a; return ()
143 put bh a = do p <- tellBin bh; put_ bh a; return p
145 putAt :: Binary a => BinHandle -> Bin a -> a -> IO ()
146 putAt bh p x = do seekBin bh p; put bh x; return ()
148 getAt :: Binary a => BinHandle -> Bin a -> IO a
149 getAt bh p = do seekBin bh p; get bh
151 openBinIO_ :: IO.Handle -> IO BinHandle
152 openBinIO_ h = openBinIO h
154 openBinIO :: IO.Handle -> IO BinHandle
158 return (BinIO noUserData r h)
160 openBinMem :: Int -> IO BinHandle
162 | size <= 0 = error "Data.Binary.openBinMem: size must be >= 0"
164 arr <- mallocForeignPtrBytes size
165 arr_r <- newIORef arr
166 ix_r <- newFastMutInt
167 writeFastMutInt ix_r 0
168 sz_r <- newFastMutInt
169 writeFastMutInt sz_r size
170 return (BinMem noUserData ix_r sz_r arr_r)
172 tellBin :: BinHandle -> IO (Bin a)
173 tellBin (BinIO _ r _) = do ix <- readFastMutInt r; return (BinPtr ix)
174 tellBin (BinMem _ r _ _) = do ix <- readFastMutInt r; return (BinPtr ix)
176 seekBin :: BinHandle -> Bin a -> IO ()
177 seekBin (BinIO _ ix_r h) (BinPtr p) = do
178 writeFastMutInt ix_r p
179 hSeek h AbsoluteSeek (fromIntegral p)
180 seekBin h@(BinMem _ ix_r sz_r _) (BinPtr p) = do
181 sz <- readFastMutInt sz_r
183 then do expandBin h p; writeFastMutInt ix_r p
184 else writeFastMutInt ix_r p
186 seekBy :: BinHandle -> Int -> IO ()
187 seekBy (BinIO _ ix_r h) off = do
188 ix <- readFastMutInt ix_r
190 writeFastMutInt ix_r ix'
191 hSeek h AbsoluteSeek (fromIntegral ix')
192 seekBy h@(BinMem _ ix_r sz_r _) off = do
193 sz <- readFastMutInt sz_r
194 ix <- readFastMutInt ix_r
197 then do expandBin h ix'; writeFastMutInt ix_r ix'
198 else writeFastMutInt ix_r ix'
200 isEOFBin :: BinHandle -> IO Bool
201 isEOFBin (BinMem _ ix_r sz_r _) = do
202 ix <- readFastMutInt ix_r
203 sz <- readFastMutInt sz_r
205 isEOFBin (BinIO _ _ h) = hIsEOF h
207 writeBinMem :: BinHandle -> FilePath -> IO ()
208 writeBinMem (BinIO _ _ _) _ = error "Data.Binary.writeBinMem: not a memory handle"
209 writeBinMem (BinMem _ ix_r _ arr_r) fn = do
210 h <- openBinaryFile fn WriteMode
211 arr <- readIORef arr_r
212 ix <- readFastMutInt ix_r
213 withForeignPtr arr $ \p -> hPutBuf h p ix
216 readBinMem :: FilePath -> IO BinHandle
217 -- Return a BinHandle with a totally undefined State
218 readBinMem filename = do
219 h <- openBinaryFile filename ReadMode
220 filesize' <- hFileSize h
221 let filesize = fromIntegral filesize'
222 arr <- mallocForeignPtrBytes (filesize*2)
223 count <- withForeignPtr arr $ \p -> hGetBuf h p filesize
224 when (count /= filesize) $
225 error ("Binary.readBinMem: only read " ++ show count ++ " bytes")
227 arr_r <- newIORef arr
228 ix_r <- newFastMutInt
229 writeFastMutInt ix_r 0
230 sz_r <- newFastMutInt
231 writeFastMutInt sz_r filesize
232 return (BinMem noUserData ix_r sz_r arr_r)
234 fingerprintBinMem :: BinHandle -> IO Fingerprint
235 fingerprintBinMem (BinIO _ _ _) = error "Binary.md5BinMem: not a memory handle"
236 fingerprintBinMem (BinMem _ ix_r _ arr_r) = do
237 arr <- readIORef arr_r
238 ix <- readFastMutInt ix_r
239 withForeignPtr arr $ \p -> fingerprintData p ix
241 -- expand the size of the array to include a specified offset
242 expandBin :: BinHandle -> Int -> IO ()
243 expandBin (BinMem _ _ sz_r arr_r) off = do
244 sz <- readFastMutInt sz_r
245 let sz' = head (dropWhile (<= off) (iterate (* 2) sz))
246 arr <- readIORef arr_r
247 arr' <- mallocForeignPtrBytes sz'
248 withForeignPtr arr $ \old ->
249 withForeignPtr arr' $ \new ->
251 writeFastMutInt sz_r sz'
252 writeIORef arr_r arr'
253 when False $ -- disabled
254 hPutStrLn stderr ("Binary: expanding to size: " ++ show sz')
256 expandBin (BinIO _ _ _) _ = return ()
257 -- no need to expand a file, we'll assume they expand by themselves.
259 -- -----------------------------------------------------------------------------
260 -- Low-level reading/writing of bytes
262 putWord8 :: BinHandle -> Word8 -> IO ()
263 putWord8 h@(BinMem _ ix_r sz_r arr_r) w = do
264 ix <- readFastMutInt ix_r
265 sz <- readFastMutInt sz_r
266 -- double the size of the array if it overflows
268 then do expandBin h ix
270 else do arr <- readIORef arr_r
271 withForeignPtr arr $ \p -> pokeByteOff p ix w
272 writeFastMutInt ix_r (ix+1)
274 putWord8 (BinIO _ ix_r h) w = do
275 ix <- readFastMutInt ix_r
276 hPutChar h (chr (fromIntegral w)) -- XXX not really correct
277 writeFastMutInt ix_r (ix+1)
280 getWord8 :: BinHandle -> IO Word8
281 getWord8 (BinMem _ ix_r sz_r arr_r) = do
282 ix <- readFastMutInt ix_r
283 sz <- readFastMutInt sz_r
285 ioError (mkIOError eofErrorType "Data.Binary.getWord8" Nothing Nothing)
286 arr <- readIORef arr_r
287 w <- withForeignPtr arr $ \p -> peekByteOff p ix
288 writeFastMutInt ix_r (ix+1)
290 getWord8 (BinIO _ ix_r h) = do
291 ix <- readFastMutInt ix_r
293 writeFastMutInt ix_r (ix+1)
294 return $! (fromIntegral (ord c)) -- XXX not really correct
296 putByte :: BinHandle -> Word8 -> IO ()
297 putByte bh w = put_ bh w
299 getByte :: BinHandle -> IO Word8
302 -- -----------------------------------------------------------------------------
303 -- Primitve Word writes
305 instance Binary Word8 where
309 instance Binary Word16 where
310 put_ h w = do -- XXX too slow.. inline putWord8?
311 putByte h (fromIntegral (w `shiftR` 8))
312 putByte h (fromIntegral (w .&. 0xff))
316 return $! ((fromIntegral w1 `shiftL` 8) .|. fromIntegral w2)
319 instance Binary Word32 where
321 putByte h (fromIntegral (w `shiftR` 24))
322 putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
323 putByte h (fromIntegral ((w `shiftR` 8) .&. 0xff))
324 putByte h (fromIntegral (w .&. 0xff))
330 return $! ((fromIntegral w1 `shiftL` 24) .|.
331 (fromIntegral w2 `shiftL` 16) .|.
332 (fromIntegral w3 `shiftL` 8) .|.
335 instance Binary Word64 where
337 putByte h (fromIntegral (w `shiftR` 56))
338 putByte h (fromIntegral ((w `shiftR` 48) .&. 0xff))
339 putByte h (fromIntegral ((w `shiftR` 40) .&. 0xff))
340 putByte h (fromIntegral ((w `shiftR` 32) .&. 0xff))
341 putByte h (fromIntegral ((w `shiftR` 24) .&. 0xff))
342 putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
343 putByte h (fromIntegral ((w `shiftR` 8) .&. 0xff))
344 putByte h (fromIntegral (w .&. 0xff))
354 return $! ((fromIntegral w1 `shiftL` 56) .|.
355 (fromIntegral w2 `shiftL` 48) .|.
356 (fromIntegral w3 `shiftL` 40) .|.
357 (fromIntegral w4 `shiftL` 32) .|.
358 (fromIntegral w5 `shiftL` 24) .|.
359 (fromIntegral w6 `shiftL` 16) .|.
360 (fromIntegral w7 `shiftL` 8) .|.
363 -- -----------------------------------------------------------------------------
364 -- Primitve Int writes
366 instance Binary Int8 where
367 put_ h w = put_ h (fromIntegral w :: Word8)
368 get h = do w <- get h; return $! (fromIntegral (w::Word8))
370 instance Binary Int16 where
371 put_ h w = put_ h (fromIntegral w :: Word16)
372 get h = do w <- get h; return $! (fromIntegral (w::Word16))
374 instance Binary Int32 where
375 put_ h w = put_ h (fromIntegral w :: Word32)
376 get h = do w <- get h; return $! (fromIntegral (w::Word32))
378 instance Binary Int64 where
379 put_ h w = put_ h (fromIntegral w :: Word64)
380 get h = do w <- get h; return $! (fromIntegral (w::Word64))
382 -- -----------------------------------------------------------------------------
383 -- Instances for standard types
385 instance Binary () where
386 put_ _ () = return ()
388 -- getF bh p = case getBitsF bh 0 p of (_,b) -> ((),b)
390 instance Binary Bool where
391 put_ bh b = putByte bh (fromIntegral (fromEnum b))
392 get bh = do x <- getWord8 bh; return $! (toEnum (fromIntegral x))
393 -- getF bh p = case getBitsF bh 1 p of (x,b) -> (toEnum x,b)
395 instance Binary Char where
396 put_ bh c = put_ bh (fromIntegral (ord c) :: Word32)
397 get bh = do x <- get bh; return $! (chr (fromIntegral (x :: Word32)))
398 -- getF bh p = case getBitsF bh 8 p of (x,b) -> (toEnum x,b)
400 instance Binary Int where
401 #if SIZEOF_HSINT == 4
402 put_ bh i = put_ bh (fromIntegral i :: Int32)
405 return $! (fromIntegral (x :: Int32))
406 #elif SIZEOF_HSINT == 8
407 put_ bh i = put_ bh (fromIntegral i :: Int64)
410 return $! (fromIntegral (x :: Int64))
412 #error "unsupported sizeof(HsInt)"
414 -- getF bh = getBitsF bh 32
416 instance Binary a => Binary [a] where
420 then putByte bh (fromIntegral len :: Word8)
421 else do putByte bh 0xff; put_ bh (fromIntegral len :: Word32)
427 else return (fromIntegral b :: Word32)
428 let loop 0 = return []
429 loop n = do a <- get bh; as <- loop (n-1); return (a:as)
432 instance (Binary a, Binary b) => Binary (a,b) where
433 put_ bh (a,b) = do put_ bh a; put_ bh b
434 get bh = do a <- get bh
438 instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where
439 put_ bh (a,b,c) = do put_ bh a; put_ bh b; put_ bh c
440 get bh = do a <- get bh
445 instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where
446 put_ bh (a,b,c,d) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d
447 get bh = do a <- get bh
453 instance Binary a => Binary (Maybe a) where
454 put_ bh Nothing = putByte bh 0
455 put_ bh (Just a) = do putByte bh 1; put_ bh a
456 get bh = do h <- getWord8 bh
459 _ -> do x <- get bh; return (Just x)
461 instance (Binary a, Binary b) => Binary (Either a b) where
462 put_ bh (Left a) = do putByte bh 0; put_ bh a
463 put_ bh (Right b) = do putByte bh 1; put_ bh b
464 get bh = do h <- getWord8 bh
466 0 -> do a <- get bh ; return (Left a)
467 _ -> do b <- get bh ; return (Right b)
469 #if defined(__GLASGOW_HASKELL__) || 1
470 --to quote binary-0.3 on this code idea,
472 -- TODO This instance is not architecture portable. GMP stores numbers as
473 -- arrays of machine sized words, so the byte format is not portable across
474 -- architectures with different endianess and word size.
476 -- This makes it hard (impossible) to make an equivalent instance
477 -- with code that is compilable with non-GHC. Do we need any instance
478 -- Binary Integer, and if so, does it have to be blazing fast? Or can
479 -- we just change this instance to be portable like the rest of the
480 -- instances? (binary package has code to steal for that)
482 -- yes, we need Binary Integer and Binary Rational in basicTypes/Literal.lhs
484 instance Binary Integer where
485 -- XXX This is hideous
486 put_ bh i = put_ bh (show i)
487 get bh = do str <- get bh
489 [(i, "")] -> return i
490 _ -> fail ("Binary Integer: got " ++ show str)
493 put_ bh (S# i#) = do putByte bh 0; put_ bh (I# i#)
494 put_ bh (J# s# a#) = do
497 let sz# = sizeofByteArray# a# -- in *bytes*
498 put_ bh (I# sz#) -- in *bytes*
499 putByteArray bh a# sz#
504 0 -> do (I# i#) <- get bh
506 _ -> do (I# s#) <- get bh
508 (BA a#) <- getByteArray bh sz
512 -- As for the rest of this code, even though this module
513 -- exports it, it doesn't seem to be used anywhere else
516 putByteArray :: BinHandle -> ByteArray# -> Int# -> IO ()
517 putByteArray bh a s# = loop 0#
519 | n# ==# s# = return ()
521 putByte bh (indexByteArray a n#)
524 getByteArray :: BinHandle -> Int -> IO ByteArray
525 getByteArray bh (I# sz) = do
526 (MBA arr) <- newByteArray sz
528 | n ==# sz = return ()
531 writeByteArray arr n w
537 data ByteArray = BA ByteArray#
538 data MBA = MBA (MutableByteArray# RealWorld)
540 newByteArray :: Int# -> IO MBA
541 newByteArray sz = IO $ \s ->
542 case newByteArray# sz s of { (# s, arr #) ->
545 freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray
546 freezeByteArray arr = IO $ \s ->
547 case unsafeFreezeByteArray# arr s of { (# s, arr #) ->
550 writeByteArray :: MutableByteArray# RealWorld -> Int# -> Word8 -> IO ()
551 writeByteArray arr i (W8# w) = IO $ \s ->
552 case writeWord8Array# arr i w s of { s ->
555 indexByteArray :: ByteArray# -> Int# -> Word8
556 indexByteArray a# n# = W8# (indexWord8Array# a# n#)
558 instance (Integral a, Binary a) => Binary (Ratio a) where
559 put_ bh (a :% b) = do put_ bh a; put_ bh b
560 get bh = do a <- get bh; b <- get bh; return (a :% b)
563 instance Binary (Bin a) where
564 put_ bh (BinPtr i) = put_ bh i
565 get bh = do i <- get bh; return (BinPtr i)
567 -- -----------------------------------------------------------------------------
568 -- Lazy reading/writing
570 lazyPut :: Binary a => BinHandle -> a -> IO ()
572 -- output the obj with a ptr to skip over it:
574 put_ bh pre_a -- save a slot for the ptr
575 put_ bh a -- dump the object
576 q <- tellBin bh -- q = ptr to after object
577 putAt bh pre_a q -- fill in slot before a with ptr to q
578 seekBin bh q -- finally carry on writing at q
580 lazyGet :: Binary a => BinHandle -> IO a
582 p <- get bh -- a BinPtr
584 a <- unsafeInterleaveIO (getAt bh p_a)
585 seekBin bh p -- skip over the object for now
588 -- -----------------------------------------------------------------------------
590 -- -----------------------------------------------------------------------------
594 -- for *deserialising* only:
595 ud_dict :: Dictionary,
596 ud_symtab :: SymbolTable,
598 -- for *serialising* only:
599 ud_put_name :: BinHandle -> Name -> IO (),
600 ud_put_fs :: BinHandle -> FastString -> IO ()
603 newReadState :: Dictionary -> IO UserData
604 newReadState dict = do
605 return UserData { ud_dict = dict,
606 ud_symtab = undef "symtab",
607 ud_put_name = undef "put_name",
608 ud_put_fs = undef "put_fs"
611 newWriteState :: (BinHandle -> Name -> IO ())
612 -> (BinHandle -> FastString -> IO ())
614 newWriteState put_name put_fs = do
615 return UserData { ud_dict = undef "dict",
616 ud_symtab = undef "symtab",
617 ud_put_name = put_name,
622 noUserData = undef "UserData"
625 undef s = panic ("Binary.UserData: no " ++ s)
627 ---------------------------------------------------------
629 ---------------------------------------------------------
631 type Dictionary = Array Int FastString -- The dictionary
632 -- Should be 0-indexed
634 putDictionary :: BinHandle -> Int -> UniqFM (Int,FastString) -> IO ()
635 putDictionary bh sz dict = do
637 mapM_ (putFS bh) (elems (array (0,sz-1) (eltsUFM dict)))
639 getDictionary :: BinHandle -> IO Dictionary
640 getDictionary bh = do
642 elems <- sequence (take sz (repeat (getFS bh)))
643 return (listArray (0,sz-1) elems)
645 ---------------------------------------------------------
647 ---------------------------------------------------------
649 -- On disk, the symbol table is an array of IfaceExtName, when
650 -- reading it in we turn it into a SymbolTable.
652 type SymbolTable = Array Int Name
654 ---------------------------------------------------------
655 -- Reading and writing FastStrings
656 ---------------------------------------------------------
658 putFS :: BinHandle -> FastString -> IO ()
659 putFS bh (FastString _ l _ buf _) = do
661 withForeignPtr buf $ \ptr ->
663 go n | n == l = return ()
665 b <- peekElemOff ptr n
671 {- -- possible faster version, not quite there yet:
672 getFS bh@BinMem{} = do
674 arr <- readIORef (arr_r bh)
675 off <- readFastMutInt (off_r bh)
676 return $! (mkFastSubStringBA# arr off l)
678 getFS :: BinHandle -> IO FastString
681 fp <- mallocForeignPtrBytes l
682 withForeignPtr fp $ \ptr -> do
684 go n | n == l = mkFastStringForeignPtr ptr fp l
692 instance Binary FastString where
694 case getUserData bh of
695 UserData { ud_put_fs = put_fs } -> put_fs bh f
699 return $! (ud_dict (getUserData bh) ! j)
701 -- Here to avoid loop
703 instance Binary Fingerprint where
704 put_ h (Fingerprint w1 w2) = do put_ h w1; put_ h w2
705 get h = do w1 <- get h; w2 <- get h; return (Fingerprint w1 w2)