@@ -150,6 +150,7 @@ module Data.IntSet.Internal (
150
150
-- * Folds
151
151
, foldr
152
152
, foldl
153
+ , foldMap
153
154
-- ** Strict folds
154
155
, foldr'
155
156
, foldl'
@@ -206,7 +207,7 @@ import qualified Data.Foldable1 as Foldable1
206
207
import Data.List.NonEmpty (NonEmpty (.. ))
207
208
#endif
208
209
import Utils.Containers.Internal.Prelude hiding
209
- (filter , foldr , foldl , foldl' , null , map )
210
+ (filter , foldr , foldl , foldl' , foldMap , null , map )
210
211
import Prelude ()
211
212
212
213
import Utils.Containers.Internal.BitUtil
@@ -1252,6 +1253,29 @@ foldl' f z = \t -> -- Use lambda t to be inlinable with two arguments only.
1252
1253
go z' (Bin _ l r) = go (go z' l) r
1253
1254
{-# INLINE foldl' #-}
1254
1255
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
+
1255
1279
{- -------------------------------------------------------------------
1256
1280
List variations
1257
1281
--------------------------------------------------------------------}
@@ -1675,6 +1699,11 @@ foldlBits :: Int -> (a -> Int -> a) -> a -> Nat -> a
1675
1699
foldl'Bits :: Int -> (a -> Int -> a ) -> a -> Nat -> a
1676
1700
foldrBits :: Int -> (Int -> a -> a ) -> a -> Nat -> a
1677
1701
foldr'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
1678
1707
takeWhileAntitoneBits :: Int -> (Int -> Bool ) -> Nat -> Nat
1679
1708
1680
1709
{-# INLINE lowestBitSet #-}
@@ -1683,6 +1712,7 @@ takeWhileAntitoneBits :: Int -> (Int -> Bool) -> Nat -> Nat
1683
1712
{-# INLINE foldl'Bits #-}
1684
1713
{-# INLINE foldrBits #-}
1685
1714
{-# INLINE foldr'Bits #-}
1715
+ {-# INLINE foldMapBits #-}
1686
1716
{-# INLINE takeWhileAntitoneBits #-}
1687
1717
1688
1718
lowestBitMask :: Nat -> Nat
@@ -1738,6 +1768,20 @@ foldr'Bits prefix f z bitmap = go (revNat bitmap) z
1738
1768
where ! bitmask = lowestBitMask bm
1739
1769
! bi = countTrailingZeros bitmask
1740
1770
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
+
1741
1785
takeWhileAntitoneBits prefix predicate bitmap =
1742
1786
-- Binary search for the first index where the predicate returns false, but skip a predicate
1743
1787
-- 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
1810
1854
go bi n | n `testBit` 0 = f bi $! go (bi + 1 ) (n `shiftRL` 1 )
1811
1855
| otherwise = go (bi + 1 ) (n `shiftRL` 1 )
1812
1856
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
+
1813
1870
takeWhileAntitoneBits prefix predicate = foldl'Bits prefix f 0 -- Does not use antitone property
1814
1871
where
1815
1872
f acc bi | predicate bi = acc .|. bitmapOf bi
0 commit comments