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