module Data.Rope.Mutable
( Rope
, Data.Rope.Mutable.new
, new'
, fromList
, write
, reset
) where
import Control.Monad
import Control.Monad.Primitive
import Data.Foldable as F
import Data.Primitive.MutVar
import Data.Proxy
import qualified Data.Vector as V
import qualified Data.Vector.Generic as VG
import qualified Data.Vector.Generic.Mutable as M
import Data.Vector.Generic.Mutable as M (MVector, read, new)
data RopeState m v a = RopeState
{ ropeDepth :: !Int
, ropeLastIndex :: !Int
, ropeElements :: [v (PrimState m) a]
, spillOver :: v (PrimState m) a
}
data Rope m v a = Rope
{ ropeState :: MutVar (PrimState m) (RopeState m v a)
, ropeDim :: !Int
}
defaultRopeDim = 10000
write :: forall v a m . (PrimMonad m, MVector v a) => Rope m v a -> Int -> a -> m ()
write Rope {..} (fromEnum -> ix) a = join $ atomicModifyMutVar' ropeState updateState
where
(d, r) = divMod ix ropeDim
updateState :: RopeState m v a -> (RopeState m v a, m ())
updateState st@RopeState {..}
| d < ropeDepth =
( st {ropeLastIndex = max ropeLastIndex ix}
, M.unsafeWrite (ropeElements !! (ropeDepth 1 d)) r a)
| d == ropeDepth =
( st
{ ropeElements = spillOver : ropeElements
, ropeDepth = d + 1
, ropeLastIndex = max ropeLastIndex ix
}
, do M.unsafeWrite spillOver r a
v <- M.new ropeDim
atomicModifyMutVar' ropeState $ \st' -> (st' {spillOver = v}, ()))
| otherwise = error $ "index " ++ show ix ++ " too far away from the last index " ++ show ropeLastIndex
new :: forall v a m . (PrimMonad m, MVector v a) => m (Rope m v a)
new = new' defaultRopeDim
new' :: forall v a m . (PrimMonad m, MVector v a) => Int -> m (Rope m v a)
new' ropeDim = do
spillOver <- M.new ropeDim
ropeState <- newMutVar (RopeState 0 (1) [] spillOver)
return Rope{..}
reset :: forall v a m . (VG.Vector v a, PrimMonad m) => Proxy v -> Rope m (VG.Mutable v) a -> m (v a)
reset proxy it@Rope{..} = do
(lastIndex, ropeElements) <-
atomicModifyMutVar' ropeState $ \RopeState {..} ->
(RopeState 0 (1) [] spillOver, (ropeLastIndex, ropeElements))
lv <- mapM VG.unsafeFreeze ropeElements
let joined :: v a
| h:t <- lv
= VG.concat (reverse t ++ [VG.slice 0 (lastIndex `mod` ropeDim + 1) h])
| otherwise = VG.empty
return joined
fromList :: forall v m a. (PrimMonad m, MVector v a) => Int -> [a] -> m(Rope m v a)
fromList dim xx = do
rope <- new' dim
forM_ (zip [0..] xx) $ \(i,x) -> write rope i x
return rope
propFromList dim xx =
check . toList <$> (reset (Proxy :: Proxy V.Vector) =<< fromList dim xx)
where
check xx'
| xx == xx' = True
| otherwise = error (show xx')