PageRenderTime 131ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/ghc-7.0.4/compiler/utils/Binary.hs

http://picorec.googlecode.com/
Haskell | 727 lines | 500 code | 112 blank | 115 comment | 14 complexity | 3c06589be1ed78af6c9b987d1419572e MD5 | raw file
Possible License(s): BSD-3-Clause, BSD-2-Clause
  1. {-# OPTIONS -cpp #-}
  2. {-# OPTIONS_GHC -O -funbox-strict-fields #-}
  3. -- We always optimise this, otherwise performance of a non-optimised
  4. -- compiler is severely affected
  5. --
  6. -- (c) The University of Glasgow 2002-2006
  7. --
  8. -- Binary I/O library, with special tweaks for GHC
  9. --
  10. -- Based on the nhc98 Binary library, which is copyright
  11. -- (c) Malcolm Wallace and Colin Runciman, University of York, 1998.
  12. -- Under the terms of the license for that software, we must tell you
  13. -- where you can obtain the original version of the Binary library, namely
  14. -- http://www.cs.york.ac.uk/fp/nhc98/
  15. module Binary
  16. ( {-type-} Bin,
  17. {-class-} Binary(..),
  18. {-type-} BinHandle,
  19. openBinIO, openBinIO_,
  20. openBinMem,
  21. -- closeBin,
  22. seekBin,
  23. seekBy,
  24. tellBin,
  25. castBin,
  26. writeBinMem,
  27. readBinMem,
  28. fingerprintBinMem,
  29. isEOFBin,
  30. putAt, getAt,
  31. -- for writing instances:
  32. putByte,
  33. getByte,
  34. -- lazy Bin I/O
  35. lazyGet,
  36. lazyPut,
  37. #ifdef __GLASGOW_HASKELL__
  38. -- GHC only:
  39. ByteArray(..),
  40. getByteArray,
  41. putByteArray,
  42. #endif
  43. UserData(..), getUserData, setUserData,
  44. newReadState, newWriteState,
  45. putDictionary, getDictionary, putFS,
  46. ) where
  47. #include "HsVersions.h"
  48. -- The *host* architecture version:
  49. #include "../includes/MachDeps.h"
  50. import {-# SOURCE #-} Name (Name)
  51. import FastString
  52. import Panic
  53. import UniqFM
  54. import FastMutInt
  55. import Fingerprint
  56. import BasicTypes
  57. import Foreign
  58. import Data.Array
  59. import Data.IORef
  60. import Data.Char ( ord, chr )
  61. import Data.Typeable
  62. import Control.Monad ( when )
  63. import System.IO as IO
  64. import System.IO.Unsafe ( unsafeInterleaveIO )
  65. import System.IO.Error ( mkIOError, eofErrorType )
  66. import GHC.Real ( Ratio(..) )
  67. import GHC.Exts
  68. import GHC.Word ( Word8(..) )
  69. #if __GLASGOW_HASKELL__ >= 611
  70. import GHC.IO ( IO(..) )
  71. #else
  72. import GHC.IOBase ( IO(..) )
  73. #endif
  74. type BinArray = ForeignPtr Word8
  75. ---------------------------------------------------------------
  76. -- BinHandle
  77. ---------------------------------------------------------------
  78. data BinHandle
  79. = BinMem { -- binary data stored in an unboxed array
  80. bh_usr :: UserData, -- sigh, need parameterized modules :-)
  81. _off_r :: !FastMutInt, -- the current offset
  82. _sz_r :: !FastMutInt, -- size of the array (cached)
  83. _arr_r :: !(IORef BinArray) -- the array (bounds: (0,size-1))
  84. }
  85. -- XXX: should really store a "high water mark" for dumping out
  86. -- the binary data to a file.
  87. | BinIO { -- binary data stored in a file
  88. bh_usr :: UserData,
  89. _off_r :: !FastMutInt, -- the current offset (cached)
  90. _hdl :: !IO.Handle -- the file handle (must be seekable)
  91. }
  92. -- cache the file ptr in BinIO; using hTell is too expensive
  93. -- to call repeatedly. If anyone else is modifying this Handle
  94. -- at the same time, we'll be screwed.
  95. getUserData :: BinHandle -> UserData
  96. getUserData bh = bh_usr bh
  97. setUserData :: BinHandle -> UserData -> BinHandle
  98. setUserData bh us = bh { bh_usr = us }
  99. ---------------------------------------------------------------
  100. -- Bin
  101. ---------------------------------------------------------------
  102. newtype Bin a = BinPtr Int
  103. deriving (Eq, Ord, Show, Bounded)
  104. castBin :: Bin a -> Bin b
  105. castBin (BinPtr i) = BinPtr i
  106. ---------------------------------------------------------------
  107. -- class Binary
  108. ---------------------------------------------------------------
  109. class Binary a where
  110. put_ :: BinHandle -> a -> IO ()
  111. put :: BinHandle -> a -> IO (Bin a)
  112. get :: BinHandle -> IO a
  113. -- define one of put_, put. Use of put_ is recommended because it
  114. -- is more likely that tail-calls can kick in, and we rarely need the
  115. -- position return value.
  116. put_ bh a = do _ <- put bh a; return ()
  117. put bh a = do p <- tellBin bh; put_ bh a; return p
  118. putAt :: Binary a => BinHandle -> Bin a -> a -> IO ()
  119. putAt bh p x = do seekBin bh p; put_ bh x; return ()
  120. getAt :: Binary a => BinHandle -> Bin a -> IO a
  121. getAt bh p = do seekBin bh p; get bh
  122. openBinIO_ :: IO.Handle -> IO BinHandle
  123. openBinIO_ h = openBinIO h
  124. openBinIO :: IO.Handle -> IO BinHandle
  125. openBinIO h = do
  126. r <- newFastMutInt
  127. writeFastMutInt r 0
  128. return (BinIO noUserData r h)
  129. openBinMem :: Int -> IO BinHandle
  130. openBinMem size
  131. | size <= 0 = error "Data.Binary.openBinMem: size must be >= 0"
  132. | otherwise = do
  133. arr <- mallocForeignPtrBytes size
  134. arr_r <- newIORef arr
  135. ix_r <- newFastMutInt
  136. writeFastMutInt ix_r 0
  137. sz_r <- newFastMutInt
  138. writeFastMutInt sz_r size
  139. return (BinMem noUserData ix_r sz_r arr_r)
  140. tellBin :: BinHandle -> IO (Bin a)
  141. tellBin (BinIO _ r _) = do ix <- readFastMutInt r; return (BinPtr ix)
  142. tellBin (BinMem _ r _ _) = do ix <- readFastMutInt r; return (BinPtr ix)
  143. seekBin :: BinHandle -> Bin a -> IO ()
  144. seekBin (BinIO _ ix_r h) (BinPtr p) = do
  145. writeFastMutInt ix_r p
  146. hSeek h AbsoluteSeek (fromIntegral p)
  147. seekBin h@(BinMem _ ix_r sz_r _) (BinPtr p) = do
  148. sz <- readFastMutInt sz_r
  149. if (p >= sz)
  150. then do expandBin h p; writeFastMutInt ix_r p
  151. else writeFastMutInt ix_r p
  152. seekBy :: BinHandle -> Int -> IO ()
  153. seekBy (BinIO _ ix_r h) off = do
  154. ix <- readFastMutInt ix_r
  155. let ix' = ix + off
  156. writeFastMutInt ix_r ix'
  157. hSeek h AbsoluteSeek (fromIntegral ix')
  158. seekBy h@(BinMem _ ix_r sz_r _) off = do
  159. sz <- readFastMutInt sz_r
  160. ix <- readFastMutInt ix_r
  161. let ix' = ix + off
  162. if (ix' >= sz)
  163. then do expandBin h ix'; writeFastMutInt ix_r ix'
  164. else writeFastMutInt ix_r ix'
  165. isEOFBin :: BinHandle -> IO Bool
  166. isEOFBin (BinMem _ ix_r sz_r _) = do
  167. ix <- readFastMutInt ix_r
  168. sz <- readFastMutInt sz_r
  169. return (ix >= sz)
  170. isEOFBin (BinIO _ _ h) = hIsEOF h
  171. writeBinMem :: BinHandle -> FilePath -> IO ()
  172. writeBinMem (BinIO _ _ _) _ = error "Data.Binary.writeBinMem: not a memory handle"
  173. writeBinMem (BinMem _ ix_r _ arr_r) fn = do
  174. h <- openBinaryFile fn WriteMode
  175. arr <- readIORef arr_r
  176. ix <- readFastMutInt ix_r
  177. withForeignPtr arr $ \p -> hPutBuf h p ix
  178. hClose h
  179. readBinMem :: FilePath -> IO BinHandle
  180. -- Return a BinHandle with a totally undefined State
  181. readBinMem filename = do
  182. h <- openBinaryFile filename ReadMode
  183. filesize' <- hFileSize h
  184. let filesize = fromIntegral filesize'
  185. arr <- mallocForeignPtrBytes (filesize*2)
  186. count <- withForeignPtr arr $ \p -> hGetBuf h p filesize
  187. when (count /= filesize) $
  188. error ("Binary.readBinMem: only read " ++ show count ++ " bytes")
  189. hClose h
  190. arr_r <- newIORef arr
  191. ix_r <- newFastMutInt
  192. writeFastMutInt ix_r 0
  193. sz_r <- newFastMutInt
  194. writeFastMutInt sz_r filesize
  195. return (BinMem noUserData ix_r sz_r arr_r)
  196. fingerprintBinMem :: BinHandle -> IO Fingerprint
  197. fingerprintBinMem (BinIO _ _ _) = error "Binary.md5BinMem: not a memory handle"
  198. fingerprintBinMem (BinMem _ ix_r _ arr_r) = do
  199. arr <- readIORef arr_r
  200. ix <- readFastMutInt ix_r
  201. withForeignPtr arr $ \p -> fingerprintData p ix
  202. -- expand the size of the array to include a specified offset
  203. expandBin :: BinHandle -> Int -> IO ()
  204. expandBin (BinMem _ _ sz_r arr_r) off = do
  205. sz <- readFastMutInt sz_r
  206. let sz' = head (dropWhile (<= off) (iterate (* 2) sz))
  207. arr <- readIORef arr_r
  208. arr' <- mallocForeignPtrBytes sz'
  209. withForeignPtr arr $ \old ->
  210. withForeignPtr arr' $ \new ->
  211. copyBytes new old sz
  212. writeFastMutInt sz_r sz'
  213. writeIORef arr_r arr'
  214. when False $ -- disabled
  215. hPutStrLn stderr ("Binary: expanding to size: " ++ show sz')
  216. return ()
  217. expandBin (BinIO _ _ _) _ = return ()
  218. -- no need to expand a file, we'll assume they expand by themselves.
  219. -- -----------------------------------------------------------------------------
  220. -- Low-level reading/writing of bytes
  221. putWord8 :: BinHandle -> Word8 -> IO ()
  222. putWord8 h@(BinMem _ ix_r sz_r arr_r) w = do
  223. ix <- readFastMutInt ix_r
  224. sz <- readFastMutInt sz_r
  225. -- double the size of the array if it overflows
  226. if (ix >= sz)
  227. then do expandBin h ix
  228. putWord8 h w
  229. else do arr <- readIORef arr_r
  230. withForeignPtr arr $ \p -> pokeByteOff p ix w
  231. writeFastMutInt ix_r (ix+1)
  232. return ()
  233. putWord8 (BinIO _ ix_r h) w = do
  234. ix <- readFastMutInt ix_r
  235. hPutChar h (chr (fromIntegral w)) -- XXX not really correct
  236. writeFastMutInt ix_r (ix+1)
  237. return ()
  238. getWord8 :: BinHandle -> IO Word8
  239. getWord8 (BinMem _ ix_r sz_r arr_r) = do
  240. ix <- readFastMutInt ix_r
  241. sz <- readFastMutInt sz_r
  242. when (ix >= sz) $
  243. ioError (mkIOError eofErrorType "Data.Binary.getWord8" Nothing Nothing)
  244. arr <- readIORef arr_r
  245. w <- withForeignPtr arr $ \p -> peekByteOff p ix
  246. writeFastMutInt ix_r (ix+1)
  247. return w
  248. getWord8 (BinIO _ ix_r h) = do
  249. ix <- readFastMutInt ix_r
  250. c <- hGetChar h
  251. writeFastMutInt ix_r (ix+1)
  252. return $! (fromIntegral (ord c)) -- XXX not really correct
  253. putByte :: BinHandle -> Word8 -> IO ()
  254. putByte bh w = put_ bh w
  255. getByte :: BinHandle -> IO Word8
  256. getByte = getWord8
  257. -- -----------------------------------------------------------------------------
  258. -- Primitve Word writes
  259. instance Binary Word8 where
  260. put_ = putWord8
  261. get = getWord8
  262. instance Binary Word16 where
  263. put_ h w = do -- XXX too slow.. inline putWord8?
  264. putByte h (fromIntegral (w `shiftR` 8))
  265. putByte h (fromIntegral (w .&. 0xff))
  266. get h = do
  267. w1 <- getWord8 h
  268. w2 <- getWord8 h
  269. return $! ((fromIntegral w1 `shiftL` 8) .|. fromIntegral w2)
  270. instance Binary Word32 where
  271. put_ h w = do
  272. putByte h (fromIntegral (w `shiftR` 24))
  273. putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
  274. putByte h (fromIntegral ((w `shiftR` 8) .&. 0xff))
  275. putByte h (fromIntegral (w .&. 0xff))
  276. get h = do
  277. w1 <- getWord8 h
  278. w2 <- getWord8 h
  279. w3 <- getWord8 h
  280. w4 <- getWord8 h
  281. return $! ((fromIntegral w1 `shiftL` 24) .|.
  282. (fromIntegral w2 `shiftL` 16) .|.
  283. (fromIntegral w3 `shiftL` 8) .|.
  284. (fromIntegral w4))
  285. instance Binary Word64 where
  286. put_ h w = do
  287. putByte h (fromIntegral (w `shiftR` 56))
  288. putByte h (fromIntegral ((w `shiftR` 48) .&. 0xff))
  289. putByte h (fromIntegral ((w `shiftR` 40) .&. 0xff))
  290. putByte h (fromIntegral ((w `shiftR` 32) .&. 0xff))
  291. putByte h (fromIntegral ((w `shiftR` 24) .&. 0xff))
  292. putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
  293. putByte h (fromIntegral ((w `shiftR` 8) .&. 0xff))
  294. putByte h (fromIntegral (w .&. 0xff))
  295. get h = do
  296. w1 <- getWord8 h
  297. w2 <- getWord8 h
  298. w3 <- getWord8 h
  299. w4 <- getWord8 h
  300. w5 <- getWord8 h
  301. w6 <- getWord8 h
  302. w7 <- getWord8 h
  303. w8 <- getWord8 h
  304. return $! ((fromIntegral w1 `shiftL` 56) .|.
  305. (fromIntegral w2 `shiftL` 48) .|.
  306. (fromIntegral w3 `shiftL` 40) .|.
  307. (fromIntegral w4 `shiftL` 32) .|.
  308. (fromIntegral w5 `shiftL` 24) .|.
  309. (fromIntegral w6 `shiftL` 16) .|.
  310. (fromIntegral w7 `shiftL` 8) .|.
  311. (fromIntegral w8))
  312. -- -----------------------------------------------------------------------------
  313. -- Primitve Int writes
  314. instance Binary Int8 where
  315. put_ h w = put_ h (fromIntegral w :: Word8)
  316. get h = do w <- get h; return $! (fromIntegral (w::Word8))
  317. instance Binary Int16 where
  318. put_ h w = put_ h (fromIntegral w :: Word16)
  319. get h = do w <- get h; return $! (fromIntegral (w::Word16))
  320. instance Binary Int32 where
  321. put_ h w = put_ h (fromIntegral w :: Word32)
  322. get h = do w <- get h; return $! (fromIntegral (w::Word32))
  323. instance Binary Int64 where
  324. put_ h w = put_ h (fromIntegral w :: Word64)
  325. get h = do w <- get h; return $! (fromIntegral (w::Word64))
  326. -- -----------------------------------------------------------------------------
  327. -- Instances for standard types
  328. instance Binary () where
  329. put_ _ () = return ()
  330. get _ = return ()
  331. instance Binary Bool where
  332. put_ bh b = putByte bh (fromIntegral (fromEnum b))
  333. get bh = do x <- getWord8 bh; return $! (toEnum (fromIntegral x))
  334. instance Binary Char where
  335. put_ bh c = put_ bh (fromIntegral (ord c) :: Word32)
  336. get bh = do x <- get bh; return $! (chr (fromIntegral (x :: Word32)))
  337. instance Binary Int where
  338. put_ bh i = put_ bh (fromIntegral i :: Int64)
  339. get bh = do
  340. x <- get bh
  341. return $! (fromIntegral (x :: Int64))
  342. instance Binary a => Binary [a] where
  343. put_ bh l = do
  344. let len = length l
  345. if (len < 0xff)
  346. then putByte bh (fromIntegral len :: Word8)
  347. else do putByte bh 0xff; put_ bh (fromIntegral len :: Word32)
  348. mapM_ (put_ bh) l
  349. get bh = do
  350. b <- getByte bh
  351. len <- if b == 0xff
  352. then get bh
  353. else return (fromIntegral b :: Word32)
  354. let loop 0 = return []
  355. loop n = do a <- get bh; as <- loop (n-1); return (a:as)
  356. loop len
  357. instance (Binary a, Binary b) => Binary (a,b) where
  358. put_ bh (a,b) = do put_ bh a; put_ bh b
  359. get bh = do a <- get bh
  360. b <- get bh
  361. return (a,b)
  362. instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where
  363. put_ bh (a,b,c) = do put_ bh a; put_ bh b; put_ bh c
  364. get bh = do a <- get bh
  365. b <- get bh
  366. c <- get bh
  367. return (a,b,c)
  368. instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where
  369. put_ bh (a,b,c,d) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d
  370. get bh = do a <- get bh
  371. b <- get bh
  372. c <- get bh
  373. d <- get bh
  374. return (a,b,c,d)
  375. instance Binary a => Binary (Maybe a) where
  376. put_ bh Nothing = putByte bh 0
  377. put_ bh (Just a) = do putByte bh 1; put_ bh a
  378. get bh = do h <- getWord8 bh
  379. case h of
  380. 0 -> return Nothing
  381. _ -> do x <- get bh; return (Just x)
  382. instance (Binary a, Binary b) => Binary (Either a b) where
  383. put_ bh (Left a) = do putByte bh 0; put_ bh a
  384. put_ bh (Right b) = do putByte bh 1; put_ bh b
  385. get bh = do h <- getWord8 bh
  386. case h of
  387. 0 -> do a <- get bh ; return (Left a)
  388. _ -> do b <- get bh ; return (Right b)
  389. #if defined(__GLASGOW_HASKELL__) || 1
  390. --to quote binary-0.3 on this code idea,
  391. --
  392. -- TODO This instance is not architecture portable. GMP stores numbers as
  393. -- arrays of machine sized words, so the byte format is not portable across
  394. -- architectures with different endianess and word size.
  395. --
  396. -- This makes it hard (impossible) to make an equivalent instance
  397. -- with code that is compilable with non-GHC. Do we need any instance
  398. -- Binary Integer, and if so, does it have to be blazing fast? Or can
  399. -- we just change this instance to be portable like the rest of the
  400. -- instances? (binary package has code to steal for that)
  401. --
  402. -- yes, we need Binary Integer and Binary Rational in basicTypes/Literal.lhs
  403. instance Binary Integer where
  404. -- XXX This is hideous
  405. put_ bh i = put_ bh (show i)
  406. get bh = do str <- get bh
  407. case reads str of
  408. [(i, "")] -> return i
  409. _ -> fail ("Binary Integer: got " ++ show str)
  410. {-
  411. put_ bh (S# i#) = do putByte bh 0; put_ bh (I# i#)
  412. put_ bh (J# s# a#) = do
  413. putByte bh 1
  414. put_ bh (I# s#)
  415. let sz# = sizeofByteArray# a# -- in *bytes*
  416. put_ bh (I# sz#) -- in *bytes*
  417. putByteArray bh a# sz#
  418. get bh = do
  419. b <- getByte bh
  420. case b of
  421. 0 -> do (I# i#) <- get bh
  422. return (S# i#)
  423. _ -> do (I# s#) <- get bh
  424. sz <- get bh
  425. (BA a#) <- getByteArray bh sz
  426. return (J# s# a#)
  427. -}
  428. -- As for the rest of this code, even though this module
  429. -- exports it, it doesn't seem to be used anywhere else
  430. -- in GHC!
  431. putByteArray :: BinHandle -> ByteArray# -> Int# -> IO ()
  432. putByteArray bh a s# = loop 0#
  433. where loop n#
  434. | n# ==# s# = return ()
  435. | otherwise = do
  436. putByte bh (indexByteArray a n#)
  437. loop (n# +# 1#)
  438. getByteArray :: BinHandle -> Int -> IO ByteArray
  439. getByteArray bh (I# sz) = do
  440. (MBA arr) <- newByteArray sz
  441. let loop n
  442. | n ==# sz = return ()
  443. | otherwise = do
  444. w <- getByte bh
  445. writeByteArray arr n w
  446. loop (n +# 1#)
  447. loop 0#
  448. freezeByteArray arr
  449. data ByteArray = BA ByteArray#
  450. data MBA = MBA (MutableByteArray# RealWorld)
  451. newByteArray :: Int# -> IO MBA
  452. newByteArray sz = IO $ \s ->
  453. case newByteArray# sz s of { (# s, arr #) ->
  454. (# s, MBA arr #) }
  455. freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray
  456. freezeByteArray arr = IO $ \s ->
  457. case unsafeFreezeByteArray# arr s of { (# s, arr #) ->
  458. (# s, BA arr #) }
  459. writeByteArray :: MutableByteArray# RealWorld -> Int# -> Word8 -> IO ()
  460. writeByteArray arr i (W8# w) = IO $ \s ->
  461. case writeWord8Array# arr i w s of { s ->
  462. (# s, () #) }
  463. indexByteArray :: ByteArray# -> Int# -> Word8
  464. indexByteArray a# n# = W8# (indexWord8Array# a# n#)
  465. instance (Integral a, Binary a) => Binary (Ratio a) where
  466. put_ bh (a :% b) = do put_ bh a; put_ bh b
  467. get bh = do a <- get bh; b <- get bh; return (a :% b)
  468. #endif
  469. instance Binary (Bin a) where
  470. put_ bh (BinPtr i) = put_ bh (fromIntegral i :: Int32)
  471. get bh = do i <- get bh; return (BinPtr (fromIntegral (i :: Int32)))
  472. -- -----------------------------------------------------------------------------
  473. -- Instances for Data.Typeable stuff
  474. instance Binary TyCon where
  475. put_ bh ty_con = do
  476. let s = tyConString ty_con
  477. put_ bh s
  478. get bh = do
  479. s <- get bh
  480. return (mkTyCon s)
  481. instance Binary TypeRep where
  482. put_ bh type_rep = do
  483. let (ty_con, child_type_reps) = splitTyConApp type_rep
  484. put_ bh ty_con
  485. put_ bh child_type_reps
  486. get bh = do
  487. ty_con <- get bh
  488. child_type_reps <- get bh
  489. return (mkTyConApp ty_con child_type_reps)
  490. -- -----------------------------------------------------------------------------
  491. -- Lazy reading/writing
  492. lazyPut :: Binary a => BinHandle -> a -> IO ()
  493. lazyPut bh a = do
  494. -- output the obj with a ptr to skip over it:
  495. pre_a <- tellBin bh
  496. put_ bh pre_a -- save a slot for the ptr
  497. put_ bh a -- dump the object
  498. q <- tellBin bh -- q = ptr to after object
  499. putAt bh pre_a q -- fill in slot before a with ptr to q
  500. seekBin bh q -- finally carry on writing at q
  501. lazyGet :: Binary a => BinHandle -> IO a
  502. lazyGet bh = do
  503. p <- get bh -- a BinPtr
  504. p_a <- tellBin bh
  505. a <- unsafeInterleaveIO (getAt bh p_a)
  506. seekBin bh p -- skip over the object for now
  507. return a
  508. -- -----------------------------------------------------------------------------
  509. -- UserData
  510. -- -----------------------------------------------------------------------------
  511. data UserData =
  512. UserData {
  513. -- for *deserialising* only:
  514. ud_dict :: Dictionary,
  515. ud_symtab :: SymbolTable,
  516. -- for *serialising* only:
  517. ud_put_name :: BinHandle -> Name -> IO (),
  518. ud_put_fs :: BinHandle -> FastString -> IO ()
  519. }
  520. newReadState :: Dictionary -> IO UserData
  521. newReadState dict = do
  522. return UserData { ud_dict = dict,
  523. ud_symtab = undef "symtab",
  524. ud_put_name = undef "put_name",
  525. ud_put_fs = undef "put_fs"
  526. }
  527. newWriteState :: (BinHandle -> Name -> IO ())
  528. -> (BinHandle -> FastString -> IO ())
  529. -> IO UserData
  530. newWriteState put_name put_fs = do
  531. return UserData { ud_dict = undef "dict",
  532. ud_symtab = undef "symtab",
  533. ud_put_name = put_name,
  534. ud_put_fs = put_fs
  535. }
  536. noUserData :: a
  537. noUserData = undef "UserData"
  538. undef :: String -> a
  539. undef s = panic ("Binary.UserData: no " ++ s)
  540. ---------------------------------------------------------
  541. -- The Dictionary
  542. ---------------------------------------------------------
  543. type Dictionary = Array Int FastString -- The dictionary
  544. -- Should be 0-indexed
  545. putDictionary :: BinHandle -> Int -> UniqFM (Int,FastString) -> IO ()
  546. putDictionary bh sz dict = do
  547. put_ bh sz
  548. mapM_ (putFS bh) (elems (array (0,sz-1) (eltsUFM dict)))
  549. getDictionary :: BinHandle -> IO Dictionary
  550. getDictionary bh = do
  551. sz <- get bh
  552. elems <- sequence (take sz (repeat (getFS bh)))
  553. return (listArray (0,sz-1) elems)
  554. ---------------------------------------------------------
  555. -- The Symbol Table
  556. ---------------------------------------------------------
  557. -- On disk, the symbol table is an array of IfaceExtName, when
  558. -- reading it in we turn it into a SymbolTable.
  559. type SymbolTable = Array Int Name
  560. ---------------------------------------------------------
  561. -- Reading and writing FastStrings
  562. ---------------------------------------------------------
  563. putFS :: BinHandle -> FastString -> IO ()
  564. putFS bh (FastString _ l _ buf _) = do
  565. put_ bh l
  566. withForeignPtr buf $ \ptr ->
  567. let
  568. go n | n == l = return ()
  569. | otherwise = do
  570. b <- peekElemOff ptr n
  571. putByte bh b
  572. go (n+1)
  573. in
  574. go 0
  575. {- -- possible faster version, not quite there yet:
  576. getFS bh@BinMem{} = do
  577. (I# l) <- get bh
  578. arr <- readIORef (arr_r bh)
  579. off <- readFastMutInt (off_r bh)
  580. return $! (mkFastSubStringBA# arr off l)
  581. -}
  582. getFS :: BinHandle -> IO FastString
  583. getFS bh = do
  584. l <- get bh
  585. fp <- mallocForeignPtrBytes l
  586. withForeignPtr fp $ \ptr -> do
  587. let
  588. go n | n == l = mkFastStringForeignPtr ptr fp l
  589. | otherwise = do
  590. b <- getByte bh
  591. pokeElemOff ptr n b
  592. go (n+1)
  593. --
  594. go 0
  595. instance Binary FastString where
  596. put_ bh f =
  597. case getUserData bh of
  598. UserData { ud_put_fs = put_fs } -> put_fs bh f
  599. get bh = do
  600. j <- get bh
  601. return $! (ud_dict (getUserData bh) ! (fromIntegral (j :: Word32)))
  602. -- Here to avoid loop
  603. instance Binary Fingerprint where
  604. put_ h (Fingerprint w1 w2) = do put_ h w1; put_ h w2
  605. get h = do w1 <- get h; w2 <- get h; return (Fingerprint w1 w2)
  606. instance Binary FunctionOrData where
  607. put_ bh IsFunction = putByte bh 0
  608. put_ bh IsData = putByte bh 1
  609. get bh = do
  610. h <- getByte bh
  611. case h of
  612. 0 -> return IsFunction
  613. 1 -> return IsData
  614. _ -> panic "Binary FunctionOrData"