{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UnliftedFFITypes #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UnboxedTuples #-}
module Data.Primitive.PVar.Internal
( PVar(..)
, newPVar
, newPinnedPVar
, newAlignedPinnedPVar
, rawPVar
, rawPinnedPVar
, rawAlignedPinnedPVar
, rawStorablePVar
, rawAlignedStorablePVar
, unsafeToPtrPVar
, runWithPokedPtr
, peekPrim
, pokePrim
, readPVar
, writePVar
, isPinnedPVar
, sizeOfPVar
, sizeOfPVar#
, alignmentPVar
, alignmentPVar#
, unI#
, atomicModifyIntArray#
, atomicModifyIntPVar
, atomicModifyIntArray_#
, atomicModifyIntPVar_
, isByteArrayPinned#
, isMutableByteArrayPinned#
, sizeOf
, alignment
)
where
import Control.DeepSeq
import Control.Monad.Primitive (MonadPrim, primitive, primitive_,
touch, unsafePrimToPrim)
import Data.Primitive.Types
import qualified Foreign.Storable as S
import GHC.Exts
#if !MIN_VERSION_primitive(0,6,3)
import Data.Primitive (sizeOf, alignment)
#endif
data PVar a s = PVar (MutableByteArray# s)
instance Prim a => S.Storable (PVar a RealWorld) where
sizeOf = sizeOfPVar
{-# INLINE sizeOf #-}
alignment = alignmentPVar
{-# INLINE alignment #-}
peekElemOff (Ptr addr#) (I# i#) = do
a <- primitive (readOffAddr# addr# i#)
newAlignedPinnedPVar a
{-# INLINE peekElemOff #-}
pokeElemOff (Ptr addr#) (I# i#) pvar = do
a <- readPVar pvar
primitive_ (writeOffAddr# addr# i# a)
{-# INLINE pokeElemOff #-}
instance NFData (PVar a s) where
rnf (PVar _) = ()
newPVar :: (MonadPrim s m, Prim a) => a -> m (PVar a s)
newPVar v = do
pvar <- rawPVar
writePVar pvar v
return pvar
{-# INLINE newPVar #-}
rawPVar ::
forall a m s. (MonadPrim s m, Prim a)
=> m (PVar a s)
rawPVar =
primitive $ \s# ->
case newByteArray# (sizeOf# (undefined :: a)) s# of
(# s'#, mba# #) -> (# s'#, PVar mba# #)
{-# INLINE rawPVar #-}
newPinnedPVar :: (MonadPrim s m, Prim a) => a -> m (PVar a s)
newPinnedPVar v = do
pvar <- rawPinnedPVar
writePVar pvar v
return pvar
{-# INLINE newPinnedPVar #-}
rawPinnedPVar ::
forall a m s. (MonadPrim s m, Prim a)
=> m (PVar a s)
rawPinnedPVar =
primitive $ \s# ->
case newPinnedByteArray# (sizeOf# (undefined :: a)) s# of
(# s'#, mba# #) -> (# s'#, PVar mba# #)
{-# INLINE rawPinnedPVar #-}
newAlignedPinnedPVar :: (MonadPrim s m, Prim a) => a -> m (PVar a s)
newAlignedPinnedPVar v = do
pvar <- rawAlignedPinnedPVar
writePVar pvar v
return pvar
{-# INLINE newAlignedPinnedPVar #-}
rawAlignedPinnedPVar ::
forall a m s. (MonadPrim s m, Prim a)
=> m (PVar a s)
rawAlignedPinnedPVar =
let dummy = undefined :: a
in primitive $ \s# ->
case newAlignedPinnedByteArray# (sizeOf# dummy) (alignment# dummy) s# of
(# s'#, mba# #) -> (# s'#, PVar mba# #)
{-# INLINE rawAlignedPinnedPVar #-}
rawStorablePVar ::
forall a m s. (MonadPrim s m, S.Storable a)
=> m (PVar a s)
rawStorablePVar =
case S.sizeOf (undefined :: a) of
I# size# ->
primitive $ \s# ->
case newPinnedByteArray# size# s# of
(# s'#, mba# #) -> (# s'#, PVar mba# #)
{-# INLINE rawStorablePVar #-}
rawAlignedStorablePVar ::
forall a m s. (MonadPrim s m, S.Storable a)
=> m (PVar a s)
rawAlignedStorablePVar =
let dummy = undefined :: a
in case S.sizeOf dummy of
I# size# ->
case S.alignment dummy of
I# align# ->
primitive $ \s# ->
case newAlignedPinnedByteArray# size# align# s# of
(# s'#, mba# #) -> (# s'#, PVar mba# #)
{-# INLINE rawAlignedStorablePVar #-}
unsafeToPtrPVar :: PVar a s -> Ptr a
unsafeToPtrPVar (PVar mba#) = Ptr (byteArrayContents# (unsafeCoerce# mba#))
{-# INLINE unsafeToPtrPVar #-}
runWithPokedPtr ::
(S.Storable a, MonadPrim s m)
=> PVar a s
-> a
-> (PVar a s -> Ptr a -> m b)
-> m b
runWithPokedPtr pvar a f = do
let ptr = unsafeToPtrPVar pvar
pokePrim ptr a
r <- f pvar ptr
touch pvar
return r
{-# INLINE runWithPokedPtr #-}
peekPrim :: (S.Storable a, MonadPrim s m) => Ptr a -> m a
peekPrim = unsafePrimToPrim . S.peek
{-# INLINE peekPrim #-}
pokePrim :: (S.Storable a, MonadPrim s m) => Ptr a -> a -> m ()
pokePrim ptr = unsafePrimToPrim . S.poke ptr
{-# INLINE pokePrim #-}
readPVar :: (MonadPrim s m, Prim a) => PVar a s -> m a
readPVar (PVar mba#) = primitive (readByteArray# mba# 0#)
{-# INLINE readPVar #-}
writePVar :: (MonadPrim s m, Prim a) => PVar a s -> a -> m ()
writePVar (PVar mba#) v = primitive_ (writeByteArray# mba# 0# v)
{-# INLINE writePVar #-}
sizeOfPVar# :: forall a s. Prim a => PVar a s -> Int#
sizeOfPVar# _ = sizeOf# (undefined :: a)
{-# INLINE sizeOfPVar# #-}
alignmentPVar# :: forall a s. Prim a => PVar a s -> Int#
alignmentPVar# _ = alignment# (undefined :: a)
{-# INLINE alignmentPVar# #-}
sizeOfPVar :: Prim a => PVar a s -> Int
sizeOfPVar pvar = I# (sizeOfPVar# pvar)
{-# INLINE sizeOfPVar #-}
alignmentPVar :: Prim a => PVar a s -> Int
alignmentPVar pvar = I# (alignmentPVar# pvar)
{-# INLINE alignmentPVar #-}
unI# :: Int -> Int#
unI# (I# i#) = i#
{-# INLINE unI# #-}
isPinnedPVar :: PVar a s -> Bool
isPinnedPVar (PVar mba#) = isTrue# (isMutableByteArrayPinned# mba#)
{-# INLINE isPinnedPVar #-}
atomicModifyIntArray# ::
MutableByteArray# d
-> Int#
-> (Int# -> (# Int#, b #))
-> State# d
-> (# State# d, b #)
atomicModifyIntArray# mba# i# f s0# =
let go s# o# =
case f o# of
(# n#, artifact #) ->
case casIntArray# mba# i# o# n# s# of
(# s'#, o'# #) ->
case o# ==# o'# of
0# -> go s# o'#
_ -> seq# artifact s'#
in case atomicReadIntArray# mba# i# s0# of
(# s'#, o# #) -> go s'# o#
{-# INLINE atomicModifyIntArray# #-}
atomicModifyIntPVar ::
MonadPrim s m => PVar Int s -> (Int -> (Int, a)) -> m a
atomicModifyIntPVar (PVar mba#) f = primitive (atomicModifyIntArray# mba# 0# g)
where
g i# =
case f (I# i#) of
(I# o#, a) -> (# o#, a #)
{-# INLINE g #-}
{-# INLINE atomicModifyIntPVar #-}
atomicModifyIntArray_# ::
MutableByteArray# d
-> Int#
-> (Int# -> Int#)
-> State# d
-> State# d
atomicModifyIntArray_# mba# i# f s0# =
let go s# o# =
case casIntArray# mba# i# o# (f o#) s# of
(# s'#, o'# #) ->
case o# ==# o'# of
0# -> go s# o'#
_ -> s'#
in case atomicReadIntArray# mba# i# s0# of
(# s'#, o# #) -> go s'# o#
{-# INLINE atomicModifyIntArray_# #-}
atomicModifyIntPVar_ ::
MonadPrim s m => PVar Int s -> (Int -> Int) -> m ()
atomicModifyIntPVar_ (PVar mba#) f =
primitive_ (atomicModifyIntArray_# mba# 0# (\i# -> unI# (f (I# i#))))
{-# INLINE atomicModifyIntPVar_ #-}
# if __GLASGOW_HASKELL__ < 802
foreign import ccall unsafe "pvar.c pvar_is_byte_array_pinned"
isByteArrayPinned# :: ByteArray# -> Int#
foreign import ccall unsafe "pvar.c pvar_is_byte_array_pinned"
isMutableByteArrayPinned# :: MutableByteArray# s -> Int#
#endif