on 80daa14 help sign in
83 lines 2.7 kB history raw
1{-# LANGUAGE UnboxedTuples #-}
3#include "inline.hs"
5-- |
6-- Module : Streamly.Internal.Mutable.Prim.Var
7-- Copyright : (c) 2019 Composewell Technologies
8--
9-- License : BSD3
10-- Maintainer : streamly@composewell.com
11-- Stability : experimental
12-- Portability : GHC
13--
14-- A mutable variable in a mutation capable monad (IO/ST) holding a 'Prim'
15-- value. This allows fast modification because of unboxed storage.
16--
17-- = Multithread Consistency Notes
18--
19-- In general, any value that straddles a machine word cannot be guaranteed to
20-- be consistently read from another thread without a lock. GHC heap objects
21-- are always machine word aligned, therefore, a 'Var' is also word aligned. On
22-- a 64-bit platform, writing a 64-bit aligned type from one thread and reading
23-- it from another thread should give consistent old or new value. The same
24-- holds true for 32-bit values on a 32-bit platform.
26module Streamly.Internal.Mutable.Prim.Var
27 (
28 Var
29 , MonadMut
30 , Prim
32 -- * Construction
33 , newVar
35 -- * Write
36 , writeVar
37 , modifyVar'
39 -- * Read
40 , readVar
41 )
42where
44import Control.Monad.Primitive (PrimMonad(..), primitive_)
45import Data.Primitive.Types (Prim, sizeOf#, readByteArray#, writeByteArray#)
46import GHC.Exts (MutableByteArray#, newByteArray#)
48-- | A 'Var' holds a single 'Prim' value.
49data Var m a = Var (MutableByteArray# (PrimState m))
51-- The name PrimMonad does not give a clue what it means, an explicit "Mut"
52-- suffix provides a better hint. MonadMut is just a generalization of MonadIO.
53--
54-- | A monad that allows mutable operations using a state token.
55type MonadMut = PrimMonad
57-- | Create a new mutable variable.
58{-# INLINE newVar #-}
59newVar :: forall m a. (MonadMut m, Prim a) => a -> m (Var m a)
60newVar x = primitive (\s# ->
61 case newByteArray# (sizeOf# (undefined :: a)) s# of
62 (# s1#, arr# #) ->
63 case writeByteArray# arr# 0# x s1# of
64 s2# -> (# s2#, Var arr# #)
65 )
67-- | Write a value to a mutable variable.
68{-# INLINE writeVar #-}
69writeVar :: (MonadMut m, Prim a) => Var m a -> a -> m ()
70writeVar (Var arr#) x = primitive_ (writeByteArray# arr# 0# x)
72-- | Read a value from a variable.
73{-# INLINE readVar #-}
74readVar :: (MonadMut m, Prim a) => Var m a -> m a
75readVar (Var arr#) = primitive (readByteArray# arr# 0#)
77-- | Modify the value of a mutable variable using a function with strict
78-- application.
79{-# INLINE modifyVar' #-}
80modifyVar' :: (MonadMut m, Prim a) => Var m a -> (a -> a) -> m ()
81modifyVar' (Var arr#) g = primitive_ $ \s# ->
82 case readByteArray# arr# 0# s# of
83 (# s'#, a #) -> let a' = g a in a' `seq` writeByteArray# arr# 0# a' s'#