int-interval-map-0.0.1.0: Data/IntervalIntMap/Internal/GrowableVector.hs
{-# LANGUAGE FlexibleContexts #-}
module Data.IntervalIntMap.Internal.GrowableVector
( GrowableVector
, GrowableVectorData(..)
, new
, pushBack
, unsafeFreeze
, length
) where
import Prelude hiding (length)
import qualified Data.Vector.Storable as VS
import qualified Data.Vector.Storable.Mutable as VSM
import Foreign.Storable (Storable(..))
import Control.Monad.Primitive (PrimMonad, PrimState)
import Data.Primitive.MutVar (MutVar, newMutVar, readMutVar, writeMutVar)
{--| This is a growable vector (i.e., one that includes the 'pushBack'
- function) which must exist in a 'PrimMonad'. It only supports Storable data
- items.
-}
type GrowableVector s a = MutVar s (GrowableVectorData s a)
data GrowableVectorData s a = GrowableVectorData !Int !(VSM.MVector s a)
-- | Empty vector
new :: (PrimMonad m, Storable a) => m (GrowableVector (PrimState m) a)
new = do
vd <- GrowableVectorData 0 <$> VSM.unsafeNew 16
newMutVar vd
-- | Insert an element at the end of the vector
pushBack :: (PrimMonad m, Storable a) => a -> GrowableVector (PrimState m) a -> m ()
pushBack val gv =
readMutVar gv >>= pushBack' val >>= writeMutVar gv
pushBack' :: (PrimMonad m, Storable a) => a -> GrowableVectorData (PrimState m) a -> m (GrowableVectorData (PrimState m) a)
pushBack' val (GrowableVectorData used vec)
| used == VSM.length vec = do
vec' <- VSM.grow vec (VSM.length vec `div` 2) -- multiplying by 1.5 is close to optimal
pushBack' val (GrowableVectorData used vec')
| otherwise = do
VSM.write vec used val
return $! GrowableVectorData (used+1) vec
-- | This operation is unsafe as original vector should not be used again!
unsafeFreeze :: (PrimMonad m, Storable a) => GrowableVector (PrimState m) a -> m (VS.Vector a)
unsafeFreeze gv = do
GrowableVectorData used vec <- readMutVar gv
VS.take used <$> VS.unsafeFreeze vec
-- | Return the current number of stored elements
length :: (PrimMonad m, Storable a) => GrowableVector (PrimState m) a -> m Int
length gv = do
GrowableVectorData len _ <- readMutVar gv
return len