{-# LANGUAGE MagicHash, UnboxedTuples, CPP #-} -- | -- Module : Data.Primitive.Addr -- Copyright : (c) Roman Leshchinskiy 2009-2012 -- License : BSD-style -- -- Maintainer : Roman Leshchinskiy -- 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#)