hmatrix-mmap-0.0.2: Data/Packed/Vector/MMap.hs
{-# LANGUAGE ScopedTypeVariables #-}
-- | Functions to represent a 'Vector' on disk in efficient, if
-- unportable, ways.
--
-- This module uses memory-mapping, a feature of all modern
-- operating-systems, to mirror the disk contents in memory. There are
-- quite a few advantages to memory-mapping files instead of reading
-- the files traditionally:
--
-- * Speed: memory-mapping is often much faster than traditional
-- reading.
--
-- * Memory efficiency: Memory-mapped files are loaded into RAM
-- on-demand, and easily swapped out. The upside is that the
-- program can work with data-sets larger than the available RAM,
-- as long as they are accessed carefully.
--
-- The caveat to using memory-mapping is that it makes the files
-- specific to the current architecture because of the endianness of
-- the data. For more information, see the description in
-- "System.IO.MMap"
--
-- If you wish to write the contents in a portable fashion, either use
-- the ASCII load and save functions in "Numeric.Container", or use
-- the binary serialization in "Data.Binary".
module Data.Packed.Vector.MMap (
-- * Memory-mapping 'Vector' from disk
unsafeMMapVector,
-- * Writing 'Vector' to disk
-- | These functions write the 'Vector' in a way suitable for
-- reading back with 'unsafeMMapVector'.
hPutVector,
writeVector
) where
import System.IO
import System.IO.MMap
import Foreign.ForeignPtr
import Foreign.Ptr
import Foreign.Storable
import qualified Data.Packed.Development as I
import qualified Data.Packed.Vector as I
import Data.Int
---------------------------
-- Memory-Mapping 'Vector' from disk
-- | Map a file into memory (read-only) as a 'Vector'.
--
-- It is considered unsafe because changes to the underlying file may
-- (or may not) be reflected in the 'Vector', which breaks referential
-- transparency.
unsafeMMapVector :: forall a. Storable a => FilePath -- ^ Path of the file to map
-> Maybe (Int64, Int) -- ^ 'Nothing' to map entire file into memory, otherwise 'Just (fileOffset, elementCount)'
-> IO (I.Vector a)
unsafeMMapVector path range =
do (foreignPtr, offset, size) <- mmapFileForeignPtr path ReadOnly $
case range of
Nothing -> Nothing
Just (start, length) -> Just (start, length * sizeOf (undefined :: a))
return $ I.unsafeFromForeignPtr foreignPtr offset (size `div` sizeOf (undefined :: a))
---------------------------
-- Writing 'Vector' to disk
-- | Write out a vector verbatim into an open file handle.
hPutVector :: forall a. Storable a => Handle -> I.Vector a -> IO ()
hPutVector h v = withForeignPtr fp $ \p -> hPutBuf h (p `plusPtr` offset) sz
where
(fp, offset, n) = I.unsafeToForeignPtr v
eltsize = sizeOf (undefined :: a)
sz = n * eltsize
-- | Write the vector verbatim to a file.
writeVector :: forall a. Storable a => FilePath -> I.Vector a -> IO ()
writeVector fp v = withFile fp WriteMode $ \h -> hPutVector h v