Skip to content

Commit 43c15f0

Browse files
committed
Introduce ‘partitionKeys’ that fuses ‘restrictKeys’ and ‘withoutKeys’ in one go
1 parent f5d0b13 commit 43c15f0

File tree

6 files changed

+66
-2
lines changed

6 files changed

+66
-2
lines changed

containers-tests/benchmarks/Map.hs

+10-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module Main where
55
import Control.Applicative (Const(Const, getConst), pure)
66
import Control.DeepSeq (rnf)
77
import Control.Exception (evaluate)
8-
import Test.Tasty.Bench (bench, defaultMain, whnf, nf)
8+
import Test.Tasty.Bench (bench, defaultMain, whnf, nf, bcompare)
99
import Data.Functor.Identity (Identity(..))
1010
import Data.List (foldl')
1111
import qualified Data.Map as M
@@ -15,13 +15,16 @@ import Data.Maybe (fromMaybe)
1515
import Data.Functor ((<$))
1616
import Data.Coerce
1717
import Prelude hiding (lookup)
18+
import Utils.Containers.Internal.StrictPair
1819

1920
main = do
2021
let m = M.fromAscList elems :: M.Map Int Int
2122
m_even = M.fromAscList elems_even :: M.Map Int Int
2223
m_odd = M.fromAscList elems_odd :: M.Map Int Int
24+
m_odd_keys = M.keysSet m_odd
2325
evaluate $ rnf [m, m_even, m_odd]
2426
evaluate $ rnf elems_rev
27+
evaluate $ rnf m_odd_keys
2528
defaultMain
2629
[ bench "lookup absent" $ whnf (lookup evens) m_odd
2730
, bench "lookup present" $ whnf (lookup evens) m_even
@@ -95,6 +98,12 @@ main = do
9598
, bench "fromDistinctDescList" $ whnf M.fromDistinctDescList elems_rev
9699
, bench "fromDistinctDescList:fusion" $ whnf (\n -> M.fromDistinctDescList [(i,i) | i <- [n,n-1..1]]) bound
97100
, bench "minView" $ whnf (\m' -> case M.minViewWithKey m' of {Nothing -> 0; Just ((k,v),m'') -> k+v+M.size m''}) (M.fromAscList $ zip [1..10::Int] [100..110::Int])
101+
102+
, bench "restrictKeys+withoutKeys"
103+
$ whnf (\ks -> M.restrictKeys m ks :*: M.withoutKeys m ks) m_odd_keys
104+
, bcompare "/restrictKeys+withoutKeys/"
105+
$ bench "partitionKeys"
106+
$ whnf (M.partitionKeys m) m_odd_keys
98107
]
99108
where
100109
bound = 2^12

containers-tests/tests/map-properties.hs

+7
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ main = defaultMain $ testGroup "map-properties"
173173
, testProperty "withoutKeys" prop_withoutKeys
174174
, testProperty "intersection" prop_intersection
175175
, testProperty "restrictKeys" prop_restrictKeys
176+
, testProperty "partitionKeys" prop_partitionKeys
176177
, testProperty "intersection model" prop_intersectionModel
177178
, testProperty "intersectionWith" prop_intersectionWith
178179
, testProperty "intersectionWithModel" prop_intersectionWithModel
@@ -1138,6 +1139,12 @@ prop_withoutKeys m s0 = valid reduced .&&. (m `withoutKeys` s === filterWithKey
11381139
s = keysSet s0
11391140
reduced = withoutKeys m s
11401141

1142+
prop_partitionKeys :: IMap -> IMap -> Property
1143+
prop_partitionKeys m s0 = valid with .&&. valid without .&&. (m `partitionKeys` s === (m `restrictKeys` s, m `withoutKeys` s))
1144+
where
1145+
s = keysSet s0
1146+
(with, without) = partitionKeys m s
1147+
11411148
prop_intersection :: IMap -> IMap -> Bool
11421149
prop_intersection t1 t2 = valid (intersection t1 t2)
11431150

containers/src/Data/Map/Internal.hs

+44
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
{-# LANGUAGE StandaloneDeriving #-}
88
{-# LANGUAGE Trustworthy #-}
99
{-# LANGUAGE TypeFamilies #-}
10+
{-# LANGUAGE ScopedTypeVariables #-}
1011
#endif
1112
#define USE_MAGIC_PROXY 1
1213

@@ -296,6 +297,7 @@ module Data.Map.Internal (
296297

297298
, restrictKeys
298299
, withoutKeys
300+
, partitionKeys
299301
, partition
300302
, partitionWithKey
301303

@@ -1943,6 +1945,48 @@ withoutKeys m (Set.Bin _ k ls rs) = case splitMember k m of
19431945
{-# INLINABLE withoutKeys #-}
19441946
#endif
19451947

1948+
-- | \(O\bigl(m \log\bigl(\frac{n}{m}+1\bigr)\bigr), \; 0 < m \leq n\). Restrict a 'Map' to only those keys
1949+
-- found in a 'Set' Remove all keys in a 'Set' from a 'Map'.
1950+
--
1951+
-- @
1952+
-- m \`partitionKeys\` s = (m ``restrictKeys`` s, m ``withoutKeys`` s)
1953+
-- @
1954+
--
1955+
-- @since 0.7
1956+
partitionKeys :: forall k a. Ord k => Map k a -> Set k -> (Map k a, Map k a)
1957+
partitionKeys xs ys =
1958+
case go xs ys of
1959+
xs' :*: ys' -> (xs', ys')
1960+
where
1961+
go :: Map k a -> Set k -> StrictPair (Map k a) (Map k a)
1962+
go Tip _ = Tip :*: Tip
1963+
go m Set.Tip = Tip :*: m
1964+
go m@(Bin _ k x lm rm) s@Set.Bin{} =
1965+
case b of
1966+
True -> with :*: without
1967+
where
1968+
with =
1969+
if lmWith `ptrEq` lm && rmWith `ptrEq` rm
1970+
then m
1971+
else link k x lmWith rmWith
1972+
without =
1973+
link2 lmWithout rmWithout
1974+
False -> with :*: without
1975+
where
1976+
with = link2 lmWith rmWith
1977+
without =
1978+
if lmWithout `ptrEq` lm && rmWithout `ptrEq` rm
1979+
then m
1980+
else link k x lmWithout rmWithout
1981+
where
1982+
!(lmWith :*: lmWithout) = go lm ls'
1983+
!(rmWith :*: rmWithout) = go rm rs'
1984+
1985+
!(!ls', b, !rs') = Set.splitMember k s
1986+
#if __GLASGOW_HASKELL__
1987+
{-# INLINABLE partitionKeys #-}
1988+
#endif
1989+
19461990
-- | \(O(n+m)\). Difference with a combining function.
19471991
-- When two equal keys are
19481992
-- encountered, the combining function is applied to the values of these keys.

containers/src/Data/Map/Lazy.hs

+1
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ module Data.Map.Lazy (
222222
, filterWithKey
223223
, restrictKeys
224224
, withoutKeys
225+
, partitionKeys
225226
, partition
226227
, partitionWithKey
227228
, takeWhileAntitone

containers/src/Data/Map/Strict.hs

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ module Data.Map.Strict
238238
, filterWithKey
239239
, restrictKeys
240240
, withoutKeys
241+
, partitionKeys
241242
, partition
242243
, partitionWithKey
243244

containers/src/Data/Map/Strict/Internal.hs

+3-1
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ module Data.Map.Strict.Internal
253253
, filterWithKey
254254
, restrictKeys
255255
, withoutKeys
256+
, partitionKeys
256257
, partition
257258
, partitionWithKey
258259
, takeWhileAntitone
@@ -416,7 +417,8 @@ import Data.Map.Internal
416417
, toDescList
417418
, union
418419
, unions
419-
, withoutKeys )
420+
, withoutKeys
421+
, partitionKeys )
420422

421423
#if defined(__GLASGOW_HASKELL__)
422424
import Data.Map.Internal.DeprecatedShowTree (showTree, showTreeWith)

0 commit comments

Comments
 (0)