@@ -1,38 +1,58 @@
1−{-# LANGUAGE ExplicitForAll #-}
1+{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE KindSignatures #-}
3{-# LANGUAGE KindSignatures #-}
4+{-# LANGUAGE MagicHash #-}
3{-# LANGUAGE PolyKinds #-}
5{-# LANGUAGE PolyKinds #-}
4{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE ScopedTypeVariables #-}
7+{-# LANGUAGE TypeApplications #-}
8+{-# LANGUAGE TypeFamilies #-}
6module Data.TypeRep.Map
10module Data.TypeRep.Map
7− ( TypeRepMap (..)
12+ TypeRepMap (..)
14+ -- 'TypeRepMap' interface
20+ -- * Helpful testing functions
15import Prelude hiding (lookup)
25import Prelude hiding (lookup)
27+import Control.Arrow ((&&&))
28+import Data.Kind (Type)
17import Data.Proxy (Proxy (..))
29import Data.Proxy (Proxy (..))
18−import Data.Typeable (TypeRep, Typeable, typeRep)
30+import Data.Typeable (Typeable, typeRep, typeRepFingerprint)
31+import Data.Word (Word64)
19−import GHC.Base (Any)
32+import GHC.Base (Any, Int (..), Int#, uncheckedIShiftRA#, (+#), (-#), (<#))
33+import GHC.Exts (inline, sortWith)
34+import GHC.Fingerprint (Fingerprint (..))
20import Unsafe.Coerce (unsafeCoerce)
35import Unsafe.Coerce (unsafeCoerce)
22−import qualified Data.Map.Lazy as LMap
37+import qualified Data.Vector as V
38+import qualified Data.Vector.Unboxed as Unboxed
24−-- | Map-like data structure with types served as the keys.
25−newtype TypeRepMap (f :: k -> *) = TypeRepMap
40+data TypeRepMap (f :: k -> Type) = TypeRepMap
26− { unMap :: LMap.Map TypeRep Any
41+ { fingerprintAs :: Unboxed.Vector Word64
42+ , fingerprintBs :: Unboxed.Vector Word64
43+ , anys :: V.Vector Any
47+fromAny = unsafeCoerce
29-- | Empty structure.
49-- | Empty structure.
30empty :: TypeRepMap f
50empty :: TypeRepMap f
31−empty = TypeRepMap mempty
51+empty = TypeRepMap mempty mempty mempty
33-- | Inserts the value with its type as a key.
53-- | Inserts the value with its type as a key.
34−insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
54+insert :: forall a f . Typeable a => a -> TypeRepMap f -> TypeRepMap f
35−insert val = TypeRepMap . LMap.insert (typeRep (Proxy :: Proxy a)) (unsafeCoerce val) . unMap
55+insert = undefined
37-- | Looks up the value at the type.
57-- | Looks up the value at the type.
38-- >>> let x = lookup $ insert (11 :: Int) empty
58-- >>> let x = lookup $ insert (11 :: Int) empty
@@ -41,10 +61,60 @@ insert val = TypeRepMap . LMap.insert (typeRep (Proxy :: Proxy a)) (unsafeCoerce
41-- >>> x :: Maybe ()
61-- >>> x :: Maybe ()
43lookup :: forall a f . Typeable a => TypeRepMap f -> Maybe (f a)
63lookup :: forall a f . Typeable a => TypeRepMap f -> Maybe (f a)
44−lookup = fmap unsafeCoerce . LMap.lookup (typeRep (Proxy :: Proxy a)) . unMap
64+lookup tVect = fromAny . (anys tVect V.!)
65+ <$> binarySearch (typeRepFingerprint $ typeRep $ Proxy @a)
66+ (fingerprintAs tVect)
67+ (fingerprintBs tVect)
69+-- | Returns the size of the 'TypeRepMap'.
46size :: TypeRepMap f -> Int
70size :: TypeRepMap f -> Int
47−size = LMap.size . unMap
71+size = Unboxed.length . fingerprintAs
73+-- | Returns the index is found.
74+binarySearch :: Fingerprint -> Unboxed.Vector Word64 -> Unboxed.Vector Word64 -> Maybe Int
75+binarySearch (Fingerprint a b) fpAs fpBs =
77+ !(I# len) = Unboxed.length fpAs
78+ checkfpBs :: Int# -> Maybe Int
83+ if a /= Unboxed.unsafeIndex fpAs (I# i)
85+ else if b == Unboxed.unsafeIndex fpBs (I# i)
87+ else checkfpBs (i +# 1#)
89+ inline (checkfpBs (binSearchHelp (-1#) len))
91+ binSearchHelp :: Int# -> Int# -> Int#
92+ binSearchHelp l r = case l <# (r -# 1#) of
95+ let m = uncheckedIShiftRA# (l +# r) 1# in
96+ if Unboxed.unsafeIndex fpAs (I# m) < a
97+ then binSearchHelp m r
98+ else binSearchHelp l m
100+----------------------------------------------------------------------------
101+-- Functions for testing and benchmarking
102+----------------------------------------------------------------------------
105+ TF :: Typeable a => f a -> TF f
107+fromF :: Typeable a => f a -> Proxy a
110+fromList :: forall f . [TF f] -> TypeRepMap f
111+fromList tfs = TypeRepMap (Unboxed.fromList fpAs) (Unboxed.fromList fpBs) (V.fromList ans)
113+ (fpAs, fpBs) = unzip $ fmap (\(Fingerprint a b) -> (a, b)) fps
114+ (fps, ans) = unzip $ sortWith fst $ map (fp &&& an) tfs
116+ fp :: TF f -> Fingerprint
117+ fp (TF x) = typeRepFingerprint $ typeRep $ fromF x
49−keys :: TypeRepMap f -> [TypeRep]
119+ an :: TF f -> Any
50−keys = LMap.keys . unMap
120+ an (TF x) = unsafeCoerce x