Skip to content

Commit bc3630b

Browse files
authored
Use Array and MArray unqualified (#576)
1 parent 94811cb commit bc3630b

File tree

4 files changed

+81
-78
lines changed

4 files changed

+81
-78
lines changed

Data/HashMap/Internal.hs

Lines changed: 66 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -151,31 +151,33 @@ module Data.HashMap.Internal
151151
, adjust#
152152
) where
153153

154-
import Data.Traversable -- MicroHs needs this since its Prelude does not have Foldable&Traversable.
155-
-- It's harmless for GHC, and putting it first avoid a warning.
156-
157-
import Control.Applicative (Const (..))
158-
import Control.DeepSeq (NFData (..), NFData1 (..), NFData2 (..))
159-
import Control.Monad.ST (ST, runST)
160-
import Data.Bifoldable (Bifoldable (..))
161-
import Data.Bits (complement, countTrailingZeros, popCount,
162-
shiftL, unsafeShiftL, unsafeShiftR, (.&.),
163-
(.|.))
164-
import Data.Coerce (coerce)
165-
import Data.Data (Constr, Data (..), DataType)
166-
import Data.Functor.Classes (Eq1 (..), Eq2 (..), Ord1 (..), Ord2 (..),
167-
Read1 (..), Show1 (..), Show2 (..))
168-
import Data.Functor.Identity (Identity (..))
169-
import Data.Hashable (Hashable)
170-
import Data.Hashable.Lifted (Hashable1, Hashable2)
171-
import Data.HashMap.Internal.List (isPermutationBy, unorderedCompare)
172-
import Data.Maybe (isNothing)
173-
import Data.Semigroup (Semigroup (..), stimesIdempotentMonoid)
174-
import GHC.Exts (Int (..), Int#, TYPE, (==#))
175-
import GHC.Stack (HasCallStack)
176-
import Prelude hiding (Foldable (..), filter, lookup, map,
177-
pred)
178-
import Text.Read hiding (step)
154+
-- MicroHs needs this import since its Prelude does not have Foldable&Traversable.
155+
-- It's harmless for GHC, and putting it first avoids a warning.
156+
import Data.Traversable
157+
158+
import Control.Applicative (Const (..))
159+
import Control.DeepSeq (NFData (..), NFData1 (..), NFData2 (..))
160+
import Control.Monad.ST (ST, runST)
161+
import Data.Bifoldable (Bifoldable (..))
162+
import Data.Bits (complement, countTrailingZeros, popCount,
163+
shiftL, unsafeShiftL, unsafeShiftR, (.&.),
164+
(.|.))
165+
import Data.Coerce (coerce)
166+
import Data.Data (Constr, Data (..), DataType)
167+
import Data.Functor.Classes (Eq1 (..), Eq2 (..), Ord1 (..), Ord2 (..),
168+
Read1 (..), Show1 (..), Show2 (..))
169+
import Data.Functor.Identity (Identity (..))
170+
import Data.Hashable (Hashable)
171+
import Data.Hashable.Lifted (Hashable1, Hashable2)
172+
import Data.HashMap.Internal.Array (Array, MArray)
173+
import Data.HashMap.Internal.List (isPermutationBy, unorderedCompare)
174+
import Data.Maybe (isNothing)
175+
import Data.Semigroup (Semigroup (..), stimesIdempotentMonoid)
176+
import GHC.Exts (Int (..), Int#, TYPE, (==#))
177+
import GHC.Stack (HasCallStack)
178+
import Prelude hiding (Foldable (..), filter, lookup, map,
179+
pred)
180+
import Text.Read hiding (step)
179181

180182
import qualified Data.Data as Data
181183
import qualified Data.Foldable as Foldable
@@ -218,7 +220,7 @@ data HashMap k v
218220
-- ^ Invariants:
219221
--
220222
-- * 'Empty' is not a valid sub-node. It can only appear at the root. (INV1)
221-
| BitmapIndexed !Bitmap !(A.Array (HashMap k v))
223+
| BitmapIndexed !Bitmap !(Array (HashMap k v))
222224
-- ^ Invariants:
223225
--
224226
-- * Only the lower @maxChildren@ bits of the 'Bitmap' may be set. The
@@ -236,11 +238,11 @@ data HashMap k v
236238
-- compatible with its 'Hash'. (INV6)
237239
-- (TODO: Document this properly (#425))
238240
-- * The 'Hash' of a 'Leaf' node must be the 'hash' of its key. (INV7)
239-
| Full !(A.Array (HashMap k v))
241+
| Full !(Array (HashMap k v))
240242
-- ^ Invariants:
241243
--
242244
-- * The array of a 'Full' node stores exactly 'maxChildren' sub-nodes. (INV8)
243-
| Collision !Hash !(A.Array (Leaf k v))
245+
| Collision !Hash !(Array (Leaf k v))
244246
-- ^ Invariants:
245247
--
246248
-- * The location of a 'Leaf' or 'Collision' node in the tree must be
@@ -546,11 +548,11 @@ instance Hashable2 HashMap where
546548
-- hashLeafWithSalt :: Int -> Leaf k v -> Int
547549
hashLeafWithSalt s (L k v) = (s `hk` k) `hv` v
548550

549-
-- hashCollisionWithSalt :: Int -> A.Array (Leaf k v) -> Int
551+
-- hashCollisionWithSalt :: Int -> Array (Leaf k v) -> Int
550552
hashCollisionWithSalt s
551553
= List.foldl' H.hashWithSalt s . arrayHashesSorted s
552554

553-
-- arrayHashesSorted :: Int -> A.Array (Leaf k v) -> [Int]
555+
-- arrayHashesSorted :: Int -> Array (Leaf k v) -> [Int]
554556
arrayHashesSorted s = List.sort . List.map (hashLeafWithSalt s) . A.toList
555557

556558
instance (Hashable k) => Hashable1 (HashMap k) where
@@ -573,11 +575,11 @@ instance (Hashable k, Hashable v) => Hashable (HashMap k v) where
573575
hashLeafWithSalt :: Int -> Leaf k v -> Int
574576
hashLeafWithSalt s (L k v) = s `H.hashWithSalt` k `H.hashWithSalt` v
575577

576-
hashCollisionWithSalt :: Int -> A.Array (Leaf k v) -> Int
578+
hashCollisionWithSalt :: Int -> Array (Leaf k v) -> Int
577579
hashCollisionWithSalt s
578580
= List.foldl' H.hashWithSalt s . arrayHashesSorted s
579581

580-
arrayHashesSorted :: Int -> A.Array (Leaf k v) -> [Int]
582+
arrayHashesSorted :: Int -> Array (Leaf k v) -> [Int]
581583
arrayHashesSorted s = List.sort . List.map (hashLeafWithSalt s) . A.toList
582584

583585
-- | Helper to get 'Leaf's and 'Collision's as a list.
@@ -832,7 +834,7 @@ collision h !e1 !e2 =
832834
{-# INLINE collision #-}
833835

834836
-- | Create a 'BitmapIndexed' or 'Full' node.
835-
bitmapIndexedOrFull :: Bitmap -> A.Array (HashMap k v) -> HashMap k v
837+
bitmapIndexedOrFull :: Bitmap -> Array (HashMap k v) -> HashMap k v
836838
-- The strictness in @ary@ helps achieve a nice code size reduction in
837839
-- @unionWith[Key]@ with GHC 9.2.2. See the Core diffs in
838840
-- https://github.com/haskell-unordered-containers/unordered-containers/pull/376.
@@ -956,7 +958,7 @@ insertKeyExists !collPos0 !h0 !k0 x0 m0 = go collPos0 h0 k0 x0 m0
956958
-- | Replace the ith Leaf with Leaf k v.
957959
--
958960
-- This does not check that @i@ is within bounds of the array.
959-
setAtPosition :: Int -> k -> v -> A.Array (Leaf k v) -> A.Array (Leaf k v)
961+
setAtPosition :: Int -> k -> v -> Array (Leaf k v) -> Array (Leaf k v)
960962
setAtPosition i k x ary = A.update ary i (L k x)
961963
{-# INLINE setAtPosition #-}
962964

@@ -1097,8 +1099,8 @@ insertModifying x f k0 m0 = go h0 k0 0 m0
10971099
{-# INLINABLE insertModifying #-}
10981100

10991101
-- | Like insertModifying for arrays; used to implement insertModifying
1100-
insertModifyingArr :: Eq k => v -> (v -> (# v #)) -> k -> A.Array (Leaf k v)
1101-
-> A.Array (Leaf k v)
1102+
insertModifyingArr :: Eq k => v -> (v -> (# v #)) -> k -> Array (Leaf k v)
1103+
-> Array (Leaf k v)
11021104
insertModifyingArr x f k0 ary0 = go k0 ary0 0 (A.length ary0)
11031105
where
11041106
go !k !ary !i !n
@@ -1574,7 +1576,7 @@ isSubmapOfBy comp !m1 !m2 = go 0 m1 m2
15741576
{-# INLINABLE isSubmapOfBy #-}
15751577

15761578
-- | \(O(\min n m))\) Checks if a bitmap indexed node is a submap of another.
1577-
submapBitmapIndexed :: (HashMap k v1 -> HashMap k v2 -> Bool) -> Bitmap -> A.Array (HashMap k v1) -> Bitmap -> A.Array (HashMap k v2) -> Bool
1579+
submapBitmapIndexed :: (HashMap k v1 -> HashMap k v2 -> Bool) -> Bitmap -> Array (HashMap k v1) -> Bitmap -> Array (HashMap k v2) -> Bool
15781580
submapBitmapIndexed comp !b1 !ary1 !b2 !ary2 = subsetBitmaps && go 0 0 (b1Orb2 .&. negate b1Orb2)
15791581
where
15801582
go :: Int -> Int -> Bitmap -> Bool
@@ -1712,8 +1714,8 @@ unionWithKey f = go 0
17121714
{-# INLINE unionWithKey #-}
17131715

17141716
-- | Strict in the result of @f@.
1715-
unionArrayBy :: (a -> a -> a) -> Bitmap -> Bitmap -> A.Array a -> A.Array a
1716-
-> A.Array a
1717+
unionArrayBy :: (a -> a -> a) -> Bitmap -> Bitmap -> Array a -> Array a
1718+
-> Array a
17171719
-- The manual forcing of @b1@, @b2@, @ary1@ and @ary2@ results in handsome
17181720
-- Core size reductions with GHC 9.2.2. See the Core diffs in
17191721
-- https://github.com/haskell-unordered-containers/unordered-containers/pull/376.
@@ -1947,7 +1949,7 @@ difference = go_difference 0
19471949
-- TODO: This could be faster if we would keep track of which elements of ary2
19481950
-- we've already matched. Those could be skipped when we check the following
19491951
-- elements of ary1.
1950-
differenceCollisions :: Eq k => Hash -> A.Array (Leaf k v1) -> HashMap k v1 -> Hash -> A.Array (Leaf k v2) -> HashMap k v1
1952+
differenceCollisions :: Eq k => Hash -> Array (Leaf k v1) -> HashMap k v1 -> Hash -> Array (Leaf k v2) -> HashMap k v1
19511953
differenceCollisions !h1 !ary1 t1 !h2 !ary2
19521954
| h1 == h2 =
19531955
if A.unsafeSameArray ary1 ary2
@@ -2112,7 +2114,7 @@ updateCollision
21122114
=> (v -> Maybe v)
21132115
-> Hash
21142116
-> k
2115-
-> A.Array (Leaf k v)
2117+
-> Array (Leaf k v)
21162118
-> HashMap k v
21172119
-- ^ The original Collision node which will be re-used if the array is unchanged.
21182120
-> HashMap k v
@@ -2133,7 +2135,7 @@ updateCollision f !h k !ary orig =
21332135
-- we've already matched. Those could be skipped when we check the following
21342136
-- elements of ary1.
21352137
-- TODO: Return tA when the array is unchanged.
2136-
differenceWithKey_Collisions :: Eq k => (k -> v -> w -> Maybe v) -> Word -> A.Array (Leaf k v) -> HashMap k v -> Word -> A.Array (Leaf k w) -> HashMap k v
2138+
differenceWithKey_Collisions :: Eq k => (k -> v -> w -> Maybe v) -> Word -> Array (Leaf k v) -> HashMap k v -> Word -> Array (Leaf k w) -> HashMap k v
21372139
differenceWithKey_Collisions f !hA !aryA !tA !hB !aryB
21382140
| hA == hB =
21392141
let f' l@(L kA vA) =
@@ -2234,8 +2236,8 @@ intersectionArrayBy ::
22342236
) ->
22352237
Bitmap ->
22362238
Bitmap ->
2237-
A.Array (HashMap k v1) ->
2238-
A.Array (HashMap k v2) ->
2239+
Array (HashMap k v1) ->
2240+
Array (HashMap k v2) ->
22392241
HashMap k v3
22402242
intersectionArrayBy f !b1 !b2 !ary1 !ary2
22412243
| b1 .&. b2 == 0 = Empty
@@ -2272,7 +2274,7 @@ intersectionArrayBy f !b1 !b2 !ary1 !ary2
22722274
bIntersect = b1 .&. b2
22732275
{-# INLINE intersectionArrayBy #-}
22742276

2275-
intersectionCollisions :: Eq k => (k -> v1 -> v2 -> (# v3 #)) -> Hash -> Hash -> A.Array (Leaf k v1) -> A.Array (Leaf k v2) -> HashMap k v3
2277+
intersectionCollisions :: Eq k => (k -> v1 -> v2 -> (# v3 #)) -> Hash -> Hash -> Array (Leaf k v1) -> Array (Leaf k v2) -> HashMap k v3
22762278
intersectionCollisions f h1 h2 ary1 ary2
22772279
| h1 == h2 = runST $ do
22782280
let !n2 = A.length ary2
@@ -2306,7 +2308,7 @@ intersectionCollisions f h1 h2 ary1 ary2
23062308
-- undefined 2 1 4
23072309
-- @
23082310
-- We don't actually need to write undefined, we just have to make sure that the next search starts 1 after the current one.
2309-
searchSwap :: Eq k => A.MArray s (Leaf k v) -> Int -> k -> Int -> ST s (Maybe (Leaf k v))
2311+
searchSwap :: Eq k => MArray s (Leaf k v) -> Int -> k -> Int -> ST s (Maybe (Leaf k v))
23102312
searchSwap mary n toFind start = go start toFind start
23112313
where
23122314
go i0 k i
@@ -2382,7 +2384,7 @@ disjointSubtrees s a (Leaf hB (L kB _)) =
23822384
disjointSubtrees s a b@Collision{} = disjointSubtrees s b a
23832385
{-# INLINABLE disjointSubtrees #-}
23842386

2385-
disjointArrays :: Eq k => Shift -> Bitmap -> A.Array (HashMap k a) -> Bitmap -> A.Array (HashMap k b) -> Bool
2387+
disjointArrays :: Eq k => Shift -> Bitmap -> Array (HashMap k a) -> Bitmap -> Array (HashMap k b) -> Bool
23862388
disjointArrays !s !bmA !aryA !bmB !aryB = go (bmA .&. bmB)
23872389
where
23882390
go 0 = True
@@ -2400,7 +2402,7 @@ disjointArrays !s !bmA !aryA !bmB !aryB = go (bmA .&. bmB)
24002402
-- TODO: GHC 9.12.2 inlines disjointCollisions into `disjoint @Int`.
24012403
-- How do you prevent this while preserving specialization?
24022404
-- https://stackoverflow.com/questions/79838305/ensuring-specialization-while-preventing-inlining
2403-
disjointCollisions :: Eq k => Hash -> A.Array (Leaf k a) -> Hash -> A.Array (Leaf k b) -> Bool
2405+
disjointCollisions :: Eq k => Hash -> Array (Leaf k a) -> Hash -> Array (Leaf k b) -> Bool
24042406
disjointCollisions !hA !aryA !hB !aryB
24052407
| hA == hB = A.all predicate aryA
24062408
| otherwise = True
@@ -2566,7 +2568,7 @@ filterMapAux onLeaf onColl = go
25662568
mary <- A.new_ n
25672569
step ary0 mary b0 0 0 1 n
25682570
where
2569-
step :: A.Array (HashMap k v1) -> A.MArray s (HashMap k v2)
2571+
step :: Array (HashMap k v1) -> MArray s (HashMap k v2)
25702572
-> Bitmap -> Int -> Int -> Bitmap -> Int
25712573
-> ST s (HashMap k v2)
25722574
step !ary !mary !b i !j !bi n
@@ -2598,7 +2600,7 @@ filterMapAux onLeaf onColl = go
25982600
mary <- A.new_ n
25992601
step ary0 mary 0 0 n
26002602
where
2601-
step :: A.Array (Leaf k v1) -> A.MArray s (Leaf k v2)
2603+
step :: Array (Leaf k v1) -> MArray s (Leaf k v2)
26022604
-> Int -> Int -> Int
26032605
-> ST s (HashMap k v2)
26042606
step !ary !mary i !j n
@@ -2731,11 +2733,11 @@ lookupInArrayCont ::
27312733
#else
27322734
forall r k v.
27332735
#endif
2734-
Eq k => ((# #) -> r) -> (v -> Int -> r) -> k -> A.Array (Leaf k v) -> r
2736+
Eq k => ((# #) -> r) -> (v -> Int -> r) -> k -> Array (Leaf k v) -> r
27352737
lookupInArrayCont absent present k0 ary0 =
27362738
lookupInArrayCont_ k0 ary0 0 (A.length ary0)
27372739
where
2738-
lookupInArrayCont_ :: Eq k => k -> A.Array (Leaf k v) -> Int -> Int -> r
2740+
lookupInArrayCont_ :: Eq k => k -> Array (Leaf k v) -> Int -> Int -> r
27392741
lookupInArrayCont_ !k !ary !i !n
27402742
| i >= n = absent (# #)
27412743
| otherwise = case A.index# ary i of
@@ -2746,7 +2748,7 @@ lookupInArrayCont absent present k0 ary0 =
27462748

27472749
-- | \(O(n)\) Lookup the value associated with the given key in this
27482750
-- array. Returns 'Nothing' if the key wasn't found.
2749-
indexOf :: Eq k => k -> A.Array (Leaf k v) -> Maybe Int
2751+
indexOf :: Eq k => k -> Array (Leaf k v) -> Maybe Int
27502752
indexOf k0 ary0 = go k0 ary0 0 (A.length ary0)
27512753
where
27522754
go !k !ary !i !n
@@ -2757,7 +2759,7 @@ indexOf k0 ary0 = go k0 ary0 0 (A.length ary0)
27572759
| otherwise -> go k ary (i+1) n
27582760
{-# INLINABLE indexOf #-}
27592761

2760-
updateWith# :: Eq k => (v -> (# v #)) -> k -> A.Array (Leaf k v) -> A.Array (Leaf k v)
2762+
updateWith# :: Eq k => (v -> (# v #)) -> k -> Array (Leaf k v) -> Array (Leaf k v)
27612763
updateWith# f k0 ary0 = go k0 ary0 0 (A.length ary0)
27622764
where
27632765
go !k !ary !i !n
@@ -2770,13 +2772,13 @@ updateWith# f k0 ary0 = go k0 ary0 0 (A.length ary0)
27702772
| otherwise -> go k ary (i+1) n
27712773
{-# INLINABLE updateWith# #-}
27722774

2773-
updateOrSnocWith :: Eq k => (v -> v -> (# v #)) -> k -> v -> A.Array (Leaf k v)
2774-
-> A.Array (Leaf k v)
2775+
updateOrSnocWith :: Eq k => (v -> v -> (# v #)) -> k -> v -> Array (Leaf k v)
2776+
-> Array (Leaf k v)
27752777
updateOrSnocWith f = updateOrSnocWithKey (const f)
27762778
{-# INLINABLE updateOrSnocWith #-}
27772779

2778-
updateOrSnocWithKey :: Eq k => (k -> v -> v -> (# v #)) -> k -> v -> A.Array (Leaf k v)
2779-
-> A.Array (Leaf k v)
2780+
updateOrSnocWithKey :: Eq k => (k -> v -> v -> (# v #)) -> k -> v -> Array (Leaf k v)
2781+
-> Array (Leaf k v)
27802782
updateOrSnocWithKey f k0 v0 ary0 = go k0 v0 ary0 0 (A.length ary0)
27812783
where
27822784
go !k v !ary !i !n
@@ -2789,7 +2791,7 @@ updateOrSnocWithKey f k0 v0 ary0 = go k0 v0 ary0 0 (A.length ary0)
27892791
| otherwise -> go k v ary (i+1) n
27902792
{-# INLINABLE updateOrSnocWithKey #-}
27912793

2792-
updateOrConcatWithKey :: Eq k => (k -> v -> v -> (# v #)) -> A.Array (Leaf k v) -> A.Array (Leaf k v) -> A.Array (Leaf k v)
2794+
updateOrConcatWithKey :: Eq k => (k -> v -> v -> (# v #)) -> Array (Leaf k v) -> Array (Leaf k v) -> Array (Leaf k v)
27932795
updateOrConcatWithKey f ary1 ary2 = A.run $ do
27942796
-- TODO: instead of mapping and then folding, should we traverse?
27952797
-- We'll have to be careful to avoid allocating pairs or similar.
@@ -2822,7 +2824,7 @@ updateOrConcatWithKey f ary1 ary2 = A.run $ do
28222824
{-# INLINABLE updateOrConcatWithKey #-}
28232825

28242826
-- | \(O(n*m)\) Check if the first array is a subset of the second array.
2825-
subsetArray :: Eq k => (v1 -> v2 -> Bool) -> A.Array (Leaf k v1) -> A.Array (Leaf k v2) -> Bool
2827+
subsetArray :: Eq k => (v1 -> v2 -> Bool) -> Array (Leaf k v1) -> Array (Leaf k v2) -> Bool
28262828
subsetArray cmpV ary1 ary2 = A.length ary1 <= A.length ary2 && A.all inAry2 ary1
28272829
where
28282830
inAry2 (L k1 v1) = lookupInArrayCont (\_ -> False) (\v2 _ -> cmpV v1 v2) k1 ary2
@@ -2832,28 +2834,28 @@ subsetArray cmpV ary1 ary2 = A.length ary1 <= A.length ary2 && A.all inAry2 ary1
28322834
-- Manually unrolled loops
28332835

28342836
-- | \(O(n)\) Update the element at the given position in this array.
2835-
updateFullArray :: A.Array e -> Int -> e -> A.Array e
2837+
updateFullArray :: Array e -> Int -> e -> Array e
28362838
updateFullArray ary idx b = runST (updateFullArrayM ary idx b)
28372839
{-# INLINE updateFullArray #-}
28382840

28392841
-- | \(O(n)\) Update the element at the given position in this array.
2840-
updateFullArrayM :: A.Array e -> Int -> e -> ST s (A.Array e)
2842+
updateFullArrayM :: Array e -> Int -> e -> ST s (Array e)
28412843
updateFullArrayM ary idx b = do
28422844
mary <- clone ary
28432845
A.write mary idx b
28442846
A.unsafeFreeze mary
28452847
{-# INLINE updateFullArrayM #-}
28462848

28472849
-- | \(O(n)\) Update the element at the given position in this array, by applying a function to it.
2848-
updateFullArrayWith' :: A.Array e -> Int -> (e -> e) -> A.Array e
2850+
updateFullArrayWith' :: Array e -> Int -> (e -> e) -> Array e
28492851
updateFullArrayWith' ary idx f =
28502852
case A.index# ary idx of
28512853
(# x #) -> updateFullArray ary idx $! f x
28522854
{-# INLINE updateFullArrayWith' #-}
28532855

28542856
-- | Unsafely clone an array of (2^bitsPerSubkey) elements. The length of the input
28552857
-- array is not checked.
2856-
clone :: A.Array e -> ST s (A.MArray s e)
2858+
clone :: Array e -> ST s (MArray s e)
28572859
clone ary =
28582860
A.thaw ary 0 (2^bitsPerSubkey)
28592861

0 commit comments

Comments
 (0)