module ADP.Fusion.SynVar.Fill where
import Control.Monad
import Control.Monad.Morph (hoist, MFunctor (..))
import Control.Monad.Primitive (PrimMonad (..))
import Control.Monad.ST
import Control.Monad.Trans.Class (lift, MonadTrans (..))
import Data.Vector.Fusion.Util (Id(..))
import GHC.Exts (inline)
import qualified Data.Vector.Fusion.Stream.Monadic as SM
import System.IO.Unsafe
import Control.Monad (when,forM_)
import Data.List (nub,sort,group)
import qualified Data.Vector.Unboxed as VU
import Data.Proxy
import qualified GHC.Generics as G
import qualified Data.Typeable as T
import qualified Data.Data as D
import Data.Dynamic
import Data.Type.Equality
import qualified Data.List as L
import Data.PrimitiveArray
import ADP.Fusion.SynVar.Array
import ADP.Fusion.SynVar.Recursive.Type
import ADP.Fusion.SynVar.TableWrap
import Debug.Trace
data CFG
data MonotoneMCFG
class MutateCell (h :: *) (s :: *) (im :: * -> *) i where
mutateCell :: (Monad om, PrimMonad om) => Proxy h -> Int -> Int -> (forall a . im a -> om a) -> s -> i -> i -> om ()
class MutateTables (h :: *) (s :: *) (im :: * -> *) where
mutateTables :: (Monad om, PrimMonad om) => Proxy h -> (forall a . im a -> om a) -> s -> om s
class TableOrder (s :: *) where
tableLittleOrder :: s -> [Int]
tableBigOrder :: s -> [Int]
instance TableOrder Z where
tableLittleOrder Z = []
tableBigOrder Z = []
instance (TableOrder ts) => TableOrder (ts:.TwITbl im arr c i x) where
tableLittleOrder (ts:.TW (ITbl _ tlo _ _) _) = tlo : tableLittleOrder ts
tableBigOrder (ts:.TW (ITbl tbo _ _ _) _) = tbo : tableBigOrder ts
instance (TableOrder ts) => TableOrder (ts:.TwIRec im c i x) where
tableLittleOrder (ts:._) = tableLittleOrder ts
tableBigOrder (ts:._) = tableBigOrder ts
instance
(
) => MutateCell p Z im i where
mutateCell _ _ _ _ Z _ _ = return ()
instance
( MutateCell CFG ts im i
) => MutateCell CFG (ts:.TwIRec im c i x) im i where
mutateCell h bo lo mrph (ts:._) lu i = do
mutateCell h bo lo mrph ts lu i
instance
( PrimArrayOps arr i x
, MPrimArrayOps arr i x
, MutateCell CFG ts im i
) => MutateCell CFG (ts:.TwITbl im arr c i x) im i where
mutateCell h bo lo mrph (ts:.TW (ITbl tbo tlo c arr) f) lu i = do
mutateCell h bo lo mrph ts lu i
when (bo==tbo && lo==tlo) $ do
marr <- unsafeThaw arr
z <- (inline mrph) $ f lu i
writeM marr i z
type ZS2 = Z:.Subword I:.Subword I
instance
( PrimArrayOps arr ZS2 x
, MPrimArrayOps arr ZS2 x
, MutateCell MonotoneMCFG ts im ZS2
) => MutateCell MonotoneMCFG (ts:.TwITbl im arr c ZS2 x) im ZS2 where
mutateCell h bo lo mrph (ts:.TW (ITbl tbo tlo c arr) f) lu iklj@(Z:.Subword (i:.k):.Subword(l:.j)) = do
mutateCell h bo lo mrph ts lu iklj
when (bo==tbo && lo==tlo && k<=l) $ do
marr <- unsafeThaw arr
z <- (inline mrph) $ f lu iklj
writeM marr iklj z
instance
( PrimArrayOps arr (Subword I) x
, MPrimArrayOps arr (Subword I) x
, MutateCell h ts im (Z:.Subword I:.Subword I)
) => MutateCell h (ts:.TwITbl im arr c (Subword I) x) im (Z:.Subword I:.Subword I) where
mutateCell h bo lo mrph (ts:.TW (ITbl tbo tlo c arr) f) lu@(Z:.Subword (l:._):.Subword(_:.u)) ix@(Z:.Subword (i1:.j1):.Subword (i2:.j2)) = do
mutateCell h bo lo mrph ts lu ix
when (bo==tbo && lo==tlo && i1==i2 && j1==j2) $ do
let i = i1
let j = j1
marr <- unsafeThaw arr
z <- (inline mrph) $ f (subword l u) (subword i j)
writeM marr (subword i j) z
instance
( MutateCell h (ts:.TwITbl im arr c i x) im i
, PrimArrayOps arr i x
, Show i
, IndexStream i
, TableOrder (ts:.TwITbl im arr c i x)
) => MutateTables h (ts:.TwITbl im arr c i x) im where
mutateTables h mrph tt@(_:.TW (ITbl _ _ _ arr) _) = do
let (from,to) = bounds arr
let !tbos = VU.fromList . nub . sort $ tableBigOrder tt
let !tlos = VU.fromList . nub . sort $ tableLittleOrder tt
VU.forM_ tbos $ \bo ->
case (VU.length tlos) of
1 -> let lo = VU.head tlos
in flip SM.mapM_ (streamUp from to) $ \k ->
mutateCell h bo lo (inline mrph) tt to k
_ -> flip SM.mapM_ (streamUp from to) $ \k ->
VU.forM_ tlos $ \lo ->
mutateCell h bo lo (inline mrph) tt to k
return tt
mutateTablesDefault :: MutateTables CFG t Id => t -> t
mutateTablesDefault t = unsafePerformIO $ mutateTables (Proxy :: Proxy CFG) (return . unId) t
mutateTablesWithHints :: MutateTables h t Id => Proxy h -> t -> t
mutateTablesWithHints h t = unsafePerformIO $ mutateTables h (return . unId) t
mutateTablesST t = runST $ mutateTablesNew t
mutateTablesNew
:: forall t m .
( TableOrder t
, TSBO t
, Monad m
, PrimMonad m
)
=> t
-> m t
mutateTablesNew ts = do
let !tbos = VU.fromList . nub . sort $ tableBigOrder ts
let ds = L.sort $ asDyn ts
let goM :: (Monad m, PrimMonad m) => [Q] -> m ()
goM [] = return ()
goM xs = do
ys <- fillWithDyn xs ts
if null ys
then return ()
else goM ys
goM ds
return ts
data Q = Q
{ qBigOrder :: Int
, qLittleOrder :: Int
, qTypeRep :: T.TypeRep
, qObject :: Dynamic
}
deriving (Show)
instance Eq Q where
Q bo1 lo1 tr1 _ == Q bo2 lo2 tr2 _ = (bo1,tr1,lo1) == (bo2,tr2,lo2)
instance Ord Q where
Q bo1 lo1 tr1 _ `compare` Q bo2 lo2 tr2 _ = (bo1,tr1,lo1) `compare` (bo2,tr2,lo2)
class TSBO t where
asDyn :: t -> [Q]
fillWithDyn :: (Monad m, PrimMonad m) => [Q] -> t -> m [Q]
instance TSBO Z where
asDyn Z = []
fillWithDyn qs Z = return qs
instance
( TSBO ts
, Typeable arr
, Typeable c
, Typeable i
, Typeable x
, PrimArrayOps arr i x
, MPrimArrayOps arr i x
, IndexStream i
) => TSBO (ts:.TwITbl Id arr c i x) where
asDyn (ts:.t@(TW (ITbl bo lo _ _) _)) = Q bo lo (T.typeOf t) (toDyn t) : asDyn ts
fillWithDyn qs (ts:.t@(TW (ITbl bo lo _ arr) f)) = do
let (from,to) = bounds arr
let (hs,ns) = L.span (\Q{..} -> qBigOrder == bo && qTypeRep == T.typeOf t) qs
if null hs
then fillWithDyn qs ts
else do
let ms = Prelude.map concrete hs
concrete = (maybe (error "fromDynamic should not fail!")
(\x -> x `asTypeOf` t)
. fromDynamic . qObject)
case (length ms) of
1 -> do marr <- unsafeThaw arr
flip SM.mapM_ (streamUp from to) $ \k -> do
z <- (return . unId) $ f to k
writeM marr k z
_ -> do marrfs <- Prelude.mapM (\(TW (ITbl _ _ _ arr) f) -> unsafeThaw arr >>= \marr -> return (marr,f)) ms
flip SM.mapM_ (streamUp from to) $ \k ->
forM_ marrfs $ \(marr,f) -> do
z <- (return . unId) $ f to k
writeM marr k z
return ns
instance
( TSBO ts
) => TSBO (ts:.TwIRec Id c i x) where
asDyn (ts:.t@(TW (IRec _ _ _) _)) = asDyn ts
fillWithDyn qs (ts:._) = fillWithDyn qs ts