{-# LANGUAGE MagicHash, UnboxedTuples #-}
module Std.Data.PrimIORef
  ( 
    PrimIORef
  , newPrimIORef
  , readPrimIORef
  , writePrimIORef
  , modifyPrimIORef
    
  , Counter
  , newCounter
    
  , atomicAddCounter
  , atomicSubCounter
  , atomicAndCounter
  , atomicNandCounter
  , atomicOrCounter
  , atomicXorCounter
    
  , atomicAddCounter'
  , atomicSubCounter'
  , atomicAndCounter'
  , atomicNandCounter'
  , atomicOrCounter'
  , atomicXorCounter'
    
  , atomicAddCounter_
  , atomicSubCounter_
  , atomicAndCounter_
  , atomicNandCounter_
  , atomicOrCounter_
  , atomicXorCounter_
  ) where
import Data.Primitive.Types
import Data.Primitive.ByteArray
import GHC.Prim
import GHC.Types
import GHC.ST
import GHC.IO(stToIO)
import Std.Data.PrimSTRef.Base
newtype PrimIORef a = PrimIORef (PrimSTRef RealWorld a)
newPrimIORef :: Prim a => a -> IO (PrimIORef a)
newPrimIORef init = PrimIORef `fmap` stToIO (newPrimSTRef init)
{-# INLINE newPrimIORef #-}
readPrimIORef :: Prim a => PrimIORef a -> IO a
readPrimIORef (PrimIORef ref) = stToIO (readPrimSTRef ref)
{-# INLINE readPrimIORef #-}
writePrimIORef :: Prim a => PrimIORef a -> a -> IO ()
writePrimIORef (PrimIORef ref) x = stToIO (writePrimSTRef ref x)
{-# INLINE writePrimIORef #-}
modifyPrimIORef :: Prim a => PrimIORef a -> (a -> a) -> IO ()
modifyPrimIORef ref f = readPrimIORef ref >>= writePrimIORef ref . f
{-# INLINE modifyPrimIORef #-}
type Counter = PrimIORef Int
newCounter :: Int -> IO Counter
newCounter = newPrimIORef
{-# INLINE newCounter #-}
atomicAddCounter' :: Counter -> Int -> IO Int
atomicAddCounter' (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchAddIntArray# mba# 0# x# s1# in (# s2#, (I# (res# +# x#)) #)
atomicAddCounter :: Counter -> Int -> IO Int
atomicAddCounter (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchAddIntArray# mba# 0# x# s1# in (# s2#, (I# res#) #)
atomicAddCounter_ :: Counter -> Int -> IO ()
atomicAddCounter_ (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, _ #) = fetchAddIntArray# mba# 0# x# s1# in (# s2#, () #)
{-# INLINE atomicAddCounter_ #-}
atomicSubCounter' :: Counter -> Int -> IO Int
atomicSubCounter' (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchSubIntArray# mba# 0# x# s1# in (# s2#, (I# (res# -# x#)) #)
atomicSubCounter :: Counter -> Int -> IO Int
atomicSubCounter (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchSubIntArray# mba# 0# x# s1# in (# s2#, (I# res#) #)
atomicSubCounter_ :: Counter -> Int -> IO ()
atomicSubCounter_ (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, _ #) = fetchSubIntArray# mba# 0# x# s1# in (# s2#, () #)
{-# INLINE atomicSubCounter_ #-}
atomicAndCounter' :: Counter -> Int -> IO Int
atomicAndCounter' (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchAndIntArray# mba# 0# x# s1# in (# s2#, (I# (res# `andI#` x#)) #)
{-# INLINE atomicAndCounter' #-}
atomicAndCounter :: Counter -> Int -> IO Int
atomicAndCounter (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchAndIntArray# mba# 0# x# s1# in (# s2#, (I# res#) #)
{-# INLINE atomicAndCounter #-}
atomicAndCounter_ :: Counter -> Int -> IO ()
atomicAndCounter_ (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchAndIntArray# mba# 0# x# s1# in (# s2#, () #)
{-# INLINE atomicAndCounter_ #-}
atomicNandCounter' :: Counter -> Int -> IO Int
atomicNandCounter' (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchNandIntArray# mba# 0# x# s1# in (# s2#, (I# (notI# (res# `andI#` x#))) #)
{-# INLINE atomicNandCounter' #-}
atomicNandCounter :: Counter -> Int -> IO Int
atomicNandCounter (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchNandIntArray# mba# 0# x# s1# in (# s2#, (I# res#) #)
{-# INLINE atomicNandCounter #-}
atomicNandCounter_ :: Counter -> Int -> IO ()
atomicNandCounter_ (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchNandIntArray# mba# 0# x# s1# in (# s2#, () #)
{-# INLINE atomicNandCounter_ #-}
atomicOrCounter' :: Counter -> Int -> IO Int
atomicOrCounter' (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchOrIntArray# mba# 0# x# s1# in (# s2#, (I# (res# `orI#` x#)) #)
{-# INLINE atomicOrCounter' #-}
atomicOrCounter :: Counter -> Int -> IO Int
atomicOrCounter (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchOrIntArray# mba# 0# x# s1# in (# s2#, (I# res#) #)
{-# INLINE atomicOrCounter #-}
atomicOrCounter_ :: Counter -> Int -> IO ()
atomicOrCounter_ (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchOrIntArray# mba# 0# x# s1# in (# s2#, () #)
{-# INLINE atomicOrCounter_ #-}
atomicXorCounter' :: Counter -> Int -> IO Int
atomicXorCounter' (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchXorIntArray# mba# 0# x# s1# in (# s2#, (I# (res# `xorI#` x#)) #)
{-# INLINE atomicXorCounter' #-}
atomicXorCounter :: Counter -> Int -> IO Int
atomicXorCounter (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchXorIntArray# mba# 0# x# s1# in (# s2#, (I# res#) #)
{-# INLINE atomicXorCounter #-}
atomicXorCounter_ :: Counter -> Int -> IO ()
atomicXorCounter_ (PrimIORef (PrimSTRef (MutableByteArray mba#))) (I# x#) = IO $ \ s1# ->
    let (# s2#, res# #) = fetchXorIntArray# mba# 0# x# s1# in (# s2#, () #)
{-# INLINE atomicXorCounter_ #-}