3 -- (c) The University of Glasgow 2002-2006
5 -- Binary I/O library, with special tweaks for GHC
7 -- Based on the nhc98 Binary library, which is copyright
8 -- (c) Malcolm Wallace and Colin Runciman, University of York, 1998.
9 -- Under the terms of the license for that software, we must tell you
10 -- where you can obtain the original version of the Binary library, namely
11 -- http://www.cs.york.ac.uk/fp/nhc98/
18 openBinIO, openBinIO_,
33 -- for writing instances:
46 UserData(..), getUserData, setUserData,
47 newReadState, newWriteState,
48 putDictionary, getDictionary,
51 #include "HsVersions.h"
53 -- The *host* architecture version:
56 import {-# SOURCE #-} Name (Name)
71 import Data.Char ( ord, chr )
72 import Data.Array.Base ( unsafeRead, unsafeWrite )
73 import Control.Monad ( when )
74 import System.IO as IO
75 import System.IO.Unsafe ( unsafeInterleaveIO )
76 import System.IO.Error ( mkIOError, eofErrorType )
77 import GHC.Real ( Ratio(..) )
79 import GHC.IOBase ( IO(..) )
80 import GHC.Word ( Word8(..) )
81 #if __GLASGOW_HASKELL__ < 601
82 -- openFileEx is available from the lang package, but we want to
83 -- be independent of hslibs libraries.
84 import GHC.Handle ( openFileEx, IOModeEx(..) )
86 import System.IO ( openBinaryFile )
89 #if __GLASGOW_HASKELL__ < 601
90 openBinaryFile f mode = openFileEx f (BinaryMode mode)
93 type BinArray = IOUArray Int Word8
95 ---------------------------------------------------------------
97 ---------------------------------------------------------------
100 = BinMem { -- binary data stored in an unboxed array
101 bh_usr :: UserData, -- sigh, need parameterized modules :-)
102 off_r :: !FastMutInt, -- the current offset
103 sz_r :: !FastMutInt, -- size of the array (cached)
104 arr_r :: !(IORef BinArray) -- the array (bounds: (0,size-1))
106 -- XXX: should really store a "high water mark" for dumping out
107 -- the binary data to a file.
109 | BinIO { -- binary data stored in a file
111 off_r :: !FastMutInt, -- the current offset (cached)
112 hdl :: !IO.Handle -- the file handle (must be seekable)
114 -- cache the file ptr in BinIO; using hTell is too expensive
115 -- to call repeatedly. If anyone else is modifying this Handle
116 -- at the same time, we'll be screwed.
118 getUserData :: BinHandle -> UserData
119 getUserData bh = bh_usr bh
121 setUserData :: BinHandle -> UserData -> BinHandle
122 setUserData bh us = bh { bh_usr = us }
125 ---------------------------------------------------------------
127 ---------------------------------------------------------------
129 newtype Bin a = BinPtr Int
130 deriving (Eq, Ord, Show, Bounded)
132 castBin :: Bin a -> Bin b
133 castBin (BinPtr i) = BinPtr i
135 ---------------------------------------------------------------
137 ---------------------------------------------------------------
140 put_ :: BinHandle -> a -> IO ()
141 put :: BinHandle -> a -> IO (Bin a)
142 get :: BinHandle -> IO a
144 -- define one of put_, put. Use of put_ is recommended because it
145 -- is more likely that tail-calls can kick in, and we rarely need the
146 -- position return value.
147 put_ bh a = do put bh a; return ()
148 put bh a = do p <- tellBin bh; put_ bh a; return p
150 putAt :: Binary a => BinHandle -> Bin a -> a -> IO ()
151 putAt bh p x = do seekBin bh p; put bh x; return ()
153 getAt :: Binary a => BinHandle -> Bin a -> IO a
154 getAt bh p = do seekBin bh p; get bh
156 openBinIO_ :: IO.Handle -> IO BinHandle
157 openBinIO_ h = openBinIO h
159 openBinIO :: IO.Handle -> IO BinHandle
163 return (BinIO noUserData r h)
165 openBinMem :: Int -> IO BinHandle
167 | size <= 0 = error "Data.Binary.openBinMem: size must be >= 0"
169 arr <- newArray_ (0,size-1)
170 arr_r <- newIORef arr
171 ix_r <- newFastMutInt
172 writeFastMutInt ix_r 0
173 sz_r <- newFastMutInt
174 writeFastMutInt sz_r size
175 return (BinMem noUserData ix_r sz_r arr_r)
177 tellBin :: BinHandle -> IO (Bin a)
178 tellBin (BinIO _ r _) = do ix <- readFastMutInt r; return (BinPtr ix)
179 tellBin (BinMem _ r _ _) = do ix <- readFastMutInt r; return (BinPtr ix)
181 seekBin :: BinHandle -> Bin a -> IO ()
182 seekBin (BinIO _ ix_r h) (BinPtr p) = do
183 writeFastMutInt ix_r p
184 hSeek h AbsoluteSeek (fromIntegral p)
185 seekBin h@(BinMem _ ix_r sz_r a) (BinPtr p) = do
186 sz <- readFastMutInt sz_r
188 then do expandBin h p; writeFastMutInt ix_r p
189 else writeFastMutInt ix_r p
191 isEOFBin :: BinHandle -> IO Bool
192 isEOFBin (BinMem _ ix_r sz_r a) = do
193 ix <- readFastMutInt ix_r
194 sz <- readFastMutInt sz_r
196 isEOFBin (BinIO _ ix_r h) = hIsEOF h
198 writeBinMem :: BinHandle -> FilePath -> IO ()
199 writeBinMem (BinIO _ _ _) _ = error "Data.Binary.writeBinMem: not a memory handle"
200 writeBinMem (BinMem _ ix_r sz_r arr_r) fn = do
201 h <- openBinaryFile fn WriteMode
202 arr <- readIORef arr_r
203 ix <- readFastMutInt ix_r
205 #if __GLASGOW_HASKELL__ <= 500
206 -- workaround a bug in old implementation of hPutBuf (it doesn't
207 -- set the FILEOBJ_RW_WRITTEN flag on the file object, so the file doens't
208 -- get flushed properly). Adding an extra '\0' doens't do any harm.
213 readBinMem :: FilePath -> IO BinHandle
214 -- Return a BinHandle with a totally undefined State
215 readBinMem filename = do
216 h <- openBinaryFile filename ReadMode
217 filesize' <- hFileSize h
218 let filesize = fromIntegral filesize'
219 arr <- newArray_ (0,filesize-1)
220 count <- hGetArray h arr filesize
221 when (count /= filesize)
222 (error ("Binary.readBinMem: only read " ++ show count ++ " bytes"))
224 arr_r <- newIORef arr
225 ix_r <- newFastMutInt
226 writeFastMutInt ix_r 0
227 sz_r <- newFastMutInt
228 writeFastMutInt sz_r filesize
229 return (BinMem noUserData ix_r sz_r arr_r)
231 -- expand the size of the array to include a specified offset
232 expandBin :: BinHandle -> Int -> IO ()
233 expandBin (BinMem _ ix_r sz_r arr_r) off = do
234 sz <- readFastMutInt sz_r
235 let sz' = head (dropWhile (<= off) (iterate (* 2) sz))
236 arr <- readIORef arr_r
237 arr' <- newArray_ (0,sz'-1)
238 sequence_ [ unsafeRead arr i >>= unsafeWrite arr' i
239 | i <- [ 0 .. sz-1 ] ]
240 writeFastMutInt sz_r sz'
241 writeIORef arr_r arr'
243 hPutStrLn stderr ("Binary: expanding to size: " ++ show sz')
246 expandBin (BinIO _ _ _) _ = return ()
247 -- no need to expand a file, we'll assume they expand by themselves.
249 -- -----------------------------------------------------------------------------
250 -- Low-level reading/writing of bytes
252 putWord8 :: BinHandle -> Word8 -> IO ()
253 putWord8 h@(BinMem _ ix_r sz_r arr_r) w = do
254 ix <- readFastMutInt ix_r
255 sz <- readFastMutInt sz_r
256 -- double the size of the array if it overflows
258 then do expandBin h ix
260 else do arr <- readIORef arr_r
262 writeFastMutInt ix_r (ix+1)
264 putWord8 (BinIO _ ix_r h) w = do
265 ix <- readFastMutInt ix_r
266 hPutChar h (chr (fromIntegral w)) -- XXX not really correct
267 writeFastMutInt ix_r (ix+1)
270 getWord8 :: BinHandle -> IO Word8
271 getWord8 (BinMem _ ix_r sz_r arr_r) = do
272 ix <- readFastMutInt ix_r
273 sz <- readFastMutInt sz_r
275 #if __GLASGOW_HASKELL__ <= 408
276 throw (mkIOError eofErrorType "Data.Binary.getWord8" Nothing Nothing)
278 ioError (mkIOError eofErrorType "Data.Binary.getWord8" Nothing Nothing)
280 arr <- readIORef arr_r
281 w <- unsafeRead arr ix
282 writeFastMutInt ix_r (ix+1)
284 getWord8 (BinIO _ ix_r h) = do
285 ix <- readFastMutInt ix_r
287 writeFastMutInt ix_r (ix+1)
288 return $! (fromIntegral (ord c)) -- XXX not really correct
290 putByte :: BinHandle -> Word8 -> IO ()
291 putByte bh w = put_ bh w
293 getByte :: BinHandle -> IO Word8
296 -- -----------------------------------------------------------------------------
297 -- Primitve Word writes
299 instance Binary Word8 where
303 instance Binary Word16 where
304 put_ h w = do -- XXX too slow.. inline putWord8?
305 putByte h (fromIntegral (w `shiftR` 8))
306 putByte h (fromIntegral (w .&. 0xff))
310 return $! ((fromIntegral w1 `shiftL` 8) .|. fromIntegral w2)
313 instance Binary Word32 where
315 putByte h (fromIntegral (w `shiftR` 24))
316 putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
317 putByte h (fromIntegral ((w `shiftR` 8) .&. 0xff))
318 putByte h (fromIntegral (w .&. 0xff))
324 return $! ((fromIntegral w1 `shiftL` 24) .|.
325 (fromIntegral w2 `shiftL` 16) .|.
326 (fromIntegral w3 `shiftL` 8) .|.
330 instance Binary Word64 where
332 putByte h (fromIntegral (w `shiftR` 56))
333 putByte h (fromIntegral ((w `shiftR` 48) .&. 0xff))
334 putByte h (fromIntegral ((w `shiftR` 40) .&. 0xff))
335 putByte h (fromIntegral ((w `shiftR` 32) .&. 0xff))
336 putByte h (fromIntegral ((w `shiftR` 24) .&. 0xff))
337 putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
338 putByte h (fromIntegral ((w `shiftR` 8) .&. 0xff))
339 putByte h (fromIntegral (w .&. 0xff))
349 return $! ((fromIntegral w1 `shiftL` 56) .|.
350 (fromIntegral w2 `shiftL` 48) .|.
351 (fromIntegral w3 `shiftL` 40) .|.
352 (fromIntegral w4 `shiftL` 32) .|.
353 (fromIntegral w5 `shiftL` 24) .|.
354 (fromIntegral w6 `shiftL` 16) .|.
355 (fromIntegral w7 `shiftL` 8) .|.
358 -- -----------------------------------------------------------------------------
359 -- Primitve Int writes
361 instance Binary Int8 where
362 put_ h w = put_ h (fromIntegral w :: Word8)
363 get h = do w <- get h; return $! (fromIntegral (w::Word8))
365 instance Binary Int16 where
366 put_ h w = put_ h (fromIntegral w :: Word16)
367 get h = do w <- get h; return $! (fromIntegral (w::Word16))
369 instance Binary Int32 where
370 put_ h w = put_ h (fromIntegral w :: Word32)
371 get h = do w <- get h; return $! (fromIntegral (w::Word32))
373 instance Binary Int64 where
374 put_ h w = put_ h (fromIntegral w :: Word64)
375 get h = do w <- get h; return $! (fromIntegral (w::Word64))
377 -- -----------------------------------------------------------------------------
378 -- Instances for standard types
380 instance Binary () where
381 put_ bh () = return ()
383 -- getF bh p = case getBitsF bh 0 p of (_,b) -> ((),b)
385 instance Binary Bool where
386 put_ bh b = putByte bh (fromIntegral (fromEnum b))
387 get bh = do x <- getWord8 bh; return $! (toEnum (fromIntegral x))
388 -- getF bh p = case getBitsF bh 1 p of (x,b) -> (toEnum x,b)
390 instance Binary Char where
391 put_ bh c = put_ bh (fromIntegral (ord c) :: Word32)
392 get bh = do x <- get bh; return $! (chr (fromIntegral (x :: Word32)))
393 -- getF bh p = case getBitsF bh 8 p of (x,b) -> (toEnum x,b)
395 instance Binary Int where
396 #if SIZEOF_HSINT == 4
397 put_ bh i = put_ bh (fromIntegral i :: Int32)
400 return $! (fromIntegral (x :: Int32))
401 #elif SIZEOF_HSINT == 8
402 put_ bh i = put_ bh (fromIntegral i :: Int64)
405 return $! (fromIntegral (x :: Int64))
407 #error "unsupported sizeof(HsInt)"
409 -- getF bh = getBitsF bh 32
411 instance Binary a => Binary [a] where
415 then putByte bh (fromIntegral len :: Word8)
416 else do putByte bh 0xff; put_ bh (fromIntegral len :: Word32)
422 else return (fromIntegral b :: Word32)
423 let loop 0 = return []
424 loop n = do a <- get bh; as <- loop (n-1); return (a:as)
427 instance (Binary a, Binary b) => Binary (a,b) where
428 put_ bh (a,b) = do put_ bh a; put_ bh b
429 get bh = do a <- get bh
433 instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where
434 put_ bh (a,b,c) = do put_ bh a; put_ bh b; put_ bh c
435 get bh = do a <- get bh
440 instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where
441 put_ bh (a,b,c,d) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d
442 get bh = do a <- get bh
448 instance Binary a => Binary (Maybe a) where
449 put_ bh Nothing = putByte bh 0
450 put_ bh (Just a) = do putByte bh 1; put_ bh a
451 get bh = do h <- getWord8 bh
454 _ -> do x <- get bh; return (Just x)
456 instance (Binary a, Binary b) => Binary (Either a b) where
457 put_ bh (Left a) = do putByte bh 0; put_ bh a
458 put_ bh (Right b) = do putByte bh 1; put_ bh b
459 get bh = do h <- getWord8 bh
461 0 -> do a <- get bh ; return (Left a)
462 _ -> do b <- get bh ; return (Right b)
464 #ifdef __GLASGOW_HASKELL__
465 instance Binary Integer where
466 put_ bh (S# i#) = do putByte bh 0; put_ bh (I# i#)
467 put_ bh (J# s# a#) = do
470 let sz# = sizeofByteArray# a# -- in *bytes*
471 put_ bh (I# sz#) -- in *bytes*
472 putByteArray bh a# sz#
477 0 -> do (I# i#) <- get bh
479 _ -> do (I# s#) <- get bh
481 (BA a#) <- getByteArray bh sz
484 putByteArray :: BinHandle -> ByteArray# -> Int# -> IO ()
485 putByteArray bh a s# = loop 0#
487 | n# ==# s# = return ()
489 putByte bh (indexByteArray a n#)
492 getByteArray :: BinHandle -> Int -> IO ByteArray
493 getByteArray bh (I# sz) = do
494 (MBA arr) <- newByteArray sz
496 | n ==# sz = return ()
499 writeByteArray arr n w
505 data ByteArray = BA ByteArray#
506 data MBA = MBA (MutableByteArray# RealWorld)
508 newByteArray :: Int# -> IO MBA
509 newByteArray sz = IO $ \s ->
510 case newByteArray# sz s of { (# s, arr #) ->
513 freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray
514 freezeByteArray arr = IO $ \s ->
515 case unsafeFreezeByteArray# arr s of { (# s, arr #) ->
518 writeByteArray :: MutableByteArray# RealWorld -> Int# -> Word8 -> IO ()
520 #if __GLASGOW_HASKELL__ < 503
521 writeByteArray arr i w8 = IO $ \s ->
522 case word8ToWord w8 of { W# w# ->
523 case writeCharArray# arr i (chr# (word2Int# w#)) s of { s ->
526 writeByteArray arr i (W8# w) = IO $ \s ->
527 case writeWord8Array# arr i w s of { s ->
531 #if __GLASGOW_HASKELL__ < 503
532 indexByteArray a# n# = fromIntegral (I# (ord# (indexCharArray# a# n#)))
534 indexByteArray a# n# = W8# (indexWord8Array# a# n#)
537 instance (Integral a, Binary a) => Binary (Ratio a) where
538 put_ bh (a :% b) = do put_ bh a; put_ bh b
539 get bh = do a <- get bh; b <- get bh; return (a :% b)
542 instance Binary (Bin a) where
543 put_ bh (BinPtr i) = put_ bh i
544 get bh = do i <- get bh; return (BinPtr i)
546 -- -----------------------------------------------------------------------------
547 -- Lazy reading/writing
549 lazyPut :: Binary a => BinHandle -> a -> IO ()
551 -- output the obj with a ptr to skip over it:
553 put_ bh pre_a -- save a slot for the ptr
554 put_ bh a -- dump the object
555 q <- tellBin bh -- q = ptr to after object
556 putAt bh pre_a q -- fill in slot before a with ptr to q
557 seekBin bh q -- finally carry on writing at q
559 lazyGet :: Binary a => BinHandle -> IO a
561 p <- get bh -- a BinPtr
563 a <- unsafeInterleaveIO (getAt bh p_a)
564 seekBin bh p -- skip over the object for now
567 -- -----------------------------------------------------------------------------
569 -- -----------------------------------------------------------------------------
573 -- for *deserialising* only:
574 ud_dict :: Dictionary,
575 ud_symtab :: SymbolTable,
577 -- for *serialising* only:
578 ud_dict_next :: !FastMutInt, -- The next index to use
579 ud_dict_map :: !(IORef (UniqFM (Int,FastString))),
580 -- indexed by FastString
582 ud_symtab_next :: !FastMutInt, -- The next index to use
583 ud_symtab_map :: !(IORef (UniqFM (Int,Name)))
587 newReadState :: Dictionary -> IO UserData
588 newReadState dict = do
589 dict_next <- newFastMutInt
590 dict_map <- newIORef (undef "dict_map")
591 symtab_next <- newFastMutInt
592 symtab_map <- newIORef (undef "symtab_map")
593 return UserData { ud_dict = dict,
594 ud_symtab = undef "symtab",
595 ud_dict_next = dict_next,
596 ud_dict_map = dict_map,
597 ud_symtab_next = symtab_next,
598 ud_symtab_map = symtab_map
601 newWriteState :: IO UserData
603 dict_next <- newFastMutInt
604 writeFastMutInt dict_next 0
605 dict_map <- newIORef emptyUFM
606 symtab_next <- newFastMutInt
607 writeFastMutInt symtab_next 0
608 symtab_map <- newIORef emptyUFM
609 return UserData { ud_dict = undef "dict",
610 ud_symtab = undef "symtab",
611 ud_dict_next = dict_next,
612 ud_dict_map = dict_map,
613 ud_symtab_next = symtab_next,
614 ud_symtab_map = symtab_map
617 noUserData = undef "UserData"
619 undef s = panic ("Binary.UserData: no " ++ s)
621 ---------------------------------------------------------
623 ---------------------------------------------------------
625 type Dictionary = Array Int FastString -- The dictionary
626 -- Should be 0-indexed
628 putDictionary :: BinHandle -> Int -> UniqFM (Int,FastString) -> IO ()
629 putDictionary bh sz dict = do
631 mapM_ (putFS bh) (elems (array (0,sz-1) (eltsUFM dict)))
633 getDictionary :: BinHandle -> IO Dictionary
634 getDictionary bh = do
636 elems <- sequence (take sz (repeat (getFS bh)))
637 return (listArray (0,sz-1) elems)
639 ---------------------------------------------------------
641 ---------------------------------------------------------
643 -- On disk, the symbol table is an array of IfaceExtName, when
644 -- reading it in we turn it into a SymbolTable.
646 type SymbolTable = Array Int Name
648 ---------------------------------------------------------
649 -- Reading and writing FastStrings
650 ---------------------------------------------------------
652 putFS bh (FastString id l _ buf _) = do
654 withForeignPtr buf $ \ptr ->
656 go n | n == l = return ()
658 b <- peekElemOff ptr n
664 {- -- possible faster version, not quite there yet:
665 getFS bh@BinMem{} = do
667 arr <- readIORef (arr_r bh)
668 off <- readFastMutInt (off_r bh)
669 return $! (mkFastSubStringBA# arr off l)
673 fp <- mallocForeignPtrBytes l
674 withForeignPtr fp $ \ptr -> do
676 go n | n == l = mkFastStringForeignPtr ptr fp l
684 #if __GLASGOW_HASKELL__ < 600
685 mallocForeignPtrBytes :: Int -> IO (ForeignPtr a)
686 mallocForeignPtrBytes n = do
688 newForeignPtr r (finalizerFree r)
690 foreign import ccall unsafe "stdlib.h free"
691 finalizerFree :: Ptr a -> IO ()
694 instance Binary PackageId where
695 put_ bh pid = put_ bh (packageIdFS pid)
696 get bh = do { fs <- get bh; return (fsToPackageId fs) }
698 instance Binary FastString where
699 put_ bh f@(FastString id l _ fp _) =
700 case getUserData bh of {
701 UserData { ud_dict_next = j_r,
703 ud_dict = dict} -> do
704 out <- readIORef out_r
705 let uniq = getUnique f
706 case lookupUFM out uniq of
707 Just (j,f) -> put_ bh j
709 j <- readFastMutInt j_r
711 writeFastMutInt j_r (j+1)
712 writeIORef out_r $! addToUFM out uniq (j,f)
717 return $! (ud_dict (getUserData bh) ! j)