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