Skip to content

Commit e79f2ad

Browse files
authored
Merge pull request #54 from haskellari/small-impr
Small improvement in speed
2 parents e897d6a + 6f1ffd0 commit e79f2ad

File tree

4 files changed

+58
-34
lines changed

4 files changed

+58
-34
lines changed

src/Data/TreeDiff/Class.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ import qualified Data.Strict as Strict
101101
-- these
102102
import Data.These (These (..))
103103

104+
-- primitive
105+
-- import qualified Data.Primitive as Prim
106+
104107
-- $setup
105108
-- >>> :set -XDeriveGeneric
106109
-- >>> import Data.Foldable (traverse_)
@@ -571,3 +574,9 @@ instance (ToExpr a, ToExpr b) => ToExpr (These a b) where
571574
toExpr (This x) = App "This" [toExpr x]
572575
toExpr (That y) = App "That" [toExpr y]
573576
toExpr (These x y) = App "These " [toExpr x, toExpr y]
577+
578+
-------------------------------------------------------------------------------
579+
-- primitive
580+
-------------------------------------------------------------------------------
581+
582+
-- TODO: add instances

src/Data/TreeDiff/List.hs

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
-- | A list diff.
33
module Data.TreeDiff.List (diffBy, Edit (..)) where
44

5-
import Control.DeepSeq (NFData (..))
6-
import Data.List.Compat (sortOn)
5+
import Control.DeepSeq (NFData (..))
76

8-
import qualified Data.Vector as V
7+
import qualified Data.Primitive as P
98

109
-- | List edit operations
1110
--
@@ -39,43 +38,55 @@ instance NFData a => NFData (Edit a) where
3938
-- of more obviously correct implementation.
4039
--
4140
diffBy :: forall a. (a -> a -> Bool) -> [a] -> [a] -> [Edit a]
42-
diffBy eq xs' ys' = reverse (snd (lcs xn yn))
41+
diffBy eq xs' ys' = reverse (getCell (lcs xn yn))
4342
where
44-
xn = V.length xs
45-
yn = V.length ys
43+
xn = length xs'
44+
yn = length ys'
4645

47-
xs = V.fromList xs'
48-
ys = V.fromList ys'
46+
xs = P.arrayFromListN xn xs'
47+
ys = P.arrayFromListN yn ys'
4948

50-
memo :: V.Vector (Int, [Edit a])
51-
memo = V.fromList
49+
memo :: P.Array (Cell [Edit a])
50+
memo = P.arrayFromListN ((xn + 1) * (yn + 1))
5251
[ impl xi yi
5352
| xi <- [0 .. xn]
5453
, yi <- [0 .. yn]
5554
]
5655

57-
lcs :: Int -> Int -> (Int, [Edit a])
58-
lcs xi yi = memo V.! (yi + xi * (yn + 1))
56+
lcs :: Int -> Int -> Cell [Edit a]
57+
lcs xi yi = P.indexArray memo (yi + xi * (yn + 1))
5958

60-
impl :: Int -> Int -> (Int, [Edit a])
61-
impl 0 0 = (0, [])
62-
impl 0 m = case lcs 0 (m-1) of
63-
(w, edit) -> (w + 1, Ins (ys V.! (m - 1)) : edit)
64-
impl n 0 = case lcs (n -1) 0 of
65-
(w, edit) -> (w + 1, Del (xs V.! (n - 1)) : edit)
59+
impl :: Int -> Int -> Cell [Edit a]
60+
impl 0 0 = Cell 0 []
61+
impl 0 m = case lcs 0 (m - 1) of
62+
Cell w edit -> Cell (w + 1) (Ins (P.indexArray ys (m - 1)) : edit)
63+
impl n 0 = case lcs (n - 1) 0 of
64+
Cell w edit -> Cell (w + 1) (Del (P.indexArray xs (n - 1)) : edit)
6665

67-
impl n m = head $ sortOn fst
68-
[ edit
69-
, bimap (+1) (Ins y :) (lcs n (m - 1))
70-
, bimap (+1) (Del x :) (lcs (n - 1) m)
71-
]
66+
impl n m = bestOfThree
67+
edit
68+
(bimap (+1) (Ins y :) (lcs n (m - 1)))
69+
(bimap (+1) (Del x :) (lcs (n - 1) m))
7270
where
73-
x = xs V.! (n - 1)
74-
y = ys V.! (m - 1)
71+
x = P.indexArray xs (n - 1)
72+
y = P.indexArray ys (m - 1)
7573

7674
edit
7775
| eq x y = bimap id (Cpy x :) (lcs (n - 1) (m - 1))
78-
| otherwise = bimap (+1) (Swp x y :) (lcs (n -1 ) (m - 1))
76+
| otherwise = bimap (+1) (Swp x y :) (lcs (n - 1) (m - 1))
77+
78+
data Cell a = Cell !Int !a
79+
80+
getCell :: Cell a -> a
81+
getCell (Cell _ x) = x
82+
83+
bestOfThree :: Cell a -> Cell a -> Cell a -> Cell a
84+
bestOfThree a@(Cell i _x) b@(Cell j _y) c@(Cell k _z)
85+
| i <= j
86+
= if i <= k then a else c
87+
88+
| otherwise
89+
= if j <= k then b else c
7990

80-
bimap :: (a -> c) -> (b -> d) -> (a, b) -> (c, d)
81-
bimap f g (x, y) = (f x, g y)
91+
bimap :: (Int -> Int) -> (a -> b) -> Cell a -> Cell b
92+
bimap f g (Cell i x) = Cell (f i) (g x)

tests/Tests.hs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
{-# LANGUAGE DeriveGeneric #-}
1+
{-# LANGUAGE DeriveGeneric #-}
22
module Main (main) where
33

44
import Data.Proxy (Proxy (..))
5-
import Data.TreeDiff
6-
import Data.TreeDiff.Golden
7-
import Data.TreeDiff.QuickCheck
85
import GHC.Generics (Generic)
96
import Prelude ()
107
import Prelude.Compat
@@ -18,6 +15,10 @@ import qualified Text.PrettyPrint.ANSI.Leijen as WL
1815
import qualified Text.Trifecta as T (eof, parseString)
1916
import qualified Text.Trifecta.Result as T (ErrInfo (..), Result (..))
2017

18+
import Data.TreeDiff
19+
import Data.TreeDiff.Golden
20+
import Data.TreeDiff.QuickCheck
21+
2122
main :: IO ()
2223
main = defaultMain $ testGroup "tests"
2324
[ testProperty "trifecta-pretty roundtrip" roundtripTrifectaPretty
@@ -26,7 +27,7 @@ main = defaultMain $ testGroup "tests"
2627
]
2728

2829
-------------------------------------------------------------------------------
29-
-- QuickCheck: ediffEq
30+
-- Roundtrip
3031
-------------------------------------------------------------------------------
3132

3233
-- | This property tests that we can parse pretty printed 'Expr'.

tree-diff.cabal

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ library
100100
, bytestring-builder ^>=0.10.8.2.0
101101
, hashable ^>=1.2.7.0 || ^>=1.3.0.0
102102
, parsers ^>=0.12.10
103+
, primitive ^>=0.7.1.0
103104
, QuickCheck ^>=2.14.2
104105
, scientific ^>=0.3.6.2
105106
, semialign >=1.1 && <1.3
@@ -180,4 +181,6 @@ benchmark tree-diff-bench
180181
, tree-diff
181182

182183
-- extra dependencies
183-
build-depends: criterion ^>=1.5.9.0, Diff ^>=0.4.0
184+
build-depends:
185+
, criterion ^>=1.5.9.0
186+
, Diff ^>=0.4.0

0 commit comments

Comments
 (0)