diff options
| author | Krasimir Angelov <kr.angelov@gmail.com> | 2017-09-04 09:55:17 +0200 |
|---|---|---|
| committer | Krasimir Angelov <kr.angelov@gmail.com> | 2017-09-04 09:55:17 +0200 |
| commit | 4fe9f88128515a75f790c353190f340c4179d464 (patch) | |
| tree | 2abd8102f4d2196a00af3018acd2a882ad035696 /src/binary/Data/Binary.hs | |
| parent | bbdbf2bc5d34d75cef032b395e4a5cc35a89066d (diff) | |
move the custom Binary package back to src/runtime/haskell
Diffstat (limited to 'src/binary/Data/Binary.hs')
| -rw-r--r-- | src/binary/Data/Binary.hs | 814 |
1 files changed, 0 insertions, 814 deletions
diff --git a/src/binary/Data/Binary.hs b/src/binary/Data/Binary.hs deleted file mode 100644 index 4b3f06a80..000000000 --- a/src/binary/Data/Binary.hs +++ /dev/null @@ -1,814 +0,0 @@ -{-# LANGUAGE CPP, FlexibleInstances, FlexibleContexts #-} ------------------------------------------------------------------------------ --- | --- Module : Data.Binary --- Copyright : Lennart Kolmodin --- License : BSD3-style (see LICENSE) --- --- Maintainer : Lennart Kolmodin <kolmodin@dtek.chalmers.se> --- Stability : unstable --- Portability : portable to Hugs and GHC. Requires the FFI and some flexible instances --- --- Binary serialisation of Haskell values to and from lazy ByteStrings. --- The Binary library provides methods for encoding Haskell values as --- streams of bytes directly in memory. The resulting @ByteString@ can --- then be written to disk, sent over the network, or futher processed --- (for example, compressed with gzip). --- --- The 'Binary' package is notable in that it provides both pure, and --- high performance serialisation. --- --- Values are always encoded in network order (big endian) form, and --- encoded data should be portable across machine endianess, word size, --- or compiler version. For example, data encoded using the Binary class --- could be written from GHC, and read back in Hugs. --- ------------------------------------------------------------------------------ - -module Data.Binary ( - - -- * The Binary class - Binary(..) - - -- $example - - -- * The Get and Put monads - , Get - , Put - - -- * Useful helpers for writing instances - , putWord8 - , getWord8 - - -- * Binary serialisation - , encode -- :: Binary a => a -> ByteString - , decode -- :: Binary a => ByteString -> a - - -- * IO functions for serialisation - , encodeFile -- :: Binary a => FilePath -> a -> IO () - , decodeFile -- :: Binary a => FilePath -> IO a - - , encodeFile_ -- :: FilePath -> Put -> IO () - , decodeFile_ -- :: FilePath -> Get a -> IO a - --- Lazy put and get --- , lazyPut --- , lazyGet - - , module Data.Word -- useful - - ) where - -#include "MachDeps.h" - -import Data.Word - -import Data.Binary.Put -import Data.Binary.Get -import Data.Binary.IEEE754 ( putFloat64be, getFloat64be) -import Control.Monad -import Control.Exception -import Foreign -import System.IO - -import Data.ByteString.Lazy (ByteString) -import qualified Data.ByteString.Lazy as L - -import Data.Char (chr,ord) -import Data.List (unfoldr) - --- And needed for the instances: -import qualified Data.ByteString as B -import qualified Data.Map as Map -import qualified Data.Set as Set -import qualified Data.IntMap as IntMap -import qualified Data.IntSet as IntSet -import qualified Data.Ratio as R - -import qualified Data.Tree as T - -import Data.Array.Unboxed - --- --- This isn't available in older Hugs or older GHC --- -#if __GLASGOW_HASKELL__ >= 606 -import qualified Data.Sequence as Seq -import qualified Data.Foldable as Fold -#endif - ------------------------------------------------------------------------- - --- | The @Binary@ class provides 'put' and 'get', methods to encode and --- decode a Haskell value to a lazy ByteString. It mirrors the Read and --- Show classes for textual representation of Haskell types, and is --- suitable for serialising Haskell values to disk, over the network. --- --- For parsing and generating simple external binary formats (e.g. C --- structures), Binary may be used, but in general is not suitable --- for complex protocols. Instead use the Put and Get primitives --- directly. --- --- Instances of Binary should satisfy the following property: --- --- > decode . encode == id --- --- That is, the 'get' and 'put' methods should be the inverse of each --- other. A range of instances are provided for basic Haskell types. --- -class Binary t where - -- | Encode a value in the Put monad. - put :: t -> Put - -- | Decode a value in the Get monad - get :: Get t - --- $example --- To serialise a custom type, an instance of Binary for that type is --- required. For example, suppose we have a data structure: --- --- > data Exp = IntE Int --- > | OpE String Exp Exp --- > deriving Show --- --- We can encode values of this type into bytestrings using the --- following instance, which proceeds by recursively breaking down the --- structure to serialise: --- --- > instance Binary Exp where --- > put (IntE i) = do put (0 :: Word8) --- > put i --- > put (OpE s e1 e2) = do put (1 :: Word8) --- > put s --- > put e1 --- > put e2 --- > --- > get = do t <- get :: Get Word8 --- > case t of --- > 0 -> do i <- get --- > return (IntE i) --- > 1 -> do s <- get --- > e1 <- get --- > e2 <- get --- > return (OpE s e1 e2) --- --- Note how we write an initial tag byte to indicate each variant of the --- data type. --- --- We can simplify the writing of 'get' instances using monadic --- combinators: --- --- > get = do tag <- getWord8 --- > case tag of --- > 0 -> liftM IntE get --- > 1 -> liftM3 OpE get get get --- --- The generation of Binary instances has been automated by a script --- using Scrap Your Boilerplate generics. Use the script here: --- <http://darcs.haskell.org/binary/tools/derive/BinaryDerive.hs>. --- --- To derive the instance for a type, load this script into GHCi, and --- bring your type into scope. Your type can then have its Binary --- instances derived as follows: --- --- > $ ghci -fglasgow-exts BinaryDerive.hs --- > *BinaryDerive> :l Example.hs --- > *Main> deriveM (undefined :: Drinks) --- > --- > instance Binary Main.Drinks where --- > put (Beer a) = putWord8 0 >> put a --- > put Coffee = putWord8 1 --- > put Tea = putWord8 2 --- > put EnergyDrink = putWord8 3 --- > put Water = putWord8 4 --- > put Wine = putWord8 5 --- > put Whisky = putWord8 6 --- > get = do --- > tag_ <- getWord8 --- > case tag_ of --- > 0 -> get >>= \a -> return (Beer a) --- > 1 -> return Coffee --- > 2 -> return Tea --- > 3 -> return EnergyDrink --- > 4 -> return Water --- > 5 -> return Wine --- > 6 -> return Whisky --- > --- --- To serialise this to a bytestring, we use 'encode', which packs the --- data structure into a binary format, in a lazy bytestring --- --- > > let e = OpE "*" (IntE 7) (OpE "/" (IntE 4) (IntE 2)) --- > > let v = encode e --- --- Where 'v' is a binary encoded data structure. To reconstruct the --- original data, we use 'decode' --- --- > > decode v :: Exp --- > OpE "*" (IntE 7) (OpE "/" (IntE 4) (IntE 2)) --- --- The lazy ByteString that results from 'encode' can be written to --- disk, and read from disk using Data.ByteString.Lazy IO functions, --- such as hPutStr or writeFile: --- --- > > writeFile "/tmp/exp.txt" (encode e) --- --- And read back with: --- --- > > readFile "/tmp/exp.txt" >>= return . decode :: IO Exp --- > OpE "*" (IntE 7) (OpE "/" (IntE 4) (IntE 2)) --- --- We can also directly serialise a value to and from a Handle, or a file: --- --- > > v <- decodeFile "/tmp/exp.txt" :: IO Exp --- > OpE "*" (IntE 7) (OpE "/" (IntE 4) (IntE 2)) --- --- And write a value to disk --- --- > > encodeFile "/tmp/a.txt" v --- - ------------------------------------------------------------------------- --- Wrappers to run the underlying monad - --- | Encode a value using binary serialisation to a lazy ByteString. --- -encode :: Binary a => a -> ByteString -encode = runPut . put -{-# INLINE encode #-} - --- | Decode a value from a lazy ByteString, reconstructing the original structure. --- -decode :: Binary a => ByteString -> a -decode = runGet get - ------------------------------------------------------------------------- --- Convenience IO operations - --- | Lazily serialise a value to a file --- --- This is just a convenience function, it's defined simply as: --- --- > encodeFile f = B.writeFile f . encode --- --- So for example if you wanted to compress as well, you could use: --- --- > B.writeFile f . compress . encode --- -encodeFile :: Binary a => FilePath -> a -> IO () -encodeFile f v = L.writeFile f (encode v) - -encodeFile_ :: FilePath -> Put -> IO () -encodeFile_ f m = L.writeFile f (runPut m) - --- | Lazily reconstruct a value previously written to a file. --- --- This is just a convenience function, it's defined simply as: --- --- > decodeFile f = return . decode =<< B.readFile f --- --- So for example if you wanted to decompress as well, you could use: --- --- > return . decode . decompress =<< B.readFile f --- -decodeFile :: Binary a => FilePath -> IO a -decodeFile f = bracket (openBinaryFile f ReadMode) hClose $ \h -> do - s <- L.hGetContents h - evaluate $ runGet get s - -decodeFile_ :: FilePath -> Get a -> IO a -decodeFile_ f m = bracket (openBinaryFile f ReadMode) hClose $ \h -> do - s <- L.hGetContents h - evaluate $ runGet m s - --- needs bytestring 0.9.1.x to work - ------------------------------------------------------------------------- --- Lazy put and get - --- lazyPut :: (Binary a) => a -> Put --- lazyPut a = put (encode a) - --- lazyGet :: (Binary a) => Get a --- lazyGet = fmap decode get - ------------------------------------------------------------------------- --- Simple instances - --- The () type need never be written to disk: values of singleton type --- can be reconstructed from the type alone -instance Binary () where - put () = return () - get = return () - --- Bools are encoded as a byte in the range 0 .. 1 -instance Binary Bool where - put = putWord8 . fromIntegral . fromEnum - get = liftM (toEnum . fromIntegral) getWord8 - --- Values of type 'Ordering' are encoded as a byte in the range 0 .. 2 -instance Binary Ordering where - put = putWord8 . fromIntegral . fromEnum - get = liftM (toEnum . fromIntegral) getWord8 - ------------------------------------------------------------------------- --- Words and Ints - --- Words8s are written as bytes -instance Binary Word8 where - put = putWord8 - get = getWord8 - --- Words16s are written as 2 bytes in big-endian (network) order -instance Binary Word16 where - put = putWord16be - get = getWord16be - --- Words32s are written as 4 bytes in big-endian (network) order -instance Binary Word32 where - put = putWord32be - get = getWord32be - --- Words64s are written as 8 bytes in big-endian (network) order -instance Binary Word64 where - put = putWord64be - get = getWord64be - --- Int8s are written as a single byte. -instance Binary Int8 where - put i = put (fromIntegral i :: Word8) - get = liftM fromIntegral (get :: Get Word8) - --- Int16s are written as a 2 bytes in big endian format -instance Binary Int16 where - put i = put (fromIntegral i :: Word16) - get = liftM fromIntegral (get :: Get Word16) - --- Int32s are written as a 4 bytes in big endian format -instance Binary Int32 where - put i = put (fromIntegral i :: Word32) - get = liftM fromIntegral (get :: Get Word32) - --- Int64s are written as a 8 bytes in big endian format -instance Binary Int64 where - put i = put (fromIntegral i :: Word64) - get = liftM fromIntegral (get :: Get Word64) - ------------------------------------------------------------------------- - --- Words are written as sequence of bytes. The last bit of each --- byte indicates whether there are more bytes to be read -instance Binary Word where - put i | i <= 0x7f = do put a - | i <= 0x3fff = do put (a .|. 0x80) - put b - | i <= 0x1fffff = do put (a .|. 0x80) - put (b .|. 0x80) - put c - | i <= 0xfffffff = do put (a .|. 0x80) - put (b .|. 0x80) - put (c .|. 0x80) - put d --- -- #if WORD_SIZE_IN_BITS < 64 - | otherwise = do put (a .|. 0x80) - put (b .|. 0x80) - put (c .|. 0x80) - put (d .|. 0x80) - put e -{- --- Restricted to 32 bits even on 64-bit systems, so that negative --- Ints are written as 5 bytes instead of 10 bytes (TH 2013-02-13) ---#else - | i <= 0x7ffffffff = do put (a .|. 0x80) - put (b .|. 0x80) - put (c .|. 0x80) - put (d .|. 0x80) - put e - | i <= 0x3ffffffffff = do put (a .|. 0x80) - put (b .|. 0x80) - put (c .|. 0x80) - put (d .|. 0x80) - put (e .|. 0x80) - put f - | i <= 0x1ffffffffffff = do put (a .|. 0x80) - put (b .|. 0x80) - put (c .|. 0x80) - put (d .|. 0x80) - put (e .|. 0x80) - put (f .|. 0x80) - put g - | i <= 0xffffffffffffff = do put (a .|. 0x80) - put (b .|. 0x80) - put (c .|. 0x80) - put (d .|. 0x80) - put (e .|. 0x80) - put (f .|. 0x80) - put (g .|. 0x80) - put h - | i <= 0xffffffffffffff = do put (a .|. 0x80) - put (b .|. 0x80) - put (c .|. 0x80) - put (d .|. 0x80) - put (e .|. 0x80) - put (f .|. 0x80) - put (g .|. 0x80) - put h - | i <= 0x7fffffffffffffff = do put (a .|. 0x80) - put (b .|. 0x80) - put (c .|. 0x80) - put (d .|. 0x80) - put (e .|. 0x80) - put (f .|. 0x80) - put (g .|. 0x80) - put (h .|. 0x80) - put j - | otherwise = do put (a .|. 0x80) - put (b .|. 0x80) - put (c .|. 0x80) - put (d .|. 0x80) - put (e .|. 0x80) - put (f .|. 0x80) - put (g .|. 0x80) - put (h .|. 0x80) - put (j .|. 0x80) - put k --- #endif --} - where - a = fromIntegral ( i .&. 0x7f) :: Word8 - b = fromIntegral (shiftR i 7 .&. 0x7f) :: Word8 - c = fromIntegral (shiftR i 14 .&. 0x7f) :: Word8 - d = fromIntegral (shiftR i 21 .&. 0x7f) :: Word8 - e = fromIntegral (shiftR i 28 .&. 0x7f) :: Word8 -{- - f = fromIntegral (shiftR i 35 .&. 0x7f) :: Word8 - g = fromIntegral (shiftR i 42 .&. 0x7f) :: Word8 - h = fromIntegral (shiftR i 49 .&. 0x7f) :: Word8 - j = fromIntegral (shiftR i 56 .&. 0x7f) :: Word8 - k = fromIntegral (shiftR i 63 .&. 0x7f) :: Word8 --} - get = do i <- getWord8 - (if i <= 0x7f - then return (fromIntegral i) - else do n <- get - return $ (n `shiftL` 7) .|. (fromIntegral (i .&. 0x7f))) - --- Int has the same representation as Word -instance Binary Int where - put i = put (fromIntegral i :: Word) - get = liftM toInt32 (get :: Get Word) - where - -- restrict to 32 bits (for PGF portability, TH 2013-02-13) - toInt32 w = fromIntegral (fromIntegral w::Int32)::Int - ------------------------------------------------------------------------- --- --- Portable, and pretty efficient, serialisation of Integer --- - --- Fixed-size type for a subset of Integer -type SmallInt = Int32 - --- Integers are encoded in two ways: if they fit inside a SmallInt, --- they're written as a byte tag, and that value. If the Integer value --- is too large to fit in a SmallInt, it is written as a byte array, --- along with a sign and length field. - -instance Binary Integer where - - {-# INLINE put #-} - put n | n >= lo && n <= hi = do - putWord8 0 - put (fromIntegral n :: SmallInt) -- fast path - where - lo = fromIntegral (minBound :: SmallInt) :: Integer - hi = fromIntegral (maxBound :: SmallInt) :: Integer - - put n = do - putWord8 1 - put sign - put (unroll (abs n)) -- unroll the bytes - where - sign = fromIntegral (signum n) :: Word8 - - {-# INLINE get #-} - get = do - tag <- get :: Get Word8 - case tag of - 0 -> liftM fromIntegral (get :: Get SmallInt) - _ -> do sign <- get - bytes <- get - let v = roll bytes - return $! if sign == (1 :: Word8) then v else - v - --- --- Fold and unfold an Integer to and from a list of its bytes --- -unroll :: Integer -> [Word8] -unroll = unfoldr step - where - step 0 = Nothing - step i = Just (fromIntegral i, i `shiftR` 8) - -roll :: [Word8] -> Integer -roll = foldr unstep 0 - where - unstep b a = a `shiftL` 8 .|. fromIntegral b - -{- - --- --- An efficient, raw serialisation for Integer (GHC only) --- - --- TODO This instance is not architecture portable. GMP stores numbers as --- arrays of machine sized words, so the byte format is not portable across --- architectures with different endianess and word size. - -import Data.ByteString.Base (toForeignPtr,unsafePackAddress, memcpy) -import GHC.Base hiding (ord, chr) -import GHC.Prim -import GHC.Ptr (Ptr(..)) -import GHC.IOBase (IO(..)) - -instance Binary Integer where - put (S# i) = putWord8 0 >> put (I# i) - put (J# s ba) = do - putWord8 1 - put (I# s) - put (BA ba) - - get = do - b <- getWord8 - case b of - 0 -> do (I# i#) <- get - return (S# i#) - _ -> do (I# s#) <- get - (BA a#) <- get - return (J# s# a#) - -instance Binary ByteArray where - - -- Pretty safe. - put (BA ba) = - let sz = sizeofByteArray# ba -- (primitive) in *bytes* - addr = byteArrayContents# ba - bs = unsafePackAddress (I# sz) addr - in put bs -- write as a ByteString. easy, yay! - - -- Pretty scary. Should be quick though - get = do - (fp, off, n@(I# sz)) <- liftM toForeignPtr get -- so decode a ByteString - assert (off == 0) $ return $ unsafePerformIO $ do - (MBA arr) <- newByteArray sz -- and copy it into a ByteArray# - let to = byteArrayContents# (unsafeCoerce# arr) -- urk, is this safe? - withForeignPtr fp $ \from -> memcpy (Ptr to) from (fromIntegral n) - freezeByteArray arr - --- wrapper for ByteArray# -data ByteArray = BA {-# UNPACK #-} !ByteArray# -data MBA = MBA {-# UNPACK #-} !(MutableByteArray# RealWorld) - -newByteArray :: Int# -> IO MBA -newByteArray sz = IO $ \s -> - case newPinnedByteArray# sz s of { (# s', arr #) -> - (# s', MBA arr #) } - -freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray -freezeByteArray arr = IO $ \s -> - case unsafeFreezeByteArray# arr s of { (# s', arr' #) -> - (# s', BA arr' #) } - --} - -instance (Binary a,Integral a) => Binary (R.Ratio a) where - put r = put (R.numerator r) >> put (R.denominator r) - get = liftM2 (R.%) get get - ------------------------------------------------------------------------- - --- Char is serialised as UTF-8 -instance Binary Char where - put a | c <= 0x7f = put (fromIntegral c :: Word8) - | c <= 0x7ff = do put (0xc0 .|. y) - put (0x80 .|. z) - | c <= 0xffff = do put (0xe0 .|. x) - put (0x80 .|. y) - put (0x80 .|. z) - | c <= 0x10ffff = do put (0xf0 .|. w) - put (0x80 .|. x) - put (0x80 .|. y) - put (0x80 .|. z) - | otherwise = error "Not a valid Unicode code point" - where - c = ord a - z, y, x, w :: Word8 - z = fromIntegral (c .&. 0x3f) - y = fromIntegral (shiftR c 6 .&. 0x3f) - x = fromIntegral (shiftR c 12 .&. 0x3f) - w = fromIntegral (shiftR c 18 .&. 0x7) - - get = do - let getByte = liftM (fromIntegral :: Word8 -> Int) get - shiftL6 = flip shiftL 6 :: Int -> Int - w <- getByte - r <- case () of - _ | w < 0x80 -> return w - | w < 0xe0 -> do - x <- liftM (xor 0x80) getByte - return (x .|. shiftL6 (xor 0xc0 w)) - | w < 0xf0 -> do - x <- liftM (xor 0x80) getByte - y <- liftM (xor 0x80) getByte - return (y .|. shiftL6 (x .|. shiftL6 - (xor 0xe0 w))) - | otherwise -> do - x <- liftM (xor 0x80) getByte - y <- liftM (xor 0x80) getByte - z <- liftM (xor 0x80) getByte - return (z .|. shiftL6 (y .|. shiftL6 - (x .|. shiftL6 (xor 0xf0 w)))) - return $! chr r - ------------------------------------------------------------------------- --- Instances for the first few tuples - -instance (Binary a, Binary b) => Binary (a,b) where - put (a,b) = put a >> put b - get = liftM2 (,) get get - -instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where - put (a,b,c) = put a >> put b >> put c - get = liftM3 (,,) get get get - -instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where - put (a,b,c,d) = put a >> put b >> put c >> put d - get = liftM4 (,,,) get get get get - -instance (Binary a, Binary b, Binary c, Binary d, Binary e) => Binary (a,b,c,d,e) where - put (a,b,c,d,e) = put a >> put b >> put c >> put d >> put e - get = liftM5 (,,,,) get get get get get - --- --- and now just recurse: --- - -instance (Binary a, Binary b, Binary c, Binary d, Binary e, Binary f) - => Binary (a,b,c,d,e,f) where - put (a,b,c,d,e,f) = put (a,(b,c,d,e,f)) - get = do (a,(b,c,d,e,f)) <- get ; return (a,b,c,d,e,f) - -instance (Binary a, Binary b, Binary c, Binary d, Binary e, Binary f, Binary g) - => Binary (a,b,c,d,e,f,g) where - put (a,b,c,d,e,f,g) = put (a,(b,c,d,e,f,g)) - get = do (a,(b,c,d,e,f,g)) <- get ; return (a,b,c,d,e,f,g) - -instance (Binary a, Binary b, Binary c, Binary d, Binary e, - Binary f, Binary g, Binary h) - => Binary (a,b,c,d,e,f,g,h) where - put (a,b,c,d,e,f,g,h) = put (a,(b,c,d,e,f,g,h)) - get = do (a,(b,c,d,e,f,g,h)) <- get ; return (a,b,c,d,e,f,g,h) - -instance (Binary a, Binary b, Binary c, Binary d, Binary e, - Binary f, Binary g, Binary h, Binary i) - => Binary (a,b,c,d,e,f,g,h,i) where - put (a,b,c,d,e,f,g,h,i) = put (a,(b,c,d,e,f,g,h,i)) - get = do (a,(b,c,d,e,f,g,h,i)) <- get ; return (a,b,c,d,e,f,g,h,i) - -instance (Binary a, Binary b, Binary c, Binary d, Binary e, - Binary f, Binary g, Binary h, Binary i, Binary j) - => Binary (a,b,c,d,e,f,g,h,i,j) where - put (a,b,c,d,e,f,g,h,i,j) = put (a,(b,c,d,e,f,g,h,i,j)) - get = do (a,(b,c,d,e,f,g,h,i,j)) <- get ; return (a,b,c,d,e,f,g,h,i,j) - ------------------------------------------------------------------------- --- Container types - -instance Binary a => Binary [a] where - put l = put (length l) >> mapM_ put l - get = do n <- get :: Get Int - xs <- replicateM n get - return xs - -instance (Binary a) => Binary (Maybe a) where - put Nothing = putWord8 0 - put (Just x) = putWord8 1 >> put x - get = do - w <- getWord8 - case w of - 0 -> return Nothing - _ -> liftM Just get - -instance (Binary a, Binary b) => Binary (Either a b) where - put (Left a) = putWord8 0 >> put a - put (Right b) = putWord8 1 >> put b - get = do - w <- getWord8 - case w of - 0 -> liftM Left get - _ -> liftM Right get - ------------------------------------------------------------------------- --- ByteStrings (have specially efficient instances) - -instance Binary B.ByteString where - put bs = do put (B.length bs) - putByteString bs - get = get >>= getByteString - --- --- Using old versions of fps, this is a type synonym, and non portable --- --- Requires 'flexible instances' --- -instance Binary ByteString where - put bs = do put (fromIntegral (L.length bs) :: Int) - putLazyByteString bs - get = get >>= getLazyByteString - ------------------------------------------------------------------------- --- Maps and Sets - -instance (Ord a, Binary a) => Binary (Set.Set a) where - put s = put (Set.size s) >> mapM_ put (Set.toAscList s) - get = liftM Set.fromDistinctAscList get - -instance (Ord k, Binary k, Binary e) => Binary (Map.Map k e) where - put m = put (Map.size m) >> mapM_ put (Map.toAscList m) - get = liftM Map.fromDistinctAscList get - -instance Binary IntSet.IntSet where - put s = put (IntSet.size s) >> mapM_ put (IntSet.toAscList s) - get = liftM IntSet.fromDistinctAscList get - -instance (Binary e) => Binary (IntMap.IntMap e) where - put m = put (IntMap.size m) >> mapM_ put (IntMap.toAscList m) - get = liftM IntMap.fromDistinctAscList get - ------------------------------------------------------------------------- --- Queues and Sequences - -#if __GLASGOW_HASKELL__ >= 606 --- --- This is valid Hugs, but you need the most recent Hugs --- - -instance (Binary e) => Binary (Seq.Seq e) where - put s = put (Seq.length s) >> Fold.mapM_ put s - get = do n <- get :: Get Int - rep Seq.empty n get - where rep xs 0 _ = return $! xs - rep xs n g = xs `seq` n `seq` do - x <- g - rep (xs Seq.|> x) (n-1) g - -#endif - ------------------------------------------------------------------------- --- Floating point - --- instance Binary Double where --- put d = put (decodeFloat d) --- get = liftM2 encodeFloat get get - -instance Binary Double where - put = putFloat64be - get = getFloat64be - -instance Binary Float where - put f = put (decodeFloat f) - get = liftM2 encodeFloat get get - ------------------------------------------------------------------------- --- Trees - -instance (Binary e) => Binary (T.Tree e) where - put (T.Node r s) = put r >> put s - get = liftM2 T.Node get get - ------------------------------------------------------------------------- --- Arrays - -instance (Binary i, Ix i, Binary e) => Binary (Array i e) where - put a = do - put (bounds a) - put (rangeSize $ bounds a) -- write the length - mapM_ put (elems a) -- now the elems. - get = do - bs <- get - n <- get -- read the length - xs <- replicateM n get -- now the elems. - return (listArray bs xs) - --- --- The IArray UArray e constraint is non portable. Requires flexible instances --- -instance (Binary i, Ix i, Binary e, IArray UArray e) => Binary (UArray i e) where - put a = do - put (bounds a) - put (rangeSize $ bounds a) -- now write the length - mapM_ put (elems a) - get = do - bs <- get - n <- get - xs <- replicateM n get - return (listArray bs xs) |
