on 3feeec2 help sign in
110 lines 3.2 kB history raw
1{-# LANGUAGE UnboxedTuples #-}
3-- |
4-- Module : Streamly.Internal.Data.IORef.Prim
5-- Copyright : (c) 2019 Composewell Technologies
6--
7-- License : BSD3
8-- Maintainer : streamly@composewell.com
9-- Stability : experimental
10-- Portability : GHC
11--
12-- A mutable variable in a mutation capable monad (IO) holding a 'Prim'
13-- value. This allows fast modification because of unboxed storage.
14--
15-- = Multithread Consistency Notes
16--
17-- In general, any value that straddles a machine word cannot be guaranteed to
18-- be consistently read from another thread without a lock. GHC heap objects
19-- are always machine word aligned, therefore, a 'IORef' is also word aligned.
20-- On a 64-bit platform, writing a 64-bit aligned type from one thread and
21-- reading it from another thread should give consistent old or new value. The
22-- same holds true for 32-bit values on a 32-bit platform.
24module Streamly.Internal.Data.IORef.Prim
25 (
26 IORef
27 , Prim
29 -- * Construction
30 , newIORef
32 -- * Write
33 , writeIORef
34 , modifyIORef'
36 -- * Read
37 , readIORef
38 , toStream
39 , toStreamD
40 )
41where
43#include "inline.hs"
45import Control.Monad.IO.Class (MonadIO(..))
46import Control.Monad.Primitive (primitive_)
47import Data.Primitive.Types (Prim, sizeOf#, readByteArray#, writeByteArray#)
48import GHC.Exts (MutableByteArray#, newByteArray#, RealWorld)
49import GHC.IO (IO(..))
51import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
52import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
54-- | An 'IORef' holds a single 'Prim' value.
55data IORef a = IORef (MutableByteArray# RealWorld)
57-- | Create a new 'IORef'.
58--
59-- /Pre-release/
60{-# INLINE newIORef #-}
61newIORef :: forall a. Prim a => a -> IO (IORef a)
62newIORef x = IO (\s# ->
63 case newByteArray# (sizeOf# (undefined :: a)) s# of
64 (# s1#, arr# #) ->
65 case writeByteArray# arr# 0# x s1# of
66 s2# -> (# s2#, IORef arr# #)
67 )
69-- | Write a value to an 'IORef'.
70--
71-- /Pre-release/
72{-# INLINE writeIORef #-}
73writeIORef :: Prim a => IORef a -> a -> IO ()
74writeIORef (IORef arr#) x = primitive_ (writeByteArray# arr# 0# x)
76-- | Read a value from an 'IORef'.
77--
78-- /Pre-release/
79{-# INLINE readIORef #-}
80readIORef :: Prim a => IORef a -> IO a
81readIORef (IORef arr#) = IO (readByteArray# arr# 0#)
83-- | Modify the value of an 'IORef' using a function with strict application.
84--
85-- /Pre-release/
86{-# INLINE modifyIORef' #-}
87modifyIORef' :: Prim a => IORef a -> (a -> a) -> IO ()
88modifyIORef' (IORef arr#) g = primitive_ $ \s# ->
89 case readByteArray# arr# 0# s# of
90 (# s'#, a #) -> let a' = g a in a' `seq` writeByteArray# arr# 0# a' s'#
92-- | Generate a stream by continuously reading the IORef.
93--
94-- /Pre-release/
95{-# INLINE_NORMAL toStreamD #-}
96toStreamD :: (MonadIO m, Prim a) => IORef a -> D.Stream m a
97toStreamD var = D.Stream step ()
99 where
101 {-# INLINE_LATE step #-}
102 step _ () = liftIO (readIORef var) >>= \x -> return $ D.Yield x ()
104-- | Construct a stream by reading a 'Prim' 'IORef' repeatedly.
105--
106-- /Pre-release/
107--
108{-# INLINE toStream #-}
109toStream :: (K.IsStream t, MonadIO m, Prim a) => IORef a -> t m a
110toStream = D.fromStreamD . toStreamD