Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ghc-typerep-map for openSUSE:Factory 
checked in at 2021-08-25 20:57:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-typerep-map (Old)
 and      /work/SRC/openSUSE:Factory/.ghc-typerep-map.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ghc-typerep-map"

Wed Aug 25 20:57:13 2021 rev:3 rq:912641 version:0.4.0.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-typerep-map/ghc-typerep-map.changes  
2020-12-22 11:48:13.369947886 +0100
+++ 
/work/SRC/openSUSE:Factory/.ghc-typerep-map.new.1899/ghc-typerep-map.changes    
    2021-08-25 20:58:19.793151607 +0200
@@ -1,0 +2,9 @@
+Wed Aug  4 08:16:38 UTC 2021 - [email protected]
+
+- Update typerep-map to version 0.4.0.0.
+  Upstream has edited the change log file since the last release in
+  a non-trivial way, i.e. they did more than just add a new entry
+  at the top. You can review the file at:
+  http://hackage.haskell.org/package/typerep-map-0.4.0.0/src/CHANGELOG.md
+
+-------------------------------------------------------------------

Old:
----
  typerep-map-0.3.3.0.tar.gz

New:
----
  typerep-map-0.4.0.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ghc-typerep-map.spec ++++++
--- /var/tmp/diff_new_pack.l0GxPR/_old  2021-08-25 20:58:20.601150547 +0200
+++ /var/tmp/diff_new_pack.l0GxPR/_new  2021-08-25 20:58:20.601150547 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package ghc-typerep-map
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -20,7 +20,7 @@
 %global has_internal_sub_libraries 1
 %bcond_with tests
 Name:           ghc-%{pkg_name}
-Version:        0.3.3.0
+Version:        0.4.0.0
 Release:        0
 Summary:        Efficient implementation of a dependent map with types as keys
 License:        MPL-2.0

++++++ typerep-map-0.3.3.0.tar.gz -> typerep-map-0.4.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typerep-map-0.3.3.0/CHANGELOG.md 
new/typerep-map-0.4.0.0/CHANGELOG.md
--- old/typerep-map-0.3.3.0/CHANGELOG.md        2001-09-09 03:46:40.000000000 
+0200
+++ new/typerep-map-0.4.0.0/CHANGELOG.md        2001-09-09 03:46:40.000000000 
+0200
@@ -3,6 +3,23 @@
 `typerep-map` uses [PVP Versioning][1].
 The changelog is available [on GitHub][2].
 
+## 0.4.0.0 ??? Aug 3, 2021
+
+* [#109](https://github.com/kowainik/typerep-map/issues/109):
+  Support GHC-9.0.
+* [#30](https://github.com/kowainik/typerep-map/issues/30):
+  Remove `containers` from dependencies.
+* [#94](https://github.com/kowainik/typerep-map/issues/94),
+  [#99](https://github.com/kowainik/typerep-map/issues/99),
+  [#100](https://github.com/kowainik/typerep-map/issues/100):
+  Improve performance of `insert` and `delete`.
+* [#95](https://github.com/kowainik/typerep-map/issues/95):
+  Add `alter`.
+* [#96](https://github.com/kowainik/typerep-map/issues/96):
+  Add `intersection` and `intersectionWith`.
+* [#105](https://github.com/kowainik/typerep-map/issues/105):
+  Add `keysWith` and `toListWith`.
+
 ## 0.3.3.0 ??? Apr 18, 2020
 
 * [#83](https://github.com/kowainik/typerep-map/issues/83):
@@ -53,4 +70,4 @@
 * Initially created.
 
 [1]: https://pvp.haskell.org
-[2]: https://github.com/kowainik/typerep-map/blob/master/CHANGELOG.md
+[2]: https://github.com/kowainik/typerep-map/releases
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typerep-map-0.3.3.0/README.md 
new/typerep-map-0.4.0.0/README.md
--- old/typerep-map-0.3.3.0/README.md   2001-09-09 03:46:40.000000000 +0200
+++ new/typerep-map-0.4.0.0/README.md   2001-09-09 03:46:40.000000000 +0200
@@ -3,11 +3,7 @@
 
![logo](https://user-images.githubusercontent.com/8126674/44323413-788dd700-a484-11e8-842e-f224cfaa4206.png)
 
 [![GitHub 
CI](https://github.com/kowainik/typerep-map/workflows/CI/badge.svg)](https://github.com/kowainik/typerep-map/actions)
-[![Build 
status](https://img.shields.io/travis/kowainik/typerep-map.svg?logo=travis)](https://travis-ci.org/kowainik/typerep-map)
-[![Windows build 
status](https://ci.appveyor.com/api/projects/status/github/kowainik/typerep-map?branch=master&svg=true)](https://ci.appveyor.com/project/kowainik/typerep-map)
 
[![Hackage](https://img.shields.io/hackage/v/typerep-map.svg?logo=haskell)](https://hackage.haskell.org/package/typerep-map)
-[![Stackage 
LTS](http://stackage.org/package/typerep-map/badge/lts)](http://stackage.org/lts/package/typerep-map)
-[![Stackage 
Nightly](http://stackage.org/package/typerep-map/badge/nightly)](http://stackage.org/nightly/package/typerep-map)
 [![MPL-2.0 
license](https://img.shields.io/badge/license-MPL--2.0-blue.svg)](LICENSE)
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typerep-map-0.3.3.0/benchmark/CMap.hs 
new/typerep-map-0.4.0.0/benchmark/CMap.hs
--- old/typerep-map-0.3.3.0/benchmark/CMap.hs   2001-09-09 03:46:40.000000000 
+0200
+++ new/typerep-map-0.4.0.0/benchmark/CMap.hs   2001-09-09 03:46:40.000000000 
+0200
@@ -17,7 +17,7 @@
 import Data.Maybe (fromJust)
 import Data.Proxy (Proxy (..))
 import Data.Typeable (Typeable)
-import GHC.TypeLits (type (+), KnownNat, Nat)
+import GHC.TypeLits (KnownNat, Nat, type (+))
 
 import Data.TypeRep.CMap (TypeRepMap (..), empty, insert, lookup)
 
@@ -30,16 +30,16 @@
         env (mkMap 10000) $ \ ~bigMap ->
             bench name $ nf tenLookups bigMap
     , benchInsertSmall = Just $ \name ->
-          bench name $ whnf (inserts empty 10) (Proxy @ 99999)
+          bench name $ whnf (inserts empty 10) (Proxy @99999)
     , benchInsertBig = Just $ \name ->
         env (mkMap 10000) $ \ ~bigMap ->
-            bench name $ whnf (inserts bigMap 1) (Proxy @ 99999)
+            bench name $ whnf (inserts bigMap 1) (Proxy @99999)
     , benchUpdateSmall = Just $ \name ->
         env (mkMap 10) $ \ ~smallMap ->
-            bench name $ whnf (inserts smallMap 10) (Proxy @ 0)
+            bench name $ whnf (inserts smallMap 10) (Proxy @0)
     , benchUpdateBig = Just $ \name ->
         env (mkMap 10000) $ \ ~bigMap ->
-            bench name $ whnf (inserts bigMap 10) (Proxy @ 0)
+            bench name $ whnf (inserts bigMap 10) (Proxy @0)
     }
 
 tenLookups
@@ -49,7 +49,7 @@
        )
 tenLookups tmap = (lp, lp, lp, lp, lp, lp, lp, lp)
   where
-    lp :: forall (a::Nat). Typeable a => Proxy a
+    lp :: forall (a :: Nat) . Typeable a => Proxy a
     lp = fromJust $ lookup tmap
 
 inserts
@@ -61,8 +61,8 @@
 inserts !c 0 _ = c
 inserts !c n x = inserts
     (insert x c)
-    (n-1)
-    (Proxy :: Proxy (a+1))
+    (n - 1)
+    (Proxy :: Proxy (a + 1))
 
 mkMap :: Int -> IO (TypeRepMap (Proxy :: Nat -> Type))
 mkMap n = pure $ buildBigMap n (Proxy :: Proxy 0) empty
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typerep-map-0.3.3.0/benchmark/CacheMap.hs 
new/typerep-map-0.4.0.0/benchmark/CacheMap.hs
--- old/typerep-map-0.3.3.0/benchmark/CacheMap.hs       2001-09-09 
03:46:40.000000000 +0200
+++ new/typerep-map-0.4.0.0/benchmark/CacheMap.hs       2001-09-09 
03:46:40.000000000 +0200
@@ -18,7 +18,7 @@
 import Data.Proxy (Proxy (..))
 import Data.Typeable (Typeable)
 import GHC.Exts (fromList)
-import GHC.TypeLits (type (+), KnownNat, Nat)
+import GHC.TypeLits (KnownNat, Nat, type (+))
 
 import Data.TypeRepMap.Internal (TypeRepMap (..), WrapTypeable (..), empty, 
insert, lookup)
 
@@ -31,16 +31,16 @@
         env (mkMap 10000) $ \ ~bigMap ->
             bench name $ nf tenLookups bigMap
     , benchInsertSmall = Just $ \name ->
-        bench name $ whnf (inserts empty 10) (Proxy @ 99999)
+        bench name $ whnf (inserts empty 10) (Proxy @99999)
     , benchInsertBig = Just $ \name ->
         env (mkMap 10000) $ \ ~bigMap ->
-            bench name $ whnf (inserts bigMap 1) (Proxy @ 99999)
+            bench name $ whnf (inserts bigMap 1) (Proxy @99999)
     , benchUpdateSmall = Just $ \name ->
         env (mkMap 10) $ \ ~smallMap ->
-            bench name $ whnf (inserts smallMap 10) (Proxy @ 0)
+            bench name $ whnf (inserts smallMap 10) (Proxy @0)
     , benchUpdateBig = Just $ \name ->
         env (mkMap 10000) $ \ ~bigMap ->
-            bench name $ whnf (inserts bigMap 10) (Proxy @ 0)
+            bench name $ whnf (inserts bigMap 10) (Proxy @0)
     }
 
 tenLookups
@@ -62,7 +62,7 @@
 inserts !c 0 _ = c
 inserts !c n x = inserts
     (insert x c)
-    (n-1)
+    (n - 1)
     (Proxy :: Proxy (a + 1))
 
 mkMap :: Int -> IO (TypeRepMap (Proxy :: Nat -> Type))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typerep-map-0.3.3.0/benchmark/DMap.hs 
new/typerep-map-0.4.0.0/benchmark/DMap.hs
--- old/typerep-map-0.3.3.0/benchmark/DMap.hs   2001-09-09 03:46:40.000000000 
+0200
+++ new/typerep-map-0.4.0.0/benchmark/DMap.hs   2001-09-09 03:46:40.000000000 
+0200
@@ -18,7 +18,7 @@
 import Data.Kind (Type)
 import Data.Maybe (fromJust)
 import Data.Proxy (Proxy (..))
-import GHC.TypeLits (type (+), KnownNat, Nat)
+import GHC.TypeLits (KnownNat, Nat, type (+))
 import Type.Reflection (TypeRep, Typeable, typeRep)
 import Type.Reflection.Unsafe (typeRepFingerprint)
 
@@ -36,10 +36,10 @@
         env mkBigMap $ \ ~(DMapNF bigMap) ->
             bench name $ nf tenLookups bigMap
     , benchInsertSmall = Just $ \name ->
-        bench name $ whnf (inserts empty 10) (Proxy @ 99999)
+        bench name $ whnf (inserts empty 10) (Proxy @99999)
     , benchInsertBig = Just $ \name ->
         env mkBigMap $ \ ~(DMapNF bigMap) ->
-            bench name $ whnf (inserts bigMap 1) (Proxy @ 99999)
+            bench name $ whnf (inserts bigMap 1) (Proxy @99999)
     , benchUpdateSmall = Nothing -- Not implemented
     , benchUpdateBig = Nothing -- Not implemented
     }
@@ -62,9 +62,9 @@
     -> TypeRepMap (Proxy :: Nat -> Type)
 inserts !c 0 _ = c
 inserts !c n x = inserts
-    (insert (typeRep @ a) x c)
-    (n-1)
-    (Proxy :: Proxy (a+1))
+    (insert (typeRep @a) x c)
+    (n - 1)
+    (Proxy :: Proxy (a + 1))
 
 -- TypeRepMap of 10000 elements
 mkBigMap :: IO (DMapNF (Proxy :: Nat -> Type))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typerep-map-0.3.3.0/src/Data/TMap.hs 
new/typerep-map-0.4.0.0/src/Data/TMap.hs
--- old/typerep-map-0.3.3.0/src/Data/TMap.hs    2001-09-09 03:46:40.000000000 
+0200
+++ new/typerep-map-0.4.0.0/src/Data/TMap.hs    2001-09-09 03:46:40.000000000 
+0200
@@ -2,9 +2,12 @@
 {-# LANGUAGE Rank2Types          #-}
 
 {- |
-Copyright:  (c) 2017-2020 Kowainik
-SPDX-License-Identifier: MPL-2.0
-Maintainer: Kowainik <[email protected]>
+Module                  : Data.TMap
+Copyright               : (c) 2017-2021 Kowainik
+SPDX-License-Identifier : MPL-2.0
+Maintainer              : Kowainik <[email protected]>
+Stability               : Stable
+Portability             : Portable
 
 'TMap' is a heterogeneous data structure similar in its essence to
 'Data.Map.Map' with types as keys, where each value has the type of its key.
@@ -21,7 +24,6 @@
 
 The runtime representation of 'TMap' is an array, not a tree. This makes
 'lookup' significantly more efficient.
-
 -}
 
 module Data.TMap
@@ -37,14 +39,19 @@
        , delete
        , unionWith
        , union
+       , intersectionWith
+       , intersection
        , map
        , adjust
+       , alter
 
          -- * Query
        , lookup
        , member
        , size
        , keys
+       , keysWith
+       , toListWith
        ) where
 
 import Prelude hiding (lookup, map)
@@ -52,7 +59,7 @@
 import Data.Functor.Identity (Identity (..))
 import Data.Typeable (Typeable)
 import GHC.Exts (coerce)
-import Type.Reflection (SomeTypeRep)
+import Type.Reflection (SomeTypeRep, TypeRep)
 
 import qualified Data.TypeRepMap as F
 
@@ -87,6 +94,7 @@
 {- |
 
 Insert a value into a 'TMap'.
+TMap optimizes for fast reads rather than inserts, as a trade-off inserts are 
@O(n)@.
 
 prop> size (insert v tm) >= size tm
 prop> member @a (insert (x :: a) tm) == True
@@ -98,6 +106,9 @@
 
 {- | Delete a value from a 'TMap'.
 
+TMap optimizes for fast reads rather than modifications, as a trade-off 
deletes are @O(n)@,
+with an @O(log(n))@ optimization for when the element is already missing.
+
 prop> size (delete @a tm) <= size tm
 prop> member @a (delete @a tm) == False
 
@@ -114,7 +125,7 @@
 {-# INLINE delete #-}
 
 -- | The union of two 'TMap's using a combining function.
-unionWith :: (forall x. Typeable x => x -> x -> x) -> TMap -> TMap -> TMap
+unionWith :: (forall x . Typeable x => x -> x -> x) -> TMap -> TMap -> TMap
 unionWith f = F.unionWith fId
   where
     fId :: forall y . Typeable y => Identity y -> Identity y -> Identity y
@@ -127,6 +138,24 @@
 union = F.union
 {-# INLINE union #-}
 
+-- | The intersection of two 'TMap's using a combining function.
+--
+-- @O(n + m)@
+intersectionWith :: (forall x . Typeable x => x -> x -> x) -> TMap -> TMap -> 
TMap
+intersectionWith f = F.intersectionWith fId
+  where
+    fId :: forall y . Typeable y => Identity y -> Identity y -> Identity y
+    fId y1 y2 = f (coerce y1) (coerce y2)
+{-# INLINE intersectionWith #-}
+
+-- | The intersection of two 'TMap's.
+-- It keeps all values from the first map whose keys are present in the second.
+--
+-- @O(n + m)@
+intersection :: TMap -> TMap -> TMap
+intersection = F.intersection
+{-# INLINE intersection #-}
+
 {- | Lookup a value of the given type in a 'TMap'.
 
 >>> x = lookup $ insert (11 :: Int) empty
@@ -135,7 +164,7 @@
 >>> x :: Maybe ()
 Nothing
 -}
-lookup :: forall a. Typeable a => TMap -> Maybe a
+lookup :: forall a . Typeable a => TMap -> Maybe a
 lookup = coerce (F.lookup @a @Identity)
 {-# INLINE lookup #-}
 
@@ -160,8 +189,18 @@
 keys = F.keys
 {-# INLINE keys #-}
 
+-- | Return the list of keys by wrapping them with a user-provided function.
+keysWith :: (forall a . TypeRep a -> r) -> TMap -> [r]
+keysWith = F.keysWith
+{-# INLINE keysWith #-}
+
+-- | Return the list of key-value pairs by wrapping them with a user-provided 
function.
+toListWith :: (forall a . Typeable a => a -> r) -> TMap -> [r]
+toListWith f = F.toListWith (f . runIdentity)
+{-# INLINE toListWith #-}
+
 -- | Map a function over the values.
-map :: (forall a. Typeable a => a -> a) -> TMap -> TMap
+map :: (forall a . Typeable a => a -> a) -> TMap -> TMap
 map f = F.hoistWithKey (liftToIdentity f)
 {-# INLINE map #-}
 
@@ -170,5 +209,14 @@
 adjust f = F.adjust (liftToIdentity f)
 {-# INLINE adjust #-}
 
-liftToIdentity :: forall a. (a -> a) -> Identity a -> Identity a
+-- | Updates a value at a specific key, whether or not it exists.
+--   This can be used to insert, delete, or update a value of a given type in 
the map.
+alter :: Typeable a => (Maybe a -> Maybe a) -> TMap -> TMap
+alter f = F.alter (liftF f)
+  where
+    liftF :: forall a . (Maybe a -> Maybe a) -> Maybe (Identity a) -> Maybe 
(Identity a)
+    liftF = coerce
+{-# INLINE alter #-}
+
+liftToIdentity :: forall a . (a -> a) -> Identity a -> Identity a
 liftToIdentity = coerce
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typerep-map-0.3.3.0/src/Data/TypeRepMap/Internal.hs 
new/typerep-map-0.4.0.0/src/Data/TypeRepMap/Internal.hs
--- old/typerep-map-0.3.3.0/src/Data/TypeRepMap/Internal.hs     2001-09-09 
03:46:40.000000000 +0200
+++ new/typerep-map-0.4.0.0/src/Data/TypeRepMap/Internal.hs     2001-09-09 
03:46:40.000000000 +0200
@@ -20,9 +20,12 @@
 -- {-# OPTIONS_GHC -ddump-simpl -dsuppress-idinfo -dsuppress-coercions 
-dsuppress-type-applications -dsuppress-uniques -dsuppress-module-prefixes #-}
 
 {- |
-Copyright:  (c) 2017-2020 Kowainik
-SPDX-License-Identifier: MPL-2.0
-Maintainer: Kowainik <[email protected]>
+Module                  : Data.TypeRepMap.Internal
+Copyright               : (c) 2017-2021 Kowainik
+SPDX-License-Identifier : MPL-2.0
+Maintainer              : Kowainik <[email protected]>
+Stability               : Stable
+Portability             : Portable
 
 Internal API for 'TypeRepMap' and operations on it. The functions here do
 not have any stability guarantees and can change between minor versions.
@@ -42,13 +45,15 @@
 import Control.Monad.Zip (mzip)
 import Data.Function (on)
 import Data.Kind (Type)
-import Data.Type.Equality ((:~:) (..), TestEquality (..))
 import Data.List (intercalate, nubBy)
 import Data.Maybe (fromMaybe)
-import Data.Primitive.Array (Array, MutableArray, indexArray, mapArray', 
readArray, sizeofArray,
-                             thawArray, unsafeFreezeArray, writeArray)
-import Data.Primitive.PrimArray (PrimArray, indexPrimArray, sizeofPrimArray)
-import Data.Semigroup (Semigroup (..), All(..))
+import Data.Primitive.Array (Array, MutableArray, indexArray, mapArray', 
sizeofArray, thawArray,
+                             unsafeFreezeArray, writeArray)
+import Data.Primitive.PrimArray (MutablePrimArray, PrimArray, indexPrimArray, 
newPrimArray,
+                                 primArrayFromListN, primArrayToList, 
sizeofPrimArray,
+                                 unsafeFreezePrimArray, writePrimArray)
+import Data.Semigroup (All (..), Semigroup (..))
+import Data.Type.Equality (TestEquality (..), (:~:) (..))
 import GHC.Base (Any, Int (..), Int#, (*#), (+#), (<#))
 import GHC.Exts (IsList (..), inline, sortWith)
 import GHC.Fingerprint (Fingerprint (..))
@@ -64,7 +69,6 @@
 import Type.Reflection.Unsafe (typeRepFingerprint)
 import Unsafe.Coerce (unsafeCoerce)
 
-import qualified Data.Map.Strict as Map
 import qualified GHC.Exts as GHC (fromList, toList)
 
 {- |
@@ -127,7 +131,7 @@
         go i
             | i == size tm1 = True
             | otherwise = case testEquality tr1i tr2i of
-                  Nothing -> False
+                  Nothing   -> False
                   Just Refl -> repEq tr1i (fromAny tv1i) (fromAny tv2i) && go 
(i + 1)
           where
             tr1i :: TypeRep x
@@ -170,33 +174,49 @@
 
 -}
 one :: forall a f . Typeable a => f a -> TypeRepMap f
-one x = insert x empty
+one x = TypeRepMap (primArrayFromListN 1 [fa])
+                   (primArrayFromListN 1 [fb])
+                   (pure @Array v)
+                   (pure @Array k)
+  where
+    (Fingerprint fa fb, v, k) = (calcFp @a, toAny x, unsafeCoerce $ typeRep @a)
 {-# INLINE one #-}
 
 {- |
 
 Insert a value into a 'TypeRepMap'.
+TypeRepMap optimizes for fast reads rather than inserts, as a trade-off 
inserts are @O(n)@.
 
 prop> size (insert v tm) >= size tm
 prop> member @a (insert (x :: f a) tm) == True
 
 -}
 insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
-insert x = fromTriples . addX . toTriples
+insert x m
+  | size m == 0 = one x
+  | otherwise = case cachedBinarySearch (typeFp @a) (fingerprintAs m) 
(fingerprintBs m) of
+      Nothing -> union m $ one x
+      Just i  -> m {trAnys = changeAnyArr i (trAnys m)}
   where
-    tripleX :: (Fingerprint, Any, Any)
-    tripleX@(fpX, _, _) = (calcFp @a, toAny x, unsafeCoerce $ typeRep @a)
-
-    addX :: [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)]
-    addX l = tripleX : deleteByFst fpX l
+    changeAnyArr :: Int -> Array Any -> Array Any
+    changeAnyArr i trAs = runST $ do
+      let n = sizeofArray trAs
+      mutArr <- thawArray trAs 0 n
+      writeArray mutArr i $ toAny x
+      unsafeFreezeArray mutArr
 {-# INLINE insert #-}
 
 -- Extract the kind of a type. We use it to work around lack of syntax for
 -- inferred type variables (which are not subject to type applications).
 type KindOf (a :: k) = k
 
+type ArgKindOf (f :: k -> l) = k
+
 {- | Delete a value from a 'TypeRepMap'.
 
+TypeRepMap optimizes for fast reads rather than modifications, as a trade-off 
deletes are
+@O(n)@, with an @O(log(n))@ optimization for when the element is already 
missing.
+
 prop> size (delete @a tm) <= size tm
 prop> member @a (delete @a tm) == False
 
@@ -209,30 +229,60 @@
 True
 -}
 delete :: forall a (f :: KindOf a -> Type) . Typeable a => TypeRepMap f -> 
TypeRepMap f
-delete = fromTriples . deleteByFst (typeFp @a) . toTriples
+delete m
+  -- Lookups are fast, so check if we even have the element first.
+  | not (member @a m) = m
+  -- We know we have the element, If the map has exactly one element, we can 
return the empty map
+  | size m == 1 = empty
+  -- Otherwise, filter out the element in linear time.
+  | otherwise = fromSortedTriples . deleteFirst ((== typeFp @a) . fst3) . 
toSortedTriples $ m
 {-# INLINE delete #-}
 
+deleteFirst :: (a -> Bool) -> [a] -> [a]
+deleteFirst _ []       = []
+deleteFirst p (x : xs) = if p x then xs else x : deleteFirst p xs
+
 {- |
-Update a value at a specific key with the result of the provided function. When
-the key is not a member of the map, the original map is returned.
+Update a value at a specific key with the result of the provided function.
+When the key is not a member of the map, the original map is returned.
 
 >>> trmap = fromList @(TypeRepMap Identity) [WrapTypeable $ Identity "a"]
 >>> lookup @String $ adjust (fmap (++ "ww")) trmap
 Just (Identity "aww")
 -}
 adjust :: forall a f . Typeable a => (f a -> f a) -> TypeRepMap f -> 
TypeRepMap f
-adjust fun tr = case cachedBinarySearch (typeFp @a) (fingerprintAs tr) 
(fingerprintBs tr) of
-    Nothing -> tr
-    Just i  -> tr {trAnys = changeAnyArr i (trAnys tr)}
+adjust fun = alter (fmap fun)
+{-# INLINE adjust #-}
+
+{- |
+Updates a value at a specific key, whether or not it exists.
+This can be used to insert, delete, or update a value of a given type in the 
map.
+
+>>> func = (\case Nothing -> Just (Identity "new"); Just (Identity s) -> Just 
(Identity (reverse s)))
+>>> lookup @String $ alter func empty
+Just (Identity "new")
+>>> trmap = fromList @(TypeRepMap Identity) [WrapTypeable $ Identity "helllo"]
+>>> lookup @String $ alter func trmap
+>>> Just (Identity "olleh")
+-}
+alter :: forall a f . Typeable a => (Maybe (f a) -> Maybe (f a)) -> TypeRepMap 
f -> TypeRepMap f
+alter fun tr = case cachedBinarySearch (typeFp @a) (fingerprintAs tr) 
(fingerprintBs tr) of
+    Nothing ->
+        case (fun Nothing) of
+            Nothing -> tr
+            Just v  -> insert v tr
+    Just i  ->
+        case fun (Just . fromAny $ indexArray (trAnys tr) i) of
+            Nothing -> delete @a tr
+            Just v  -> tr{trAnys = replaceAnyAt i (toAny v) (trAnys tr)}
   where
-    changeAnyArr :: Int -> Array Any -> Array Any
-    changeAnyArr i trAs = runST $ do
+    replaceAnyAt :: Int -> Any -> Array Any -> Array Any
+    replaceAnyAt i v trAs = runST $ do
         let n = sizeofArray trAs
         mutArr <- thawArray trAs 0 n
-        a <- toAny . fun . fromAny <$> readArray mutArr i
-        writeArray mutArr i a
+        writeArray mutArr i v
         unsafeFreezeArray mutArr
-{-# INLINE adjust #-}
+{-# INLINE alter #-}
 
 {- | Map over the elements of a 'TypeRepMap'.
 
@@ -266,33 +316,89 @@
     withTr t = withTypeable t f
 {-# INLINE hoistWithKey #-}
 
--- | The union of two 'TypeRepMap's using a combining function.
+-- | The union of two 'TypeRepMap's using a combining function for conflicting 
entries. @O(n + m)@
 unionWith :: forall f. (forall x. Typeable x => f x -> f x -> f x) -> 
TypeRepMap f -> TypeRepMap f -> TypeRepMap f
-unionWith f m1 m2 = fromTriples
-                  $ toTripleList
-                  $ Map.unionWith combine
-                                  (fromTripleList $ toTriples m1)
-                                  (fromTripleList $ toTriples m2)
+unionWith f ma mb = do
+    fromSortedTriples $ mergeMaps (toSortedTriples ma) (toSortedTriples mb)
   where
     f' :: forall x. TypeRep x -> f x -> f x -> f x
     f' tr = withTypeable tr f
 
-    combine :: (Any, Any) -> (Any, Any) -> (Any, Any)
-    combine (av, ak) (bv, _) = (toAny $ f' (fromAny ak) (fromAny av) (fromAny 
bv), ak)
+    combine :: (Fingerprint, Any, Any) -> (Fingerprint, Any, Any) -> 
(Fingerprint, Any, Any)
+    combine (fp, av, ak) (_, bv, _) = (fp, toAny $ f' (fromAny ak) (fromAny 
av) (fromAny bv), ak)
 
-    fromTripleList :: Ord a => [(a, b, c)] -> Map.Map a (b, c)
-    fromTripleList = Map.fromList . map (\(a, b, c) -> (a, (b, c)))
-
-    toTripleList :: Map.Map a (b, c) -> [(a, b, c)]
-    toTripleList = map (\(a, (b, c)) -> (a, b, c)) . Map.toList
+    -- Merges two typrepmaps into a sorted, dedup'd list of triples.
+    -- Using 'toSortedTriples' allows us to assume the triples are sorted by 
fingerprint,
+    -- Given O(n) performance from 'toSortedTriples', and given that we can 
merge-sort in
+    -- O(n + m) time, then can '.fromSortedTriples' back into 
cachedBinarySearch order in O(n + m)
+    -- that gives a total of O(n + m).
+    mergeMaps :: [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)] -> 
[(Fingerprint, Any, Any)]
+    -- We've addressed all elements from both maps
+    mergeMaps as [] = as
+    mergeMaps [] bs = bs
+    -- Merge
+    mergeMaps (a@(af, _, _) : as) (b@(bf, _, _) : bs) =
+        case compare af bf of
+            -- Fingerprints are equal, union the elements using our function
+            -- If the incoming maps were de-duped, there shouldn't be any 
other equivalent
+            -- fingerprints
+            EQ -> combine a b : mergeMaps as bs
+            -- First fingerprint must not be in the second map or we would 
have seen it by now
+            -- Add it to the result as-is
+            LT -> a : mergeMaps as (b : bs)
+            -- Second fingerprint must not be in the first map or we would 
have seen it by now
+            -- Add it to the result as-is
+            GT -> b : mergeMaps (a:as) bs
 {-# INLINE unionWith #-}
 
--- | The (left-biased) union of two 'TypeRepMap's. It prefers the first map 
when
+-- | The (left-biased) union of two 'TypeRepMap's in @O(n + m)@. It prefers 
the first map when
 -- duplicate keys are encountered, i.e. @'union' == 'unionWith' const@.
 union :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
 union = unionWith const
 {-# INLINE union #-}
 
+-- | The 'intersection' of two 'TypeRepMap's using a combining function
+--
+-- @O(n + m)@
+intersectionWith :: forall f. (forall x. Typeable x => f x -> f x -> f x) -> 
TypeRepMap f -> TypeRepMap f -> TypeRepMap f
+intersectionWith f ma mb =
+    fromSortedTriples $ mergeMaps (toSortedTriples ma) (toSortedTriples mb)
+  where
+    f' :: forall x. TypeRep x -> f x -> f x -> f x
+    f' tr = withTypeable tr f
+
+    combine :: (Fingerprint, Any, Any) -> (Fingerprint, Any, Any) -> 
(Fingerprint, Any, Any)
+    combine (fp, av, ak) (_, bv, _) = (fp, toAny $ f' (fromAny ak) (fromAny 
av) (fromAny bv), ak)
+
+    -- Merges two typrepmaps into a sorted, dedup'd list of triples.
+    mergeMaps :: [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)] -> 
[(Fingerprint, Any, Any)]
+    -- If either list is empty, the intersection must be finished.
+    mergeMaps _ [] = []
+    mergeMaps [] _ = []
+    -- Merge the two maps considering one element at a time.
+    mergeMaps (a@(af, _, _) : as) (b@(bf, _, _) : bs) =
+        case compare af bf of
+            -- Fingerprints are equal, union the elements using our function
+            -- If the incoming maps were de-duped, there shouldn't be any 
other equivalent
+            -- fingerprints
+            EQ -> combine a b : mergeMaps as bs
+            -- First fingerprint must not be in the second map or we would 
have seen it by now
+            -- Skip it an move on
+            LT -> mergeMaps as (b : bs)
+            -- Second fingerprint must not be in the first map or we would 
have seen it by now
+            -- Skip it an move on
+            GT -> mergeMaps (a:as) bs
+{-# INLINE intersectionWith #-}
+
+-- | The intersection of two 'TypeRepMap's.
+-- It keeps all values from the first map whose keys are present in the second.
+--
+-- @O(n + m)@
+intersection :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
+intersection = intersectionWith const
+{-# INLINE intersection #-}
+
+
 {- | Check if a value of the given type is present in a 'TypeRepMap'.
 
 >>> member @Char $ one (Identity 'a')
@@ -328,9 +434,22 @@
 
 -- | Return the list of 'SomeTypeRep' from the keys.
 keys :: TypeRepMap f -> [SomeTypeRep]
-keys TypeRepMap{..} = SomeTypeRep . anyToTypeRep <$> toList trKeys
+keys = keysWith SomeTypeRep
 {-# INLINE keys #-}
 
+-- | Return the list of keys by wrapping them with a user-provided function.
+keysWith :: (forall (a :: ArgKindOf f). TypeRep a -> r) -> TypeRepMap f -> [r]
+keysWith f TypeRepMap{..} = f . anyToTypeRep <$> toList trKeys
+{-# INLINE keysWith #-}
+
+-- | Return the list of key-value pairs by wrapping them with a user-provided 
function.
+toListWith :: forall f r . (forall (a :: ArgKindOf f) . Typeable a => f a -> 
r) -> TypeRepMap f -> [r]
+toListWith f = map toF . toTriples
+  where
+    withTypeRep :: TypeRep a -> f a -> r
+    withTypeRep tr an = withTypeable tr $ f an
+    toF (_, an, k) = withTypeRep (unsafeCoerce k) (fromAny an)
+
 -- | Binary searched based on this article
 -- http://bannalia.blogspot.com/2015/06/cache-friendly-binary-search.html
 -- with modification for our two-vector search case.
@@ -374,8 +493,20 @@
 toTriples :: TypeRepMap f -> [(Fingerprint, Any, Any)]
 toTriples tm = zip3 (toFingerprints tm) (GHC.toList $ trAnys tm) (GHC.toList $ 
trKeys tm)
 
-deleteByFst :: Eq a => a -> [(a, b, c)] -> [(a, b, c)]
-deleteByFst x = filter ((/= x) . fst3)
+-- | Efficiently get sorted triples from a map in O(n) time
+--
+-- We assume the incoming TypeRepMap is already sorted into 
'cachedBinarySearch' order using fromSortedList.
+-- Then we can construct the index mapping from the "cached" ordering into 
monotonically
+-- increasing order using 'generateOrderMapping' with the length of the TRM. 
This takes @O(n).
+-- We then pull those indexes from the source TRM to get the sorted triples in 
a total of @O(n).
+toSortedTriples :: TypeRepMap f -> [(Fingerprint, Any, Any)]
+toSortedTriples tm = trip <$> ordering
+  where
+    trip i = ( Fingerprint (indexPrimArray (fingerprintAs tm) i) 
(indexPrimArray (fingerprintBs tm) i)
+             , indexArray (trAnys tm) i
+             , indexArray (trKeys tm) i)
+    ordering :: [ Int ]
+    ordering = generateOrderMapping (size tm)
 
 nubByFst :: (Eq a) => [(a, b, c)] -> [(a, b, c)]
 nubByFst = nubBy ((==) `on` fst3)
@@ -395,9 +526,6 @@
 instance Show (WrapTypeable f) where
     show (WrapTypeable (_ :: f a)) = show $ calcFp @a
 
-wrapTypeable :: TypeRep a -> f a -> WrapTypeable f
-wrapTypeable tr = withTypeable tr WrapTypeable
-
 {- |
 
 prop> fromList . toList == 'id'
@@ -425,19 +553,19 @@
         k (WrapTypeable (_ :: f a)) = unsafeCoerce $ typeRep @a
 
     toList :: TypeRepMap f -> [WrapTypeable f]
-    toList = map toWrapTypeable . toTriples
-      where
-        toWrapTypeable :: (Fingerprint, Any, Any) -> WrapTypeable f
-        toWrapTypeable (_, an, k) = wrapTypeable (unsafeCoerce k) (fromAny an)
+    toList = toListWith WrapTypeable
 
 calcFp :: forall a . Typeable a => Fingerprint
 calcFp = typeRepFingerprint $ typeRep @a
 
 fromTriples :: [(Fingerprint, Any, Any)] -> TypeRepMap f
-fromTriples kvs = TypeRepMap (GHC.fromList fpAs) (GHC.fromList fpBs) 
(GHC.fromList ans) (GHC.fromList ks)
+fromTriples = fromSortedTriples . sortWith fst3 . nubByFst
+
+fromSortedTriples :: [(Fingerprint, Any, Any)] -> TypeRepMap f
+fromSortedTriples kvs = TypeRepMap (GHC.fromList fpAs) (GHC.fromList fpBs) 
(GHC.fromList ans) (GHC.fromList ks)
   where
     (fpAs, fpBs) = unzip $ map (\(Fingerprint a b) -> (a, b)) fps
-    (fps, ans, ks) = unzip3 $ fromSortedList $ sortWith fst3 $ nubByFst kvs
+    (fps, ans, ks) = unzip3 $ fromSortedList kvs
 
 ----------------------------------------------------------------------------
 -- Tree-like conversion
@@ -464,11 +592,35 @@
                 writeArray result i (indexArray origin newFirst)
                 loop (2 * i + 2) (newFirst + 1)
 
+-- Returns a list of indexes which represents the "sorted" order of an array 
generated by
+-- fromSortedList of the provided length.
+-- I.e. fmap (fromSortedList [1, 2, 3, 4, 5, 6] !!) (generateOrderMapping 6) 
== [1, 2, 3, 4, 5, 6]
+--
+--     >>> generateOrderMapping 6
+--     [3,1,4,0,5,2]
+--
+--     >>> generateOrderMapping 8
+--     [7,3,1,4,0,5,2,6]
+generateOrderMapping :: Int -> [Int]
+generateOrderMapping len = runST $ do
+    orderMappingArr <- newPrimArray len
+    _ <- loop orderMappingArr 0 0
+    primArrayToList <$> unsafeFreezePrimArray orderMappingArr
+  where
+    loop :: MutablePrimArray s Int -> Int -> Int -> ST s Int
+    loop result i first =
+        if i >= len
+        then pure first
+        else do
+            newFirst <- loop result (2 * i + 1) first
+            writePrimArray result newFirst i
+            loop result (2 * i + 2) (newFirst + 1)
+
 ----------------------------------------------------------------------------
 --  Helper functions.
 ----------------------------------------------------------------------------
 
--- | Check that invariant of the structure is hold.
+-- | Check that invariant of the structure holds.
 -- The structure maintains the following invariant.
 -- For each element @A@ at index @i@:
 --
@@ -481,8 +633,8 @@
 invariantCheck :: TypeRepMap f -> Bool
 invariantCheck TypeRepMap{..} = getAll (check 0)
   where
-    lastMay [] = Nothing
-    lastMay [x] = Just x
+    lastMay []     = Nothing
+    lastMay [x]    = Just x
     lastMay (_:xs) = lastMay xs
     sz = sizeofPrimArray fingerprintAs
     check i | i >= sz = All True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typerep-map-0.3.3.0/src/Data/TypeRepMap.hs 
new/typerep-map-0.4.0.0/src/Data/TypeRepMap.hs
--- old/typerep-map-0.3.3.0/src/Data/TypeRepMap.hs      2001-09-09 
03:46:40.000000000 +0200
+++ new/typerep-map-0.4.0.0/src/Data/TypeRepMap.hs      2001-09-09 
03:46:40.000000000 +0200
@@ -1,11 +1,14 @@
 {-# LANGUAGE NoImplicitPrelude #-}
 
 {- |
-Copyright:  (c) 2017-2020 Kowainik
-SPDX-License-Identifier: MPL-2.0
-Maintainer: Kowainik <[email protected]>
+Module                  : Data.TypeRepMap
+Copyright               : (c) 2017-2021 Kowainik
+SPDX-License-Identifier : MPL-2.0
+Maintainer              : Kowainik <[email protected]>
+Stability               : Stable
+Portability             : Portable
 
- A version of 'Data.TMap.TMap' parametrized by an interpretation @f@. This
+A version of 'Data.TMap.TMap' parametrized by an interpretation @f@. This
 sort of parametrization may be familiar to users of @vinyl@ records.
 
 @'TypeRepMap' f@ is a more efficient replacement for @DMap
@@ -44,7 +47,8 @@
  "border-color" -> F (rgb 148 0 211)
  "border-width" -> F 0.5
 @
---}
+-}
+
 module Data.TypeRepMap
        ( -- * Map type
          TypeRepMap()
@@ -57,17 +61,22 @@
        , insert
        , delete
        , adjust
+       , alter
        , hoist
        , hoistA
        , hoistWithKey
        , unionWith
        , union
+       , intersectionWith
+       , intersection
 
          -- * Query
        , lookup
        , member
        , size
        , keys
+       , keysWith
+       , toListWith
 
          -- * 'IsList'
        , WrapTypeable (..)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typerep-map-0.3.3.0/test/Test/TypeRep/TypeRepMap.hs 
new/typerep-map-0.4.0.0/test/Test/TypeRep/TypeRepMap.hs
--- old/typerep-map-0.3.3.0/test/Test/TypeRep/TypeRepMap.hs     2001-09-09 
03:46:40.000000000 +0200
+++ new/typerep-map-0.4.0.0/test/Test/TypeRep/TypeRepMap.hs     2001-09-09 
03:46:40.000000000 +0200
@@ -5,14 +5,18 @@
 import Prelude hiding (lookup)
 
 import Data.Functor.Identity (Identity (..))
-import GHC.Exts (fromList)
-import Test.Hspec (Spec, describe, it, shouldBe)
+import Data.List (sortBy)
+import Data.Ord (comparing)
+import Data.Typeable (cast)
+import GHC.Exts (fromList, toList)
+import Type.Reflection (SomeTypeRep(..), typeRep)
+import Test.Hspec (Spec, describe, it, shouldBe, shouldMatchList, 
shouldSatisfy, expectationFailure)
 
-import Data.TMap (TMap, empty, insert, lookup, one, size, union)
+import Data.TMap (TMap, empty, insert, lookup, one, size, union, keys)
 import Data.TypeRepMap.Internal (WrapTypeable (..))
 
 
--- Simple test for 'lookup', 'insert' and 'size' functions.
+-- Simple test for 'lookup', 'insert', 'size', 'keys', 'toList' functions.
 typeRepMapSpec :: Spec
 typeRepMapSpec = describe "TypeRepMap" $ do
     describe "Lookup Test" $ do
@@ -39,6 +43,60 @@
             lookup m `shouldBe` Just True
             lookup @Int m `shouldBe` Nothing
 
+    describe "Keys Test" $ do
+      it "returns nothing on empty map" $
+        keys empty `shouldBe` []
+      it "returns the correct TypeRep" $
+        keys (one 'a') `shouldBe` [SomeTypeRep $ typeRep @Char]
+      it "returns the correct TypeReps for 10 different types" $
+        keys mapOf10 `shouldMatchList`
+          [ SomeTypeRep $ typeRep @Bool
+          , SomeTypeRep $ typeRep @[Bool]
+          , SomeTypeRep $ typeRep @(Maybe Bool)
+          , SomeTypeRep $ typeRep @(Maybe ())
+          , SomeTypeRep $ typeRep @[()]
+          , SomeTypeRep $ typeRep @()
+          , SomeTypeRep $ typeRep @String
+          , SomeTypeRep $ typeRep @(Maybe Char)
+          , SomeTypeRep $ typeRep @Char
+          , SomeTypeRep $ typeRep @Int
+          ]
+
+    describe "ToList Test" $ do
+      it "returns nothing on empty map" $
+        toList empty `shouldSatisfy` null
+      it "returns correct result when 1 element is inserted" $
+        case toList (one 'a') of
+          [WrapTypeable (Identity x)] -> cast x `shouldBe` Just 'a'
+          _ -> expectationFailure "did not return exactly 1 result"
+      it "returns correct result when 10 elements are inserted" $ do
+        let
+          getTypeRep (WrapTypeable (Identity (_ :: a))) = SomeTypeRep $ 
typeRep @a
+          got = sortBy (comparing getTypeRep) (toList mapOf10)
+          expected = sortBy (comparing fst)
+            [ (SomeTypeRep $ typeRep @Bool,
+              \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just True)
+            , (SomeTypeRep $ typeRep @[Bool],
+              \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just [True, 
False])
+            , (SomeTypeRep $ typeRep @(Maybe Bool),
+              \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (Just 
True))
+            , (SomeTypeRep $ typeRep @(Maybe ()),
+              \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (Just ()))
+            , (SomeTypeRep $ typeRep @[()],
+              \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just [()])
+            , (SomeTypeRep $ typeRep @(),
+              \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just ())
+            , (SomeTypeRep $ typeRep @String,
+              \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just ("aaa" :: 
String))
+            , (SomeTypeRep $ typeRep @(Maybe Char),
+              \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (Just 
'a'))
+            , (SomeTypeRep $ typeRep @Char,
+              \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just 'a')
+            , (SomeTypeRep $ typeRep @Int,
+              \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (11 :: 
Int))
+            ]
+        length got `shouldBe` 10
+        sequence_ $ zipWith snd expected got
 
 mapOf10 :: TMap
 mapOf10 = insert True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/typerep-map-0.3.3.0/test/Test/TypeRep/TypeRepMapProperty.hs 
new/typerep-map-0.4.0.0/test/Test/TypeRep/TypeRepMapProperty.hs
--- old/typerep-map-0.3.3.0/test/Test/TypeRep/TypeRepMapProperty.hs     
2001-09-09 03:46:40.000000000 +0200
+++ new/typerep-map-0.4.0.0/test/Test/TypeRep/TypeRepMapProperty.hs     
2001-09-09 03:46:40.000000000 +0200
@@ -20,7 +20,8 @@
 import Test.Hspec.Hedgehog (hedgehog)
 
 import Data.TypeRepMap.Internal (TypeRepMap (..), WrapTypeable (..), delete, 
insert, invariantCheck,
-                                 lookup, member)
+                                 lookup, member, union, generateOrderMapping, 
fromSortedList,
+                                 adjust, alter, intersection)
 
 import qualified Hedgehog.Gen as Gen
 import qualified Hedgehog.Range as Range
@@ -34,6 +35,13 @@
         deleteMemberSpec
         insertInvariantSpec
         deleteInvariantSpec
+        alterInsertSpec
+        alterDeleteSpec
+        alterAdjustSpec
+        alterModifySpec
+        intersectionSpec
+    describe "Internal helpers" $ do
+        generateOrderMappingInvariantSpec
     describe "Instance Laws" $ do
         semigroupAssocSpec
         monoidIdentitySpec
@@ -80,45 +88,66 @@
     WrapTypeable (_ :: IntProxy n) <- forAll genTF
     assert $ invariantCheck (delete @n m)
 
+alterInsertSpec :: Property
+alterInsertSpec = it "insert proxy m === alter (const (Just proxy)) m" $ 
hedgehog $ do
+    m <- forAll genMap
+    WrapTypeable (proxy :: IntProxy n) <- forAll genTF
+    insert proxy m === alter (const (Just proxy)) m
+
+alterDeleteSpec :: Property
+alterDeleteSpec = it "delete proxy m === alter (const Nothing) m" $ hedgehog $ 
do
+    WrapTypeable (proxy :: IntProxy n) <- forAll genTF
+    m <- insert proxy <$> forAll genMap
+    delete @n @IntProxy m === alter @n @IntProxy (const Nothing) m
+
+alterAdjustSpec :: Property
+alterAdjustSpec = it "adjust f m == alter (fmap f) m" $ hedgehog $ do
+    m <- forAll genMap
+    WrapTypeable (_ :: IntProxy n) <- forAll genTF
+    let f (IntProxy p n) = IntProxy p (n * 10)
+    adjust @n @IntProxy f m === alter @n @IntProxy (fmap f) m
+
+alterModifySpec :: Property
+alterModifySpec = it "lookup k (alter f) == f (lookup k m)" $ hedgehog $ do
+    m <- forAll genMap
+    WrapTypeable (_ :: IntProxy n) <- forAll genTF
+    randInt <- forAll (Gen.int Range.constantBounded)
+    -- Function with some interesting behaviour, which inserts, seletes and 
modifies
+    let f Nothing = Just (IntProxy Proxy randInt)
+        f (Just (IntProxy p n))
+          | even n = Nothing
+          | otherwise = Just $ IntProxy p (n * 10)
+    lookup @n @IntProxy (alter @n f m) === f (lookup @n @IntProxy m)
+
+intersectionSpec :: Property
+intersectionSpec = it "m `intersection` (m `union` n) == m" $ hedgehog $ do
+    m <- forAll genMap
+    n <- forAll genMap
+    m `intersection` (m `union` n) === m
+
 ----------------------------------------------------------------------------
--- Semigroup and Monoid laws
+-- Internal helpers
 ----------------------------------------------------------------------------
+generateOrderMappingInvariantSpec :: Property
+generateOrderMappingInvariantSpec =
+    it "fmap (fromSortedList [1 .. n] !!) (generateOrderMapping n) == [1 .. 
n]" $ hedgehog $ do
+        n <- forAll $ Gen.int (Range.linear 0 100)
+        fmap (fromSortedList [1 .. n] !!) (generateOrderMapping n) === [1 .. n]
 
-#if __GLASGOW_HASKELL__ < 806
-{- | This newtype is used to compare 'TypeRepMap's using only 'Fingerprint's.
-It's not a good idea to write such 'Eq' instance for 'TypeRepMap' itself 
because
-it doesn't compare values so it's not true equality. But this should be enough
-for tests.
--}
-newtype FpMap f = FpMap (TypeRepMap f)
-    deriving newtype (Show, Semigroup, Monoid)
-
-instance Eq (FpMap f) where
-    FpMap (TypeRepMap as1 bs1 _ _) == FpMap (TypeRepMap as2 bs2 _ _) =
-        as1 == as2 && bs1 == bs2
-#endif
+----------------------------------------------------------------------------
+-- Semigroup and Monoid laws
+----------------------------------------------------------------------------
 
 semigroupAssocSpec :: Property
 semigroupAssocSpec = it "x <> (y <> z) == (x <> y) <> z" $ hedgehog $ do
-#if __GLASGOW_HASKELL__ >= 806
     x <- forAll genMap
     y <- forAll genMap
     z <- forAll genMap
-#else
-    x <- FpMap <$> forAll genMap
-    y <- FpMap <$> forAll genMap
-    z <- FpMap <$> forAll genMap
-#endif
     (x <> (y <> z)) === ((x <> y) <> z)
 
 monoidIdentitySpec :: Property
 monoidIdentitySpec = it "x <> mempty == mempty <> x == x" $ hedgehog $ do
-#if __GLASGOW_HASKELL__ >= 806
     x <- forAll genMap
-#else
-    x <- FpMap <$> forAll genMap
-#endif
-
     x <> mempty === x
     mempty <> x === x
 
@@ -139,3 +168,17 @@
     case someNatVal randNat of
         Just (SomeNat proxyNat) -> pure $ WrapTypeable $ IntProxy proxyNat 
randInt
         Nothing                 -> error "Invalid test generator"
+
+----------------------------------------------------------------------------
+-- Helpers
+----------------------------------------------------------------------------
+#if __GLASGOW_HASKELL__ < 806
+{- | We add an orphan Eq instance for old GHC versions just to make testing 
easier.
+It's not a good idea to write such 'Eq' instance for 'TypeRepMap' itself 
because
+it doesn't compare values so it's not true equality. But this should be enough
+for tests.
+-}
+instance Eq (TypeRepMap f) where
+    TypeRepMap as1 bs1 _ _ == TypeRepMap as2 bs2 _ _ =
+        as1 == as2 && bs1 == bs2
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typerep-map-0.3.3.0/typerep-map.cabal 
new/typerep-map-0.4.0.0/typerep-map.cabal
--- old/typerep-map-0.3.3.0/typerep-map.cabal   2001-09-09 03:46:40.000000000 
+0200
+++ new/typerep-map-0.4.0.0/typerep-map.cabal   2001-09-09 03:46:40.000000000 
+0200
@@ -1,6 +1,6 @@
 cabal-version:       2.4
 name:                typerep-map
-version:             0.3.3.0
+version:             0.4.0.0
 synopsis:            Efficient implementation of a dependent map with types as 
keys
 description:
     A dependent map from type representations to values of these types.
@@ -23,7 +23,7 @@
 license-file:        LICENSE
 author:              Veronika Romashkina, Vladislav Zavialov, Dmitrii Kovanikov
 maintainer:          Kowainik <[email protected]>
-copyright:           2017-2020 Kowainik
+copyright:           2017-2021 Kowainik
 category:            Data, Data Structures, Types
 build-type:          Simple
 extra-doc-files:     README.md
@@ -31,15 +31,16 @@
 tested-with:         GHC == 8.2.2
                    , GHC == 8.4.4
                    , GHC == 8.6.5
-                   , GHC == 8.8.3
-                   , GHC == 8.10.1
+                   , GHC == 8.8.4
+                   , GHC == 8.10.5
+                   , GHC == 9.0.1
 
 source-repository head
   type:                git
   location:            https://github.com/kowainik/typerep-map.git
 
 common common-options
-  build-depends:       base >= 4.10 && < 4.15
+  build-depends:       base >= 4.10 && < 4.16
 
   default-language:    Haskell2010
   default-extensions:  BangPatterns
@@ -53,10 +54,8 @@
                        -Widentities
                        -Wincomplete-uni-patterns
                        -Wincomplete-record-updates
-  if impl(ghc >= 8.0)
-    ghc-options:       -Wredundant-constraints
-  if impl(ghc >= 8.2)
-    ghc-options:       -fhide-source-paths
+                       -Wredundant-constraints
+                       -fhide-source-paths
   if impl(ghc >= 8.4)
     ghc-options:       -Wmissing-export-lists
                        -Wpartial-fields
@@ -73,8 +72,7 @@
                        Data.TypeRepMap
                        Data.TypeRepMap.Internal
 
-  build-depends:       containers >= 0.5.10.2 && < 0.7
-                     , ghc-prim >= 0.5.1.1 && < 0.7
+  build-depends:       ghc-prim >= 0.5.1.1 && < 0.8
                      , primitive ^>= 0.7.0
                      , deepseq ^>= 1.4
 
@@ -103,7 +101,7 @@
 
   build-depends:       ghc-typelits-knownnat >= 0.4.2 && < 0.8
                      , hedgehog ^>= 1.0
-                     , hspec ^>= 2.7.1
+                     , hspec >= 2.7.1 && < 2.9
                      , hspec-hedgehog ^>= 0.0.1
                      , typerep-map
                      , typerep-extra-impls

Reply via email to