Skip to content

Commit 98472aa

Browse files
committed
Add draft
1 parent 6588174 commit 98472aa

File tree

1 file changed

+49
-25
lines changed

1 file changed

+49
-25
lines changed

Data/HashMap/Internal.hs

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
{-# LANGUAGE RoleAnnotations #-}
55
{-# LANGUAGE TypeFamilies #-}
66
{-# LANGUAGE UnboxedTuples #-}
7+
{-# LANGUAGE TypeSynonymInstances #-}
8+
{-# LANGUAGE FlexibleInstances #-}
79
{-# LANGUAGE LambdaCase #-}
810
#if __GLASGOW_HASKELL__ >= 802
911
{-# LANGUAGE TypeInType #-}
@@ -26,7 +28,8 @@
2628

2729
module Data.HashMap.Internal
2830
(
29-
HashMap(..)
31+
HashMapT(..)
32+
, HashMap
3033
, Leaf(..)
3134

3235
-- * Construction
@@ -158,6 +161,7 @@ import qualified Data.List as L
158161
import GHC.Exts ((==#), build, reallyUnsafePtrEquality#, inline)
159162
import Prelude hiding (filter, foldl, foldr, lookup, map, null, pred)
160163
import Text.Read hiding (step)
164+
import GHC.TypeLits(Nat, natVal)
161165

162166
import qualified Data.HashMap.Internal.Array as A
163167
import qualified Data.Hashable as H
@@ -196,8 +200,8 @@ import Data.Coerce (coerce)
196200
------------------------------------------------------------------------
197201

198202
-- | Convenience function. Compute a hash value for the given value.
199-
hash :: H.Hashable a => a -> Hash
200-
hash = fromIntegral . H.hash
203+
hash :: H.Hashable a => Integer -> a -> Hash
204+
hash salt = fromIntegral . H.hashWithSalt (fromIntegral salt)
201205

202206
data Leaf k v = L !k v
203207
deriving (Eq)
@@ -218,17 +222,27 @@ instance NF.NFData2 Leaf where
218222
-- Invariant: The length of the 1st argument to 'Full' is
219223
-- 2^bitsPerSubkey
220224

225+
226+
#if WORD_SIZE_IN_BITS == 64
227+
type DefaultSalt = -2578643520546668380 -- 0xdc36d1615b7400a4
228+
#else
229+
type DefaultSalt = 0x087fc72c
230+
#endif
231+
221232
-- | A map from keys to values. A map cannot contain duplicate keys;
222233
-- each key can map to at most one value.
223-
data HashMap k v
234+
data HashMapT (salt :: Nat) k v
224235
= Empty
225-
| BitmapIndexed !Bitmap !(A.Array (HashMap k v))
236+
| BitmapIndexed !Bitmap !(A.Array (HashMapT salt k v))
226237
| Leaf !Hash !(Leaf k v)
227-
| Full !(A.Array (HashMap k v))
238+
| Full !(A.Array (HashMapT salt k v))
228239
| Collision !Hash !(A.Array (Leaf k v))
229240
deriving (Typeable)
230241

231-
type role HashMap nominal representational
242+
-- backwards compatibility
243+
type HashMap = HashMapT DefaultSalt
244+
245+
type role HashMapT nominal nominal representational
232246

233247
instance (NFData k, NFData v) => NFData (HashMap k v) where
234248
rnf Empty = ()
@@ -397,17 +411,18 @@ instance Eq k => Eq1 (HashMap k) where
397411
--
398412
-- In general, the lack of substitutivity can be observed with any function
399413
-- that depends on the key ordering, such as folds and traversals.
400-
instance (Eq k, Eq v) => Eq (HashMap k v) where
414+
instance (Eq k, Eq v) => Eq (HashMapT salt k v) where
401415
(==) = equal1 (==)
402416

403417
-- We rely on there being no Empty constructors in the tree!
404418
-- This ensures that two equal HashMaps will have the same
405419
-- shape, modulo the order of entries in Collisions.
406-
equal1 :: Eq k
420+
equal1 :: forall k v v' salt . Eq k
407421
=> (v -> v' -> Bool)
408-
-> HashMap k v -> HashMap k v' -> Bool
422+
-> HashMapT salt k v -> HashMapT salt k v' -> Bool
409423
equal1 eq = go
410424
where
425+
go :: HashMapT salt k v -> HashMapT salt k v' -> Bool
411426
go Empty Empty = True
412427
go (BitmapIndexed bm1 ary1) (BitmapIndexed bm2 ary2)
413428
= bm1 == bm2 && A.sameArray1 go ary1 ary2
@@ -420,7 +435,7 @@ equal1 eq = go
420435
leafEq (L k1 v1) (L k2 v2) = k1 == k2 && eq v1 v2
421436

422437
equal2 :: (k -> k' -> Bool) -> (v -> v' -> Bool)
423-
-> HashMap k v -> HashMap k' v' -> Bool
438+
-> HashMapT salt k v -> HashMapT salt k' v' -> Bool
424439
equal2 eqk eqv t1 t2 = go (toList' t1 []) (toList' t2 [])
425440
where
426441
-- If the two trees are the same, then their lists of 'Leaf's and
@@ -562,7 +577,7 @@ instance (Hashable k, Hashable v) => Hashable (HashMap k v) where
562577
arrayHashesSorted s = L.sort . L.map (hashLeafWithSalt s) . A.toList
563578

564579
-- Helper to get 'Leaf's and 'Collision's as a list.
565-
toList' :: HashMap k v -> [HashMap k v] -> [HashMap k v]
580+
toList' :: HashMapT salt k v -> [HashMapT salt k v] -> [HashMapT salt k v]
566581
toList' (BitmapIndexed _ ary) a = A.foldr toList' a ary
567582
toList' (Full ary) a = A.foldr toList' a ary
568583
toList' l@(Leaf _ _) a = l : a
@@ -579,12 +594,17 @@ isLeafOrCollision _ = False
579594
-- * Construction
580595

581596
-- | /O(1)/ Construct an empty map.
582-
empty :: HashMap k v
597+
empty :: forall k v salt . HashMapT salt k v
583598
empty = Empty
584599

585600
-- | /O(1)/ Construct a map with a single element.
586601
singleton :: (Hashable k) => k -> v -> HashMap k v
587-
singleton k v = Leaf (hash k) (L k v)
602+
singleton = singleton'
603+
604+
singleton' :: forall k v salt . (Hashable k) => k -> v -> HashMapT salt k v
605+
singleton' k v = Leaf (hash salt k) (L k v)
606+
where
607+
salt = natVal (Proxy :: Proxy salt)
588608

589609
------------------------------------------------------------------------
590610
-- * Basic interface
@@ -614,7 +634,7 @@ member k m = case lookup k m of
614634

615635
-- | /O(log n)/ Return the value to which the specified key is mapped,
616636
-- or 'Nothing' if this map contains no mapping for the key.
617-
lookup :: (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
637+
lookup :: (Eq k, Hashable k) => k -> HashMapT salt k v -> Maybe v
618638
#if __GLASGOW_HASKELL__ >= 802
619639
-- GHC does not yet perform a worker-wrapper transformation on
620640
-- unboxed sums automatically. That seems likely to happen at some
@@ -624,8 +644,10 @@ lookup k m = case lookup# k m of
624644
(# | a #) -> Just a
625645
{-# INLINE lookup #-}
626646

627-
lookup# :: (Eq k, Hashable k) => k -> HashMap k v -> (# (# #) | v #)
628-
lookup# k m = lookupCont (\_ -> (# (# #) | #)) (\v _i -> (# | v #)) (hash k) k 0 m
647+
lookup# :: (Eq k, Hashable k) => k -> HashMapT salt k v -> (# (# #) | v #)
648+
lookup# k m = lookupCont (\_ -> (# (# #) | #)) (\v _i -> (# | v #)) (hash salt k) k 0 m
649+
where
650+
salt = natVal (Proxy :: Proxy salt)
629651
{-# INLINABLE lookup# #-}
630652

631653
#else
@@ -708,20 +730,20 @@ lookupRecordCollision h k m = lookupCont (\_ -> Absent) Present h k 0 m
708730
-- keys at level @n@ of a hashmap, the offset should be @n * bitsPerSubkey@.
709731
lookupCont ::
710732
#if __GLASGOW_HASKELL__ >= 802
711-
forall rep (r :: TYPE rep) k v.
733+
forall rep (r :: TYPE rep) k v salt.
712734
#else
713-
forall r k v.
735+
forall r k v salt.
714736
#endif
715737
Eq k
716738
=> ((# #) -> r) -- Absent continuation
717739
-> (v -> Int -> r) -- Present continuation
718740
-> Hash -- The hash of the key
719741
-> k
720742
-> Int -- The offset of the subkey in the hash.
721-
-> HashMap k v -> r
743+
-> HashMapT salt k v -> r
722744
lookupCont absent present !h0 !k0 !s0 !m0 = go h0 k0 s0 m0
723745
where
724-
go :: Eq k => Hash -> k -> Int -> HashMap k v -> r
746+
go :: Eq k => Hash -> k -> Int -> HashMapT salt k v -> r
725747
go !_ !_ !_ Empty = absent (# #)
726748
go h k _ (Leaf hx (L kx x))
727749
| h == hx && k == kx = present x (-1)
@@ -806,11 +828,13 @@ bitmapIndexedOrFull b ary
806828
-- | /O(log n)/ Associate the specified value with the specified
807829
-- key in this map. If this map previously contained a mapping for
808830
-- the key, the old value is replaced.
809-
insert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v
810-
insert k v m = insert' (hash k) k v m
831+
insert :: forall k v salt . (Eq k, Hashable k) => k -> v -> HashMapT salt k v -> HashMapT salt k v
832+
insert k v m = insert' (hash salt k) k v m
833+
where
834+
salt = natVal (Proxy :: Proxy salt)
811835
{-# INLINABLE insert #-}
812836

813-
insert' :: Eq k => Hash -> k -> v -> HashMap k v -> HashMap k v
837+
insert' :: forall k v salt . Eq k => Hash -> k -> v -> HashMapT salt k v -> HashMapT salt k v
814838
insert' h0 k0 v0 m0 = go h0 k0 v0 0 m0
815839
where
816840
go !h !k x !_ Empty = Leaf h (L k x)
@@ -934,7 +958,7 @@ setAtPosition i k x ary = A.update ary i (L k x)
934958

935959

936960
-- | In-place update version of insert
937-
unsafeInsert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v
961+
unsafeInsert :: (Eq k) => k -> v -> HashMap k v -> HashMap k v
938962
unsafeInsert k0 v0 m0 = runST (go h0 k0 v0 0 m0)
939963
where
940964
h0 = hash k0

0 commit comments

Comments
 (0)