@@ -89,6 +89,7 @@ module Data.HashMap.Base
89
89
, updateOrConcatWith
90
90
, updateOrConcatWithKey
91
91
, filterMapAux
92
+ , equalKeys
92
93
) where
93
94
94
95
#if __GLASGOW_HASKELL__ < 710
@@ -125,7 +126,15 @@ import GHC.Exts (isTrue#)
125
126
import qualified GHC.Exts as Exts
126
127
#endif
127
128
129
+ #if MIN_VERSION_base(4,9,0)
130
+ import Data.Functor.Classes
131
+ #endif
132
+
133
+ #if MIN_VERSION_hashable(1,2,5)
134
+ import qualified Data.Hashable.Lifted as H
135
+ #endif
128
136
137
+ -- | A set of values. A set cannot contain duplicate values.
129
138
------------------------------------------------------------------------
130
139
131
140
-- | Convenience function. Compute a hash value for the given value.
@@ -203,6 +212,25 @@ type Hash = Word
203
212
type Bitmap = Word
204
213
type Shift = Int
205
214
215
+ #if MIN_VERSION_base(4,9,0)
216
+ instance Show2 HashMap where
217
+ liftShowsPrec2 spk slk spv slv d m =
218
+ showsUnaryWith (liftShowsPrec sp sl) " fromList" d (toList m)
219
+ where
220
+ sp = liftShowsPrec2 spk slk spv slv
221
+ sl = liftShowList2 spk slk spv slv
222
+
223
+ instance Show k => Show1 (HashMap k ) where
224
+ liftShowsPrec = liftShowsPrec2 showsPrec showList
225
+
226
+ instance (Eq k , Hashable k , Read k ) => Read1 (HashMap k ) where
227
+ liftReadsPrec rp rl = readsData $
228
+ readsUnaryWith (liftReadsPrec rp' rl') " fromList" fromList
229
+ where
230
+ rp' = liftReadsPrec rp rl
231
+ rl' = liftReadList rp rl
232
+ #endif
233
+
206
234
instance (Eq k , Hashable k , Read k , Read e ) => Read (HashMap k e ) where
207
235
readPrec = parens $ prec 10 $ do
208
236
Ident " fromList" <- lexP
@@ -218,26 +246,102 @@ instance (Show k, Show v) => Show (HashMap k v) where
218
246
instance Traversable (HashMap k ) where
219
247
traverse f = traverseWithKey (const f)
220
248
249
+ #if MIN_VERSION_base(4,9,0)
250
+ instance Eq2 HashMap where
251
+ liftEq2 = equal
252
+
253
+ instance Eq k => Eq1 (HashMap k ) where
254
+ liftEq = equal (==)
255
+ #endif
256
+
221
257
instance (Eq k , Eq v ) => Eq (HashMap k v ) where
222
- (==) = equal
258
+ (==) = equal (==) (==)
223
259
224
- equal :: (Eq k , Eq v ) => HashMap k v -> HashMap k v -> Bool
225
- equal t1 t2 = go (toList' t1 [] ) (toList' t2 [] )
260
+ equal :: (k -> k' -> Bool ) -> (v -> v' -> Bool )
261
+ -> HashMap k v -> HashMap k' v' -> Bool
262
+ equal eqk eqv t1 t2 = go (toList' t1 [] ) (toList' t2 [] )
226
263
where
227
264
-- If the two trees are the same, then their lists of 'Leaf's and
228
265
-- 'Collision's read from left to right should be the same (modulo the
229
266
-- order of elements in 'Collision').
230
267
231
268
go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)
232
- | k1 == k2 && l1 == l2
269
+ | k1 == k2 && leafEq l1 l2
270
+ = go tl1 tl2
271
+ go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)
272
+ | k1 == k2 && A. length ary1 == A. length ary2 &&
273
+ isPermutationBy leafEq (A. toList ary1) (A. toList ary2)
274
+ = go tl1 tl2
275
+ go [] [] = True
276
+ go _ _ = False
277
+
278
+ leafEq (L k v) (L k' v') = eqk k k' && eqv v v'
279
+
280
+ -- Note: previous implemenation isPermutation = null (as // bs)
281
+ -- was O(n^2) too.
282
+ --
283
+ -- This assumes lists are of equal length
284
+ isPermutationBy :: (a -> b -> Bool ) -> [a ] -> [b ] -> Bool
285
+ isPermutationBy f = go
286
+ where
287
+ f' = flip f
288
+
289
+ go [] [] = True
290
+ go (x : xs) (y : ys)
291
+ | f x y = go xs ys
292
+ | otherwise = go (deleteBy f' y xs) (deleteBy f x ys)
293
+ go [] (_ : _) = False
294
+ go (_ : _) [] = False
295
+
296
+ -- Data.List.deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]
297
+ deleteBy :: (a -> b -> Bool ) -> a -> [b ] -> [b ]
298
+ deleteBy _ _ [] = []
299
+ deleteBy eq x (y: ys) = if x `eq` y then ys else y : deleteBy eq x ys
300
+
301
+ -- Same as 'equal' but doesn't compare the values.
302
+ equalKeys :: (k -> k' -> Bool ) -> HashMap k v -> HashMap k' v' -> Bool
303
+ equalKeys eq t1 t2 = go (toList' t1 [] ) (toList' t2 [] )
304
+ where
305
+ go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)
306
+ | k1 == k2 && leafEq l1 l2
233
307
= go tl1 tl2
234
308
go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)
235
309
| k1 == k2 && A. length ary1 == A. length ary2 &&
236
- L. null (A. toList ary1 L. \\ A. toList ary2)
310
+ isPermutationBy leafEq (A. toList ary1) ( A. toList ary2)
237
311
= go tl1 tl2
238
312
go [] [] = True
239
313
go _ _ = False
240
314
315
+ leafEq (L k _) (L k' _) = eq k k'
316
+
317
+ #if MIN_VERSION_hashable(1,2,5)
318
+ instance H. Hashable2 HashMap where
319
+ liftHashWithSalt2 hk hv salt hm = go salt (toList' hm [] )
320
+ where
321
+ -- go :: Int -> [HashMap k v] -> Int
322
+ go s [] = s
323
+ go s (Leaf _ l : tl)
324
+ = s `hashLeafWithSalt` l `go` tl
325
+ -- For collisions we hashmix hash value
326
+ -- and then array of values' hashes sorted
327
+ go s (Collision h a : tl)
328
+ = (s `H.hashWithSalt` h) `hashCollisionWithSalt` a `go` tl
329
+ go s (_ : tl) = s `go` tl
330
+
331
+ -- hashLeafWithSalt :: Int -> Leaf k v -> Int
332
+ hashLeafWithSalt s (L k v) = (s `hk` k) `hv` v
333
+
334
+ -- hashCollisionWithSalt :: Int -> A.Array (Leaf k v) -> Int
335
+ hashCollisionWithSalt s
336
+ = L. foldl' H. hashWithSalt s . arrayHashesSorted s
337
+
338
+ -- arrayHashesSorted :: Int -> A.Array (Leaf k v) -> [Int]
339
+ arrayHashesSorted s = L. sort . L. map (hashLeafWithSalt s) . A. toList
340
+
341
+ instance (Hashable k ) => H. Hashable1 (HashMap k ) where
342
+ liftHashWithSalt = H. liftHashWithSalt2 H. hashWithSalt
343
+ #endif
344
+
241
345
instance (Hashable k , Hashable v ) => Hashable (HashMap k v ) where
242
346
hashWithSalt salt hm = go salt (toList' hm [] )
243
347
where
@@ -256,13 +360,10 @@ instance (Hashable k, Hashable v) => Hashable (HashMap k v) where
256
360
257
361
hashCollisionWithSalt :: Int -> A. Array (Leaf k v ) -> Int
258
362
hashCollisionWithSalt s
259
- = L. foldl' H. hashWithSalt s . arrayHashesSorted
260
-
261
- arrayHashesSorted :: A. Array (Leaf k v ) -> [Int ]
262
- arrayHashesSorted = L. sort . L. map leafValueHash . A. toList
363
+ = L. foldl' H. hashWithSalt s . arrayHashesSorted s
263
364
264
- leafValueHash :: Leaf k v -> Int
265
- leafValueHash ( L _ v) = H. hash v
365
+ arrayHashesSorted :: Int -> A. Array ( Leaf k v ) -> [ Int ]
366
+ arrayHashesSorted s = L. sort . L. map (hashLeafWithSalt s) . A. toList
266
367
267
368
-- Helper to get 'Leaf's and 'Collision's as a list.
268
369
toList' :: HashMap k v -> [HashMap k v ] -> [HashMap k v ]
0 commit comments