@@ -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,6 +126,9 @@ 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
128
132
129
133
------------------------------------------------------------------------
130
134
@@ -203,6 +207,25 @@ type Hash = Word
203
207
type Bitmap = Word
204
208
type Shift = Int
205
209
210
+ #if MIN_VERSION_base(4,9,0)
211
+ instance Show2 HashMap where
212
+ liftShowsPrec2 spk slk spv slv d m =
213
+ showsUnaryWith (liftShowsPrec sp sl) " fromList" d (toList m)
214
+ where
215
+ sp = liftShowsPrec2 spk slk spv slv
216
+ sl = liftShowList2 spk slk spv slv
217
+
218
+ instance Show k => Show1 (HashMap k ) where
219
+ liftShowsPrec = liftShowsPrec2 showsPrec showList
220
+
221
+ instance (Eq k , Hashable k , Read k ) => Read1 (HashMap k ) where
222
+ liftReadsPrec rp rl = readsData $
223
+ readsUnaryWith (liftReadsPrec rp' rl') " fromList" fromList
224
+ where
225
+ rp' = liftReadsPrec rp rl
226
+ rl' = liftReadList rp rl
227
+ #endif
228
+
206
229
instance (Eq k , Hashable k , Read k , Read e ) => Read (HashMap k e ) where
207
230
readPrec = parens $ prec 10 $ do
208
231
Ident " fromList" <- lexP
@@ -218,26 +241,74 @@ instance (Show k, Show v) => Show (HashMap k v) where
218
241
instance Traversable (HashMap k ) where
219
242
traverse f = traverseWithKey (const f)
220
243
244
+ #if MIN_VERSION_base(4,9,0)
245
+ instance Eq2 HashMap where
246
+ liftEq2 = equal
247
+
248
+ instance Eq k => Eq1 (HashMap k ) where
249
+ liftEq = equal (==)
250
+ #endif
251
+
221
252
instance (Eq k , Eq v ) => Eq (HashMap k v ) where
222
- (==) = equal
253
+ (==) = equal (==) (==)
223
254
224
- equal :: (Eq k , Eq v ) => HashMap k v -> HashMap k v -> Bool
225
- equal t1 t2 = go (toList' t1 [] ) (toList' t2 [] )
255
+ equal :: (k -> k' -> Bool ) -> (v -> v' -> Bool )
256
+ -> HashMap k v -> HashMap k' v' -> Bool
257
+ equal eqk eqv t1 t2 = go (toList' t1 [] ) (toList' t2 [] )
226
258
where
227
259
-- If the two trees are the same, then their lists of 'Leaf's and
228
260
-- 'Collision's read from left to right should be the same (modulo the
229
261
-- order of elements in 'Collision').
230
262
231
263
go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)
232
- | k1 == k2 && l1 == l2
264
+ | k1 == k2 && leafEq l1 l2
233
265
= go tl1 tl2
234
266
go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)
235
267
| k1 == k2 && A. length ary1 == A. length ary2 &&
236
- L. null (A. toList ary1 L. \\ A. toList ary2)
268
+ isPermutationBy leafEq (A. toList ary1) ( A. toList ary2)
237
269
= go tl1 tl2
238
270
go [] [] = True
239
271
go _ _ = False
240
272
273
+ leafEq (L k v) (L k' v') = eqk k k' && eqv v v'
274
+
275
+ -- Note: previous implemenation isPermutation = null (as // bs)
276
+ -- was O(n^2) too.
277
+ --
278
+ -- This assumes lists are of equal length
279
+ isPermutationBy :: (a -> b -> Bool ) -> [a ] -> [b ] -> Bool
280
+ isPermutationBy f = go
281
+ where
282
+ f' = flip f
283
+
284
+ go [] [] = True
285
+ go (x : xs) (y : ys)
286
+ | f x y = go xs ys
287
+ | otherwise = go (deleteBy f' y xs) (deleteBy f x ys)
288
+ go [] (_ : _) = False
289
+ go (_ : _) [] = False
290
+
291
+ -- Data.List.deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]
292
+ deleteBy :: (a -> b -> Bool ) -> a -> [b ] -> [b ]
293
+ deleteBy _ _ [] = []
294
+ deleteBy eq x (y: ys) = if x `eq` y then ys else y : deleteBy eq x ys
295
+
296
+ -- Same as 'equal' but doesn't compare the values.
297
+ equalKeys :: (k -> k' -> Bool ) -> HashMap k v -> HashMap k' v' -> Bool
298
+ equalKeys eq t1 t2 = go (toList' t1 [] ) (toList' t2 [] )
299
+ where
300
+ go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)
301
+ | k1 == k2 && leafEq l1 l2
302
+ = go tl1 tl2
303
+ go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)
304
+ | k1 == k2 && A. length ary1 == A. length ary2 &&
305
+ isPermutationBy leafEq (A. toList ary1) (A. toList ary2)
306
+ = go tl1 tl2
307
+ go [] [] = True
308
+ go _ _ = False
309
+
310
+ leafEq (L k _) (L k' _) = eq k k'
311
+
241
312
instance (Hashable k , Hashable v ) => Hashable (HashMap k v ) where
242
313
hashWithSalt salt hm = go salt (toList' hm [] )
243
314
where
0 commit comments