From 99a4c29e4e6c42637cf8ccc99386d1f1b01943a7 Mon Sep 17 00:00:00 2001 From: Dmitrii Kovanikov Date: Thu, 14 May 2020 17:49:11 +0100 Subject: [PATCH] [#294] Add atomicModifyIORef_ and atomicModifyIORef'_ (#297) Resolves #294 --- .hlint.yaml | 12 +++++++++++ CHANGELOG.md | 2 ++ hlint/hlint.dhall | 4 ++++ src/Relude/Lifted/IORef.hs | 42 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+) diff --git a/.hlint.yaml b/.hlint.yaml index 73419835..4e7e97d2 100644 --- a/.hlint.yaml +++ b/.hlint.yaml @@ -2090,6 +2090,18 @@ name: "Use 'writeIORef' from Relude" note: "'writeIORef' is already exported from Relude" rhs: writeIORef +- warn: + lhs: "atomicModifyIORef ref (\\a -> (f a, ()))" + rhs: atomicModifyIORef_ ref f +- warn: + lhs: "atomicModifyIORef ref $ \\a -> (f a, ())" + rhs: atomicModifyIORef_ ref f +- warn: + lhs: "atomicModifyIORef' ref $ \\a -> (f a, ())" + rhs: "atomicModifyIORef'_ ref f" +- warn: + lhs: "atomicModifyIORef' ref (\\a -> (f a, ()))" + rhs: "atomicModifyIORef'_ ref f" - warn: lhs: Data.Text.IO.getLine name: "Use 'getLine' from Relude" diff --git a/CHANGELOG.md b/CHANGELOG.md index f3f702ee..55808375 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ The changelog is available [on GitHub][2]. * [#228](https://github.com/kowainik/relude/issues/228): Add `universeNonEmpty` function. +* [#294](https://github.com/kowainik/relude/issues/294): + Add `atomicModifyIORef_` and `atomicModifyIORef'_`. * [#253](https://github.com/kowainik/relude/issues/253): Support GHC-8.10. Upgrade GHC-8.8 to 8.8.3. * [#256](https://github.com/kowainik/relude/issues/256): diff --git a/hlint/hlint.dhall b/hlint/hlint.dhall index dc142ae5..81faa644 100644 --- a/hlint/hlint.dhall +++ b/hlint/hlint.dhall @@ -684,6 +684,10 @@ in [ Rule.Arguments { arguments = , warnReexport "newIORef" "Data.IORef" , warnReexport "readIORef" "Data.IORef" , warnReexport "writeIORef" "Data.IORef" + , warnSimple "atomicModifyIORef ref (\\a -> (f a, ()))" "atomicModifyIORef_ ref f" + , warnSimple "atomicModifyIORef ref $ \\a -> (f a, ())" "atomicModifyIORef_ ref f" + , warnSimple "atomicModifyIORef' ref $ \\a -> (f a, ())" "atomicModifyIORef'_ ref f" + , warnSimple "atomicModifyIORef' ref (\\a -> (f a, ()))" "atomicModifyIORef'_ ref f" -- Lifted Terminal , warnReexport "getLine" "Data.Text.IO" diff --git a/src/Relude/Lifted/IORef.hs b/src/Relude/Lifted/IORef.hs index b31000a5..3682fd04 100644 --- a/src/Relude/Lifted/IORef.hs +++ b/src/Relude/Lifted/IORef.hs @@ -16,6 +16,8 @@ module Relude.Lifted.IORef ( IORef , atomicModifyIORef , atomicModifyIORef' + , atomicModifyIORef_ + , atomicModifyIORef'_ , atomicWriteIORef , modifyIORef , modifyIORef' @@ -81,6 +83,8 @@ writeIORef ref what = liftIO $ Ref.writeIORef ref what >>> readIORef ref 48 +* To avoid space-leaks, see 'modifyIORef'' for stricter updates +* For atomic updates, see 'atomicModifyIORef' -} modifyIORef :: MonadIO m => IORef a -> (a -> a) -> m () modifyIORef ref how = liftIO $ Ref.modifyIORef ref how @@ -94,6 +98,8 @@ modifyIORef ref how = liftIO $ Ref.modifyIORef ref how >>> readIORef ref 45 +* For lazier updates, see 'modifyIORef' +* For atomic updates, see 'atomicModifyIORef'' -} modifyIORef' :: MonadIO m => IORef a -> (a -> a) -> m () modifyIORef' ref how = liftIO $ Ref.modifyIORef' ref how @@ -108,6 +114,8 @@ modifyIORef' ref how = liftIO $ Ref.modifyIORef' ref how >>> readIORef ref 42 +* To avoid space-leaks, see 'atomicModifyIORef'' for stricter updates +* If you are not interested in the return value, see 'atomicModifyIORef_' -} atomicModifyIORef :: MonadIO m => IORef a -> (a -> (a, b)) -> m b atomicModifyIORef ref how = liftIO $ Ref.atomicModifyIORef ref how @@ -122,12 +130,46 @@ atomicModifyIORef ref how = liftIO $ Ref.atomicModifyIORef ref how >>> readIORef ref 42 +* For lazier updates, see 'atomicModifyIORef' +* If you are not interested in the return value, see 'atomicModifyIORef'_' -} atomicModifyIORef' :: MonadIO m => IORef a -> (a -> (a, b)) -> m b atomicModifyIORef' ref how = liftIO $ Ref.atomicModifyIORef' ref how {-# INLINE atomicModifyIORef' #-} {-# SPECIALIZE atomicModifyIORef' :: IORef a -> (a -> (a, b)) -> IO b #-} +{- | Version of 'atomicModifyIORef' that discards return value. Useful +when you want to update 'IORef' but not interested in the returning +result. + +>>> ref <- newIORef 42 +>>> atomicModifyIORef_ ref (`div` 2) +>>> readIORef ref +21 + +@since 0.7.0.0 +-} +atomicModifyIORef_ :: MonadIO m => IORef a -> (a -> a) -> m () +atomicModifyIORef_ ref f = atomicModifyIORef ref $ \a -> (f a, ()) +{-# INLINE atomicModifyIORef_ #-} +{-# SPECIALIZE atomicModifyIORef_ :: IORef a -> (a -> a) -> IO () #-} + +{- | Version of 'atomicModifyIORef'' that discards return value. Useful +when you want to update 'IORef' but not interested in the returning +result. + +>>> ref <- newIORef 42 +>>> atomicModifyIORef'_ ref (`div` 2) +>>> readIORef ref +21 + +@since 0.7.0.0 +-} +atomicModifyIORef'_ :: MonadIO m => IORef a -> (a -> a) -> m () +atomicModifyIORef'_ ref f = atomicModifyIORef' ref $ \a -> (f a, ()) +{-# INLINE atomicModifyIORef'_ #-} +{-# SPECIALIZE atomicModifyIORef'_ :: IORef a -> (a -> a) -> IO () #-} + {- | Lifted version of 'Ref.atomicWriteIORef'. >>> ref <- newIORef 42