@@ -28,7 +28,7 @@ module Data.HashMap.Internal.Debug
2828import Data.Bits (complement , countTrailingZeros , popCount , shiftL ,
2929 unsafeShiftL , (.&.) , (.|.) )
3030import Data.Hashable (Hashable )
31- import Data.HashMap.Internal (Bitmap , Hash , HashMap (.. ), Leaf (.. ),
31+ import Data.HashMap.Internal (Bitmap , Hash , HashMap (.. ), Leaf (.. ), Tree ( .. ),
3232 bitsPerSubkey , fullBitmap , hash ,
3333 isLeafOrCollision , maxChildren , sparseIndex )
3434import Data.Semigroup (Sum (.. ))
@@ -65,6 +65,7 @@ data Error k
6565 | INV8_bad_Full_size ! Int
6666 | INV9_Collision_size ! Int
6767 | INV10_Collision_duplicate_key k ! Hash
68+ | INV11_Negative_HM_Size ! Int
6869 deriving (Eq , Show )
6970
7071-- TODO: Name this 'Index'?!
@@ -95,55 +96,60 @@ hashMatchesSubHashPath (SubHashPath ph l) h = maskToLength h l == ph
9596 maskToLength h' l' = h' .&. complement (complement 0 `shiftL` l')
9697
9798valid :: Hashable k => HashMap k v -> Validity k
98- valid Empty = Valid
99- valid t = validInternal initialSubHashPath t
99+ valid (HashMap sz hm) = if sz >= 0
100+ then valid' hm
101+ else Invalid (INV11_Negative_HM_Size $ A. unSize sz) initialSubHashPath
100102 where
101- validInternal p Empty = Invalid INV1_internal_Empty p
102- validInternal p (Leaf h l) = validHash p h <> validLeaf p h l
103- validInternal p (Collision h ary) = validHash p h <> validCollision p h ary
104- validInternal p (BitmapIndexed b ary) = validBitmapIndexed p b ary
105- validInternal p (Full ary) = validFull p ary
103+ valid' :: Hashable k => Tree k v -> Validity k
104+ valid' Empty = Valid
105+ valid' t = validInternal initialSubHashPath t
106+ where
107+ validInternal p Empty = Invalid INV1_internal_Empty p
108+ validInternal p (Leaf h l) = validHash p h <> validLeaf p h l
109+ validInternal p (Collision h ary) = validHash p h <> validCollision p h ary
110+ validInternal p (BitmapIndexed b ary) = validBitmapIndexed p b ary
111+ validInternal p (Full ary) = validFull p ary
106112
107- validHash p h | hashMatchesSubHashPath p h = Valid
108- | otherwise = Invalid (INV6_misplaced_hash h) p
113+ validHash p h | hashMatchesSubHashPath p h = Valid
114+ | otherwise = Invalid (INV6_misplaced_hash h) p
109115
110- validLeaf p h (L k _) | hash k == h = Valid
111- | otherwise = Invalid (INV7_key_hash_mismatch k h) p
116+ validLeaf p h (L k _) | hash k == h = Valid
117+ | otherwise = Invalid (INV7_key_hash_mismatch k h) p
112118
113- validCollision p h ary = validCollisionSize <> A. foldMap (validLeaf p h) ary <> distinctKeys
114- where
115- n = A. length ary
116- validCollisionSize | n < 2 = Invalid (INV9_Collision_size n) p
117- | otherwise = Valid
118- distinctKeys = A. foldMap (\ (L k _) -> appearsOnce k) ary
119- appearsOnce k | A. foldMap (\ (L k' _) -> if k' == k then Sum @ Int 1 else Sum 0 ) ary == 1 = Valid
120- | otherwise = Invalid (INV10_Collision_duplicate_key k h) p
121-
122- validBitmapIndexed p b ary = validBitmap <> validArraySize <> validSubTrees p b ary
123- where
124- validBitmap | b .&. complement fullBitmap == 0 = Valid
125- | otherwise = Invalid (INV2_Bitmap_unexpected_1_bits b) p
126- n = A. length ary
127- validArraySize | n < 1 || n >= maxChildren = Invalid (INV3_bad_BitmapIndexed_size n) p
128- | popCount b == n = Valid
129- | otherwise = Invalid (INV4_bitmap_array_size_mismatch b n) p
130-
131- validSubTrees p b ary
132- | A. length ary == 1
133- , isLeafOrCollision (A. index ary 0 )
134- = Invalid INV5_BitmapIndexed_invalid_single_subtree p
135- | otherwise = go b
136- where
137- go 0 = Valid
138- go b' = validInternal (addSubHash p (fromIntegral c)) (A. index ary i) <> go b''
119+ validCollision p h ary = validCollisionSize <> A. foldMap (validLeaf p h) ary <> distinctKeys
139120 where
140- c = countTrailingZeros b'
141- m = 1 `unsafeShiftL` c
142- i = sparseIndex b m
143- b'' = b' .&. complement m
144-
145- validFull p ary = validArraySize <> validSubTrees p fullBitmap ary
146- where
147- n = A. length ary
148- validArraySize | n == maxChildren = Valid
149- | otherwise = Invalid (INV8_bad_Full_size n) p
121+ n = A. length ary
122+ validCollisionSize | n < 2 = Invalid (INV9_Collision_size n) p
123+ | otherwise = Valid
124+ distinctKeys = A. foldMap (\ (L k _) -> appearsOnce k) ary
125+ appearsOnce k | A. foldMap (\ (L k' _) -> if k' == k then Sum @ Int 1 else Sum 0 ) ary == 1 = Valid
126+ | otherwise = Invalid (INV10_Collision_duplicate_key k h) p
127+
128+ validBitmapIndexed p b ary = validBitmap <> validArraySize <> validSubTrees p b ary
129+ where
130+ validBitmap | b .&. complement fullBitmap == 0 = Valid
131+ | otherwise = Invalid (INV2_Bitmap_unexpected_1_bits b) p
132+ n = A. length ary
133+ validArraySize | n < 1 || n >= maxChildren = Invalid (INV3_bad_BitmapIndexed_size n) p
134+ | popCount b == n = Valid
135+ | otherwise = Invalid (INV4_bitmap_array_size_mismatch b n) p
136+
137+ validSubTrees p b ary
138+ | A. length ary == 1
139+ , isLeafOrCollision (A. index ary 0 )
140+ = Invalid INV5_BitmapIndexed_invalid_single_subtree p
141+ | otherwise = go b
142+ where
143+ go 0 = Valid
144+ go b' = validInternal (addSubHash p (fromIntegral c)) (A. index ary i) <> go b''
145+ where
146+ c = countTrailingZeros b'
147+ m = 1 `unsafeShiftL` c
148+ i = sparseIndex b m
149+ b'' = b' .&. complement m
150+
151+ validFull p ary = validArraySize <> validSubTrees p fullBitmap ary
152+ where
153+ n = A. length ary
154+ validArraySize | n == maxChildren = Valid
155+ | otherwise = Invalid (INV8_bad_Full_size n) p
0 commit comments