{-# LANGUAGE TypeFamilies #-}
-- | Use 1-length mutable storable vectors for mutable references.
--
-- Motivated by: <http://stackoverflow.com/questions/27261813/why-is-my-little-stref-int-require-allocating-gigabytes> and ArrayRef.
module Data.Mutable.SRef
( -- * Types
SRef
, IOSRef
-- * Functions
, asSRef
, MutableRef (..)
) where
import Data.Mutable.Class
import Foreign.ForeignPtr
import Foreign.Storable
import Control.Monad.Primitive
-- | A storable vector reference, supporting any monad.
--
-- Since 0.2.0
newtype SRef s a = SRef (ForeignPtr a)
-- |
-- Since 0.2.0
asSRef :: SRef s a -> SRef s a
asSRef x = x
{-# INLINE asSRef #-}
-- | A storable IO vector reference.
type IOSRef = SRef (PrimState IO)
instance MutableContainer (SRef s a) where
type MCState (SRef s a) = s
instance Storable a => MutableRef (SRef s a) where
type RefElement (SRef s a) = a
newRef x = unsafePrimToPrim $ do
fptr <- mallocForeignPtr
withForeignPtr fptr $ flip poke x
return $! SRef fptr
{-# INLINE newRef#-}
readRef (SRef fptr) = unsafePrimToPrim $ withForeignPtr fptr peek
{-# INLINE readRef #-}
writeRef (SRef fptr) x = unsafePrimToPrim $ withForeignPtr fptr $ flip poke x
{-# INLINE writeRef #-}
modifyRef (SRef fptr) f = unsafePrimToPrim $ withForeignPtr fptr $ \ptr ->
peek ptr >>= poke ptr . f
{-# INLINE modifyRef #-}
modifyRef' = modifyRef
{-# INLINE modifyRef' #-}