@@ -150,6 +150,7 @@ module Data.IntSet.Internal (
150150 -- * Folds
151151 , foldr
152152 , foldl
153+ , foldMap
153154 -- ** Strict folds
154155 , foldr'
155156 , foldl'
@@ -206,7 +207,7 @@ import qualified Data.Foldable1 as Foldable1
206207import Data.List.NonEmpty (NonEmpty (.. ))
207208#endif
208209import Utils.Containers.Internal.Prelude hiding
209- (filter , foldr , foldl , foldl' , null , map )
210+ (filter , foldr , foldl , foldl' , foldMap , null , map )
210211import Prelude ()
211212
212213import Utils.Containers.Internal.BitUtil
@@ -1252,6 +1253,29 @@ foldl' f z = \t -> -- Use lambda t to be inlinable with two arguments only.
12521253 go z' (Bin _ l r) = go (go z' l) r
12531254{-# INLINE foldl' #-}
12541255
1256+ -- | \(O(n))\). Map the elements in the set to a monoid and combine with @(<>)@.
1257+ foldMap :: Monoid a => (Key -> a ) -> IntSet -> a
1258+ foldMap f = \ t -> -- Use lambda t to be inlinable with one argument only.
1259+ case t of
1260+ Bin p l r
1261+ #if MIN_VERSION_base(4,11,0)
1262+ | signBranch p -> go r <> go l -- handle negative numbers
1263+ | otherwise -> go l <> go r
1264+ #else
1265+ | signBranch p -> go r `mappend` go l -- handle negative numbers
1266+ | otherwise -> go l `mappend` go r
1267+ #endif
1268+ _ -> go t
1269+ where
1270+ #if MIN_VERSION_base(4,11,0)
1271+ go (Bin _ l r) = go l <> go r
1272+ #else
1273+ go (Bin _ l r) = go l `mappend` go r
1274+ #endif
1275+ go (Tip kx bm) = foldMapBits kx f bm
1276+ go Nil = mempty
1277+ {-# INLINE foldMap #-}
1278+
12551279{- -------------------------------------------------------------------
12561280 List variations
12571281--------------------------------------------------------------------}
@@ -1675,6 +1699,11 @@ foldlBits :: Int -> (a -> Int -> a) -> a -> Nat -> a
16751699foldl'Bits :: Int -> (a -> Int -> a ) -> a -> Nat -> a
16761700foldrBits :: Int -> (Int -> a -> a ) -> a -> Nat -> a
16771701foldr'Bits :: Int -> (Int -> a -> a ) -> a -> Nat -> a
1702+ #if MIN_VERSION_base(4,11,0)
1703+ foldMapBits :: Semigroup a => Int -> (Int -> a ) -> Nat -> a
1704+ #else
1705+ foldMapBits :: Monoid a => Int -> (Int -> a ) -> Nat -> a
1706+ #endif
16781707takeWhileAntitoneBits :: Int -> (Int -> Bool ) -> Nat -> Nat
16791708
16801709{-# INLINE lowestBitSet #-}
@@ -1683,6 +1712,7 @@ takeWhileAntitoneBits :: Int -> (Int -> Bool) -> Nat -> Nat
16831712{-# INLINE foldl'Bits #-}
16841713{-# INLINE foldrBits #-}
16851714{-# INLINE foldr'Bits #-}
1715+ {-# INLINE foldMapBits #-}
16861716{-# INLINE takeWhileAntitoneBits #-}
16871717
16881718lowestBitMask :: Nat -> Nat
@@ -1738,6 +1768,20 @@ foldr'Bits prefix f z bitmap = go (revNat bitmap) z
17381768 where ! bitmask = lowestBitMask bm
17391769 ! bi = countTrailingZeros bitmask
17401770
1771+ foldMapBits prefix f bitmap = go (prefix + bi0) (bitmap `xor` bitmask0)
1772+ where
1773+ bitmask0 = lowestBitMask bitmap
1774+ bi0 = countTrailingZeros bitmask0
1775+ go ! x 0 = f x
1776+ #if MIN_VERSION_base(4,11,0)
1777+ go ! x bm = f x <> go (prefix + bi) (bm `xor` bitmask)
1778+ #else
1779+ go ! x bm = f x `mappend` go (prefix + bi) (bm `xor` bitmask)
1780+ #endif
1781+ where
1782+ bitmask = lowestBitMask bm
1783+ bi = countTrailingZeros bitmask
1784+
17411785takeWhileAntitoneBits prefix predicate bitmap =
17421786 -- Binary search for the first index where the predicate returns false, but skip a predicate
17431787 -- call if the high half of the current range is empty. This ensures
@@ -1810,6 +1854,19 @@ foldr'Bits prefix f z bm = let lb = lowestBitSet bm
18101854 go bi n | n `testBit` 0 = f bi $! go (bi + 1 ) (n `shiftRL` 1 )
18111855 | otherwise = go (bi + 1 ) (n `shiftRL` 1 )
18121856
1857+ foldMapBits prefix f bm = go x0 (x0 + 1 ) ((bm `shiftRL` lb) `shiftRL` 1 )
1858+ where
1859+ lb = lowestBitSet bm
1860+ x0 = prefix + lb
1861+ go ! x ! _ 0 = f x
1862+ go ! x ! bi n
1863+ #if MIN_VERSION_base(4,11,0)
1864+ | n `testBit` 0 = f x <> go bi (bi + 1 ) (n `shiftRL` 1 )
1865+ #else
1866+ | n `testBit` 0 = f x `mappend` go bi (bi + 1 ) (n `shiftRL` 1 )
1867+ #endif
1868+ | otherwise = go x (bi + 1 ) (n `shiftRL` 1 )
1869+
18131870takeWhileAntitoneBits prefix predicate = foldl'Bits prefix f 0 -- Does not use antitone property
18141871 where
18151872 f acc bi | predicate bi = acc .|. bitmapOf bi
0 commit comments