Skip to content

Commit dadb590

Browse files
committed
Make bitsPerSubkey platform-dependent
1 parent 5385b0c commit dadb590

File tree

7 files changed

+39
-36
lines changed

7 files changed

+39
-36
lines changed

Data/HashMap/Internal.hs

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,9 @@ module Data.HashMap.Internal
127127
, sparseIndex
128128
, two
129129
, unionArrayBy
130-
, update32
131-
, update32M
132-
, update32With'
130+
, updateFullArray
131+
, updateFullArrayM
132+
, updateFullArrayWith'
133133
, updateOrConcatWithKey
134134
, filterMapAux
135135
, equalKeys
@@ -832,7 +832,7 @@ insert' h0 k0 v0 m0 = go h0 k0 v0 0 m0
832832
!st' = go h k x (nextShift s) st
833833
in if st' `ptrEq` st
834834
then t
835-
else Full (update32 ary i st')
835+
else Full (updateFullArray ary i st')
836836
where i = index h s
837837
go h k x s t@(Collision hy v)
838838
| h == hy = Collision h (updateOrSnocWith (\a _ -> (# a #)) k x v)
@@ -866,7 +866,7 @@ insertNewKey !h0 !k0 x0 !m0 = go h0 k0 x0 0 m0
866866
go h k x s (Full ary) =
867867
let !st = A.index ary i
868868
!st' = go h k x (nextShift s) st
869-
in Full (update32 ary i st')
869+
in Full (updateFullArray ary i st')
870870
where i = index h s
871871
go h k x s t@(Collision hy v)
872872
| h == hy = Collision h (A.snoc v (L k x))
@@ -895,7 +895,7 @@ insertKeyExists !collPos0 !h0 !k0 x0 !m0 = go collPos0 h0 k0 x0 m0
895895
go collPos shiftedHash k x (Full ary) =
896896
let !st = A.index ary i
897897
!st' = go collPos (shiftHash shiftedHash) k x st
898-
in Full (update32 ary i st')
898+
in Full (updateFullArray ary i st')
899899
where i = index' shiftedHash
900900
go collPos _shiftedHash k x (Collision h v)
901901
| collPos >= 0 = Collision h (setAtPosition collPos k x v)
@@ -1043,7 +1043,7 @@ insertModifying x f k0 m0 = go h0 k0 0 m0
10431043
go h k s t@(Full ary) =
10441044
let !st = A.index ary i
10451045
!st' = go h k (nextShift s) st
1046-
ary' = update32 ary i $! st'
1046+
ary' = updateFullArray ary i $! st'
10471047
in if ptrEq st st'
10481048
then t
10491049
else Full ary'
@@ -1272,7 +1272,7 @@ adjust# f k0 m0 = go h0 k0 0 m0
12721272
let i = index h s
12731273
!st = A.index ary i
12741274
!st' = go h k (nextShift s) st
1275-
ary' = update32 ary i $! st'
1275+
ary' = updateFullArray ary i $! st'
12761276
in if ptrEq st st'
12771277
then t
12781278
else Full ary'
@@ -1558,12 +1558,6 @@ submapBitmapIndexed comp !b1 !ary1 !b2 !ary2 = subsetBitmaps && go 0 0 (b1Orb2 .
15581558
go !i !j !m
15591559
| m > b1Orb2 = True
15601560

1561-
#if WORD_SIZE_IN_BITS == 32
1562-
-- m can overflow to 0 on 32-bit platforms.
1563-
-- See #491.
1564-
| m == 0 = True
1565-
#endif
1566-
15671561
-- In case a key is both in ary1 and ary2, check ary1[i] <= ary2[j] and
15681562
-- increment the indices i and j.
15691563
| b1Andb2 .&. m /= 0 = comp (A.index ary1 i) (A.index ary2 j) &&
@@ -1668,12 +1662,12 @@ unionWithKey f = go 0
16681662
go s (Full ary1) t2 =
16691663
let h2 = leafHashCode t2
16701664
i = index h2 s
1671-
ary' = update32With' ary1 i $ \st1 -> go (nextShift s) st1 t2
1665+
ary' = updateFullArrayWith' ary1 i $ \st1 -> go (nextShift s) st1 t2
16721666
in Full ary'
16731667
go s t1 (Full ary2) =
16741668
let h1 = leafHashCode t1
16751669
i = index h1 s
1676-
ary' = update32With' ary2 i $ \st2 -> go (nextShift s) t1 st2
1670+
ary' = updateFullArrayWith' ary2 i $ \st2 -> go (nextShift s) t1 st2
16771671
in Full ary'
16781672

16791673
leafHashCode (Leaf h _) = h
@@ -2414,24 +2408,24 @@ subsetArray cmpV ary1 ary2 = A.length ary1 <= A.length ary2 && A.all inAry2 ary1
24142408
-- Manually unrolled loops
24152409

24162410
-- | \(O(n)\) Update the element at the given position in this array.
2417-
update32 :: A.Array e -> Int -> e -> A.Array e
2418-
update32 ary idx b = runST (update32M ary idx b)
2419-
{-# INLINE update32 #-}
2411+
updateFullArray :: A.Array e -> Int -> e -> A.Array e
2412+
updateFullArray ary idx b = runST (updateFullArrayM ary idx b)
2413+
{-# INLINE updateFullArray #-}
24202414

24212415
-- | \(O(n)\) Update the element at the given position in this array.
2422-
update32M :: A.Array e -> Int -> e -> ST s (A.Array e)
2423-
update32M ary idx b = do
2416+
updateFullArrayM :: A.Array e -> Int -> e -> ST s (A.Array e)
2417+
updateFullArrayM ary idx b = do
24242418
mary <- clone ary
24252419
A.write mary idx b
24262420
A.unsafeFreeze mary
2427-
{-# INLINE update32M #-}
2421+
{-# INLINE updateFullArrayM #-}
24282422

24292423
-- | \(O(n)\) Update the element at the given position in this array, by applying a function to it.
2430-
update32With' :: A.Array e -> Int -> (e -> e) -> A.Array e
2431-
update32With' ary idx f
2424+
updateFullArrayWith' :: A.Array e -> Int -> (e -> e) -> A.Array e
2425+
updateFullArrayWith' ary idx f
24322426
| (# x #) <- A.index# ary idx
2433-
= update32 ary idx $! f x
2434-
{-# INLINE update32With' #-}
2427+
= updateFullArray ary idx $! f x
2428+
{-# INLINE updateFullArrayWith' #-}
24352429

24362430
-- | Unsafely clone an array of (2^bitsPerSubkey) elements. The length of the input
24372431
-- array is not checked.
@@ -2448,8 +2442,16 @@ clone ary =
24482442
-- | Number of bits that are inspected at each level of the hash tree.
24492443
--
24502444
-- This constant is named /t/ in the original /Ideal Hash Trees/ paper.
2445+
--
2446+
-- Note that this constant is platform-dependent. On 32-bit platforms we use
2447+
-- '4', because bitmaps using '2^5' bits turned out to be prone to integer
2448+
-- overflow bugs. See #491 for instance.
24512449
bitsPerSubkey :: Int
2450+
#if WORD_SIZE_IN_BITS < 64
2451+
bitsPerSubkey = 4
2452+
#else
24522453
bitsPerSubkey = 5
2454+
#endif
24532455

24542456
-- | The size of a 'Full' node, i.e. @2 ^ 'bitsPerSubkey'@.
24552457
maxChildren :: Int

Data/HashMap/Internal/Strict.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
-- strings.
4040
--
4141
-- Many operations have a average-case complexity of \(O(\log n)\). The
42-
-- implementation uses a large base (i.e. 32) so in practice these
42+
-- implementation uses a large base (i.e. 16 or 32) so in practice these
4343
-- operations are constant time.
4444
module Data.HashMap.Internal.Strict
4545
(
@@ -211,7 +211,7 @@ insertWith f k0 v0 m0 = go h0 k0 v0 0 m0
211211
go h k x s (Full ary) =
212212
let st = A.index ary i
213213
st' = go h k x (nextShift s) st
214-
ary' = HM.update32 ary i $! st'
214+
ary' = HM.updateFullArray ary i $! st'
215215
in Full ary'
216216
where i = index h s
217217
go h k x s t@(Collision hy v)
@@ -282,7 +282,7 @@ adjust f k0 m0 = go h0 k0 0 m0
282282
let i = index h s
283283
st = A.index ary i
284284
st' = go h k (nextShift s) st
285-
ary' = HM.update32 ary i $! st'
285+
ary' = HM.updateFullArray ary i $! st'
286286
in Full ary'
287287
go h k _ t@(Collision hy v)
288288
| h == hy = Collision h (updateWith f k v)
@@ -516,12 +516,12 @@ unionWithKey f = go 0
516516
go s (Full ary1) t2 =
517517
let h2 = leafHashCode t2
518518
i = index h2 s
519-
ary' = HM.update32With' ary1 i $ \st1 -> go (nextShift s) st1 t2
519+
ary' = HM.updateFullArrayWith' ary1 i $ \st1 -> go (nextShift s) st1 t2
520520
in Full ary'
521521
go s t1 (Full ary2) =
522522
let h1 = leafHashCode t1
523523
i = index h1 s
524-
ary' = HM.update32With' ary2 i $ \st2 -> go (nextShift s) t1 st2
524+
ary' = HM.updateFullArrayWith' ary2 i $ \st2 -> go (nextShift s) t1 st2
525525
in Full ary'
526526

527527
leafHashCode (Leaf h _) = h

Data/HashMap/Lazy.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
-- strings.
2121
--
2222
-- Many operations have a average-case complexity of \(O(\log n)\). The
23-
-- implementation uses a large base (i.e. 32) so in practice these
23+
-- implementation uses a large base (i.e. 16 or 32) so in practice these
2424
-- operations are constant time.
2525
module Data.HashMap.Lazy
2626
(

Data/HashMap/Strict.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
-- strings.
2020
--
2121
-- Many operations have a average-case complexity of \(O(\log n)\). The
22-
-- implementation uses a large base (i.e. 32) so in practice these
22+
-- implementation uses a large base (i.e. 16 or 32) so in practice these
2323
-- operations are constant time.
2424
module Data.HashMap.Strict
2525
(

Data/HashSet.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ especially when value comparisons are expensive, as in the case of
8787
strings.
8888
8989
Many operations have a average-case complexity of \(O(\log n)\). The
90-
implementation uses a large base (i.e. 16) so in practice these
90+
implementation uses a large base (i.e. 16 or 32) so in practice these
9191
operations are constant time.
9292
-}
9393

Data/HashSet/Internal.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
-- strings.
3838
--
3939
-- Many operations have a average-case complexity of \(O(\log n)\). The
40-
-- implementation uses a large base (i.e. 32) so in practice these
40+
-- implementation uses a large base (i.e. 16 or 32) so in practice these
4141
-- operations are constant time.
4242

4343
module Data.HashSet.Internal

docs/developer-guide.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ Here's a quick overview in order of simplicity:
103103
it contains *2^B* elements.
104104

105105
The number of bits of the hash value to use at each level of the tree, *B*, is a
106-
compile time constant, currently 5. In general a larger *B* improves lookup
106+
compile time constant, currently 5 on 64-bit platforms, and 4 on platforms with
107+
a smaller word size. In general a larger *B* improves lookup
107108
performance (shallower tree) but hurts modification (large nodes to copy when
108109
updating the spine of the tree).
109110

0 commit comments

Comments
 (0)