@@ -133,29 +133,38 @@ data PreExistingRunData k v b =
133133 | PreExistingMergingRunData (MergingRunData MR. LevelMergeType k v b )
134134 deriving stock (Show , Eq )
135135
136+ mergingTreeIsStructurallyEmpty :: MergingTreeData k v b -> Bool
137+ mergingTreeIsStructurallyEmpty = \ case
138+ CompletedTreeMergeData _ -> False -- could be, but we match MT
139+ OngoingTreeMergeData _ -> False
140+ PendingLevelMergeData ps t -> null ps && null t
141+ PendingUnionMergeData ts -> null ts
142+
136143-- | See @treeInvariant@ in prototype.
137144mergingTreeDataInvariant :: MergingTreeData k v b -> Either String ()
138- mergingTreeDataInvariant = \ case
139- CompletedTreeMergeData _rd ->
140- Right ()
141- OngoingTreeMergeData mr ->
142- mergingRunDataInvariant mr
143- PendingLevelMergeData prs t -> do
144- assertI " pending level merges have at least one input" $
145- length prs + length t > 0
146- for_ prs $ \ case
147- PreExistingRunData _r -> Right ()
148- PreExistingMergingRunData mr -> mergingRunDataInvariant mr
149- for_ (drop 1 (reverse prs)) $ \ case
150- PreExistingRunData _r -> Right ()
151- PreExistingMergingRunData mr ->
152- assertI " only the last pre-existing run can be a last level merge" $
153- mergingRunDataMergeType mr == MR. MergeMidLevel
154- for_ t mergingTreeDataInvariant
155- PendingUnionMergeData ts -> do
156- assertI " pending union merges are non-trivial (at least two inputs)" $
157- length ts >= 2
158- for_ ts mergingTreeDataInvariant
145+ mergingTreeDataInvariant mtd
146+ | mergingTreeIsStructurallyEmpty mtd = Right ()
147+ | otherwise = case mtd of
148+ CompletedTreeMergeData _rd ->
149+ Right ()
150+ OngoingTreeMergeData mr ->
151+ mergingRunDataInvariant mr
152+ PendingLevelMergeData prs t -> do
153+ assertI " pending level merges have at least one input" $
154+ length prs + length t > 0
155+ for_ prs $ \ case
156+ PreExistingRunData _r -> Right ()
157+ PreExistingMergingRunData mr -> mergingRunDataInvariant mr
158+ for_ (drop 1 (reverse prs)) $ \ case
159+ PreExistingRunData _r -> Right ()
160+ PreExistingMergingRunData mr ->
161+ assertI " only the last pre-existing run can be a last level merge" $
162+ mergingRunDataMergeType mr == MR. MergeMidLevel
163+ for_ t mergingTreeDataInvariant
164+ PendingUnionMergeData ts -> do
165+ assertI " pending union merges are non-trivial (at least two inputs)" $
166+ length ts >= 2
167+ for_ ts mergingTreeDataInvariant
159168 where
160169 assertI msg False = Left msg
161170 assertI _ True = Right ()
@@ -241,9 +250,16 @@ instance ( Ord k, Arbitrary k, Arbitrary v, Arbitrary b
241250
242251genMergingTreeData ::
243252 Ord k => Gen k -> Gen v -> Gen b -> Gen (MergingTreeData k v b )
244- genMergingTreeData genKey genVal genBlob = QC. sized $ \ s -> do
245- treeSize <- QC. chooseInt (1 , 1 + (s `div` 4 )) -- up to 26
246- genMergingTreeDataOfSize genKey genVal genBlob treeSize
253+ genMergingTreeData genKey genVal genBlob =
254+ QC. frequency
255+ -- Only at the root, we can have pending merges with no children, see
256+ -- 'MR.newPendingLevelMerge' and 'MR.newPendingUnionMerge'.
257+ [ ( 1 , pure $ PendingLevelMergeData [] Nothing )
258+ , ( 1 , pure $ PendingUnionMergeData [] )
259+ , (50 , QC. sized $ \ s -> do
260+ treeSize <- QC. chooseInt (1 , 1 + (s `div` 4 )) -- up to 26
261+ genMergingTreeDataOfSize genKey genVal genBlob treeSize)
262+ ]
247263
248264-- | Minimal returned size will be 1. Doesn't generate structurally empty trees!
249265--
0 commit comments