{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE TypeFamilies #-}
module Internal.AppendVec
( AppendVec
, fromVector
, makeEmpty
, getVector
, getCapacity
, FrozenAppendVec(..)
, grow
, canGrowWithoutCopy
) where
import Control.Monad (when)
import Control.Monad.Catch (MonadThrow(throwM))
import Control.Monad.Primitive (PrimMonad, PrimState)
import qualified Data.Vector.Generic as GV
import qualified Data.Vector.Generic.Mutable as GMV
import Capnp.Errors (Error(SizeError))
import Data.Mutable (Thaw (..))
data AppendVec v s a = AppendVec
{ mutVec :: v s a
, mutVecLen :: !Int
}
fromVector :: GMV.MVector v a => v s a -> AppendVec v s a
fromVector vec = AppendVec
{ mutVec = vec
, mutVecLen = GMV.length vec
}
makeEmpty :: GMV.MVector v a => v s a -> AppendVec v s a
makeEmpty vec = AppendVec
{ mutVec = vec
, mutVecLen = 0
}
getVector :: GMV.MVector v a => AppendVec v s a -> v s a
getVector AppendVec{mutVec, mutVecLen} = GMV.slice 0 mutVecLen mutVec
getCapacity :: GMV.MVector v a => AppendVec v s a -> Int
getCapacity AppendVec{mutVec} = GMV.length mutVec
newtype FrozenAppendVec v a = FrozenAppendVec { getFrozenVector :: v a }
instance GV.Vector v a => Thaw (FrozenAppendVec v a) where
type Mutable s (FrozenAppendVec v a) = AppendVec (GV.Mutable v) s a
thaw = thawAppend GV.thaw
unsafeThaw = thawAppend GV.unsafeThaw
freeze = freezeAppend GV.freeze
unsafeFreeze = freezeAppend GV.unsafeFreeze
thawAppend thaw frozen = do
mvec <- thaw $ getFrozenVector frozen
pure AppendVec
{ mutVec = mvec
, mutVecLen = GMV.length mvec
}
freezeAppend freeze = fmap FrozenAppendVec . freeze . getVector
grow :: (MonadThrow m, PrimMonad m, s ~ PrimState m, GMV.MVector v a)
=> AppendVec v s a -> Int -> Int -> m (AppendVec v s a)
grow vec@AppendVec{mutVec,mutVecLen} amount maxSize = do
when (maxSize - amount < mutVecLen) $
throwM SizeError
mutVec <-
if canGrowWithoutCopy vec amount then
pure mutVec
else
GMV.grow mutVec (max amount (mutVecLen * 2))
pure AppendVec
{ mutVec = mutVec
, mutVecLen = mutVecLen + amount
}
canGrowWithoutCopy :: (GMV.MVector v a) => AppendVec v s a -> Int -> Bool
canGrowWithoutCopy AppendVec{mutVec,mutVecLen} amount =
mutVecLen + amount <= GMV.length mutVec