on main help sign in
src/Data/TMap.hs+13−1
since splitsnapshots
unifiedsplit
@@ -48,6 +48,8 @@ module Data.TMap
48 , member
48 , member
49 , size
49 , size
50 , keys
50 , keys
51+ , keysWith
52+ , toListWith
51 ) where
53 ) where
52
54
53import Prelude hiding (lookup, map)
55import Prelude hiding (lookup, map)
@@ -55,7 +57,7 @@ import Prelude hiding (lookup, map)
55import Data.Functor.Identity (Identity (..))
57import Data.Functor.Identity (Identity (..))
56import Data.Typeable (Typeable)
58import Data.Typeable (Typeable)
57import GHC.Exts (coerce)
59import GHC.Exts (coerce)
58−import Type.Reflection (SomeTypeRep)
60+import Type.Reflection (SomeTypeRep, TypeRep)
59
61
60import qualified Data.TypeRepMap as F
62import qualified Data.TypeRepMap as F
61
63
@@ -185,6 +187,16 @@ keys :: TMap -> [SomeTypeRep]
185keys = F.keys
187keys = F.keys
186{-# INLINE keys #-}
188{-# INLINE keys #-}
187
189
190+-- | Return the list of keys by wrapping them with a user-provided function.
191+keysWith :: (forall a. TypeRep a -> r) -> TMap -> [r]
192+keysWith = F.keysWith
193+{-# INLINE keysWith #-}
194+
195+-- | Return the list of key-value pairs by wrapping them with a user-provided function.
196+toListWith :: (forall a. Typeable a => a -> r) -> TMap -> [r]
197+toListWith = F.toListWith
198+{-# INLINE toListWith #-}
199+
188-- | Map a function over the values.
200-- | Map a function over the values.
189map :: (forall a. Typeable a => a -> a) -> TMap -> TMap
201map :: (forall a. Typeable a => a -> a) -> TMap -> TMap
190map f = F.hoistWithKey (liftToIdentity f)
202map f = F.hoistWithKey (liftToIdentity f)
src/Data/TypeRepMap.hs+2
@@ -71,6 +71,8 @@ module Data.TypeRepMap
71 , member
71 , member
72 , size
72 , size
73 , keys
73 , keys
74+ , keysWith
75+ , toListWith
74
76
75 -- * 'IsList'
77 -- * 'IsList'
76 , WrapTypeable (..)
78 , WrapTypeable (..)
src/Data/TypeRepMap/Internal.hs+17−8
@@ -205,6 +205,8 @@ insert x m
205-- inferred type variables (which are not subject to type applications).
205-- inferred type variables (which are not subject to type applications).
206type KindOf (a :: k) = k
206type KindOf (a :: k) = k
207
207
208+type ArgKindOf (f :: k -> l) = k
209+
208{- | Delete a value from a 'TypeRepMap'.
210{- | Delete a value from a 'TypeRepMap'.
209
211
210TypeRepMap optimizes for fast reads rather than modifications, as a trade-off deletes are
212TypeRepMap optimizes for fast reads rather than modifications, as a trade-off deletes are
@@ -427,9 +429,22 @@ size = sizeofPrimArray . fingerprintAs
427
429
428-- | Return the list of 'SomeTypeRep' from the keys.
430-- | Return the list of 'SomeTypeRep' from the keys.
429keys :: TypeRepMap f -> [SomeTypeRep]
431keys :: TypeRepMap f -> [SomeTypeRep]
430−keys TypeRepMap{..} = SomeTypeRep . anyToTypeRep <$> toList trKeys
432+keys = keysWith SomeTypeRep
431{-# INLINE keys #-}
433{-# INLINE keys #-}
432
434
435+-- | Return the list of keys by wrapping them with a user-provided function.
436+keysWith :: (forall (a :: ArgKindOf f). TypeRep a -> r) -> TypeRepMap f -> [r]
437+keysWith f TypeRepMap{..} = f . anyToTypeRep <$> toList trKeys
438+{-# INLINE keysWith #-}
439+
440+-- | Return the list of key-value pairs by wrapping them with a user-provided function.
441+toListWith :: forall f r. (forall (a :: ArgKindOf f). Typeable a => f a -> r) -> TypeRepMap f -> [r]
442+toListWith f = map toF . toTriples
443+ where
444+ withTypeRep :: TypeRep a -> f a -> r
445+ withTypeRep tr an = withTypeable tr $ f an
446+ toF (_, an, k) = withTypeRep (unsafeCoerce k) (fromAny an)
447+
433-- | Binary searched based on this article
448-- | Binary searched based on this article
434-- http://bannalia.blogspot.com/2015/06/cache-friendly-binary-search.html
449-- http://bannalia.blogspot.com/2015/06/cache-friendly-binary-search.html
435-- with modification for our two-vector search case.
450-- with modification for our two-vector search case.
@@ -506,9 +521,6 @@ data WrapTypeable f where
506instance Show (WrapTypeable f) where
521instance Show (WrapTypeable f) where
507 show (WrapTypeable (_ :: f a)) = show $ calcFp @a
522 show (WrapTypeable (_ :: f a)) = show $ calcFp @a
508
523
509−wrapTypeable :: TypeRep a -> f a -> WrapTypeable f
510−wrapTypeable tr = withTypeable tr WrapTypeable
511−
512{- |
524{- |
513
525
514prop> fromList . toList == 'id'
526prop> fromList . toList == 'id'
@@ -536,10 +548,7 @@ instance IsList (TypeRepMap f) where
536 k (WrapTypeable (_ :: f a)) = unsafeCoerce $ typeRep @a
548 k (WrapTypeable (_ :: f a)) = unsafeCoerce $ typeRep @a
537
549
538 toList :: TypeRepMap f -> [WrapTypeable f]
550 toList :: TypeRepMap f -> [WrapTypeable f]
539− toList = map toWrapTypeable . toTriples
551+ toList = toListWith WrapTypeable
540− where
541− toWrapTypeable :: (Fingerprint, Any, Any) -> WrapTypeable f
542− toWrapTypeable (_, an, k) = wrapTypeable (unsafeCoerce k) (fromAny an)
543
552
544calcFp :: forall a . Typeable a => Fingerprint
553calcFp :: forall a . Typeable a => Fingerprint
545calcFp = typeRepFingerprint $ typeRep @a
554calcFp = typeRepFingerprint $ typeRep @a
test/Test/TypeRep/TypeRepMap.hs+62−4
@@ -5,14 +5,18 @@ module Test.TypeRep.TypeRepMap
5import Prelude hiding (lookup)
5import Prelude hiding (lookup)
6
6
7import Data.Functor.Identity (Identity (..))
7import Data.Functor.Identity (Identity (..))
8+import Data.List (sortBy)
9+import Data.Ord (comparing)
10+import Data.Typeable (cast)
8−import GHC.Exts (fromList)
11+import GHC.Exts (fromList, toList)
12+import Type.Reflection (SomeTypeRep(..), typeRep)
9−import Test.Hspec (Spec, describe, it, shouldBe)
13+import Test.Hspec (Spec, describe, it, shouldBe, shouldMatchList, shouldSatisfy, expectationFailure)
10
14
11−import Data.TMap (TMap, empty, insert, lookup, one, size, union)
15+import Data.TMap (TMap, empty, insert, lookup, one, size, union, keys)
12import Data.TypeRepMap.Internal (WrapTypeable (..))
16import Data.TypeRepMap.Internal (WrapTypeable (..))
13
17
14
18
15−-- Simple test for 'lookup', 'insert' and 'size' functions.
19+-- Simple test for 'lookup', 'insert', 'size', 'keys', 'toList' functions.
16typeRepMapSpec :: Spec
20typeRepMapSpec :: Spec
17typeRepMapSpec = describe "TypeRepMap" $ do
21typeRepMapSpec = describe "TypeRepMap" $ do
18 describe "Lookup Test" $ do
22 describe "Lookup Test" $ do
@@ -39,6 +43,60 @@ typeRepMapSpec = describe "TypeRepMap" $ do
39 lookup m `shouldBe` Just True
43 lookup m `shouldBe` Just True
40 lookup @Int m `shouldBe` Nothing
44 lookup @Int m `shouldBe` Nothing
41
45
46+ describe "Keys Test" $ do
47+ it "returns nothing on empty map" $
48+ keys empty `shouldBe` []
49+ it "returns the correct TypeRep" $
50+ keys (one 'a') `shouldBe` [SomeTypeRep $ typeRep @Char]
51+ it "returns the correct TypeReps for 10 different types" $
52+ keys mapOf10 `shouldMatchList`
53+ [ SomeTypeRep $ typeRep @Bool
54+ , SomeTypeRep $ typeRep @[Bool]
55+ , SomeTypeRep $ typeRep @(Maybe Bool)
56+ , SomeTypeRep $ typeRep @(Maybe ())
57+ , SomeTypeRep $ typeRep @[()]
58+ , SomeTypeRep $ typeRep @()
59+ , SomeTypeRep $ typeRep @String
60+ , SomeTypeRep $ typeRep @(Maybe Char)
61+ , SomeTypeRep $ typeRep @Char
62+ , SomeTypeRep $ typeRep @Int
63+ ]
64+
65+ describe "ToList Test" $ do
66+ it "returns nothing on empty map" $
67+ toList empty `shouldSatisfy` null
68+ it "returns correct result when 1 element is inserted" $
69+ case toList (one 'a') of
70+ [WrapTypeable (Identity x)] -> cast x `shouldBe` Just 'a'
71+ _ -> expectationFailure "did not return exactly 1 result"
72+ it "returns correct result when 10 elements are inserted" $ do
73+ let
74+ getTypeRep (WrapTypeable (Identity (_ :: a))) = SomeTypeRep $ typeRep @a
75+ got = sortBy (comparing getTypeRep) (toList mapOf10)
76+ expected = sortBy (comparing fst)
77+ [ (SomeTypeRep $ typeRep @Bool,
78+ \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just True)
79+ , (SomeTypeRep $ typeRep @[Bool],
80+ \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just [True, False])
81+ , (SomeTypeRep $ typeRep @(Maybe Bool),
82+ \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (Just True))
83+ , (SomeTypeRep $ typeRep @(Maybe ()),
84+ \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (Just ()))
85+ , (SomeTypeRep $ typeRep @[()],
86+ \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just [()])
87+ , (SomeTypeRep $ typeRep @(),
88+ \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just ())
89+ , (SomeTypeRep $ typeRep @String,
90+ \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just ("aaa" :: String))
91+ , (SomeTypeRep $ typeRep @(Maybe Char),
92+ \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (Just 'a'))
93+ , (SomeTypeRep $ typeRep @Char,
94+ \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just 'a')
95+ , (SomeTypeRep $ typeRep @Int,
96+ \(WrapTypeable (Identity x)) -> cast x `shouldBe` Just (11 :: Int))
97+ ]
98+ length got `shouldBe` 10
99+ sequence_ $ zipWith snd expected got
42
100
43mapOf10 :: TMap
101mapOf10 :: TMap
44mapOf10 = insert True
102mapOf10 = insert True