@@ -1,8 +1,9 @@
1{-# LANGUAGE DeriveDataTypeable #-}
1{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE DeriveFunctor #-}
2{-# LANGUAGE DeriveFunctor #-}
4−-- | An 'OMap' behaves much like a 'Map', with all the same asymptotics, but
4+-- | An 'OMap' behaves much like a 'Map', with mostly the same asymptotics, but
5−-- also remembers the order that keys were inserted.
5+-- also remembers the order that keys were inserted. All operations whose
6+-- asymptotics are worse than 'Map' have documentation saying so.
6module Data.Map.Ordered
7module Data.Map.Ordered
8 -- * Trivial maps
9 -- * Trivial maps
@@ -18,8 +19,10 @@ module Data.Map.Ordered
19 -- * If both sides contain the same key, the tuple's value wins
20 -- * If both sides contain the same key, the tuple's value wins
20 , (<|), (|<), (>|), (|>)
21 , (<|), (|<), (>|), (|>)
22+ , (<>|), (|<>), unionWithL, unionWithR
21 -- * Deletion
23 -- * Deletion
22 , delete, filter, (\\)
24 , delete, filter, (\\)
25+ , (|/\), (/\|), intersectionWith
23 -- * Query
26 -- * Query
24 , null, size, member, notMember, lookup
27 , null, size, member, notMember, lookup
25 -- * Indexing
28 -- * Indexing
@@ -67,10 +70,21 @@ oMapDataType = mkDataType "Data.Map.Ordered.Map" [fromListConstr]
68infixr 5 <|, |< -- copy :
71infixr 5 <|, |< -- copy :
69infixl 5 >|, |>
72infixl 5 >|, |>
73+infixr 6 <>|, |<> -- copy <>
71(<|) , (|<) :: Ord k => (,) k v -> OMap k v -> OMap k v
75(<|) , (|<) :: Ord k => (,) k v -> OMap k v -> OMap k v
72(>|) , (|>) :: Ord k => OMap k v -> (,) k v -> OMap k v
76(>|) , (|>) :: Ord k => OMap k v -> (,) k v -> OMap k v
78+-- | When a key occurs in both maps, prefer the value from the first map.
80+-- See asymptotics of 'unionWithR'.
81+(<>|) :: Ord k => OMap k v -> OMap k v -> OMap k v
83+-- | When a key occurs in both maps, prefer the value from the first map.
85+-- See asymptotics of 'unionWithL'.
86+(|<>) :: Ord k => OMap k v -> OMap k v -> OMap k v
74(k, v) <| OMap tvs kvs = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
88(k, v) <| OMap tvs kvs = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
75 t = maybe (nextLowerTag kvs) fst (M.lookup k tvs)
89 t = maybe (nextLowerTag kvs) fst (M.lookup k tvs)
@@ -85,7 +99,41 @@ o >| (k, v) = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
85OMap tvs kvs |> (k, v) = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
99OMap tvs kvs |> (k, v) = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
86 t = maybe (nextHigherTag kvs) fst (M.lookup k tvs)
100 t = maybe (nextHigherTag kvs) fst (M.lookup k tvs)
102+(<>|) = unionWithR (const const)
103+(|<>) = unionWithL (const const)
105+-- | Take the union. The first 'OMap' \'s argument's indices are lower than the
106+-- second. If a key appears in both maps, the first argument's index takes
107+-- precedence, and the supplied function is used to combine the values.
109+-- /O(r*log(r))/ where /r/ is the size of the result
110+unionWithL :: Ord k => (k -> v -> v -> v) -> OMap k v -> OMap k v -> OMap k v
111+unionWithL = unionWithInternal (\t t' -> t )
113+-- | Take the union. The first 'OMap' \'s argument's indices are lower than the
114+-- second. If a key appears in both maps, the second argument's index takes
115+-- precedence, and the supplied function is used to combine the values.
117+-- /O(r*log(r))/ where /r/ is the size of the result
118+unionWithR :: Ord k => (k -> v -> v -> v) -> OMap k v -> OMap k v -> OMap k v
119+unionWithR = unionWithInternal (\t t' -> t')
121+unionWithInternal :: Ord k => (Tag -> Tag -> Tag) -> (k -> v -> v -> v) -> OMap k v -> OMap k v -> OMap k v
122+unionWithInternal fT fKV (OMap tvs kvs) (OMap tvs' kvs') = fromTV tvs'' where
123+ bump = case maxTag kvs of
126+ bump' = case minTag kvs' of
129+ tvs'' = M.unionWithKey (\k (t,v) (t',v') -> (fT t t', fKV k v v'))
130+ (fmap (\(t,v) -> (bump +t,v)) tvs )
131+ (fmap (\(t,v) -> (bump'+t,v)) tvs')
88-- | @m \\\\ n@ deletes all the keys that exist in @n@ from @m@
133-- | @m \\\\ n@ deletes all the keys that exist in @n@ from @m@
135+-- /O(m*log(n))/ where /m/ is the size of the smaller map and /n/ is the size
136+-- of the larger map.
89(\\) :: Ord k => OMap k v -> OMap k v' -> OMap k v
137(\\) :: Ord k => OMap k v -> OMap k v' -> OMap k v
90o@(OMap tvs kvs) \\ o'@(OMap tvs' kvs') = if size o < size o'
138o@(OMap tvs kvs) \\ o'@(OMap tvs' kvs') = if size o < size o'
91 then filter (const . (`notMember` o')) o
139 then filter (const . (`notMember` o')) o
@@ -129,6 +177,36 @@ delete k o@(OMap tvs kvs) = case M.lookup k tvs of
129 Nothing -> o
177 Nothing -> o
130 Just (t, _) -> OMap (M.delete k tvs) (M.delete t kvs)
178 Just (t, _) -> OMap (M.delete k tvs) (M.delete t kvs)
180+-- | Intersection. (The @/\\@ is intended to look a bit like the standard
181+-- mathematical notation for set intersection.)
183+-- See asymptotics of 'intersectionWith'.
184+(/\|) :: Ord k => OMap k v -> OMap k v' -> OMap k v
185+o /\| o' = intersectionWith (\k v' v -> v) o' o
187+-- | Intersection. (The @/\\@ is intended to look a bit like the standard
188+-- mathematical notation for set intersection.)
190+-- See asymptotics of 'intersectionWith'.
191+(|/\) :: Ord k => OMap k v -> OMap k v' -> OMap k v
192+o |/\ o' = intersectionWith (\k v v' -> v) o o'
194+-- | Take the intersection. The first 'OMap' \'s argument's indices are used for
197+-- /O(m*log(n\/(m+1)) + r*log(r))/ where /m/ is the size of the smaller map, /n/
198+-- is the size of the larger map, and /r/ is the size of the result.
201+ (k -> v -> v' -> v'') ->
202+ OMap k v -> OMap k v' -> OMap k v''
203+intersectionWith f (OMap tvs kvs) (OMap tvs' kvs') = fromTV
204+ $ M.intersectionWithKey (\k (t,v) (t',v') -> (t, f k v v')) tvs tvs'
206+fromTV :: Ord k => Map k (Tag, v) -> OMap k v
207+fromTV tvs = OMap tvs kvs where
208+ kvs = M.fromList [(t,(k,v)) | (k,(t,v)) <- M.toList tvs]
132findIndex :: Ord k => k -> OMap k v -> Maybe Index
210findIndex :: Ord k => k -> OMap k v -> Maybe Index
133findIndex k o@(OMap tvs kvs) = do
211findIndex k o@(OMap tvs kvs) = do
134 (t, _) <- M.lookup k tvs
212 (t, _) <- M.lookup k tvs