Skip to content

Commit 1ea8808

Browse files
committed
Merge branch 'mapMaybe' of https://github.com/jcpetruzza/unordered-containers into mapMaybe
2 parents ab13997 + 05ec392 commit 1ea8808

File tree

4 files changed

+86
-12
lines changed

4 files changed

+86
-12
lines changed

Data/HashMap/Base.hs

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{-# LANGUAGE BangPatterns, CPP, DeriveDataTypeable, MagicHash #-}
22
{-# LANGUAGE ScopedTypeVariables #-}
3+
{-# LANGUAGE PatternGuards #-}
34
#if __GLASGOW_HASKELL__ >= 708
45
{-# LANGUAGE TypeFamilies #-}
56
#endif
@@ -52,6 +53,8 @@ module Data.HashMap.Base
5253
, foldrWithKey
5354

5455
-- * Filter
56+
, mapMaybe
57+
, mapMaybeWithKey
5558
, filter
5659
, filterWithKey
5760

@@ -81,6 +84,7 @@ module Data.HashMap.Base
8184
, update16M
8285
, update16With'
8386
, updateOrConcatWith
87+
, filterMapAux
8488
) where
8589

8690
#if __GLASGOW_HASKELL__ >= 709
@@ -855,14 +859,47 @@ trim mary n = do
855859
A.unsafeFreeze mary2
856860
{-# INLINE trim #-}
857861

862+
-- | /O(n)/ Transform this map by applying a function to every value
863+
-- and retaining only some of them.
864+
mapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
865+
mapMaybeWithKey f = filterMapAux onLeaf onColl
866+
where onLeaf (Leaf h (L k v)) | Just v' <- f k v = Just (Leaf h (L k v'))
867+
onLeaf _ = Nothing
868+
869+
onColl (L k v) | Just v' <- f k v = Just (L k v')
870+
| otherwise = Nothing
871+
{-# INLINE mapMaybeWithKey #-}
872+
873+
-- | /O(n)/ Transform this map by applying a function to every value
874+
-- and retaining only some of them.
875+
mapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
876+
mapMaybe f = mapMaybeWithKey (const f)
877+
{-# INLINE mapMaybe #-}
878+
858879
-- | /O(n)/ Filter this map by retaining only elements satisfying a
859880
-- predicate.
860881
filterWithKey :: forall k v. (k -> v -> Bool) -> HashMap k v -> HashMap k v
861-
filterWithKey pred = go
882+
filterWithKey pred = filterMapAux onLeaf onColl
883+
where onLeaf t@(Leaf _ (L k v)) | pred k v = Just t
884+
onLeaf _ = Nothing
885+
886+
onColl el@(L k v) | pred k v = Just el
887+
onColl _ = Nothing
888+
{-# INLINE filterWithKey #-}
889+
890+
891+
-- | Common implementation for 'filterWithKey' and 'mapMaybeWithKey',
892+
-- allowing the former to former to reuse terms.
893+
filterMapAux :: forall k v1 v2
894+
. (HashMap k v1 -> Maybe (HashMap k v2))
895+
-> (Leaf k v1 -> Maybe (Leaf k v2))
896+
-> HashMap k v1
897+
-> HashMap k v2
898+
filterMapAux onLeaf onColl = go
862899
where
863900
go Empty = Empty
864-
go t@(Leaf _ (L k v))
865-
| pred k v = t
901+
go t@Leaf{}
902+
| Just t' <- onLeaf t = t'
866903
| otherwise = Empty
867904
go (BitmapIndexed b ary) = filterA ary b
868905
go (Full ary) = filterA ary fullNodeMask
@@ -874,9 +911,9 @@ filterWithKey pred = go
874911
mary <- A.new_ n
875912
step ary0 mary b0 0 0 1 n
876913
where
877-
step :: A.Array (HashMap k v) -> A.MArray s (HashMap k v)
914+
step :: A.Array (HashMap k v1) -> A.MArray s (HashMap k v2)
878915
-> Bitmap -> Int -> Int -> Bitmap -> Int
879-
-> ST s (HashMap k v)
916+
-> ST s (HashMap k v2)
880917
step !ary !mary !b i !j !bi n
881918
| i >= n = case j of
882919
0 -> return Empty
@@ -903,9 +940,9 @@ filterWithKey pred = go
903940
mary <- A.new_ n
904941
step ary0 mary 0 0 n
905942
where
906-
step :: A.Array (Leaf k v) -> A.MArray s (Leaf k v)
943+
step :: A.Array (Leaf k v1) -> A.MArray s (Leaf k v2)
907944
-> Int -> Int -> Int
908-
-> ST s (HashMap k v)
945+
-> ST s (HashMap k v2)
909946
step !ary !mary i !j n
910947
| i >= n = case j of
911948
0 -> return Empty
@@ -915,10 +952,10 @@ filterWithKey pred = go
915952
return $! Collision h ary2
916953
| otherwise -> do ary2 <- trim mary j
917954
return $! Collision h ary2
918-
| pred k v = A.write mary j el >> step ary mary (i+1) (j+1) n
955+
| Just el <- onColl (A.index ary i)
956+
= A.write mary j el >> step ary mary (i+1) (j+1) n
919957
| otherwise = step ary mary (i+1) j n
920-
where el@(L k v) = A.index ary i
921-
{-# INLINE filterWithKey #-}
958+
{-# INLINE filterMapAux #-}
922959

923960
-- | /O(n)/ Filter this map by retaining only elements which values
924961
-- satisfy a predicate.

Data/HashMap/Lazy.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ module Data.HashMap.Lazy
7373
, foldrWithKey
7474

7575
-- * Filter
76+
, mapMaybe
77+
, mapMaybeWithKey
7678
, HM.filter
7779
, filterWithKey
7880

Data/HashMap/Strict.hs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# LANGUAGE BangPatterns, CPP #-}
1+
{-# LANGUAGE BangPatterns, CPP, PatternGuards #-}
22

33
#if __GLASGOW_HASKELL__ >= 702
44
{-# LANGUAGE Trustworthy #-}
@@ -73,6 +73,8 @@ module Data.HashMap.Strict
7373
, foldrWithKey
7474

7575
-- * Filter
76+
, mapMaybe
77+
, mapMaybeWithKey
7678
, HM.filter
7779
, filterWithKey
7880

@@ -95,7 +97,7 @@ import qualified Data.HashMap.Array as A
9597
import qualified Data.HashMap.Base as HM
9698
import Data.HashMap.Base hiding (
9799
alter, adjust, fromList, fromListWith, insert, insertWith, intersectionWith,
98-
map, mapWithKey, singleton, update, unionWith)
100+
map, mapWithKey, mapMaybe, mapMaybeWithKey, singleton, update, unionWith)
99101
import Data.HashMap.Unsafe (runST)
100102

101103
-- $strictness
@@ -355,6 +357,28 @@ map :: (v1 -> v2) -> HashMap k v1 -> HashMap k v2
355357
map f = mapWithKey (const f)
356358
{-# INLINE map #-}
357359

360+
361+
------------------------------------------------------------------------
362+
-- * Filter
363+
364+
-- | /O(n)/ Transform this map by applying a function to every value
365+
-- and retaining only some of them.
366+
mapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
367+
mapMaybeWithKey f = filterMapAux onLeaf onColl
368+
where onLeaf (Leaf h (L k v)) | Just v' <- f k v = Just (leaf h k v')
369+
onLeaf _ = Nothing
370+
371+
onColl (L k v) | Just v' <- f k v = Just (L k v')
372+
| otherwise = Nothing
373+
{-# INLINE mapMaybeWithKey #-}
374+
375+
-- | /O(n)/ Transform this map by applying a function to every value
376+
-- and retaining only some of them.
377+
mapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
378+
mapMaybe f = mapMaybeWithKey (const f)
379+
{-# INLINE mapMaybe #-}
380+
381+
358382
-- TODO: Should we add a strict traverseWithKey?
359383

360384
------------------------------------------------------------------------

tests/HashMapProperties.hs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
module Main (main) where
77

8+
import Control.Monad ( guard )
89
import qualified Data.Foldable as Foldable
910
import Data.Function (on)
1011
import Data.Hashable (Hashable(hashWithSalt))
@@ -173,6 +174,14 @@ foldlWithKey'Map = M.foldlWithKey
173174
------------------------------------------------------------------------
174175
-- ** Filter
175176

177+
pMapMaybeWithKey :: [(Key, Int)] -> Bool
178+
pMapMaybeWithKey = M.mapMaybeWithKey f `eq_` HM.mapMaybeWithKey f
179+
where f k v = guard (odd (unK k + v)) >> Just (v + 1)
180+
181+
pMapMaybe :: [(Key, Int)] -> Bool
182+
pMapMaybe = M.mapMaybe f `eq_` HM.mapMaybe f
183+
where f v = guard (odd v) >> Just (v + 1)
184+
176185
pFilter :: [(Key, Int)] -> Bool
177186
pFilter = M.filter odd `eq_` HM.filter odd
178187

@@ -251,6 +260,8 @@ tests =
251260
, testGroup "filter"
252261
[ testProperty "filter" pFilter
253262
, testProperty "filterWithKey" pFilterWithKey
263+
, testProperty "mapMaybe" pMapMaybe
264+
, testProperty "mapMaybeWithKey" pMapMaybeWithKey
254265
]
255266
-- Conversions
256267
, testGroup "conversions"

0 commit comments

Comments
 (0)