3131{-# LANGUAGE DeriveDataTypeable #-}
3232{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3333
34+ #include <bitset.h>
35+
3436module Data.BitSet.Generic
3537 (
3638 -- * Bit set type
@@ -79,6 +81,9 @@ import Control.Applicative ((<$>))
7981import Control.DeepSeq (NFData (.. ))
8082import Data.Bits (Bits , (.|.) , (.&.) , complement , bit ,
8183 testBit , setBit , clearBit , popCount )
84+ #if MIN_VERSION_base(4,7,0)
85+ import Data.Bits (bitSizeMaybe , isSigned , unsafeShiftR , zeroBits )
86+ #endif
8287import Data.Data (Typeable )
8388import Data.Monoid (Monoid (.. ))
8489import Foreign (Storable )
@@ -94,29 +99,35 @@ import qualified Data.List as List
9499newtype BitSet c a = BitSet { getBits :: c }
95100 deriving (Eq , NFData , Storable , Ord , Typeable )
96101
97- instance (Enum a , Read a , Bits c , Num c ) => Read (BitSet c a ) where
102+ instance (Enum a , Read a , Bits c ) => Read (BitSet c a ) where
98103 readPrec = parens . prec 10 $ do
99104 Ident " fromList" <- lexP
100105 fromList <$> readPrec
101106
102- instance (Enum a , Show a , Bits c , Num c ) => Show (BitSet c a ) where
107+ instance (Enum a , Show a , Bits c ) => Show (BitSet c a ) where
103108 showsPrec p bs = showParen (p > 10 ) $
104109 showString " fromList " . shows (toList bs)
105110
106- instance ( Enum a , Bits c , Num c ) => Monoid (BitSet c a ) where
111+ instance Bits c => Monoid (BitSet c a ) where
107112 mempty = empty
108113 mappend = union
109114
110115#if defined(__GLASGOW_HASKELL__) && (__GLASGOW_HASKELL__ >= 707)
111- instance (Enum a , Bits c , Num c ) => IsList (BitSet c a ) where
116+ instance (Enum a , Bits c ) => IsList (BitSet c a ) where
112117 type Item (BitSet c a ) = a
113118 fromList = fromList
114119 toList = toList
115120#endif
116121
122+ #if !MIN_VERSION_base(4,7,0)
123+ zeroBits :: Bits c => c
124+ zeroBits = bit 0 `clearBit` 0
125+ {-# INLINE zeroBits #-}
126+ #endif
127+
117128-- | /O(1)/. Is the bit set empty?
118- null :: ( Eq c , Num c ) => BitSet c a -> Bool
119- null = (== 0 ) . getBits
129+ null :: Bits c => BitSet c a -> Bool
130+ null = (== zeroBits ) . getBits
120131{-# INLINE null #-}
121132
122133-- | /O(1)/. The number of elements in the bit set.
@@ -136,22 +147,22 @@ notMember x = not . member x
136147
137148-- | /O(max(n, m))/. Is this a subset? (@s1 `isSubsetOf` s2@) tells whether
138149-- @s1@ is a subset of @s2@.
139- isSubsetOf :: ( Bits c , Eq c ) => BitSet c a -> BitSet c a -> Bool
150+ isSubsetOf :: Bits c => BitSet c a -> BitSet c a -> Bool
140151isSubsetOf (BitSet bits1) (BitSet bits2) = bits2 .|. bits1 == bits2
141152{-# INLINE isSubsetOf #-}
142153
143154-- | /O(max(n, m)/. Is this a proper subset? (ie. a subset but not equal).
144- isProperSubsetOf :: ( Bits c , Eq c ) => BitSet c a -> BitSet c a -> Bool
155+ isProperSubsetOf :: Bits c => BitSet c a -> BitSet c a -> Bool
145156isProperSubsetOf bs1 bs2 = bs1 `isSubsetOf` bs2 && bs1 /= bs2
146157{-# INLINE isProperSubsetOf #-}
147158
148159-- | The empty bit set.
149- empty :: ( Enum a , Bits c , Num c ) => BitSet c a
150- empty = BitSet 0
160+ empty :: Bits c => BitSet c a
161+ empty = BitSet zeroBits
151162{-# INLINE empty #-}
152163
153164-- | O(1). Create a singleton set.
154- singleton :: (Enum a , Bits c , Num c ) => a -> BitSet c a
165+ singleton :: (Enum a , Bits c ) => a -> BitSet c a
155166singleton = BitSet . bit . fromEnum
156167{-# INLINE singleton #-}
157168
@@ -186,7 +197,7 @@ intersection (BitSet bits1) (BitSet bits2) = BitSet $ bits1 .&. bits2
186197
187198-- | /O(d * n)/ Transform this bit set by applying a function to every
188199-- value. Resulting bit set may be smaller then the original.
189- map :: (Enum a , Enum b , Bits c , Num c ) => (a -> b ) -> BitSet c a -> BitSet c b
200+ map :: (Enum a , Enum b , Bits c ) => (a -> b ) -> BitSet c a -> BitSet c b
190201map f = foldl' (\ bs -> (`insert` bs) . f) empty
191202{-# INLINE map #-}
192203
@@ -195,37 +206,63 @@ map f = foldl' (\bs -> (`insert` bs) . f) empty
195206-- operator is evaluated before before using the result in the next
196207-- application. This function is strict in the starting value.
197208foldl' :: (Enum a , Bits c ) => (b -> a -> b ) -> b -> BitSet c a -> b
198- foldl' f acc0 (BitSet bits) = go acc0 (popCount bits) 0 where
199- go ! acc 0 _b = acc
200- go ! acc ! n b = if bits `testBit` b
201- then go (f acc $ toEnum b) (pred n) (succ b)
202- else go acc n (succ b)
209+ #if MIN_VERSION_base(4,7,0)
210+ -- If the bit set is represented by an unsigned type
211+ -- then we can shift the bits off one by one until we're
212+ -- left with all zeros. If the type is fairly narrow, then
213+ -- this is likely to be cheap. In particular, in this case
214+ -- we don't need to calculate the `popCount` and all shifts
215+ -- are by fixed amounts.
216+ foldl' f acc0 (BitSet bits0)
217+ | not (isSigned bits0) && maybe False (<= 128 ) (bitSizeMaybe bits0) =
218+ go acc0 bits0 0
219+ where
220+ go ! acc ! bits ! b
221+ | bits == zeroBits = acc
222+ | bits `testBit` 0 = go (f acc $ toEnum b) (bits `unsafeShiftR` 1 ) (b + 1 )
223+ | otherwise = go acc (bits `unsafeShiftR` 1 ) (b + 1 )
224+ #endif
225+ foldl' f acc0 (BitSet bits) = go acc0 (popCount bits) 0
226+ where
227+ go ! acc 0 ! _b = acc
228+ go ! acc n ! b = if bits `testBit` b
229+ then go (f acc $ toEnum b) (n - 1 ) (b + 1 )
230+ else go acc n (b + 1 )
203231{-# INLINE foldl' #-}
204232
205233-- | /O(d * n)/ Reduce this bit set by applying a binary function to
206234-- all elements, using the given starting value.
207235foldr :: (Enum a , Bits c ) => (a -> b -> b ) -> b -> BitSet c a -> b
236+ #if MIN_VERSION_base(4,7,0)
237+ foldr f acc0 (BitSet bits0)
238+ | not (isSigned bits0) && maybe False (<= 128 ) (bitSizeMaybe bits0) = go bits0 0
239+ where
240+ go ! bits ! b
241+ | bits == zeroBits = acc0
242+ | bits `testBit` 0 = toEnum b `f` go (bits `unsafeShiftR` 1 ) (b + 1 )
243+ | otherwise = go (bits `unsafeShiftR` 1 ) (b + 1 )
244+ #endif
208245foldr f acc0 (BitSet bits) = go (popCount bits) 0 where
209246 go 0 _b = acc0
210247 go ! n b = if bits `testBit` b
211- then toEnum b `f` go (pred n ) (succ b )
212- else go n (succ b )
248+ then toEnum b `f` go (n - 1 ) (b + 1 )
249+ else go n (b + 1 )
213250{-# INLINE foldr #-}
214251
215252-- | /O(d * n)/ Filter this bit set by retaining only elements satisfying
216253-- predicate.
217- filter :: (Enum a , Bits c , Num c ) => (a -> Bool ) -> BitSet c a -> BitSet c a
254+ filter :: (Enum a , Bits c ) => (a -> Bool ) -> BitSet c a -> BitSet c a
218255filter f = foldl' (\ bs x -> if f x then x `insert` bs else bs) empty
219256{-# INLINE filter #-}
220257
221258-- | /O(d * n)/. Convert this bit set set to a list of elements.
222- toList :: (Enum a , Bits c , Num c ) => BitSet c a -> [a ]
259+ toList :: (Enum a , Bits c ) => BitSet c a -> [a ]
223260toList bs = build (\ k z -> foldr k z bs)
224261{-# INLINE [0] toList #-}
225262
226263-- | /O(d * n)/. Make a bit set from a list of elements.
227- fromList :: (Enum a , Bits c , Num c ) => [a ] -> BitSet c a
228- fromList = BitSet . List. foldl' (\ i x -> i `setBit` fromEnum x) 0
264+ fromList :: (Enum a , Bits c ) => [a ] -> BitSet c a
265+ fromList = List. foldl' (\ i x -> insert x i) empty
229266{-# INLINE [0] fromList #-}
230267{-# RULES
231268"fromList/toList" forall bs. fromList (toList bs) = bs
0 commit comments