content: -- |
  -- Module      : Control.Concurrent.Classy.CRef
  -- Copyright   : (c) 2016--2018 Michael Walker
  -- License     : MIT
  -- Maintainer  : Michael Walker <mike@barrucadu.co.uk>
  -- Stability   : experimental
  -- Portability : portable
  --
  -- Deprecated re-exports of @IORef@ functions under the old @CRef@
  -- names.
  module Control.Concurrent.Classy.CRef {-# DEPRECATED "Import Control.Concurrent.Classy.IORef instead" #-}
    ( -- * CRefs
      CRef
    , newCRef
    , newCRefN
    , readCRef
    , writeCRef
    , modifyCRef
    , modifyCRef'
    , atomicModifyCRef
    , atomicModifyCRef'
    , atomicWriteCRef
  
    -- ** Compare-and-swap
    , casCRef
    , modifyCRefCAS
    , modifyCRefCAS_
  
    -- * Memory Model
  
    -- | In a concurrent program, @CRef@ operations may appear
    -- out-of-order to another thread, depending on the memory model of
    -- the underlying processor architecture. For example, on x86 (which
    -- uses total store order), loads can move ahead of stores. Consider
    -- this example:
    --
    -- > crefs :: MonadConc m => m (Bool, Bool)
    -- > crefs = do
    -- >   r1 <- newCRef False
    -- >   r2 <- newCRef False
    -- >
    -- >   x <- spawn $ writeCRef r1 True >> readCRef r2
    -- >   y <- spawn $ writeCRef r2 True >> readCRef r1
    -- >
    -- >   (,) <$> readMVar x <*> readMVar y
    --
    -- Under a sequentially consistent memory model the possible results
    -- are @(True, True)@, @(True, False)@, and @(False, True)@. Under
    -- total or partial store order, @(False, False)@ is also a possible
    -- result, even though there is no interleaving of the threads which
    -- can lead to this.
    --
    -- We can see this by testing with different memory models:
    --
    -- > > autocheckWay defaultWay SequentialConsistency relaxed
    -- > [pass] Never Deadlocks
    -- > [pass] No Exceptions
    -- > [fail] Consistent Result
    -- >        (False,True) S0---------S1----S0--S2----S0--
    -- >
    -- >        (True,True) S0---------S1-P2----S1---S0---
    -- >
    -- >        (True,False) S0---------S2----S1----S0---
    -- > False
    --
    -- > > autocheckWay defaultWay TotalStoreOrder  relaxed
    -- > [pass] Never Deadlocks
    -- > [pass] No Exceptions
    -- > [fail] Consistent Result
    -- >         (False,True) S0---------S1----S0--S2----S0--
    -- >
    -- >         (False,False) S0---------S1--P2----S1--S0---
    -- >
    -- >         (True,False) S0---------S2----S1----S0---
    -- >
    -- >         (True,True) S0---------S1-C-S2----S1---S0---
    -- > False
    --
    -- Traces for non-sequentially-consistent memory models show where
    -- writes to @CRef@s are /committed/, which makes a write visible to
    -- all threads rather than just the one which performed the
    -- write. Only 'writeCRef' is broken up into separate write and
    -- commit steps, 'atomicModifyCRef' is still atomic and imposes a
    -- memory barrier.
    ) where
  
  import qualified Control.Concurrent.Classy.IORef as IORef
  import           Control.Monad.Conc.Class        (IORef, MonadConc, Ticket)
  import qualified Control.Monad.Conc.Class        as IORef
  
  -- | Type alias for 'IORef'.
  type CRef m a = IORef m a
  {-# DEPRECATED CRef "Use IORef instead" #-}
  
  -- | Create a new reference.
  newCRef :: MonadConc m => a -> m (CRef m a)
  newCRef = IORef.newIORef
  {-# DEPRECATED newCRef "Use newIORef instead" #-}
  
  -- | Create a new reference, but it is given a name which may be used
  -- to present more useful debugging information.
  newCRefN :: MonadConc m => String -> a -> m (CRef m a)
  newCRefN = IORef.newIORefN
  {-# DEPRECATED newCRefN "Use newIORefN instead" #-}
  
  -- | Read the current value stored in a reference.
  readCRef :: MonadConc m => CRef m a -> m a
  readCRef = IORef.readIORef
  {-# DEPRECATED readCRef "Use readIORef instead" #-}
  
  -- | Write a new value into an @CRef@, without imposing a memory
  -- barrier. This means that relaxed memory effects can be observed.
  writeCRef :: MonadConc m => CRef m a -> a -> m ()
  writeCRef = IORef.writeIORef
  {-# DEPRECATED writeCRef "Use writeIORef instead" #-}
  
  -- | Mutate the contents of a @CRef@.
  --
  -- Be warned that 'modifyCRef' does not apply the function strictly.
  -- This means if the program calls 'modifyCRef' many times, but
  -- seldomly uses the value, thunks will pile up in memory resulting in
  -- a space leak.
  modifyCRef :: MonadConc m => CRef m a -> (a -> a) -> m ()
  modifyCRef = IORef.modifyIORef
  {-# DEPRECATED modifyCRef "Use modifyIORef instead" #-}
  
  -- | Strict version of 'modifyCRef'
  modifyCRef' :: MonadConc m => CRef m a -> (a -> a) -> m ()
  modifyCRef' = IORef.modifyIORef'
  {-# DEPRECATED modifyCRef' "Use modifyIORef' instead" #-}
  
  -- | Atomically modify the value stored in a reference. This imposes
  -- a full memory barrier.
  atomicModifyCRef :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
  atomicModifyCRef = IORef.atomicModifyIORef
  {-# DEPRECATED atomicModifyCRef "Use atomicModifyIORef instead" #-}
  
  -- | Strict version of 'atomicModifyCRef'. This forces both the value
  -- stored in the @CRef@ as well as the value returned.
  atomicModifyCRef' :: MonadConc m => CRef m a -> (a -> (a,b)) -> m b
  atomicModifyCRef' = IORef.atomicModifyIORef'
  {-# DEPRECATED atomicModifyCRef' "Use atomicModifyIORef' instead" #-}
  
  -- | Replace the value stored in a reference, with the
  -- barrier-to-reordering property that 'atomicModifyIORef' has.
  atomicWriteCRef :: MonadConc m => CRef m a -> a -> m ()
  atomicWriteCRef = IORef.atomicWriteIORef
  {-# DEPRECATED atomicWriteCRef "Use atomicWriteIORef instead" #-}
  
  -- | Perform a machine-level compare-and-swap (CAS) operation on a
  -- @CRef@. Returns an indication of success and a @Ticket@ for the
  -- most current value in the @CRef@.
  -- This is strict in the \"new\" value argument.
  casCRef :: MonadConc m => CRef m a -> Ticket m a -> a -> m (Bool, Ticket m a)
  casCRef = IORef.casIORef
  {-# DEPRECATED casCRef "Use casIORef instead" #-}
  
  -- | A replacement for 'atomicModifyCRef' using a compare-and-swap.
  --
  -- This is strict in the \"new\" value argument.
  modifyCRefCAS :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
  modifyCRefCAS = IORef.modifyIORefCAS
  {-# DEPRECATED modifyCRefCAS "Use modifyIORefCAS instead" #-}
  
  -- | A variant of 'modifyCRefCAS' which doesn't return a result.
  modifyCRefCAS_ :: MonadConc m => CRef m a -> (a -> a) -> m ()
  modifyCRefCAS_ = IORef.modifyIORefCAS_
  {-# DEPRECATED modifyCRefCAS_ "Use modifyIORefCAS_ instead" #-}
  