1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
|
Taken from https://github.com/bos/bloomfilter/pull/20
From fb79b39c44404fd791a3bed973e9d844fb084f1e Mon Sep 17 00:00:00 2001
From: Simon Jakobi <simon.jakobi@gmail.com>
Date: Fri, 12 Nov 2021 01:37:36 +0100
Subject: [PATCH] Fix build with GHC 9.2
The `FastShift.shift{L,R}` methods are replaced with `unsafeShift{L,R}`
introduced in base-4.5.
Fixes #19.
---
Data/BloomFilter.hs | 16 +++++------
Data/BloomFilter/Hash.hs | 15 +++++-----
Data/BloomFilter/Mutable.hs | 20 +++++++-------
Data/BloomFilter/Util.hs | 55 ++++++-------------------------------
bloomfilter.cabal | 2 +-
5 files changed, 34 insertions(+), 74 deletions(-)
diff --git a/Data/BloomFilter.hs b/Data/BloomFilter.hs
index 2210cef..6b47c21 100644
--- a/Data/BloomFilter.hs
+++ b/Data/BloomFilter.hs
@@ -78,8 +78,8 @@ import Control.DeepSeq (NFData(..))
import Data.Array.Base (unsafeAt)
import qualified Data.Array.Base as ST
import Data.Array.Unboxed (UArray)
-import Data.Bits ((.&.))
-import Data.BloomFilter.Util (FastShift(..), (:*)(..))
+import Data.Bits ((.&.), unsafeShiftL, unsafeShiftR)
+import Data.BloomFilter.Util ((:*)(..))
import qualified Data.BloomFilter.Mutable as MB
import qualified Data.BloomFilter.Mutable.Internal as MB
import Data.BloomFilter.Mutable.Internal (Hash, MBloom)
@@ -98,7 +98,7 @@ data Bloom a = B {
}
instance Show (Bloom a) where
- show ub = "Bloom { " ++ show ((1::Int) `shiftL` shift ub) ++ " bits } "
+ show ub = "Bloom { " ++ show ((1::Int) `unsafeShiftL` shift ub) ++ " bits } "
instance NFData (Bloom a) where
rnf !_ = ()
@@ -172,7 +172,7 @@ singleton hash numBits elt = create hash numBits (\mb -> MB.insert mb elt)
-- | Given a filter's mask and a hash value, compute an offset into
-- a word array and a bit offset within that word.
hashIdx :: Int -> Word32 -> (Int :* Int)
-hashIdx mask x = (y `shiftR` logBitsInHash) :* (y .&. hashMask)
+hashIdx mask x = (y `unsafeShiftR` logBitsInHash) :* (y .&. hashMask)
where hashMask = 31 -- bitsInHash - 1
y = fromIntegral x .&. mask
@@ -191,7 +191,7 @@ hashesU ub elt = hashIdx (mask ub) `map` hashes ub elt
-- /still/ some possibility that @True@ will be returned.
elem :: a -> Bloom a -> Bool
elem elt ub = all test (hashesU ub elt)
- where test (off :* bit) = (bitArray ub `unsafeAt` off) .&. (1 `shiftL` bit) /= 0
+ where test (off :* bit) = (bitArray ub `unsafeAt` off) .&. (1 `unsafeShiftL` bit) /= 0
modify :: (forall s. (MBloom s a -> ST s z)) -- ^ mutation function (result is discarded)
-> Bloom a
@@ -255,11 +255,11 @@ insertList elts = modify $ \mb -> mapM_ (MB.insert mb) elts
-- is /still/ some possibility that @True@ will be returned.
notElem :: a -> Bloom a -> Bool
notElem elt ub = any test (hashesU ub elt)
- where test (off :* bit) = (bitArray ub `unsafeAt` off) .&. (1 `shiftL` bit) == 0
+ where test (off :* bit) = (bitArray ub `unsafeAt` off) .&. (1 `unsafeShiftL` bit) == 0
-- | Return the size of an immutable Bloom filter, in bits.
length :: Bloom a -> Int
-length = shiftL 1 . shift
+length = unsafeShiftL 1 . shift
-- | Build an immutable Bloom filter from a seed value. The seeding
-- function populates the filter as follows.
@@ -318,7 +318,7 @@ fromList hashes numBits = unfold hashes numBits convert
logPower2 :: Int -> Int
logPower2 k = go 0 k
where go j 1 = j
- go j n = go (j+1) (n `shiftR` 1)
+ go j n = go (j+1) (n `unsafeShiftR` 1)
-- $overview
--
diff --git a/Data/BloomFilter/Hash.hs b/Data/BloomFilter/Hash.hs
index 132a3a4..d071fd4 100644
--- a/Data/BloomFilter/Hash.hs
+++ b/Data/BloomFilter/Hash.hs
@@ -38,8 +38,7 @@ module Data.BloomFilter.Hash
) where
import Control.Monad (foldM)
-import Data.Bits ((.&.), (.|.), xor)
-import Data.BloomFilter.Util (FastShift(..))
+import Data.Bits ((.&.), (.|.), unsafeShiftL, unsafeShiftR, xor)
import Data.List (unfoldr)
import Data.Int (Int8, Int16, Int32, Int64)
import Data.Word (Word8, Word16, Word32, Word64)
@@ -91,11 +90,11 @@ class Hashable a where
-> Word64 -- ^ salt
-> IO Word64
hashIO64 v salt = do
- let s1 = fromIntegral (salt `shiftR` 32) .&. maxBound
+ let s1 = fromIntegral (salt `unsafeShiftR` 32) .&. maxBound
s2 = fromIntegral salt
h1 <- hashIO32 v s1
h2 <- hashIO32 v s2
- return $ (fromIntegral h1 `shiftL` 32) .|. fromIntegral h2
+ return $ (fromIntegral h1 `unsafeShiftL` 32) .|. fromIntegral h2
-- | Compute a 32-bit hash.
hash32 :: Hashable a => a -> Word32
@@ -149,8 +148,8 @@ cheapHashes :: Hashable a => Int -- ^ number of hashes to compute
cheapHashes k v = go 0
where go i | i == j = []
| otherwise = hash : go (i + 1)
- where !hash = h1 + (h2 `shiftR` i)
- h1 = fromIntegral (h `shiftR` 32)
+ where !hash = h1 + (h2 `unsafeShiftR` i)
+ h1 = fromIntegral (h `unsafeShiftR` 32)
h2 = fromIntegral h
h = hashSalt64 0x9150a946c4a8966e v
j = fromIntegral k
@@ -163,7 +162,7 @@ instance Hashable Integer where
(salt `xor` 0x3ece731e)
| otherwise = hashIO32 (unfoldr go k) salt
where go 0 = Nothing
- go i = Just (fromIntegral i :: Word32, i `shiftR` 32)
+ go i = Just (fromIntegral i :: Word32, i `unsafeShiftR` 32)
instance Hashable Bool where
hashIO32 = hashOne32
@@ -224,7 +223,7 @@ instance Hashable Word64 where
-- | A fast unchecked shift. Nasty, but otherwise GHC 6.8.2 does a
-- test and branch on every shift.
div4 :: CSize -> CSize
-div4 k = fromIntegral ((fromIntegral k :: HTYPE_SIZE_T) `shiftR` 2)
+div4 k = fromIntegral ((fromIntegral k :: HTYPE_SIZE_T) `unsafeShiftR` 2)
alignedHash :: Ptr a -> CSize -> Word32 -> IO Word32
alignedHash ptr bytes salt
diff --git a/Data/BloomFilter/Mutable.hs b/Data/BloomFilter/Mutable.hs
index edff1fc..0bb5cc9 100644
--- a/Data/BloomFilter/Mutable.hs
+++ b/Data/BloomFilter/Mutable.hs
@@ -65,9 +65,9 @@ module Data.BloomFilter.Mutable
import Control.Monad (liftM, forM_)
import Control.Monad.ST (ST)
import Data.Array.Base (unsafeRead, unsafeWrite)
-import Data.Bits ((.&.), (.|.))
+import Data.Bits ((.&.), (.|.), unsafeShiftL, unsafeShiftR)
import Data.BloomFilter.Array (newArray)
-import Data.BloomFilter.Util (FastShift(..), (:*)(..), nextPowerOfTwo)
+import Data.BloomFilter.Util ((:*)(..), nextPowerOfTwo)
import Data.Word (Word32)
import Data.BloomFilter.Mutable.Internal
@@ -86,9 +86,9 @@ new hash numBits = MB hash shft msk `liftM` newArray numElems numBytes
| numBits > maxHash = maxHash
| isPowerOfTwo numBits = numBits
| otherwise = nextPowerOfTwo numBits
- numElems = max 2 (twoBits `shiftR` logBitsInHash)
- numBytes = numElems `shiftL` logBytesInHash
- trueBits = numElems `shiftL` logBitsInHash
+ numElems = max 2 (twoBits `unsafeShiftR` logBitsInHash)
+ numBytes = numElems `unsafeShiftL` logBytesInHash
+ trueBits = numElems `unsafeShiftL` logBitsInHash
shft = logPower2 trueBits
msk = trueBits - 1
isPowerOfTwo n = n .&. (n - 1) == 0
@@ -109,7 +109,7 @@ logBytesInHash = 2 -- logPower2 (sizeOf (undefined :: Hash))
-- | Given a filter's mask and a hash value, compute an offset into
-- a word array and a bit offset within that word.
hashIdx :: Int -> Word32 -> (Int :* Int)
-hashIdx msk x = (y `shiftR` logBitsInHash) :* (y .&. hashMask)
+hashIdx msk x = (y `unsafeShiftR` logBitsInHash) :* (y .&. hashMask)
where hashMask = 31 -- bitsInHash - 1
y = fromIntegral x .&. msk
@@ -125,7 +125,7 @@ insert mb elt = do
let mu = bitArray mb
forM_ (hashesM mb elt) $ \(word :* bit) -> do
old <- unsafeRead mu word
- unsafeWrite mu word (old .|. (1 `shiftL` bit))
+ unsafeWrite mu word (old .|. (1 `unsafeShiftL` bit))
-- | Query a mutable Bloom filter for membership. If the value is
-- present, return @True@. If the value is not present, there is
@@ -135,7 +135,7 @@ elem elt mb = loop (hashesM mb elt)
where mu = bitArray mb
loop ((word :* bit):wbs) = do
i <- unsafeRead mu word
- if i .&. (1 `shiftL` bit) == 0
+ if i .&. (1 `unsafeShiftL` bit) == 0
then return False
else loop wbs
loop _ = return True
@@ -145,7 +145,7 @@ elem elt mb = loop (hashesM mb elt)
-- | Return the size of a mutable Bloom filter, in bits.
length :: MBloom s a -> Int
-length = shiftL 1 . shift
+length = unsafeShiftL 1 . shift
-- | Slow, crummy way of computing the integer log of an integer known
@@ -153,7 +153,7 @@ length = shiftL 1 . shift
logPower2 :: Int -> Int
logPower2 k = go 0 k
where go j 1 = j
- go j n = go (j+1) (n `shiftR` 1)
+ go j n = go (j+1) (n `unsafeShiftR` 1)
-- $overview
--
diff --git a/Data/BloomFilter/Util.hs b/Data/BloomFilter/Util.hs
index 7f695dc..6ade6e5 100644
--- a/Data/BloomFilter/Util.hs
+++ b/Data/BloomFilter/Util.hs
@@ -2,15 +2,11 @@
module Data.BloomFilter.Util
(
- FastShift(..)
- , nextPowerOfTwo
+ nextPowerOfTwo
, (:*)(..)
) where
-import Data.Bits ((.|.))
-import qualified Data.Bits as Bits
-import GHC.Base
-import GHC.Word
+import Data.Bits ((.|.), unsafeShiftR)
-- | A strict pair type.
data a :* b = !a :* !b
@@ -22,46 +18,11 @@ nextPowerOfTwo :: Int -> Int
{-# INLINE nextPowerOfTwo #-}
nextPowerOfTwo n =
let a = n - 1
- b = a .|. (a `shiftR` 1)
- c = b .|. (b `shiftR` 2)
- d = c .|. (c `shiftR` 4)
- e = d .|. (d `shiftR` 8)
- f = e .|. (e `shiftR` 16)
- g = f .|. (f `shiftR` 32) -- in case we're on a 64-bit host
+ b = a .|. (a `unsafeShiftR` 1)
+ c = b .|. (b `unsafeShiftR` 2)
+ d = c .|. (c `unsafeShiftR` 4)
+ e = d .|. (d `unsafeShiftR` 8)
+ f = e .|. (e `unsafeShiftR` 16)
+ g = f .|. (f `unsafeShiftR` 32) -- in case we're on a 64-bit host
!h = g + 1
in h
-
--- | This is a workaround for poor optimisation in GHC 6.8.2. It
--- fails to notice constant-width shifts, and adds a test and branch
--- to every shift. This imposes about a 10% performance hit.
-class FastShift a where
- shiftL :: a -> Int -> a
- shiftR :: a -> Int -> a
-
-instance FastShift Word32 where
- {-# INLINE shiftL #-}
- shiftL (W32# x#) (I# i#) = W32# (x# `uncheckedShiftL#` i#)
-
- {-# INLINE shiftR #-}
- shiftR (W32# x#) (I# i#) = W32# (x# `uncheckedShiftRL#` i#)
-
-instance FastShift Word64 where
- {-# INLINE shiftL #-}
- shiftL (W64# x#) (I# i#) = W64# (x# `uncheckedShiftL64#` i#)
-
- {-# INLINE shiftR #-}
- shiftR (W64# x#) (I# i#) = W64# (x# `uncheckedShiftRL64#` i#)
-
-instance FastShift Int where
- {-# INLINE shiftL #-}
- shiftL (I# x#) (I# i#) = I# (x# `iShiftL#` i#)
-
- {-# INLINE shiftR #-}
- shiftR (I# x#) (I# i#) = I# (x# `iShiftRA#` i#)
-
-instance FastShift Integer where
- {-# INLINE shiftL #-}
- shiftL = Bits.shiftL
-
- {-# INLINE shiftR #-}
- shiftR = Bits.shiftR
diff --git a/bloomfilter.cabal b/bloomfilter.cabal
index 821a5d7..c621f7f 100644
--- a/bloomfilter.cabal
+++ b/bloomfilter.cabal
@@ -18,7 +18,7 @@ extra-source-files: README.markdown cbits/lookup3.c cbits/lookup3.h
library
build-depends:
array,
- base >= 4.4 && < 5,
+ base >= 4.5 && < 5,
bytestring >= 0.9,
deepseq
exposed-modules: Data.BloomFilter
|