{-# OPTIONS_GHC -fno-warn-orphans #-} module Darcs.Patch.Prim.V1 ( Prim ) where import Darcs.Prelude import Data.Maybe ( fromMaybe ) import Darcs.Patch.Prim.V1.Apply () import Darcs.Patch.Prim.V1.Coalesce () import Darcs.Patch.Prim.V1.Commute () import Darcs.Patch.Prim.V1.Core ( Prim ) import Darcs.Patch.Prim.V1.Details () import Darcs.Patch.Prim.V1.Mangle () import Darcs.Patch.Prim.V1.Read () import Darcs.Patch.Prim.V1.Show () import Darcs.Patch.Commute ( Commute(..), commuteFL ) import Darcs.Patch.Invert ( Invert(..), dropInverses ) import Darcs.Patch.Prim.Class ( PrimSift(..) , PrimClassify ( primIsHunk , primIsBinary , primIsSetpref , primIsAddfile , primIsAdddir ) , PrimCanonize(tryToShrink) ) import Darcs.Patch.Witnesses.Eq ( Eq2(..), EqCheck(..) ) import Darcs.Patch.Witnesses.Ordered ( FL(..) , RL(..) , (:>)(..) , allFL , lengthFL , reverseFL , filterOutFLFL ) import Darcs.Patch.Witnesses.Sealed ( Sealed(..), seal ) import Darcs.Patch.Witnesses.Unsafe ( unsafeCoerceP ) instance PrimSift Prim where siftForPending = v1siftForPending where -- | An optimized version of 'siftForPending' that avoids commutation -- in case all prim patches are "simple" i.e. hunk, binary, or setpref. -- Otherwise it returns the original sequence. crudeSift :: forall prim wX wY. PrimClassify prim => FL prim wX wY -> FL prim wX wY crudeSift xs = if isSimple xs then filterOutFLFL ishunkbinary xs else xs where ishunkbinary :: prim wA wB -> EqCheck wA wB ishunkbinary x | primIsHunk x || primIsBinary x = unsafeCoerceP IsEq | otherwise = NotEq isSimple = allFL $ \x -> primIsHunk x || primIsBinary x || primIsSetpref x -- | Alternately 'sift' and 'tryToShrink' until shrinking no longer reduces -- the length of the sequence. Here, 'sift' means to commute hunks -- and binary patches to the end of the sequence and then drop them. v1siftForPending :: forall prim wX wY. (Commute prim, Invert prim, Eq2 prim, PrimCanonize prim, PrimClassify prim) => FL prim wX wY -> Sealed (FL prim wX) v1siftForPending simple_ps -- optimization: no need to sift if only adddir or addfile are present | allFL (\p -> primIsAddfile p || primIsAdddir p) oldps = seal oldps | otherwise = case sift (reverseFL oldps) NilFL of Sealed x -> let ps = tryToShrink x in if (lengthFL ps < lengthFL oldps) then v1siftForPending ps else seal ps where oldps = fromMaybe simple_ps $ dropInverses $ crudeSift simple_ps -- get rid of any hunk/binary patches that we can commute out the -- back (ie. we work our way backwards, pushing the patches down -- to the very end and popping them off; so in (addfile f :> hunk) -- we can nuke the hunk, but not so in (hunk :> replace) sift :: RL prim wA wB -> FL prim wB wC -> Sealed (FL prim wA) sift NilRL sofar = seal sofar sift (ps :<: p) sofar | primIsHunk p || primIsBinary p , Just (sofar' :> _) <- commuteFL (p :> sofar) = sift ps sofar' | otherwise = sift ps (p :>: sofar)