git.iko.soy/typeable/ordered-containers
on master help sign in
7 files changed+506−172
since splitsnapshots
unifiedsplit
ChangeLog.md+21 Data/Map/Ordered.hs+14−133 Data/Map/Ordered/Internal.hs+250 Data/Map/Ordered/Strict.hs+114 Data/Map/Util.hs+25 Data/Set/Ordered.hs+78−28 ordered-containers.cabal+4−11
ChangeLog.md+21
@@ -1,5 +1,26 @@
11# Revision history for ordered-containers
22
3+## 0.2.2 -- 2019-07-05
4+
5+* Add `toMap` and `toSet`, which support efficient conversions from
6+ `OMap`s/`OSet`s to `Map`s/`Set`s, respectively.
7+
8+## 0.2.1 -- 2019-03-25
9+
10+* Compatibility fixes from Ryan Scott (thanks!)
11+
12+## 0.2 -- 2019-03-24
13+
14+* Support many more operations:
15+ * Semigroup,Monoid,Data,Typeable for OSet
16+ * Semigroup,Monoid,Functor,Traversable,Data,Typeable for OMap
17+ * union and intersection primitives for both
18+* Document asymptotics (when they vary from Set and Map)
19+
20+## 0.1.1 -- 2018-10-31
21+
22+* Metadata changes only
23+
324## 0.1.0 -- 2016-12-26
425
526* Documentation fix
Data/Map/Ordered.hs+14−133
@@ -1,10 +1,11 @@
11{-# LANGUAGE CPP #-}
2−#if __GLASGOW_HASKELL__
3−{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}
4−#endif
2+{-# LANGUAGE DeriveDataTypeable #-}
3+{-# LANGUAGE DeriveFunctor #-}
4+{-# LANGUAGE FlexibleInstances #-}
55
6−-- | An 'OMap' behaves much like a 'Map', with all the same asymptotics, but
7−-- also remembers the order that keys were inserted.
6+-- | An 'OMap' behaves much like a 'M.Map', with mostly the same asymptotics, but
7+-- also remembers the order that keys were inserted. All operations whose
8+-- asymptotics are worse than 'M.Map' have documentation saying so.
89module Data.Map.Ordered
910 ( OMap
1011 -- * Trivial maps
@@ -20,142 +21,22 @@ module Data.Map.Ordered
2021 --
2122 -- * If both sides contain the same key, the tuple's value wins
2223 , (<|), (|<), (>|), (|>)
24+ , (<>|), (|<>), unionWithL, unionWithR
25+ , Bias(Bias, unbiased), L, R
2326 -- * Deletion
2427 , delete, filter, (\\)
28+ , (|/\), (/\|), intersectionWith
2529 -- * Query
2630 , null, size, member, notMember, lookup
2731 -- * Indexing
2832 , Index, findIndex, elemAt
2933 -- * List conversions
3034 , fromList, assocs, toAscList
35+ -- * 'M.Map' conversion
36+ , toMap
3137 ) where
3238
33−import Control.Applicative ((<|>))
34−import Control.Monad (guard)
35−import Data.Foldable (Foldable, foldl', foldMap)
36−import Data.Function (on)
37−import Data.Map (Map)
38−import Data.Map.Util (Index, Tag, maxTag, minTag, nextHigherTag, nextLowerTag, readsPrecList, showsPrecList)
39+import qualified Data.Map as M ()
40+import Data.Map.Ordered.Internal
41+import Data.Map.Util
3942import Prelude hiding (filter, lookup, null)
40−import qualified Data.Map as M
41−
42−#if __GLASGOW_HASKELL__
43−import Data.Data
44−#endif
45−
46−data OMap k v = OMap !(Map k (Tag, v)) !(Map Tag (k, v))
47−
48−-- | Values are produced in insertion order, not key order.
49−instance Foldable (OMap k) where foldMap f (OMap _ kvs) = foldMap (f . snd) kvs
50−instance ( Eq k, Eq v) => Eq (OMap k v) where (==) = (==) `on` assocs
51−instance ( Ord k, Ord v) => Ord (OMap k v) where compare = compare `on` assocs
52−instance ( Show k, Show v) => Show (OMap k v) where showsPrec = showsPrecList assocs
53−instance (Ord k, Read k, Read v) => Read (OMap k v) where readsPrec = readsPrecList fromList
54−
55−#if __GLASGOW_HASKELL__
56−# if __GLASGOW_HASKELL__ >= 708
57−deriving instance Typeable OMap
58−# else
59−deriving instance Typeable2 OMap
60−# endif
61−
62−-- This instance preserves data abstraction at the cost of inefficiency.
63−-- We provide limited reflection services for the sake of data abstraction.
64−
65−instance (Data k, Data a, Ord k) => Data (OMap k a) where
66− gfoldl f z m = z fromList `f` assocs m
67− toConstr _ = fromListConstr
68− gunfold k z c = case constrIndex c of
69− 1 -> k (z fromList)
70− _ -> error "gunfold"
71− dataTypeOf _ = oMapDataType
72− dataCast2 f = gcast2 f
73−
74−fromListConstr :: Constr
75−fromListConstr = mkConstr oMapDataType "fromList" [] Prefix
76−
77−oMapDataType :: DataType
78−oMapDataType = mkDataType "Data.Map.Ordered.Map" [fromListConstr]
79−#endif
80−
81−infixr 5 <|, |< -- copy :
82−infixl 5 >|, |>
83−
84−(<|) , (|<) :: Ord k => (,) k v -> OMap k v -> OMap k v
85−(>|) , (|>) :: Ord k => OMap k v -> (,) k v -> OMap k v
86−
87−(k, v) <| OMap tvs kvs = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
88− t = maybe (nextLowerTag kvs) fst (M.lookup k tvs)
89−
90−(k, v) |< o = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
91− t = nextLowerTag kvs
92− OMap tvs kvs = delete k o
93−
94−o >| (k, v) = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
95− t = nextHigherTag kvs
96− OMap tvs kvs = delete k o
97−
98−OMap tvs kvs |> (k, v) = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
99− t = maybe (nextHigherTag kvs) fst (M.lookup k tvs)
100−
101−-- | @m \\\\ n@ deletes all the keys that exist in @n@ from @m@
102−(\\) :: Ord k => OMap k v -> OMap k v' -> OMap k v
103−o@(OMap tvs kvs) \\ o'@(OMap tvs' kvs') = if size o < size o'
104− then filter (const . (`notMember` o')) o
105− else foldr delete o (fmap fst (assocs o'))
106−
107−empty :: OMap k v
108−empty = OMap M.empty M.empty
109−
110−singleton :: (k, v) -> OMap k v
111−singleton kv@(k, v) = OMap (M.singleton k (0, v)) (M.singleton 0 kv)
112−
113−-- | If a key appears multiple times, the first occurrence is used for ordering
114−-- and the last occurrence is used for its value. The library author welcomes
115−-- comments on whether this default is sane.
116−fromList :: Ord k => [(k, v)] -> OMap k v
117−fromList = foldl' (|>) empty
118−
119−null :: OMap k v -> Bool
120−null (OMap tvs _) = M.null tvs
121−
122−size :: OMap k v -> Int
123−size (OMap tvs _) = M.size tvs
124−
125−member, notMember :: Ord k => k -> OMap k v -> Bool
126−member k (OMap tvs _) = M.member k tvs
127−notMember k (OMap tvs _) = M.notMember k tvs
128−
129−lookup :: Ord k => k -> OMap k v -> Maybe v
130−lookup k (OMap tvs _) = fmap snd (M.lookup k tvs)
131−
132−-- The Ord constraint is for compatibility with older (<0.5) versions of
133−-- containers.
134−-- | @filter f m@ contains exactly the key-value pairs of @m@ that satisfy @f@,
135−-- without changing the order they appear
136−filter :: Ord k => (k -> v -> Bool) -> OMap k v -> OMap k v
137−filter f (OMap tvs kvs) = OMap (M.filterWithKey (\k (t, v) -> f k v) tvs)
138− (M.filterWithKey (\t (k, v) -> f k v) kvs)
139−
140−delete :: Ord k => k -> OMap k v -> OMap k v
141−delete k o@(OMap tvs kvs) = case M.lookup k tvs of
142− Nothing -> o
143− Just (t, _) -> OMap (M.delete k tvs) (M.delete t kvs)
144−
145−findIndex :: Ord k => k -> OMap k v -> Maybe Index
146−findIndex k o@(OMap tvs kvs) = do
147− (t, _) <- M.lookup k tvs
148− M.lookupIndex t kvs
149−
150−elemAt :: OMap k v -> Index -> Maybe (k, v)
151−elemAt o@(OMap tvs kvs) i = do
152− guard (0 <= i && i < M.size kvs)
153− return . snd $ M.elemAt i kvs
154−
155−-- | Return key-value pairs in the order they were inserted.
156−assocs :: OMap k v -> [(k, v)]
157−assocs (OMap _ kvs) = map snd $ M.toAscList kvs
158−
159−-- | Return key-value pairs in order of increasing key.
160−toAscList :: OMap k v -> [(k, v)]
161−toAscList (OMap tvs kvs) = map (\(k, (t, v)) -> (k, v)) $ M.toAscList tvs
Data/Map/Ordered/Internal.hsnew file+250
@@ -0,0 +1,250 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DeriveDataTypeable #-}
3+{-# LANGUAGE DeriveFunctor #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+
6+module Data.Map.Ordered.Internal where
7+
8+import Control.Applicative ((<|>))
9+import Control.Monad (guard)
10+import Data.Data
11+import Data.Foldable (Foldable, foldl', foldMap)
12+import Data.Function (on)
13+import Data.Map (Map)
14+import Data.Map.Util
15+import Data.Monoid (Monoid(..))
16+#if MIN_VERSION_base(4,9,0)
17+import Data.Semigroup (Semigroup(..))
18+#endif
19+#if !(MIN_VERSION_base(4,8,0))
20+import Control.Applicative ((<$>))
21+import Data.Traversable
22+#endif
23+import Prelude hiding (filter, lookup, null)
24+import qualified Data.Map as M
25+
26+data OMap k v = OMap !(Map k (Tag, v)) !(Map Tag (k, v))
27+ deriving (Functor, Typeable)
28+
29+-- | Values are produced in insertion order, not key order.
30+instance Foldable (OMap k) where foldMap f (OMap _ kvs) = foldMap (f . snd) kvs
31+instance ( Eq k, Eq v) => Eq (OMap k v) where (==) = (==) `on` assocs
32+instance ( Ord k, Ord v) => Ord (OMap k v) where compare = compare `on` assocs
33+instance ( Show k, Show v) => Show (OMap k v) where showsPrec = showsPrecList assocs
34+instance (Ord k, Read k, Read v) => Read (OMap k v) where readsPrec = readsPrecList fromList
35+
36+-- This instance preserves data abstraction at the cost of inefficiency.
37+-- We provide limited reflection services for the sake of data abstraction.
38+instance (Data k, Data a, Ord k) => Data (OMap k a) where
39+ gfoldl f z m = z fromList `f` assocs m
40+ toConstr _ = fromListConstr
41+ gunfold k z c = case constrIndex c of
42+ 1 -> k (z fromList)
43+ _ -> error "gunfold"
44+ dataTypeOf _ = oMapDataType
45+ -- dataCast2 /must/ be eta-expanded in order to build on GHC 7.8.
46+ dataCast2 f = gcast2 f
47+
48+fromListConstr :: Constr
49+fromListConstr = mkConstr oMapDataType "fromList" [] Prefix
50+
51+oMapDataType :: DataType
52+oMapDataType = mkDataType "Data.Map.Ordered.Map" [fromListConstr]
53+
54+#if MIN_VERSION_base(4,9,0)
55+instance (Ord k, Semigroup v) => Semigroup (Bias L (OMap k v)) where
56+ Bias o <> Bias o' = Bias (unionWithL (const (<>)) o o')
57+instance (Ord k, Semigroup v) => Semigroup (Bias R (OMap k v)) where
58+ Bias o <> Bias o' = Bias (unionWithR (const (<>)) o o')
59+#endif
60+
61+-- | Empty maps and map union. When combining two sets that share elements, the
62+-- indices of the left argument are preferred, and the values are combined with
63+-- 'mappend'.
64+--
65+-- See the asymptotics of 'unionWithL'.
66+instance (Ord k, Monoid v) => Monoid (Bias L (OMap k v)) where
67+ mempty = Bias empty
68+ mappend (Bias o) (Bias o') = Bias (unionWithL (const mappend) o o')
69+
70+-- | Empty maps and map union. When combining two sets that share elements, the
71+-- indices of the right argument are preferred, and the values are combined
72+-- with 'mappend'.
73+--
74+-- See the asymptotics of 'unionWithR'.
75+instance (Ord k, Monoid v) => Monoid (Bias R (OMap k v)) where
76+ mempty = Bias empty
77+ mappend (Bias o) (Bias o') = Bias (unionWithR (const mappend) o o')
78+
79+-- | Values are traversed in insertion order, not key order.
80+--
81+-- /O(n*log(n))/ where /n/ is the size of the map.
82+instance Ord k => Traversable (OMap k) where
83+ traverse f (OMap tvs kvs) = fromKV <$> traverse (\(k,v) -> (,) k <$> f v) kvs
84+
85+infixr 5 <|, |< -- copy :
86+infixl 5 >|, |>
87+infixr 6 <>|, |<> -- copy <>
88+
89+(<|) , (|<) :: Ord k => (,) k v -> OMap k v -> OMap k v
90+(>|) , (|>) :: Ord k => OMap k v -> (,) k v -> OMap k v
91+
92+-- | When a key occurs in both maps, prefer the value from the first map.
93+--
94+-- See asymptotics of 'unionWithR'.
95+(<>|) :: Ord k => OMap k v -> OMap k v -> OMap k v
96+
97+-- | When a key occurs in both maps, prefer the value from the first map.
98+--
99+-- See asymptotics of 'unionWithL'.
100+(|<>) :: Ord k => OMap k v -> OMap k v -> OMap k v
101+
102+(k, v) <| OMap tvs kvs = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
103+ t = maybe (nextLowerTag kvs) fst (M.lookup k tvs)
104+
105+(k, v) |< o = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
106+ t = nextLowerTag kvs
107+ OMap tvs kvs = delete k o
108+
109+o >| (k, v) = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
110+ t = nextHigherTag kvs
111+ OMap tvs kvs = delete k o
112+
113+OMap tvs kvs |> (k, v) = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
114+ t = maybe (nextHigherTag kvs) fst (M.lookup k tvs)
115+
116+(<>|) = unionWithR (const const)
117+(|<>) = unionWithL (const const)
118+
119+-- | Take the union. The first 'OMap' \'s argument's indices are lower than the
120+-- second. If a key appears in both maps, the first argument's index takes
121+-- precedence, and the supplied function is used to combine the values.
122+--
123+-- /O(r*log(r))/ where /r/ is the size of the result
124+unionWithL :: Ord k => (k -> v -> v -> v) -> OMap k v -> OMap k v -> OMap k v
125+unionWithL = unionWithInternal (\t t' -> t )
126+
127+-- | Take the union. The first 'OMap' \'s argument's indices are lower than the
128+-- second. If a key appears in both maps, the second argument's index takes
129+-- precedence, and the supplied function is used to combine the values.
130+--
131+-- /O(r*log(r))/ where /r/ is the size of the result
132+unionWithR :: Ord k => (k -> v -> v -> v) -> OMap k v -> OMap k v -> OMap k v
133+unionWithR = unionWithInternal (\t t' -> t')
134+
135+unionWithInternal :: Ord k => (Tag -> Tag -> Tag) -> (k -> v -> v -> v) -> OMap k v -> OMap k v -> OMap k v
136+unionWithInternal fT fKV (OMap tvs kvs) (OMap tvs' kvs') = fromTV tvs'' where
137+ bump = case maxTag kvs of
138+ Nothing -> 0
139+ Just k -> -k-1
140+ bump' = case minTag kvs' of
141+ Nothing -> 0
142+ Just k -> -k
143+ tvs'' = M.unionWithKey (\k (t,v) (t',v') -> (fT t t', fKV k v v'))
144+ (fmap (\(t,v) -> (bump +t,v)) tvs )
145+ (fmap (\(t,v) -> (bump'+t,v)) tvs')
146+
147+-- | @m \\\\ n@ deletes all the keys that exist in @n@ from @m@
148+--
149+-- /O(m*log(n))/ where /m/ is the size of the smaller map and /n/ is the size
150+-- of the larger map.
151+(\\) :: Ord k => OMap k v -> OMap k v' -> OMap k v
152+o@(OMap tvs kvs) \\ o'@(OMap tvs' kvs') = if size o < size o'
153+ then filter (const . (`notMember` o')) o
154+ else foldr delete o (fmap fst (assocs o'))
155+
156+empty :: OMap k v
157+empty = OMap M.empty M.empty
158+
159+singleton :: (k, v) -> OMap k v
160+singleton kv@(k, v) = OMap (M.singleton k (0, v)) (M.singleton 0 kv)
161+
162+-- | If a key appears multiple times, the first occurrence is used for ordering
163+-- and the last occurrence is used for its value. The library author welcomes
164+-- comments on whether this default is sane.
165+fromList :: Ord k => [(k, v)] -> OMap k v
166+fromList = foldl' (|>) empty
167+
168+null :: OMap k v -> Bool
169+null (OMap tvs _) = M.null tvs
170+
171+size :: OMap k v -> Int
172+size (OMap tvs _) = M.size tvs
173+
174+member, notMember :: Ord k => k -> OMap k v -> Bool
175+member k (OMap tvs _) = M.member k tvs
176+notMember k (OMap tvs _) = M.notMember k tvs
177+
178+lookup :: Ord k => k -> OMap k v -> Maybe v
179+lookup k (OMap tvs _) = fmap snd (M.lookup k tvs)
180+
181+-- The Ord constraint is for compatibility with older (<0.5) versions of
182+-- containers.
183+-- | @filter f m@ contains exactly the key-value pairs of @m@ that satisfy @f@,
184+-- without changing the order they appear
185+filter :: Ord k => (k -> v -> Bool) -> OMap k v -> OMap k v
186+filter f (OMap tvs kvs) = OMap (M.filterWithKey (\k (t, v) -> f k v) tvs)
187+ (M.filterWithKey (\t (k, v) -> f k v) kvs)
188+
189+delete :: Ord k => k -> OMap k v -> OMap k v
190+delete k o@(OMap tvs kvs) = case M.lookup k tvs of
191+ Nothing -> o
192+ Just (t, _) -> OMap (M.delete k tvs) (M.delete t kvs)
193+
194+-- | Intersection. (The @/\\@ is intended to look a bit like the standard
195+-- mathematical notation for set intersection.)
196+--
197+-- See asymptotics of 'intersectionWith'.
198+(/\|) :: Ord k => OMap k v -> OMap k v' -> OMap k v
199+o /\| o' = intersectionWith (\k v' v -> v) o' o
200+
201+-- | Intersection. (The @/\\@ is intended to look a bit like the standard
202+-- mathematical notation for set intersection.)
203+--
204+-- See asymptotics of 'intersectionWith'.
205+(|/\) :: Ord k => OMap k v -> OMap k v' -> OMap k v
206+o |/\ o' = intersectionWith (\k v v' -> v) o o'
207+
208+-- | Take the intersection. The first 'OMap' \'s argument's indices are used for
209+-- the result.
210+--
211+-- /O(m*log(n\/(m+1)) + r*log(r))/ where /m/ is the size of the smaller map, /n/
212+-- is the size of the larger map, and /r/ is the size of the result.
213+intersectionWith ::
214+ Ord k =>
215+ (k -> v -> v' -> v'') ->
216+ OMap k v -> OMap k v' -> OMap k v''
217+intersectionWith f (OMap tvs kvs) (OMap tvs' kvs') = fromTV
218+ $ M.intersectionWithKey (\k (t,v) (t',v') -> (t, f k v v')) tvs tvs'
219+
220+fromTV :: Ord k => Map k (Tag, v) -> OMap k v
221+fromTV tvs = OMap tvs kvs where
222+ kvs = M.fromList [(t,(k,v)) | (k,(t,v)) <- M.toList tvs]
223+
224+fromKV :: Ord k => Map Tag (k, v) -> OMap k v
225+fromKV kvs = OMap tvs kvs where
226+ tvs = M.fromList [(k,(t,v)) | (t,(k,v)) <- M.toList kvs]
227+
228+findIndex :: Ord k => k -> OMap k v -> Maybe Index
229+findIndex k o@(OMap tvs kvs) = do
230+ (t, _) <- M.lookup k tvs
231+ M.lookupIndex t kvs
232+
233+elemAt :: OMap k v -> Index -> Maybe (k, v)
234+elemAt o@(OMap tvs kvs) i = do
235+ guard (0 <= i && i < M.size kvs)
236+ return . snd $ M.elemAt i kvs
237+
238+-- | Return key-value pairs in the order they were inserted.
239+assocs :: OMap k v -> [(k, v)]
240+assocs (OMap _ kvs) = map snd $ M.toAscList kvs
241+
242+-- | Return key-value pairs in order of increasing key.
243+toAscList :: OMap k v -> [(k, v)]
244+toAscList (OMap tvs kvs) = map (\(k, (t, v)) -> (k, v)) $ M.toAscList tvs
245+
246+-- | Convert an 'OMap' to a 'Map'.
247+--
248+-- /O(n)/, where /n/ is the size of the 'OMap'.
249+toMap :: OMap k v -> Map k v
250+toMap (OMap tvs _) = fmap snd tvs
Data/Map/Ordered/Strict.hsnew file+114
@@ -0,0 +1,114 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DeriveDataTypeable #-}
3+{-# LANGUAGE DeriveFunctor #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+
6+-- | An 'OMap' behaves much like a 'M.Map', with mostly the same asymptotics, but
7+-- also remembers the order that keys were inserted. All operations whose
8+-- asymptotics are worse than 'M.Map' have documentation saying so.
9+module Data.Map.Ordered.Strict
10+ ( OMap
11+ -- * Trivial maps
12+ , empty, singleton
13+ -- * Insertion
14+ -- | Conventions:
15+ --
16+ -- * The open side of an angle bracket points to an 'OMap'
17+ --
18+ -- * The pipe appears on the side whose indices take precedence if both sides contain the same key
19+ --
20+ -- * The left argument's indices are lower than the right argument's indices
21+ --
22+ -- * If both sides contain the same key, the tuple's value wins
23+ , (<|), (|<), (>|), (|>)
24+ , (<>|), (|<>), unionWithL, unionWithR
25+ , Bias(Bias, unbiased), L, R
26+ -- * Deletion
27+ , delete, filter, (\\)
28+ , (|/\), (/\|), intersectionWith
29+ -- * Query
30+ , null, size, member, notMember, lookup
31+ -- * Indexing
32+ , Index, findIndex, elemAt
33+ -- * List conversions
34+ , fromList, assocs, toAscList
35+ -- * 'M.Map' conversion
36+ , toMap
37+ ) where
38+
39+import Data.Foldable (foldl')
40+import qualified Data.Map.Strict as M
41+import Data.Map.Ordered.Internal
42+ ( OMap(..), empty, (<>|), (|<>), delete, filter, (\\), (|/\), (/\|), null, size
43+ , member, notMember, lookup, findIndex, elemAt, assocs, toAscList, fromTV, toMap )
44+import Data.Map.Util
45+import Prelude hiding (filter, lookup, null)
46+
47+infixr 5 <|, |< -- copy :
48+infixl 5 >|, |>
49+
50+(<|) , (|<) :: Ord k => (,) k v -> OMap k v -> OMap k v
51+(>|) , (|>) :: Ord k => OMap k v -> (,) k v -> OMap k v
52+
53+(k, v) <| OMap tvs kvs = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
54+ t = maybe (nextLowerTag kvs) fst (M.lookup k tvs)
55+
56+(k, v) |< o = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
57+ t = nextLowerTag kvs
58+ OMap tvs kvs = delete k o
59+
60+o >| (k, v) = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
61+ t = nextHigherTag kvs
62+ OMap tvs kvs = delete k o
63+
64+OMap tvs kvs |> (k, v) = OMap (M.insert k (t, v) tvs) (M.insert t (k, v) kvs) where
65+ t = maybe (nextHigherTag kvs) fst (M.lookup k tvs)
66+
67+-- | Take the union. The first 'OMap' \'s argument's indices are lower than the
68+-- second. If a key appears in both maps, the first argument's index takes
69+-- precedence, and the supplied function is used to combine the values.
70+--
71+-- /O(r*log(r))/ where /r/ is the size of the result
72+unionWithL :: Ord k => (k -> v -> v -> v) -> OMap k v -> OMap k v -> OMap k v
73+unionWithL = unionWithInternal (\t t' -> t )
74+
75+-- | Take the union. The first 'OMap' \'s argument's indices are lower than the
76+-- second. If a key appears in both maps, the second argument's index takes
77+-- precedence, and the supplied function is used to combine the values.
78+--
79+-- /O(r*log(r))/ where /r/ is the size of the result
80+unionWithR :: Ord k => (k -> v -> v -> v) -> OMap k v -> OMap k v -> OMap k v
81+unionWithR = unionWithInternal (\t t' -> t')
82+
83+unionWithInternal :: Ord k => (Tag -> Tag -> Tag) -> (k -> v -> v -> v) -> OMap k v -> OMap k v -> OMap k v
84+unionWithInternal fT fKV (OMap tvs kvs) (OMap tvs' kvs') = fromTV tvs'' where
85+ bump = case maxTag kvs of
86+ Nothing -> 0
87+ Just k -> -k-1
88+ bump' = case minTag kvs' of
89+ Nothing -> 0
90+ Just k -> -k
91+ tvs'' = M.unionWithKey (\k (t,v) (t',v') -> (fT t t', fKV k v v'))
92+ (fmap (\(t,v) -> (bump +t,v)) tvs )
93+ (fmap (\(t,v) -> (bump'+t,v)) tvs')
94+
95+singleton :: (k, v) -> OMap k v
96+singleton kv@(k, v) = OMap (M.singleton k (0, v)) (M.singleton 0 kv)
97+
98+-- | If a key appears multiple times, the first occurrence is used for ordering
99+-- and the last occurrence is used for its value. The library author welcomes
100+-- comments on whether this default is sane.
101+fromList :: Ord k => [(k, v)] -> OMap k v
102+fromList = foldl' (|>) empty
103+
104+-- | Take the intersection. The first 'OMap' \'s argument's indices are used for
105+-- the result.
106+--
107+-- /O(m*log(n\/(m+1)) + r*log(r))/ where /m/ is the size of the smaller map, /n/
108+-- is the size of the larger map, and /r/ is the size of the result.
109+intersectionWith ::
110+ Ord k =>
111+ (k -> v -> v' -> v'') ->
112+ OMap k v -> OMap k v' -> OMap k v''
113+intersectionWith f (OMap tvs kvs) (OMap tvs' kvs') = fromTV
114+ $ M.intersectionWithKey (\k (t,v) (t',v') -> (t, f k v v')) tvs tvs'
Data/Map/Util.hs+25
@@ -1,8 +1,23 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE DeriveDataTypeable #-}
4+{-# LANGUAGE DeriveFoldable #-}
5+{-# LANGUAGE DeriveFunctor #-}
6+{-# LANGUAGE DeriveTraversable #-}
7+{-# LANGUAGE KindSignatures #-}
8+
19module Data.Map.Util where
210
11+import Data.Data (Data, Typeable)
312import Data.Map (Map)
13+import Data.Monoid -- so that the docs for Monoid link to the right place
414import qualified Data.Map as M
515
16+#if !(MIN_VERSION_base(4,8,0))
17+import Data.Foldable (Foldable)
18+import Data.Traversable (Traversable)
19+#endif
20+
621-- | An internal index used to track ordering only -- its magnitude doesn't
722-- matter. If you manage to see this documentation, the library author has made
823-- a mistake!
@@ -29,3 +44,13 @@ readsPrecList fromList d = readParen (d > 10) $ \r -> do
2944 ("fromList", s) <- lex r
3045 (xs, t) <- reads s
3146 return (fromList xs, t)
47+
48+-- | A newtype to hand a 'Monoid' instance on. The phantom first parameter
49+-- tells whether 'mappend' will prefer the indices of its first or second
50+-- argument if there are shared elements in both.
51+newtype Bias (dir :: IndexPreference) a = Bias { unbiased :: a }
52+ deriving (Data, Eq, Foldable, Functor, Ord, Read, Show, Traversable, Typeable)
53+data IndexPreference = L | R
54+ deriving Typeable
55+type L = 'L
56+type R = 'R
Data/Set/Ordered.hs+78−28
@@ -1,16 +1,16 @@
11{-# LANGUAGE CPP #-}
2−#if __GLASGOW_HASKELL__
3−{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}
4−#endif
2+{-# LANGUAGE DeriveDataTypeable #-}
3+{-# LANGUAGE FlexibleInstances #-}
54
6−-- | An 'OSet' behaves much like a 'Set', with all the same asymptotics, but
7−-- also remembers the order that values were inserted.
5+-- | An 'OSet' behaves much like a 'Set', with mostly the same asymptotics, but
6+-- also remembers the order that values were inserted. All operations whose
7+-- asymptotics are worse than 'Set' have documentation saying so.
88module Data.Set.Ordered
99 ( OSet
1010 -- * Trivial sets
1111 , empty, singleton
1212 -- * Insertion
13− -- | Conventionts:
13+ -- | Conventions:
1414 --
1515 -- * The open side of an angle bracket points to an 'OSet'
1616 --
@@ -19,30 +19,35 @@ module Data.Set.Ordered
1919 -- * The left argument's indices are lower than the right argument's indices
2020 , (<|), (|<), (>|), (|>)
2121 , (<>|), (|<>)
22+ , Bias(Bias, unbiased), L, R
2223 -- * Query
2324 , null, size, member, notMember
2425 -- * Deletion
25− , delete, filter, (\\)
26+ , delete, filter, (\\), (|/\), (/\|)
2627 -- * Indexing
2728 , Index, findIndex, elemAt
2829 -- * List conversions
2930 , fromList, toAscList
31+ -- * 'Set' conversion
32+ , toSet
3033 ) where
3134
3235import Control.Monad (guard)
36+import Data.Data
3337import Data.Foldable (Foldable, foldl', foldMap, foldr, toList)
3438import Data.Function (on)
3539import Data.Map (Map)
36−import Data.Map.Util (Index, Tag, maxTag, minTag, nextHigherTag, nextLowerTag, readsPrecList, showsPrecList)
40+import Data.Map.Util
41+import Data.Monoid (Monoid(..))
42+#if MIN_VERSION_base(4,9,0)
43+import Data.Semigroup (Semigroup(..))
44+#endif
3745import Data.Set (Set) -- so the haddocks link to the right place
3846import Prelude hiding (filter, foldr, lookup, null)
3947import qualified Data.Map as M
4048
41−#if __GLASGOW_HASKELL__
42−import Data.Data
43−#endif
44−
4549data OSet a = OSet !(Map a Tag) !(Map Tag a)
50+ deriving Typeable
4651
4752-- | Values appear in insertion order, not ascending order.
4853instance Foldable OSet where foldMap f (OSet _ vs) = foldMap f vs
@@ -51,39 +56,59 @@ instance Ord a => Ord (OSet a) where compare = compare `on` toList
5156instance Show a => Show (OSet a) where showsPrec = showsPrecList toList
5257instance (Ord a, Read a) => Read (OSet a) where readsPrec = readsPrecList fromList
5358
54−#if __GLASGOW_HASKELL__
55−# if __GLASGOW_HASKELL__ >= 708
56−deriving instance Typeable OSet
57−# else
58−deriving instance Typeable1 OSet
59−# endif
60−
6159-- This instance preserves data abstraction at the cost of inefficiency.
6260-- We provide limited reflection services for the sake of data abstraction.
63−
6461instance (Data a, Ord a) => Data (OSet a) where
65− gfoldl f z set = z fromList `f` (toList set)
66− toConstr _ = fromListConstr
67− gunfold k z c = case constrIndex c of
68− 1 -> k (z fromList)
69− _ -> error "gunfold"
70− dataTypeOf _ = oSetDataType
71− dataCast1 f = gcast1 f
62+ gfoldl f z set = z fromList `f` toList set
63+ toConstr _ = fromListConstr
64+ gunfold k z c = case constrIndex c of
65+ 1 -> k (z fromList)
66+ _ -> error "gunfold"
67+ dataTypeOf _ = oSetDataType
68+ -- dataCast1 /must/ be eta-expanded in order to build on GHC 7.8.
69+ dataCast1 f = gcast1 f
7270
7371fromListConstr :: Constr
7472fromListConstr = mkConstr oSetDataType "fromList" [] Prefix
7573
7674oSetDataType :: DataType
7775oSetDataType = mkDataType "Data.Set.Ordered.Set" [fromListConstr]
76+
77+#if MIN_VERSION_base(4,9,0)
78+instance Ord a => Semigroup (Bias L (OSet a)) where Bias o <> Bias o' = Bias (o |<> o')
79+instance Ord a => Semigroup (Bias R (OSet a)) where Bias o <> Bias o' = Bias (o <>| o')
7880#endif
7981
82+-- | Empty sets and set union. When combining two sets that share elements, the
83+-- indices of the left argument are preferred.
84+--
85+-- See the asymptotics of ('|<>').
86+instance Ord a => Monoid (Bias L (OSet a)) where
87+ mempty = Bias empty
88+ mappend (Bias o) (Bias o') = Bias (o |<> o')
89+
90+-- | Empty sets and set union. When combining two sets that share elements, the
91+-- indices of the right argument are preferred.
92+--
93+-- See the asymptotics of ('<>|').
94+instance Ord a => Monoid (Bias R (OSet a)) where
95+ mempty = Bias empty
96+ mappend (Bias o) (Bias o') = Bias (o <>| o')
97+
8098infixr 5 <|, |< -- copy :
8199infixl 5 >|, |>
82100infixr 6 <>|, |<> -- copy <>
83101
84102(<|) , (|<) :: Ord a => a -> OSet a -> OSet a
85103(>|) , (|>) :: Ord a => OSet a -> a -> OSet a
86−(<>|), (|<>) :: Ord a => OSet a -> OSet a -> OSet a
104+
105+-- | /O(m*log(n)+n)/, where /m/ is the size of the smaller set and /n/ is the
106+-- size of the larger set.
107+(<>|) :: Ord a => OSet a -> OSet a -> OSet a
108+
109+-- | /O(m*log(n)+n)/, where /m/ is the size of the smaller set and /n/ is the
110+-- size of the larger set.
111+(|<>) :: Ord a => OSet a -> OSet a -> OSet a
87112
88113v <| o@(OSet ts vs)
89114 | v `member` o = o
@@ -124,11 +149,30 @@ unsafeMappend (OSet ts vs) (OSet ts' vs')
124149
125150-- | Set difference: @r \\\\ s@ deletes all the values in @s@ from @r@. The
126151-- order of @r@ is unchanged.
152+--
153+-- /O(m*log(n))/ where /m/ is the size of the smaller set and /n/ is the size
154+-- of the larger set.
127155(\\) :: Ord a => OSet a -> OSet a -> OSet a
128156o@(OSet ts vs) \\ o'@(OSet ts' vs') = if size o < size o'
129157 then filter (`notMember` o') o
130158 else foldr delete o vs'
131159
160+-- | Intersection. (@/\\@ is meant to look a bit like the standard mathematical
161+-- notation for intersection.)
162+--
163+-- /O(m*log(n\/(m+1)) + r*log(r))/, where /m/ is the size of the smaller set,
164+-- /n/ the size of the larger set, and /r/ the size of the result.
165+(|/\) :: Ord a => OSet a -> OSet a -> OSet a
166+OSet ts vs |/\ OSet ts' vs' = OSet ts'' vs'' where
167+ ts'' = M.intersection ts ts'
168+ vs'' = M.fromList [(t, v) | (v, t) <- M.toList ts]
169+
170+-- | @flip ('|/\')@
171+--
172+-- See asymptotics of '|/\'.
173+(/\|) :: Ord a => OSet a -> OSet a -> OSet a
174+(/\|) = flip (/\|)
175+
132176empty :: OSet a
133177empty = OSet M.empty M.empty
134178
@@ -174,3 +218,9 @@ elemAt o@(OSet ts vs) i = do
174218-- insertion order.)
175219toAscList :: OSet a -> [a]
176220toAscList o@(OSet ts _) = fmap fst (M.toAscList ts)
221+
222+-- | Convert an 'OSet' to a 'Set'.
223+--
224+-- /O(n)/, where /n/ is the size of the 'OSet'.
225+toSet :: OSet a -> Set a
226+toSet (OSet ts _) = M.keysSet ts
ordered-containers.cabal+4−11
@@ -1,15 +1,10 @@
1−-- Initial ordered-containers.cabal generated by cabal init. For further
2−-- documentation, see http://haskell.org/cabal/users-guide/
3−
41name: ordered-containers
5−version: 0.1.1
2+version: 0.2.2
63synopsis: Set- and Map-like types that remember the order elements were inserted
7−-- description:
84license: BSD3
95license-file: LICENSE
106author: Daniel Wagner
117maintainer: me@dmwit.com
12−-- copyright:
138category: Data
149build-type: Simple
1510extra-source-files: ChangeLog.md
@@ -20,10 +15,8 @@ source-repository head
2015 location: https://github.com/dmwit/ordered-containers
2116
2217library
23− exposed-modules: Data.Map.Ordered, Data.Set.Ordered
24− other-modules: Data.Map.Util
25− -- other-extensions:
26− build-depends: base >=4 && <5, containers >=0.1 && <0.7
27− -- hs-source-dirs:
18+ exposed-modules: Data.Map.Ordered, Data.Map.Ordered.Strict, Data.Set.Ordered
19+ other-modules: Data.Map.Ordered.Internal, Data.Map.Util
20+ build-depends: base >=4.7 && <5, containers >=0.1 && <0.7
2821 default-language: Haskell98
2922 ghc-options: -fno-warn-tabs