blob: 2ff25005c6aab128311cf147b2fe0fcfeb3e4fa3 (
plain) (
tree)
|
|
{-# LANGUAGE MagicHash, UnboxedTuples, CPP #-}
-- |
-- Module : Data.Primitive.Addr
-- Copyright : (c) Roman Leshchinskiy 2009-2012
-- License : BSD-style
--
-- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au>
-- Portability : non-portable
--
-- Primitive operations on machine addresses
--
module Data.Primitive.Addr (
-- * Types
Addr(..),
-- * Address arithmetic
nullAddr, plusAddr, minusAddr, remAddr,
-- * Element access
indexOffAddr, readOffAddr, writeOffAddr,
-- * Block operations
copyAddr,
#if __GLASGOW_HASKELL__ >= 708
copyAddrToByteArray,
#endif
moveAddr, setAddr,
-- * Conversion
addrToInt
) where
import Control.Monad.Primitive
import Data.Primitive.Types
#if __GLASGOW_HASKELL__ >= 708
import Data.Primitive.ByteArray
#endif
import GHC.Base ( Int(..) )
import GHC.Prim
import GHC.Ptr
import Foreign.Marshal.Utils
-- | The null address
nullAddr :: Addr
nullAddr = Addr nullAddr#
infixl 6 `plusAddr`, `minusAddr`
infixl 7 `remAddr`
-- | Offset an address by the given number of bytes
plusAddr :: Addr -> Int -> Addr
plusAddr (Addr a#) (I# i#) = Addr (plusAddr# a# i#)
-- | Distance in bytes between two addresses. The result is only valid if the
-- difference fits in an 'Int'.
minusAddr :: Addr -> Addr -> Int
minusAddr (Addr a#) (Addr b#) = I# (minusAddr# a# b#)
-- | The remainder of the address and the integer.
remAddr :: Addr -> Int -> Int
remAddr (Addr a#) (I# i#) = I# (remAddr# a# i#)
-- | Read a value from a memory position given by an address and an offset.
-- The memory block the address refers to must be immutable. The offset is in
-- elements of type @a@ rather than in bytes.
indexOffAddr :: Prim a => Addr -> Int -> a
{-# INLINE indexOffAddr #-}
indexOffAddr (Addr addr#) (I# i#) = indexOffAddr# addr# i#
-- | Read a value from a memory position given by an address and an offset.
-- The offset is in elements of type @a@ rather than in bytes.
readOffAddr :: (Prim a, PrimMonad m) => Addr -> Int -> m a
{-# INLINE readOffAddr #-}
readOffAddr (Addr addr#) (I# i#) = primitive (readOffAddr# addr# i#)
-- | Write a value to a memory position given by an address and an offset.
-- The offset is in elements of type @a@ rather than in bytes.
writeOffAddr :: (Prim a, PrimMonad m) => Addr -> Int -> a -> m ()
{-# INLINE writeOffAddr #-}
writeOffAddr (Addr addr#) (I# i#) x = primitive_ (writeOffAddr# addr# i# x)
-- | Copy the given number of bytes from the second 'Addr' to the first. The
-- areas may not overlap.
copyAddr :: PrimMonad m => Addr -- ^ destination address
-> Addr -- ^ source address
-> Int -- ^ number of bytes
-> m ()
{-# INLINE copyAddr #-}
copyAddr (Addr dst#) (Addr src#) n
= unsafePrimToPrim $ copyBytes (Ptr dst#) (Ptr src#) n
#if __GLASGOW_HASKELL__ >= 708
-- | Copy the given number of bytes from the 'Addr' to the 'MutableByteArray'.
-- The areas may not overlap. This function is only available when compiling
-- with GHC 7.8 or newer.
--
-- @since 0.6.4.0
copyAddrToByteArray :: PrimMonad m
=> MutableByteArray (PrimState m) -- ^ destination
-> Int -- ^ offset into the destination array
-> Addr -- ^ source
-> Int -- ^ number of bytes to copy
-> m ()
{-# INLINE copyAddrToByteArray #-}
copyAddrToByteArray (MutableByteArray marr) (I# off) (Addr addr) (I# len) =
primitive_ $ copyAddrToByteArray# addr marr off len
#endif
-- | Copy the given number of bytes from the second 'Addr' to the first. The
-- areas may overlap.
moveAddr :: PrimMonad m => Addr -- ^ destination address
-> Addr -- ^ source address
-> Int -- ^ number of bytes
-> m ()
{-# INLINE moveAddr #-}
moveAddr (Addr dst#) (Addr src#) n
= unsafePrimToPrim $ moveBytes (Ptr dst#) (Ptr src#) n
-- | Fill a memory block of with the given value. The length is in
-- elements of type @a@ rather than in bytes.
setAddr :: (Prim a, PrimMonad m) => Addr -> Int -> a -> m ()
{-# INLINE setAddr #-}
setAddr (Addr addr#) (I# n#) x = primitive_ (setOffAddr# addr# 0# n# x)
-- | Convert an 'Addr' to an 'Int'.
addrToInt :: Addr -> Int
{-# INLINE addrToInt #-}
addrToInt (Addr addr#) = I# (addr2Int# addr#)
|