on main help sign in
Improve delete & insert performance (#94)
91991f9Chris Penner
src/Data/TMap.hs+4
@@ -87,6 +87,7 @@ one x = coerce (F.one @a @Identity $ coerce x)
87{- |
87{- |
88
88
89Insert a value into a 'TMap'.
89Insert a value into a 'TMap'.
90+TMap optimizes for fast reads rather than inserts, as a trade-off inserts are @O(n)@.
90
91
91prop> size (insert v tm) >= size tm
92prop> size (insert v tm) >= size tm
92prop> member @a (insert (x :: a) tm) == True
93prop> member @a (insert (x :: a) tm) == True
@@ -98,6 +99,9 @@ insert x = coerce (F.insert @a @Identity $ coerce x)
98
99
99{- | Delete a value from a 'TMap'.
100{- | Delete a value from a 'TMap'.
100
101
102+TMap optimizes for fast reads rather than modifications, as a trade-off deletes are @O(n)@,
103+with an @O(log(n))@ optimization for when the element is already missing.
104+
101prop> size (delete @a tm) <= size tm
105prop> size (delete @a tm) <= size tm
102prop> member @a (delete @a tm) == False
106prop> member @a (delete @a tm) == False
103
107
src/Data/TypeRepMap/Internal.hs+12−11
@@ -180,19 +180,14 @@ one x = TypeRepMap (primArrayFromListN 1 [fa])
180{- |
180{- |
181
181
182Insert a value into a 'TypeRepMap'.
182Insert a value into a 'TypeRepMap'.
183+TypeRepMap optimizes for fast reads rather than inserts, as a trade-off inserts are @O(n)@.
183
184
184prop> size (insert v tm) >= size tm
185prop> size (insert v tm) >= size tm
185prop> member @a (insert (x :: f a) tm) == True
186prop> member @a (insert (x :: f a) tm) == True
186
187
187-}
188-}
188insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
189insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
189−insert x = fromTriples . addX . toTriples
190+insert = union . one
190− where
191− tripleX :: (Fingerprint, Any, Any)
192− tripleX@(fpX, _, _) = (calcFp @a, toAny x, unsafeCoerce $ typeRep @a)
193−
194− addX :: [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)]
195− addX l = tripleX : deleteByFst fpX l
196{-# INLINE insert #-}
191{-# INLINE insert #-}
197
192
198-- Extract the kind of a type. We use it to work around lack of syntax for
193-- Extract the kind of a type. We use it to work around lack of syntax for
@@ -201,6 +196,9 @@ type KindOf (a :: k) = k
201
196
202{- | Delete a value from a 'TypeRepMap'.
197{- | Delete a value from a 'TypeRepMap'.
203
198
199+TypeRepMap optimizes for fast reads rather than modifications, as a trade-off deletes are
200+@O(n)@, with an @O(log(n))@ optimization for when the element is already missing.
201+
204prop> size (delete @a tm) <= size tm
202prop> size (delete @a tm) <= size tm
205prop> member @a (delete @a tm) == False
203prop> member @a (delete @a tm) == False
206
204
@@ -213,7 +211,13 @@ False
213True
211True
214-}
212-}
215delete :: forall a (f :: KindOf a -> Type) . Typeable a => TypeRepMap f -> TypeRepMap f
213delete :: forall a (f :: KindOf a -> Type) . Typeable a => TypeRepMap f -> TypeRepMap f
216−delete = fromTriples . deleteByFst (typeFp @a) . toTriples
214+delete m
215+ -- Lookups are fast, so check if we even have the element first.
216+ | not (member @a m) = m
217+ -- We know we have the element, If the map has exactly one element, we can return the empty map
218+ | size m == 1 = empty
219+ -- Otherwise, filter out the element in linear time.
220+ | otherwise = fromSortedTriples . filter ((/= typeFp @a) . fst3) . toSortedTriples $ m
217{-# INLINE delete #-}
221{-# INLINE delete #-}
218
222
219{- |
223{- |
@@ -407,9 +411,6 @@ toSortedTriples tm = trip <$> ordering
407 ordering :: [ Int ]
411 ordering :: [ Int ]
408 ordering = generateOrderMapping (size tm)
412 ordering = generateOrderMapping (size tm)
409
413
410−deleteByFst :: Eq a => a -> [(a, b, c)] -> [(a, b, c)]
411−deleteByFst x = filter ((/= x) . fst3)
412−
413nubByFst :: (Eq a) => [(a, b, c)] -> [(a, b, c)]
414nubByFst :: (Eq a) => [(a, b, c)] -> [(a, b, c)]
414nubByFst = nubBy ((==) `on` fst3)
415nubByFst = nubBy ((==) `on` fst3)
415
416