3 -- (c) The University of Glasgow 2002
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 getBinFileWithDict, -- :: Binary a => FilePath -> IO a
47 putBinFileWithDict, -- :: Binary a => FilePath -> Module -> a -> IO ()
53 import {-# SOURCE #-} Module
58 #if __GLASGOW_HASKELL__ < 503
66 import GlaExts hiding (ByteArray, newByteArray, freezeByteArray)
69 import PrelIOBase ( IOError(..), IOErrorType(..), IOException(..) )
70 import PrelReal ( Ratio(..) )
71 import PrelIOBase ( IO(..) )
79 import Data.Char ( ord, chr )
80 import Data.Array.Base ( unsafeRead, unsafeWrite )
81 import Control.Monad ( when )
82 import Control.Exception ( throw )
83 import System.IO as IO
84 import System.IO.Unsafe ( unsafeInterleaveIO )
85 import System.IO.Error ( mkIOError, eofErrorType )
86 import GHC.Real ( Ratio(..) )
88 import GHC.IOBase ( IO(..) )
89 import GHC.Word ( Word8(..) )
92 #if __GLASGOW_HASKELL__ < 503
93 type BinArray = MutableByteArray RealWorld Int
94 newArray_ bounds = stToIO (newCharArray bounds)
95 unsafeWrite arr ix e = stToIO (writeWord8Array arr ix e)
96 unsafeRead arr ix = stToIO (readWord8Array arr ix)
97 #if __GLASGOW_HASKELL__ < 411
98 newByteArray# = newCharArray#
100 hPutArray h arr sz = hPutBufBAFull h arr sz
101 hGetArray h sz = hGetBufBAFull h sz
103 mkIOError :: IOErrorType -> String -> Maybe Handle -> Maybe FilePath -> Exception
104 mkIOError t location maybe_hdl maybe_filename
105 = IOException (IOError maybe_hdl t location ""
106 #if __GLASGOW_HASKELL__ > 411
114 #define SIZEOF_HSINT INT_SIZE_IN_BYTES
117 #ifndef SIZEOF_HSWORD
118 #define SIZEOF_HSWORD WORD_SIZE_IN_BYTES
122 type BinArray = IOUArray Int Word8
126 = BinMem { -- binary data stored in an unboxed array
127 state :: BinHandleState, -- sigh, need parameterized modules :-)
128 off_r :: !FastMutInt, -- the current offset
129 sz_r :: !FastMutInt, -- size of the array (cached)
130 arr_r :: !(IORef BinArray) -- the array (bounds: (0,size-1))
132 -- XXX: should really store a "high water mark" for dumping out
133 -- the binary data to a file.
135 | BinIO { -- binary data stored in a file
136 state :: BinHandleState,
137 off_r :: !FastMutInt, -- the current offset (cached)
138 hdl :: !IO.Handle -- the file handle (must be seekable)
140 -- cache the file ptr in BinIO; using hTell is too expensive
141 -- to call repeatedly. If anyone else is modifying this Handle
142 -- at the same time, we'll be screwed.
144 newtype Bin a = BinPtr Int
145 deriving (Eq, Ord, Show, Bounded)
147 castBin :: Bin a -> Bin b
148 castBin (BinPtr i) = BinPtr i
151 put_ :: BinHandle -> a -> IO ()
152 put :: BinHandle -> a -> IO (Bin a)
153 get :: BinHandle -> IO a
155 -- define one of put_, put. Use of put_ is recommended because it
156 -- is more likely that tail-calls can kick in, and we rarely need the
157 -- position return value.
158 put_ bh a = do put bh a; return ()
159 put bh a = do p <- tellBin bh; put_ bh a; return p
161 putAt :: Binary a => BinHandle -> Bin a -> a -> IO ()
162 putAt bh p x = do seekBin bh p; put bh x; return ()
164 getAt :: Binary a => BinHandle -> Bin a -> IO a
165 getAt bh p = do seekBin bh p; get bh
167 openBinIO_ :: IO.Handle -> IO BinHandle
168 openBinIO_ h = openBinIO h noBinHandleUserData
170 openBinIO :: IO.Handle -> Module -> IO BinHandle
174 state <- newWriteState mod
175 return (BinIO state r h)
177 openBinMem :: Int -> Module -> IO BinHandle
179 | size <= 0 = error "Data.Binary.openBinMem: size must be >= 0"
181 arr <- newArray_ (0,size-1)
182 arr_r <- newIORef arr
183 ix_r <- newFastMutInt
184 writeFastMutInt ix_r 0
185 sz_r <- newFastMutInt
186 writeFastMutInt sz_r size
187 state <- newWriteState mod
188 return (BinMem state ix_r sz_r arr_r)
190 noBinHandleUserData = error "Binary.BinHandle: no user data"
192 getUserData :: BinHandle -> BinHandleState
193 getUserData bh = state bh
195 tellBin :: BinHandle -> IO (Bin a)
196 tellBin (BinIO _ r _) = do ix <- readFastMutInt r; return (BinPtr ix)
197 tellBin (BinMem _ r _ _) = do ix <- readFastMutInt r; return (BinPtr ix)
199 seekBin :: BinHandle -> Bin a -> IO ()
200 seekBin (BinIO _ ix_r h) (BinPtr p) = do
201 writeFastMutInt ix_r p
202 hSeek h AbsoluteSeek (fromIntegral p)
203 seekBin h@(BinMem _ ix_r sz_r a) (BinPtr p) = do
204 sz <- readFastMutInt sz_r
206 then do expandBin h p; writeFastMutInt ix_r p
207 else writeFastMutInt ix_r p
209 isEOFBin :: BinHandle -> IO Bool
210 isEOFBin (BinMem _ ix_r sz_r a) = do
211 ix <- readFastMutInt ix_r
212 sz <- readFastMutInt sz_r
214 isEOFBin (BinIO _ ix_r h) = hIsEOF h
216 writeBinMem :: BinHandle -> FilePath -> IO ()
217 writeBinMem (BinIO _ _ _) _ = error "Data.Binary.writeBinMem: not a memory handle"
218 writeBinMem (BinMem _ ix_r sz_r arr_r) fn = do
219 h <- openFile fn WriteMode
220 arr <- readIORef arr_r
221 ix <- readFastMutInt ix_r
223 #if __GLASGOW_HASKELL__ < 500
224 -- workaround a bug in ghc 4.08's implementation of hPutBuf (it doesn't
225 -- set the FILEOBJ_RW_WRITTEN flag on the file object, so the file doens't
226 -- get flushed properly). Adding an extra '\0' doens't do any harm.
231 readBinMem :: FilePath -> IO BinHandle
232 readBinMem filename = do
233 h <- openFile filename ReadMode
234 filesize' <- hFileSize h
235 let filesize = fromIntegral filesize'
236 arr <- newArray_ (0,filesize-1)
237 count <- hGetArray h arr filesize
238 when (count /= filesize)
239 (error ("Binary.readBinMem: only read " ++ show count ++ " bytes"))
241 arr_r <- newIORef arr
242 ix_r <- newFastMutInt
243 writeFastMutInt ix_r 0
244 sz_r <- newFastMutInt
245 writeFastMutInt sz_r filesize
246 return (BinMem initReadState ix_r sz_r arr_r)
248 -- expand the size of the array to include a specified offset
249 expandBin :: BinHandle -> Int -> IO ()
250 expandBin (BinMem _ ix_r sz_r arr_r) off = do
251 sz <- readFastMutInt sz_r
252 let sz' = head (dropWhile (<= off) (iterate (* 2) sz))
253 arr <- readIORef arr_r
254 arr' <- newArray_ (0,sz'-1)
255 sequence_ [ unsafeRead arr i >>= unsafeWrite arr' i
256 | i <- [ 0 .. sz-1 ] ]
257 writeFastMutInt sz_r sz'
258 writeIORef arr_r arr'
259 hPutStrLn stderr ("expanding to size: " ++ show sz')
261 expandBin (BinIO _ _ _) _ = return ()
262 -- no need to expand a file, we'll assume they expand by themselves.
264 -- -----------------------------------------------------------------------------
265 -- Low-level reading/writing of bytes
267 putWord8 :: BinHandle -> Word8 -> IO ()
268 putWord8 h@(BinMem _ ix_r sz_r arr_r) w = do
269 ix <- readFastMutInt ix_r
270 sz <- readFastMutInt sz_r
271 -- double the size of the array if it overflows
273 then do expandBin h ix
275 else do arr <- readIORef arr_r
277 writeFastMutInt ix_r (ix+1)
279 putWord8 (BinIO _ ix_r h) w = do
280 ix <- readFastMutInt ix_r
281 hPutChar h (chr (fromIntegral w)) -- XXX not really correct
282 writeFastMutInt ix_r (ix+1)
285 getWord8 :: BinHandle -> IO Word8
286 getWord8 (BinMem _ ix_r sz_r arr_r) = do
287 ix <- readFastMutInt ix_r
288 sz <- readFastMutInt sz_r
290 throw (mkIOError eofErrorType "Data.Binary.getWord8" Nothing Nothing)
291 arr <- readIORef arr_r
292 w <- unsafeRead arr ix
293 writeFastMutInt ix_r (ix+1)
295 getWord8 (BinIO _ ix_r h) = do
296 ix <- readFastMutInt ix_r
298 writeFastMutInt ix_r (ix+1)
299 return (fromIntegral (ord c)) -- XXX not really correct
301 putByte :: BinHandle -> Word8 -> IO ()
302 putByte bh w = put_ bh w
304 getByte :: BinHandle -> IO Word8
307 -- -----------------------------------------------------------------------------
308 -- Primitve Word writes
310 instance Binary Word8 where
314 instance Binary Word16 where
315 put_ h w = do -- XXX too slow.. inline putWord8?
316 putByte h (fromIntegral (w `shiftR` 8))
317 putByte h (fromIntegral (w .&. 0xff))
321 return ((fromIntegral w1 `shiftL` 8) .|. fromIntegral w2)
324 instance Binary Word32 where
326 putByte h (fromIntegral (w `shiftR` 24))
327 putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
328 putByte h (fromIntegral ((w `shiftR` 8) .&. 0xff))
329 putByte h (fromIntegral (w .&. 0xff))
335 return ((fromIntegral w1 `shiftL` 24) .|.
336 (fromIntegral w2 `shiftL` 16) .|.
337 (fromIntegral w3 `shiftL` 8) .|.
341 instance Binary Word64 where
343 putByte h (fromIntegral (w `shiftR` 56))
344 putByte h (fromIntegral ((w `shiftR` 48) .&. 0xff))
345 putByte h (fromIntegral ((w `shiftR` 40) .&. 0xff))
346 putByte h (fromIntegral ((w `shiftR` 32) .&. 0xff))
347 putByte h (fromIntegral ((w `shiftR` 24) .&. 0xff))
348 putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
349 putByte h (fromIntegral ((w `shiftR` 8) .&. 0xff))
350 putByte h (fromIntegral (w .&. 0xff))
360 return ((fromIntegral w1 `shiftL` 56) .|.
361 (fromIntegral w2 `shiftL` 48) .|.
362 (fromIntegral w3 `shiftL` 40) .|.
363 (fromIntegral w4 `shiftL` 32) .|.
364 (fromIntegral w5 `shiftL` 24) .|.
365 (fromIntegral w6 `shiftL` 16) .|.
366 (fromIntegral w7 `shiftL` 8) .|.
369 -- -----------------------------------------------------------------------------
370 -- Primitve Int writes
372 instance Binary Int8 where
373 put_ h w = put_ h (fromIntegral w :: Word8)
374 get h = do w <- get h; return (fromIntegral (w::Word8))
376 instance Binary Int16 where
377 put_ h w = put_ h (fromIntegral w :: Word16)
378 get h = do w <- get h; return (fromIntegral (w::Word16))
380 instance Binary Int32 where
381 put_ h w = put_ h (fromIntegral w :: Word32)
382 get h = do w <- get h; return (fromIntegral (w::Word32))
384 instance Binary Int64 where
385 put_ h w = put_ h (fromIntegral w :: Word64)
386 get h = do w <- get h; return (fromIntegral (w::Word64))
388 -- -----------------------------------------------------------------------------
389 -- Instances for standard types
391 instance Binary () where
392 put_ bh () = return ()
394 -- getF bh p = case getBitsF bh 0 p of (_,b) -> ((),b)
396 instance Binary Bool where
397 put_ bh b = putByte bh (fromIntegral (fromEnum b))
398 get bh = do x <- getWord8 bh; return (toEnum (fromIntegral x))
399 -- getF bh p = case getBitsF bh 1 p of (x,b) -> (toEnum x,b)
401 instance Binary Char where
402 put_ bh c = put_ bh (fromIntegral (ord c) :: Word32)
403 get bh = do x <- get bh; return (chr (fromIntegral (x :: Word32)))
404 -- getF bh p = case getBitsF bh 8 p of (x,b) -> (toEnum x,b)
406 instance Binary Int where
407 #if SIZEOF_HSINT == 4
408 put_ bh i = put_ bh (fromIntegral i :: Int32)
411 return (fromIntegral (x :: Int32))
412 #elif SIZEOF_HSINT == 8
413 put_ bh i = put_ bh (fromIntegral i :: Int64)
416 return (fromIntegral (x :: Int64))
418 #error "unsupported sizeof(HsInt)"
420 -- getF bh = getBitsF bh 32
422 instance Binary a => Binary [a] where
423 put_ bh [] = putByte bh 0
424 put_ bh (x:xs) = do putByte bh 1; put_ bh x; put_ bh xs
425 get bh = do h <- getWord8 bh
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 #ifdef __GLASGOW_HASKELL__
470 instance Binary Integer where
471 put_ bh (S# i#) = do putByte bh 0; put_ bh (I# i#)
472 put_ bh (J# s# a#) = do
475 let sz# = sizeofByteArray# a# -- in *bytes*
476 put_ bh (I# sz#) -- in *bytes*
477 putByteArray bh a# sz#
482 0 -> do (I# i#) <- get bh
484 _ -> do (I# s#) <- get bh
486 (BA a#) <- getByteArray bh sz
489 putByteArray :: BinHandle -> ByteArray# -> Int# -> IO ()
490 putByteArray bh a s# = loop 0#
492 | n# ==# s# = return ()
494 putByte bh (indexByteArray a n#)
497 getByteArray :: BinHandle -> Int -> IO ByteArray
498 getByteArray bh (I# sz) = do
499 (MBA arr) <- newByteArray sz
501 | n ==# sz = return ()
504 writeByteArray arr n w
510 data ByteArray = BA ByteArray#
511 data MBA = MBA (MutableByteArray# RealWorld)
513 newByteArray :: Int# -> IO MBA
514 newByteArray sz = IO $ \s ->
515 case newByteArray# sz s of { (# s, arr #) ->
518 freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray
519 freezeByteArray arr = IO $ \s ->
520 case unsafeFreezeByteArray# arr s of { (# s, arr #) ->
523 writeByteArray :: MutableByteArray# RealWorld -> Int# -> Word8 -> IO ()
525 #if __GLASGOW_HASKELL__ < 503
526 writeByteArray arr i w8 = IO $ \s ->
527 case word8ToWord w8 of { W# w# ->
528 case writeCharArray# arr i (chr# (word2Int# w#)) s of { s ->
531 writeByteArray arr i (W8# w) = IO $ \s ->
532 case writeWord8Array# arr i w s of { s ->
536 #if __GLASGOW_HASKELL__ < 503
537 indexByteArray a# n# = fromIntegral (I# (ord# (indexCharArray# a# n#)))
539 indexByteArray a# n# = W8# (indexWord8Array# a# n#)
542 instance (Integral a, Binary a) => Binary (Ratio a) where
543 put_ bh (a :% b) = do put_ bh a; put_ bh b
544 get bh = do a <- get bh; b <- get bh; return (a :% b)
547 instance Binary (Bin a) where
548 put_ bh (BinPtr i) = put_ bh i
549 get bh = do i <- get bh; return (BinPtr i)
551 -- -----------------------------------------------------------------------------
552 -- unboxed mutable Ints
554 #ifdef __GLASGOW_HASKELL__
555 data FastMutInt = FastMutInt (MutableByteArray# RealWorld)
557 newFastMutInt = IO $ \s ->
558 case newByteArray# size s of { (# s, arr #) ->
559 (# s, FastMutInt arr #) }
560 where I# size = SIZEOF_HSWORD
562 readFastMutInt (FastMutInt arr) = IO $ \s ->
563 case readIntArray# arr 0# s of { (# s, i #) ->
566 writeFastMutInt (FastMutInt arr) (I# i) = IO $ \s ->
567 case writeIntArray# arr 0# i s of { s ->
571 -- -----------------------------------------------------------------------------
572 -- Lazy reading/writing
574 lazyPut :: Binary a => BinHandle -> a -> IO ()
576 -- output the obj with a ptr to skip over it:
578 put_ bh pre_a -- save a slot for the ptr
579 put_ bh a -- dump the object
580 q <- tellBin bh -- q = ptr to after object
581 putAt bh pre_a q -- fill in slot before a with ptr to q
582 seekBin bh q -- finally carry on writing at q
584 lazyGet :: Binary a => BinHandle -> IO a
586 p <- get bh -- a BinPtr
588 a <- unsafeInterleaveIO (getAt bh p_a)
589 seekBin bh p -- skip over the object for now
592 -- -----------------------------------------------------------------------------
595 type BinHandleState =
598 IORef (UniqFM (Int,FastString)),
599 Array Int FastString)
601 initReadState :: BinHandleState
602 initReadState = (undef, undef, undef, undef)
604 newWriteState :: Module -> IO BinHandleState
607 out_r <- newIORef emptyUFM
608 return (m,j_r,out_r,undef)
610 undef = error "Binary.BinHandleState"
612 -- -----------------------------------------------------------------------------
613 -- FastString binary interface
615 getBinFileWithDict :: Binary a => FilePath -> IO a
616 getBinFileWithDict file_path = do
617 bh <- Binary.readBinMem file_path
618 dict_p <- Binary.get bh -- get the dictionary ptr
621 dict <- getDictionary bh
623 let (mod, j_r, out_r, _) = state bh
624 get bh{ state = (mod,j_r,out_r,dict) }
626 initBinMemSize = (1024*1024) :: Int
628 putBinFileWithDict :: Binary a => FilePath -> Module -> a -> IO ()
629 putBinFileWithDict file_path mod a = do
630 bh <- openBinMem initBinMemSize mod
632 put_ bh p -- placeholder for ptr to dictionary
634 let (_, j_r, fm_r, _) = state bh
638 putAt bh p dict_p -- fill in the placeholder
639 seekBin bh dict_p -- seek back to the end of the file
640 putDictionary bh j (constructDictionary j fm)
641 writeBinMem bh file_path
643 type Dictionary = Array Int FastString
644 -- should be 0-indexed
646 putDictionary :: BinHandle -> Int -> Dictionary -> IO ()
647 putDictionary bh sz dict = do
649 mapM_ (putFS bh) (elems dict)
651 getDictionary :: BinHandle -> IO Dictionary
652 getDictionary bh = do
654 elems <- sequence (take sz (repeat (getFS bh)))
655 return (listArray (0,sz-1) elems)
657 constructDictionary :: Int -> UniqFM (Int,FastString) -> Dictionary
658 constructDictionary j fm = array (0,j-1) (eltsUFM fm)
660 putFS bh (FastString id l ba) = do
663 putFS bh s = error ("Binary.put_(FastString): " ++ unpackFS s)
664 -- Note: the length of the FastString is *not* the same as
665 -- the size of the ByteArray: the latter is rounded up to a
666 -- multiple of the word size.
670 (BA ba) <- getByteArray bh (I# l)
671 return (mkFastSubStringBA# ba 0# l)
672 -- XXX ToDo: one too many copies here
674 instance Binary FastString where
675 put_ bh f@(FastString id l ba) =
676 case getUserData bh of { (_, j_r, out_r, dict) -> do
677 out <- readIORef out_r
678 let uniq = getUnique f
679 case lookupUFM out uniq of
680 Just (j,f) -> put_ bh j
685 writeIORef out_r (addToUFM out uniq (j,f))
687 put_ bh s = error ("Binary.put_(FastString): " ++ show (unpackFS s))
691 case getUserData bh of (_, _, _, arr) -> return (arr ! j)