@@ -17,6 +17,7 @@ build-depends:
1717{-# LANGUAGE TypeApplications #-}
1818
1919import Control.Applicative (Alternative (.. ))
20+ import Control.Monad (unless )
2021import qualified Data.ByteString.Lazy as BSL
2122import Data.Csv
2223import Data.List (zip4 )
@@ -32,33 +33,9 @@ import qualified Data.Text.IO as TIO
3233import Data.Traversable (for )
3334import Data.Vector (Vector )
3435import qualified Data.Vector as V
36+ import System.Exit (ExitCode (.. ), exitWith )
3537import System.Process (readProcess )
3638
37- type Function = Text
38- type MergePolicy = Text
39- type MergeSchedule = Text
40- type WorstCaseDiskIOComplexity = Text
41- type Condition = Text
42-
43- data DiskIOComplexity = DiskIOComplexity
44- { function :: Function
45- , mergePolicy :: Maybe MergePolicy
46- , mergeSchedule :: Maybe MergeSchedule
47- , worstCaseDiskIOComplexity :: WorstCaseDiskIOComplexity
48- , condition :: Maybe Condition
49- }
50- deriving (Eq , Show )
51-
52- looseEq :: DiskIOComplexity -> DiskIOComplexity -> Bool
53- dioc1 `looseEq` dioc2 =
54- and
55- [ dioc1. function == dioc2. function
56- , dioc1. mergePolicy == dioc2. mergePolicy
57- , dioc1. mergeSchedule == dioc2. mergeSchedule
58- , dioc1. worstCaseDiskIOComplexity == dioc2. worstCaseDiskIOComplexity
59- , isNothing dioc1. condition || dioc1. condition == dioc2. condition
60- ]
61-
6239main :: IO ()
6340main = do
6441 -- Get the disk I/O complexities from the package description
@@ -78,91 +55,109 @@ main = do
7855
7956 -- Comparing Database.LSMTree.Simple to Database.LSMTree
8057 putStrLn " Comparing Database.LSMTree.Simple to Database.LSMTree:"
81- diskIOComplexityComparisonSimpleToFull <-
82- for (concat . M. elems $ mapForSimpleApi) $ \ diskIOComplexity @ DiskIOComplexity {.. } -> do
58+ comparisonSimpleToFull <-
59+ fmap concat . for (concat . M. elems $ mapForSimpleApi) $ \ simpleEntry @ DiskIOComplexity {.. } -> do
8360 case M. lookup function mapForFullApi of
8461 Nothing ->
85- pure [(" Database.LSMTree.Simple" , diskIOComplexity )]
86- Just fullDiskIOComplexities
87- | diskIOComplexity `elem` fullDiskIOComplexities -> pure []
88- | otherwise -> pure ((" Database.LSMTree.Simple" , diskIOComplexity ) : ((" Database.LSMTree" ,) <$> fullDiskIOComplexities ))
89- TIO. putStrLn . prettyDiskIOComplexityTable . concat $ diskIOComplexityComparisonSimpleToFull
62+ pure [(" Database.LSMTree.Simple" , simpleEntry )]
63+ Just fullEntries
64+ | simpleEntry `elem` fullEntries -> pure []
65+ | otherwise -> pure ((" Database.LSMTree.Simple" , simpleEntry ) : ((" Database.LSMTree" ,) <$> fullEntries ))
66+ TIO. putStrLn ( prettyDiskIOComplexityTable comparisonSimpleToFull)
9067
9168 -- Comparing lsm-tree.cabal to Database.LSMTree
9269 putStrLn " Comparing lsm-tree.cabal to Database.LSMTree:"
93- diskIOComplexityComparisonPackageDescriptionToFull <-
94- for (concat . M. elems $ mapForPackageDescription) $ \ diskIOComplexity @ DiskIOComplexity {.. } -> do
70+ comparisonPackageDescriptionToFull <-
71+ fmap concat . for (concat . M. elems $ mapForPackageDescription) $ \ simpleEntry @ DiskIOComplexity {.. } -> do
9572 case M. lookup function mapForFullApi of
9673 Nothing ->
97- pure [(" lsm-tree.cabal" , diskIOComplexity)]
98- Just fullDiskIOComplexities
99- | any (looseEq diskIOComplexity) fullDiskIOComplexities -> pure []
100- | otherwise -> pure ((" lsm-tree.cabal" , diskIOComplexity) : ((" Database.LSMTree" ,) <$> fullDiskIOComplexities))
101- TIO. putStrLn . prettyDiskIOComplexityTable . concat $ diskIOComplexityComparisonPackageDescriptionToFull
74+ pure [(" lsm-tree.cabal" , simpleEntry)]
75+ Just fullEntries
76+ | any (looseEq simpleEntry) fullEntries -> pure []
77+ | otherwise -> pure ((" lsm-tree.cabal" , simpleEntry) : ((" Database.LSMTree" ,) <$> fullEntries))
78+ TIO. putStrLn (prettyDiskIOComplexityTable comparisonPackageDescriptionToFull)
79+
80+ -- Set the exit code based on whether any differences were found
81+ unless (null comparisonSimpleToFull && null comparisonPackageDescriptionToFull) $
82+ exitWith (ExitFailure 1 )
10283
10384--------------------------------------------------------------------------------
10485-- Helper functions
10586--------------------------------------------------------------------------------
10687
88+ type Function = Text
89+ type MergePolicy = Text
90+ type MergeSchedule = Text
91+ type WorstCaseDiskIOComplexity = Text
92+ type Condition = Text
93+
94+ data DiskIOComplexity = DiskIOComplexity
95+ { function :: Function
96+ , mergePolicy :: Maybe MergePolicy
97+ , mergeSchedule :: Maybe MergeSchedule
98+ , worstCaseDiskIOComplexity :: WorstCaseDiskIOComplexity
99+ , condition :: Maybe Condition
100+ }
101+ deriving (Eq , Show )
102+
103+ -- | Loose equality which is used when comparing the disk I/O complexities
104+ -- listed in the package description to those in the modules. Those in the
105+ -- package description do not list complex side conditions, such as all
106+ -- tables having been closed beforehand, or all tables having the same merge
107+ -- policy. Therefore, this equality disregards mismatches when the first
108+ -- entry does not list a condition.
109+ looseEq :: DiskIOComplexity -> DiskIOComplexity -> Bool
110+ entry1 `looseEq` entry2 =
111+ and
112+ [ entry1. function == entry2. function
113+ , entry1. mergePolicy == entry2. mergePolicy
114+ , entry1. mergeSchedule == entry2. mergeSchedule
115+ , entry1. worstCaseDiskIOComplexity == entry2. worstCaseDiskIOComplexity
116+ , isNothing entry1. condition || entry1. condition == entry2. condition
117+ ]
118+
107119-- | Typeset a tagged list of 'DiskIOComplexity' records as an aligned table.
108120prettyDiskIOComplexityTable :: [(Text , DiskIOComplexity )] -> Text
109- prettyDiskIOComplexityTable diskIOComplexities =
121+ prettyDiskIOComplexityTable [] = " No differences found.\n "
122+ prettyDiskIOComplexityTable entries =
110123 T. unlines
111124 [ T. unwords
112- [ tag `padUpTo` maxTagLen
113- , function `padUpTo` maxFunctionLen
114- , condition `padUpTo` maxConditionLen
115- , worstCaseDiskIOComplexity `padUpTo` maxWorstCaseDiskIOComplexityLen
125+ [ prettyCellForColumn tag tags
126+ , prettyCellForColumn function functions
127+ , prettyCellForColumn fullCondition fullConditions
128+ , prettyCellForColumn worstCaseDiskIOComplexity worstCaseDiskIOComplexities
116129 ]
117- | (tag, function, condition , worstCaseDiskIOComplexity) <-
118- zip4 tags functions conditions worstCaseDiskIOComplexities
130+ | (tag, function, fullCondition , worstCaseDiskIOComplexity) <-
131+ zip4 tags functions fullConditions worstCaseDiskIOComplexities
119132 ]
120133 where
121- tags = fst <$> diskIOComplexities
122- maxTagLen = maximum (T. length <$> tags)
134+ tags = fst <$> entries
135+ functions = ((. function) . snd ) <$> entries
136+ fullConditions = (prettyFullCondition . snd ) <$> entries
137+ worstCaseDiskIOComplexities = ((. worstCaseDiskIOComplexity) . snd ) <$> entries
123138
124- functions = (( . function) . snd ) <$> diskIOComplexities
125- maxFunctionLen = maximum (T. length <$> functions)
139+ prettyCellForColumn :: Text -> [ Text ] -> Text
140+ prettyCellForColumn cell column = cell <> T. replicate ( maximum (T. length <$> column) - T. length cell) " "
126141
127- conditions = (prettyCondition . snd ) <$> diskIOComplexities
128- maxConditionLen = maximum (T. length <$> conditions)
129-
130- worstCaseDiskIOComplexities = ((. worstCaseDiskIOComplexity) . snd ) <$> diskIOComplexities
131- maxWorstCaseDiskIOComplexityLen = maximum (T. length <$> worstCaseDiskIOComplexities)
132-
133- padUpTo :: Text -> Int -> Text
134- padUpTo txt len = txt <> T. replicate (len - T. length txt) " "
135-
136- prettyCondition :: DiskIOComplexity -> Text
137- prettyCondition DiskIOComplexity {.. } =
138- fromMaybe " *" (unionMaybeWith slash mergePolicy (unionMaybeWith slash mergeSchedule condition))
142+ prettyFullCondition :: DiskIOComplexity -> Text
143+ prettyFullCondition DiskIOComplexity {.. } =
144+ fromMaybe " *" mergePolicy `slashWith` mergeSchedule `slashWith` condition
139145 where
140- slash :: Text -> Text -> Text
141- x `slash` y = x <> " /" <> y
142-
143- unionMaybeWith :: (a -> a -> a ) -> Maybe a -> Maybe a -> Maybe a
144- unionMaybeWith op (Just x) (Just y) = Just (x `op` y)
145- unionMaybeWith _op (Just x) Nothing = Just x
146- unionMaybeWith _op Nothing (Just y) = Just y
147- unionMaybeWith _op Nothing Nothing = Nothing
146+ slashWith :: Text -> Maybe Text -> Text
147+ slashWith x my = maybe x (\ y -> x <> " /" <> y) my
148148
149149-- | Structure vector of 'DiskIOComplexity' records into lookup table by function name.
150150buildDiskIOComplexityMap :: Vector DiskIOComplexity -> Map Function [DiskIOComplexity ]
151151buildDiskIOComplexityMap = M. unionsWith (<>) . fmap toSingletonMap . V. toList
152152 where
153153 toSingletonMap :: DiskIOComplexity -> Map Function [DiskIOComplexity ]
154- toSingletonMap diskIOComplexity = M. singleton diskIOComplexity . function [diskIOComplexity ]
154+ toSingletonMap simpleEntry = M. singleton simpleEntry . function [simpleEntry ]
155155
156156-- | Parse CSV file into vector of 'DiskIOComplexity' records.
157157decodeDiskIOComplexities :: String -> Vector DiskIOComplexity
158158decodeDiskIOComplexities =
159159 either error snd . decodeByName . BSL. fromStrict . TE. encodeUtf8 . T. pack
160160
161- -- | CSV file header for 'DiskIOComplexity' records.
162- diskIOComplexityHeader :: Header
163- diskIOComplexityHeader =
164- header [" Function" , " Merge policy" , " Merge schedule" , " Worst-case disk I/O complexity" , " Condition" ]
165-
166161normaliseWorstCaseDiskIOComplexity :: WorstCaseDiskIOComplexity -> WorstCaseDiskIOComplexity
167162normaliseWorstCaseDiskIOComplexity =
168163 T. replace " + " " +" . T. replace " +" " +" . T. replace " \\ " " \\ " . T. replace " " " " . T. replace " \\ :" " "
0 commit comments