@@ -960,6 +960,11 @@ runComputeM (ComputeM a) = liftIO . runReaderT a =<< getDeferralQueue
961newtype MergeSubscribedParent x a = MergeSubscribedParent { unMergeSubscribedParent :: EventSubscription x }
961newtype MergeSubscribedParent x a = MergeSubscribedParent { unMergeSubscribedParent :: EventSubscription x }
963+data MergeSubscribedParentWithMove x k a = MergeSubscribedParentWithMove
964+ { _mergeSubscribedParentWithMove_subscription :: !(EventSubscription x)
965+ , _mergeSubscribedParentWithMove_key :: !(IORef (k a))
963data HeightBag = HeightBag
968data HeightBag = HeightBag
964 { _heightBag_size :: {-# UNPACK #-} !Int
969 { _heightBag_size :: {-# UNPACK #-} !Int
965 , _heightBag_contents :: !(IntMap Word) -- Number of excess in each bucket
970 , _heightBag_contents :: !(IntMap Word) -- Number of excess in each bucket
@@ -1550,14 +1555,121 @@ subscribeCoincidenceSubscribed subscribed sub = WeakBag.insert sub (coincidenceS
1550merge :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1555merge :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1551merge d = cacheEvent (mergeCheap d)
1556merge d = cacheEvent (mergeCheap d)
1558+{-# INLINE mergeWithMove #-}
1559+mergeWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1560+mergeWithMove d = cacheEvent (mergeCheapWithMove d)
1553{-# INLINE [1] mergeCheap #-}
1562{-# INLINE [1] mergeCheap #-}
1554mergeCheap :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1563mergeCheap :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1555−mergeCheap d = Event $ \sub -> do
1564+mergeCheap = mergeCheap' getInitialSubscribers updateMe destroy DMap.size
1566+ updateMe :: MergeUpdateFunc k x (PatchDMap k (Event x)) (MergeSubscribedParent x)
1567+ updateMe subscriber heightBagRef oldParents (PatchDMap p) = do
1568+ let f (subscriptionsToKill, ps) (k :=> ComposeMaybe me) = do
1569+ (mOldSubd, newPs) <- case me of
1570+ Nothing -> return $ DMap.updateLookupWithKey (\_ _ -> Nothing) k ps
1572+ let s = subscriber $ return k
1573+ subscription@(EventSubscription _ subd) <- subscribe e s
1574+ newParentHeight <- liftIO $ getEventSubscribedHeight subd
1575+ let newParent = MergeSubscribedParent subscription
1576+ liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1577+ return $ DMap.insertLookupWithKey' (\_ new _ -> new) k newParent ps
1578+ forM_ mOldSubd $ \oldSubd -> do
1579+ oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ unMergeSubscribedParent oldSubd
1580+ liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1581+ return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
1582+ foldM f ([], oldParents) $ DMap.toList p
1583+ getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParent x)
1584+ getInitialSubscribers initialParents subscriber = do
1585+ subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1586+ let s = subscriber $ return k
1587+ (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1588+ height <- liftIO $ getEventSubscribedHeight parentSubd
1589+ return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParent subscription)
1590+ return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1591+ , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1592+ , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1594+ destroy :: MergeDestroyFunc k (MergeSubscribedParent x)
1595+ destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParent sub) -> unsubscribe sub
1597+{-# INLINE [1] mergeCheapWithMove #-}
1598+mergeCheapWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1599+mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy DMap.size
1601+ updateMe :: MergeUpdateFunc k x (PatchDMapWithMove k (Event x)) (MergeSubscribedParentWithMove x k)
1602+ updateMe subscriber heightBagRef oldParents pWrapped = do
1603+ let p = unPatchDMapWithMove pWrapped
1604+ let f (subscriptionsToKill, ps) (k :=> edit) = do
1605+ let deleteHere = return $ DMap.updateLookupWithKey (\_ _ -> Nothing) k ps
1607+ keyRef <- liftIO $ newIORef k
1608+ let s = subscriber $ liftIO $ readIORef keyRef
1609+ subscription@(EventSubscription _ subd) <- subscribe e s
1611+ newParentHeight <- getEventSubscribedHeight subd
1612+ let newParent = MergeSubscribedParentWithMove subscription keyRef
1613+ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1614+ return $ DMap.insertLookupWithKey' (\_ new _ -> new) k newParent ps
1615+ (mOldSubd, newPs) <- case edit of
1616+ DMapEdit_Delete moved -> do
1617+ (toDelete, newPs) <- deleteHere
1618+ return (if moved then Nothing else toDelete, newPs)
1619+ DMapEdit_Insert moved e -> do
1620+ (toDelete, newPs) <- insertHere e
1621+ return (if moved then Nothing else toDelete, newPs)
1622+ DMapEdit_Move moved sourceKey -> do
1623+ (toDelete, newPs) <- case DMap.lookup sourceKey ps of
1624+ Nothing -> deleteHere
1625+ Just s@(MergeSubscribedParentWithMove _ keyRef) -> do
1626+ liftIO $ writeIORef keyRef k
1627+ return $ DMap.insertLookupWithKey' (\_ new _ -> new) k s ps
1628+ return (if moved then Nothing else toDelete, newPs)
1629+ forM_ mOldSubd $ \oldSubd -> do
1630+ oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ _mergeSubscribedParentWithMove_subscription oldSubd
1631+ liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1632+ return (maybeToList (_mergeSubscribedParentWithMove_subscription <$> mOldSubd) ++ subscriptionsToKill, newPs)
1633+ foldM f ([], oldParents) $ DMap.toList p
1634+ getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParentWithMove x k)
1635+ getInitialSubscribers initialParents subscriber = do
1636+ subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1637+ keyRef <- liftIO $ newIORef k
1638+ let s = subscriber $ liftIO $ readIORef keyRef
1639+ (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1640+ height <- liftIO $ getEventSubscribedHeight parentSubd
1641+ return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParentWithMove subscription keyRef)
1642+ return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1643+ , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1644+ , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1646+ destroy :: MergeDestroyFunc k (MergeSubscribedParentWithMove x k)
1647+ destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParentWithMove sub _) -> unsubscribe sub
1649+type MergeUpdateFunc k x p s
1650+ = (forall a. EventM x (k a) -> Subscriber x a)
1654+ -> EventM x ([EventSubscription x], DMap k s)
1656+type MergeInitFunc k x s
1658+ -> (forall a. EventM x (k a) -> Subscriber x a)
1659+ -> EventM x (DMap k Identity, [Height], DMap k s)
1661+type MergeDestroyFunc k s
1665+{-# INLINE mergeCheap' #-}
1666+mergeCheap' :: forall k x p s. (HasSpiderTimeline x, GCompare k, PatchTarget p ~ DMap k (Event x)) => MergeInitFunc k x s -> MergeUpdateFunc k x p s -> MergeDestroyFunc k s -> (DMap k s -> Int) -> Dynamic x p -> Event x (DMap k Identity)
1667+mergeCheap' getInitialSubscribers updateFunc destroy numParents d = Event $ \sub -> do
1556 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1668 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1557 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
1669 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
1558 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
1670 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
1559 heightBagRef <- liftIO $ newIORef $ error "merge: heightBagRef not yet initialized"
1671 heightBagRef <- liftIO $ newIORef $ error "merge: heightBagRef not yet initialized"
1560− parentsRef <- liftIO $ newIORef $ error "merge: parentsRef not yet initialized"
1672+ parentsRef :: IORef (DMap k s) <- liftIO $ newIORef $ error "merge: parentsRef not yet initialized"
1561 let scheduleSelf height = scheduleMerge' height heightRef $ do
1673 let scheduleSelf height = scheduleMerge' height heightRef $ do
1562 m <- liftIO $ readIORef accumRef
1674 m <- liftIO $ readIORef accumRef
1563 liftIO $ writeIORef accumRef $! DMap.empty
1675 liftIO $ writeIORef accumRef $! DMap.empty
@@ -1574,7 +1686,7 @@ mergeCheap d = Event $ \sub -> do
1574 heights <- readIORef heightBagRef
1686 heights <- readIORef heightBagRef
1575 parents <- readIORef parentsRef
1687 parents <- readIORef parentsRef
1576 -- When the number of heights in the bag reaches the number of parents, we should have a valid height
1688 -- When the number of heights in the bag reaches the number of parents, we should have a valid height
1577− case heightBagSize heights `compare` DMap.size parents of
1689+ case heightBagSize heights `compare` numParents parents of
1578 LT -> return ()
1690 LT -> return ()
1579 EQ -> do
1691 EQ -> do
1580 let height = succHeight $ heightBagMax heights
1692 let height = succHeight $ heightBagMax heights
@@ -1582,10 +1694,11 @@ mergeCheap d = Event $ \sub -> do
1582 writeIORef heightRef $! height
1694 writeIORef heightRef $! height
1583 subscriberRecalculateHeight sub height
1695 subscriberRecalculateHeight sub height
1584 GT -> error $ "revalidateMergeHeight: more heights than parents for Merge"
1696 GT -> error $ "revalidateMergeHeight: more heights than parents for Merge"
1585− subscriber :: forall a. k a -> Subscriber x a
1697+ subscriber :: forall a. EventM x (k a) -> Subscriber x a
1586− subscriber k = Subscriber
1698+ subscriber getKey = Subscriber
1587 { subscriberPropagate = \a -> do
1699 { subscriberPropagate = \a -> do
1588 oldM <- liftIO $ readIORef accumRef
1700 oldM <- liftIO $ readIORef accumRef
1589 let newM = DMap.insertWith (error $ "Same key fired multiple times for Merge") k (Identity a) oldM
1702 let newM = DMap.insertWith (error $ "Same key fired multiple times for Merge") k (Identity a) oldM
1590 tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
1703 tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
1591 liftIO $ writeIORef accumRef $! newM
1704 liftIO $ writeIORef accumRef $! newM
@@ -1615,14 +1728,13 @@ mergeCheap d = Event $ \sub -> do
1615 modifyIORef' heightBagRef $ heightBagAdd new
1728 modifyIORef' heightBagRef $ heightBagAdd new
1616 revalidateMyHeight
1729 revalidateMyHeight
1618− subscribers :: [(Maybe (DSum k Identity), Height, DSum k (MergeSubscribedParent x))] <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1731+ let updateMe x = do
1619− let s = subscriber k
1732+ oldParents <- liftIO $ readIORef parentsRef
1620− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1733+ (subscriptionsToKill, newParents) <- updateFunc subscriber heightBagRef oldParents x
1621− height <- liftIO $ getEventSubscribedHeight parentSubd
1734+ liftIO $ writeIORef parentsRef $! newParents
1622− return $ (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParent subscription)
1735+ return subscriptionsToKill
1623− let dm = DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1736+ (dm, heights, initialParentState) <- getInitialSubscribers initialParents subscriber
1624− heights = fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1625− myHeightBag = heightBagFromList $ filter (/= invalidHeight) heights
1737+ let myHeightBag = heightBagFromList $ filter (/= invalidHeight) heights
1626 myHeight = if invalidHeight `elem` heights
1738 myHeight = if invalidHeight `elem` heights
1627 then invalidHeight
1739 then invalidHeight
1628 else succHeight $ heightBagMax myHeightBag
1740 else succHeight $ heightBagMax myHeightBag
@@ -1638,26 +1750,7 @@ mergeCheap d = Event $ \sub -> do
1638 liftIO $ writeIORef heightRef $! myHeight
1750 liftIO $ writeIORef heightRef $! myHeight
1639 liftIO $ writeIORef heightBagRef $! myHeightBag
1751 liftIO $ writeIORef heightBagRef $! myHeightBag
1640 changeSubdRef <- liftIO $ newIORef $ error "getMergeSubscribed: changeSubdRef not yet initialized"
1752 changeSubdRef <- liftIO $ newIORef $ error "getMergeSubscribed: changeSubdRef not yet initialized"
1641− liftIO $ writeIORef parentsRef $! DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1753+ liftIO $ writeIORef parentsRef $! initialParentState
1642− let updateMe (PatchDMap p) = do
1643− oldParents <- liftIO $ readIORef parentsRef
1644− let f (subscriptionsToKill, ps) (k :=> ComposeMaybe me) = do
1645− (mOldSubd, newPs) <- case me of
1646− Nothing -> return $ DMap.updateLookupWithKey (\_ _ -> Nothing) k ps
1648− let s = subscriber k
1649− subscription@(EventSubscription _ subd) <- subscribe e s
1650− newParentHeight <- liftIO $ getEventSubscribedHeight subd
1651− let newParent = MergeSubscribedParent subscription
1652− liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1653− return $ DMap.insertLookupWithKey' (\_ new _ -> new) k newParent ps
1654− forM_ mOldSubd $ \oldSubd -> do
1655− oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ unMergeSubscribedParent oldSubd
1656− liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1657− return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
1658− (subscriptionsToKill, newParents) <- foldM f ([], oldParents) $ DMap.toList p --TODO: I think this runEventM is OK, since no events are firing at this time, but it might not be
1659− liftIO $ writeIORef parentsRef $! newParents
1660− return subscriptionsToKill
1661 defer $ SomeMergeInit $ do
1754 defer $ SomeMergeInit $ do
1662 let s = Subscriber
1755 let s = Subscriber
1663 { subscriberPropagate = \a -> {-# SCC "traverseMergeChange" #-} do
1756 { subscriberPropagate = \a -> {-# SCC "traverseMergeChange" #-} do
@@ -1672,9 +1765,7 @@ mergeCheap d = Event $ \sub -> do
1672 -- If we don't do this, there are certain cases where mergeCheap will fail to properly retain
1765 -- If we don't do this, there are certain cases where mergeCheap will fail to properly retain
1673 -- its subscription.
1766 -- its subscription.
1674 liftIO $ writeIORef changeSubdRef (s, changeSubscription)
1767 liftIO $ writeIORef changeSubdRef (s, changeSubscription)
1675− let unsubscribeAll = do
1676− parents <- readIORef parentsRef
1768+ let unsubscribeAll = destroy =<< readIORef parentsRef
1677− forM_ (DMap.toList parents) $ \(_ :=> MergeSubscribedParent s) -> unsubscribe s
1678 return ( EventSubscription unsubscribeAll $ EventSubscribed heightRef $ toAny (parentsRef, changeSubdRef)
1769 return ( EventSubscription unsubscribeAll $ EventSubscribed heightRef $ toAny (parentsRef, changeSubdRef)
@@ -1972,6 +2063,8 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
1972 unsafeBuildIncremental readV0 dv = SpiderIncremental $ dynamicDyn $ unsafeDyn (coerce readV0) $ unSpiderEvent dv
2063 unsafeBuildIncremental readV0 dv = SpiderIncremental $ dynamicDyn $ unsafeDyn (coerce readV0) $ unSpiderEvent dv
1973 {-# INLINABLE mergeIncremental #-}
2064 {-# INLINABLE mergeIncremental #-}
1974 mergeIncremental = SpiderEvent . merge . (unsafeCoerce :: Dynamic x (PatchDMap k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMap k (Event x))) . unSpiderIncremental
2065 mergeIncremental = SpiderEvent . merge . (unsafeCoerce :: Dynamic x (PatchDMap k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMap k (Event x))) . unSpiderIncremental
2066+ {-# INLINABLE mergeIncrementalWithMove #-}
2067+ mergeIncrementalWithMove = SpiderEvent . mergeWithMove . (unsafeCoerce :: Dynamic x (PatchDMapWithMove k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMapWithMove k (Event x))) . unSpiderIncremental
1975 {-# INLINABLE currentIncremental #-}
2068 {-# INLINABLE currentIncremental #-}
1976 currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
2069 currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
1977 {-# INLINABLE updatedIncremental #-}
2070 {-# INLINABLE updatedIncremental #-}