on main help sign in
Improve delete & insert performance (#94)

* Improve delete performance * Improve insert performance * Add Big O Docs

commit91991f97531071b78a57e4f0fc43f0fd16d6f7bc authorChris Penner <christopher.penner@gmail.com> dateMon 12 Oct 2020, 12:33 (6 years ago) parentaeef5b8
2 files changed+16−11
src/Data/TMap.hs+4 src/Data/TypeRepMap/Internal.hs+12−11
src/Data/TMap.hs+4
@@ -87,6 +87,7 @@ one x = coerce (F.one @a @Identity $ coerce x)
8787{- |
8888
8989Insert a value into a 'TMap'.
90+TMap optimizes for fast reads rather than inserts, as a trade-off inserts are @O(n)@.
9091
9192prop> size (insert v tm) >= size tm
9293prop> member @a (insert (x :: a) tm) == True
@@ -98,6 +99,9 @@ insert x = coerce (F.insert @a @Identity $ coerce x)
9899
99100{- | Delete a value from a 'TMap'.
100101
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+
101105prop> size (delete @a tm) <= size tm
102106prop> member @a (delete @a tm) == False
103107
src/Data/TypeRepMap/Internal.hs+12−11
@@ -180,19 +180,14 @@ one x = TypeRepMap (primArrayFromListN 1 [fa])
180180{- |
181181
182182Insert a value into a 'TypeRepMap'.
183+TypeRepMap optimizes for fast reads rather than inserts, as a trade-off inserts are @O(n)@.
183184
184185prop> size (insert v tm) >= size tm
185186prop> member @a (insert (x :: f a) tm) == True
186187
187188-}
188189insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
189−insert x = fromTriples . addX . toTriples
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
190+insert = union . one
196191{-# INLINE insert #-}
197192
198193-- 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
201196
202197{- | Delete a value from a 'TypeRepMap'.
203198
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+
204202prop> size (delete @a tm) <= size tm
205203prop> member @a (delete @a tm) == False
206204
@@ -213,7 +211,13 @@ False
213211True
214212-}
215213delete :: 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
217221{-# INLINE delete #-}
218222
219223{- |
@@ -407,9 +411,6 @@ toSortedTriples tm = trip <$> ordering
407411 ordering :: [ Int ]
408412 ordering = generateOrderMapping (size tm)
409413
410−deleteByFst :: Eq a => a -> [(a, b, c)] -> [(a, b, c)]
411−deleteByFst x = filter ((/= x) . fst3)
412−
413414nubByFst :: (Eq a) => [(a, b, c)] -> [(a, b, c)]
414415nubByFst = nubBy ((==) `on` fst3)
415416