on main help sign in
[#5] Rename OptimalVector to Map (#9)

* [#5] Rename OptimalVector to Map * Fix stack travis CI

commit5ad21784db230f7d0c1b89b80d785d035283b069 authorDmitrii Kovanikov <kovanikov@gmail.com> dateSun 1 Jul 2018, 18:43 (8 years ago) parentf78299e
9 files changed+151−143
.travis.yml+2−1 benchmark/Map.hs+1−1 benchmark/OptimalVector.hs+4−4 src/Data/TypeRep/CMap.hs+50 src/Data/TypeRep/Map.hs+86−16 src/Data/TypeRep/OptimalVector.hs−114 test/Test/TypeRep/Map.hs+1−1 test/Test/TypeRep/VectorOpt.hs+1−1 typerep-map.cabal+6−5
.travis.yml+2−1
@@ -49,7 +49,7 @@ matrix:
4949 - cabal-install-head
5050
5151 - ghc: 8.4.3
52− env: STACK_YAML="$HOME/build/vrom911/typerep-map/stack.yaml"
52+ env: STACK_YAML="$HOME/build/kowainik/typerep-map/stack.yaml"
5353 os: linux
5454 addons:
5555 apt:
@@ -64,6 +64,7 @@ install:
6464 cabal new-update
6565 cabal new-build --enable-tests --enable-benchmarks
6666 else
67+ echo "$TRAVIS_BUILD_DIR"
6768 mkdir -p ~/.local/bin
6869 export PATH="$HOME/.local/bin:$PATH"
6970 travis_retry curl -L 'https://www.stackage.org/stack/linux-x86_64' | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
benchmark/Map.hs+1−1
@@ -26,7 +26,7 @@ import Data.Proxy (Proxy (..))
2626import Data.Typeable (Typeable)
2727import GHC.TypeLits
2828
29−import Data.TypeRep.Map (TypeRepMap (..), empty, insert, keys, lookup)
29+import Data.TypeRep.CMap (TypeRepMap (..), empty, insert, keys, lookup)
3030
3131benchMap :: Benchmark
3232benchMap = bgroup "map"
benchmark/OptimalVector.hs+4−4
@@ -25,7 +25,7 @@ import Data.Proxy (Proxy (..))
2525import Data.Typeable (Typeable)
2626import GHC.TypeLits
2727
28−import Data.TypeRep.OptimalVector
28+import Data.TypeRep.Map (TF (..), TypeRepMap (..), fromList, lookup)
2929
3030benchVectorOpt :: Benchmark
3131benchVectorOpt = bgroup "vector optimal"
@@ -34,7 +34,7 @@ benchVectorOpt = bgroup "vector optimal"
3434 -- , bench "update old" $ whnf (\x -> rknf $ insert x bigMap) (Proxy :: Proxy 1)
3535 ]
3636
37−tenLookups :: TypeRepVector (Proxy :: Nat -> *)
37+tenLookups :: TypeRepMap (Proxy :: Nat -> *)
3838 -> ( Proxy 10, Proxy 20, Proxy 30, Proxy 40
3939 , Proxy 50, Proxy 60, Proxy 70, Proxy 80
4040 )
@@ -44,14 +44,14 @@ tenLookups tmap = (lp, lp, lp, lp, lp, lp, lp, lp)
4444 lp = fromJust $ lookup tmap
4545
4646-- TypeRepMap of 10000 elements
47−bigMap :: TypeRepVector (Proxy :: Nat -> *)
47+bigMap :: TypeRepMap (Proxy :: Nat -> *)
4848bigMap = fromList $ buildBigMap 10000 (Proxy :: Proxy 0) []
4949
5050buildBigMap :: forall a . (KnownNat a) => Int -> Proxy (a :: Nat) -> [TF (Proxy :: Nat -> *)] -> [TF (Proxy :: Nat -> *)]
5151buildBigMap 1 x = (TF x :)
5252buildBigMap n x = (TF x :) . buildBigMap (n - 1) (Proxy :: Proxy (a + 1))
5353
54−rknf :: TypeRepVector f -> ()
54+rknf :: TypeRepMap f -> ()
5555rknf tVect = rnf (fingerprintAs tVect, fingerprintBs tVect)
5656
5757prepareBenchVectorOpt :: IO ()
src/Data/TypeRep/CMap.hsnew file+50
@@ -0,0 +1,50 @@
1+{-# LANGUAGE ExplicitForAll #-}
2+{-# LANGUAGE KindSignatures #-}
3+{-# LANGUAGE PolyKinds #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
5+
6+module Data.TypeRep.CMap
7+ ( TypeRepMap (..)
8+ , empty
9+ , insert
10+ , keys
11+ , lookup
12+ , size
13+ ) where
14+
15+import Prelude hiding (lookup)
16+
17+import Data.Proxy (Proxy (..))
18+import Data.Typeable (TypeRep, Typeable, typeRep)
19+import GHC.Base (Any)
20+import Unsafe.Coerce (unsafeCoerce)
21+
22+import qualified Data.Map.Lazy as LMap
23+
24+-- | Map-like data structure with types served as the keys.
25+newtype TypeRepMap (f :: k -> *) = TypeRepMap
26+ { unMap :: LMap.Map TypeRep Any
27+ }
28+
29+-- | Empty structure.
30+empty :: TypeRepMap f
31+empty = TypeRepMap mempty
32+
33+-- | Inserts the value with its type as a key.
34+insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
35+insert val = TypeRepMap . LMap.insert (typeRep (Proxy :: Proxy a)) (unsafeCoerce val) . unMap
36+
37+-- | Looks up the value at the type.
38+-- >>> let x = lookup $ insert (11 :: Int) empty
39+-- >>> x :: Maybe Int
40+-- Just 11
41+-- >>> x :: Maybe ()
42+-- Nothing
43+lookup :: forall a f . Typeable a => TypeRepMap f -> Maybe (f a)
44+lookup = fmap unsafeCoerce . LMap.lookup (typeRep (Proxy :: Proxy a)) . unMap
45+
46+size :: TypeRepMap f -> Int
47+size = LMap.size . unMap
48+
49+keys :: TypeRepMap f -> [TypeRep]
50+keys = LMap.keys . unMap
src/Data/TypeRep/Map.hs+86−16
@@ -1,38 +1,58 @@
1−{-# LANGUAGE ExplicitForAll #-}
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE GADTs #-}
23{-# LANGUAGE KindSignatures #-}
4+{-# LANGUAGE MagicHash #-}
35{-# LANGUAGE PolyKinds #-}
46{-# LANGUAGE ScopedTypeVariables #-}
7+{-# LANGUAGE TypeApplications #-}
8+{-# LANGUAGE TypeFamilies #-}
59
610module Data.TypeRep.Map
7− ( TypeRepMap (..)
11+ ( -- * Map type
12+ TypeRepMap (..)
13+
14+ -- 'TypeRepMap' interface
815 , empty
916 , insert
10− , keys
1117 , lookup
1218 , size
19+
20+ -- * Helpful testing functions
21+ , TF (..)
22+ , fromList
1323 ) where
1424
1525import Prelude hiding (lookup)
1626
27+import Control.Arrow ((&&&))
28+import Data.Kind (Type)
1729import Data.Proxy (Proxy (..))
18−import Data.Typeable (TypeRep, Typeable, typeRep)
19−import GHC.Base (Any)
30+import Data.Typeable (Typeable, typeRep, typeRepFingerprint)
31+import Data.Word (Word64)
32+import GHC.Base (Any, Int (..), Int#, uncheckedIShiftRA#, (+#), (-#), (<#))
33+import GHC.Exts (inline, sortWith)
34+import GHC.Fingerprint (Fingerprint (..))
2035import Unsafe.Coerce (unsafeCoerce)
2136
22−import qualified Data.Map.Lazy as LMap
37+import qualified Data.Vector as V
38+import qualified Data.Vector.Unboxed as Unboxed
2339
24−-- | Map-like data structure with types served as the keys.
25−newtype TypeRepMap (f :: k -> *) = TypeRepMap
26− { unMap :: LMap.Map TypeRep Any
40+data TypeRepMap (f :: k -> Type) = TypeRepMap
41+ { fingerprintAs :: Unboxed.Vector Word64
42+ , fingerprintBs :: Unboxed.Vector Word64
43+ , anys :: V.Vector Any
2744 }
2845
46+fromAny :: Any -> f a
47+fromAny = unsafeCoerce
48+
2949-- | Empty structure.
3050empty :: TypeRepMap f
31−empty = TypeRepMap mempty
51+empty = TypeRepMap mempty mempty mempty
3252
3353-- | Inserts the value with its type as a key.
34−insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
35−insert val = TypeRepMap . LMap.insert (typeRep (Proxy :: Proxy a)) (unsafeCoerce val) . unMap
54+insert :: forall a f . Typeable a => a -> TypeRepMap f -> TypeRepMap f
55+insert = undefined
3656
3757-- | Looks up the value at the type.
3858-- >>> let x = lookup $ insert (11 :: Int) empty
@@ -41,10 +61,60 @@ insert val = TypeRepMap . LMap.insert (typeRep (Proxy :: Proxy a)) (unsafeCoerce
4161-- >>> x :: Maybe ()
4262-- Nothing
4363lookup :: 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)
4568
69+-- | Returns the size of the 'TypeRepMap'.
4670size :: TypeRepMap f -> Int
47−size = LMap.size . unMap
71+size = Unboxed.length . fingerprintAs
72+
73+-- | Returns the index is found.
74+binarySearch :: Fingerprint -> Unboxed.Vector Word64 -> Unboxed.Vector Word64 -> Maybe Int
75+binarySearch (Fingerprint a b) fpAs fpBs =
76+ let
77+ !(I# len) = Unboxed.length fpAs
78+ checkfpBs :: Int# -> Maybe Int
79+ checkfpBs i =
80+ case i <# len of
81+ 0# -> Nothing
82+ _ ->
83+ if a /= Unboxed.unsafeIndex fpAs (I# i)
84+ then Nothing
85+ else if b == Unboxed.unsafeIndex fpBs (I# i)
86+ then Just (I# i)
87+ else checkfpBs (i +# 1#)
88+ in
89+ inline (checkfpBs (binSearchHelp (-1#) len))
90+ where
91+ binSearchHelp :: Int# -> Int# -> Int#
92+ binSearchHelp l r = case l <# (r -# 1#) of
93+ 0# -> r
94+ _ ->
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
99+
100+----------------------------------------------------------------------------
101+-- Functions for testing and benchmarking
102+----------------------------------------------------------------------------
103+
104+data TF f where
105+ TF :: Typeable a => f a -> TF f
106+
107+fromF :: Typeable a => f a -> Proxy a
108+fromF _ = Proxy
109+
110+fromList :: forall f . [TF f] -> TypeRepMap f
111+fromList tfs = TypeRepMap (Unboxed.fromList fpAs) (Unboxed.fromList fpBs) (V.fromList ans)
112+ where
113+ (fpAs, fpBs) = unzip $ fmap (\(Fingerprint a b) -> (a, b)) fps
114+ (fps, ans) = unzip $ sortWith fst $ map (fp &&& an) tfs
115+
116+ fp :: TF f -> Fingerprint
117+ fp (TF x) = typeRepFingerprint $ typeRep $ fromF x
48118
49−keys :: TypeRepMap f -> [TypeRep]
50−keys = LMap.keys . unMap
119+ an :: TF f -> Any
120+ an (TF x) = unsafeCoerce x
src/Data/TypeRep/OptimalVector.hsdeleted−114
@@ -1,114 +0,0 @@
1−{-# OPTIONS_GHC -fno-warn-orphans #-}
2−
3−{-# LANGUAGE BangPatterns #-}
4−{-# LANGUAGE ExplicitForAll #-}
5−{-# LANGUAGE GADTs #-}
6−{-# LANGUAGE KindSignatures #-}
7−{-# LANGUAGE MagicHash #-}
8−{-# LANGUAGE MultiParamTypeClasses #-}
9−{-# LANGUAGE PolyKinds #-}
10−{-# LANGUAGE ScopedTypeVariables #-}
11−{-# LANGUAGE TypeFamilies #-}
12−
13−
14−module Data.TypeRep.OptimalVector
15− ( TypeRepVector (..)
16− , TF (..)
17− , empty
18− , insert
19− , lookup
20− , size
21− , fromList
22− ) where
23−
24−import Prelude hiding (lookup)
25−
26−import Control.Arrow ((&&&))
27−import Data.Proxy (Proxy (..))
28−import Data.Typeable (Typeable, typeRep, typeRepFingerprint)
29−import Data.Word (Word64)
30−import GHC.Base hiding (empty)
31−import GHC.Exts (sortWith)
32−import GHC.Fingerprint (Fingerprint (..))
33−import Unsafe.Coerce (unsafeCoerce)
34−import Debug.Trace
35−
36−import qualified Data.Vector as V
37−import qualified Data.Vector.Unboxed as Unboxed
38−
39−data TypeRepVector f = TypeRepVect
40− { fingerprintAs :: Unboxed.Vector Word64
41− , fingerprintBs :: Unboxed.Vector Word64
42− , anys :: V.Vector Any
43− }
44−
45−fromAny :: Any -> f a
46−fromAny = unsafeCoerce
47−
48−-- | Empty structure.
49−empty :: TypeRepVector f
50−empty = TypeRepVect mempty mempty mempty
51−
52−-- | Inserts the value with its type as a key.
53−insert :: forall a f . Typeable a => a -> TypeRepVector f -> TypeRepVector f
54−insert = undefined
55−
56−-- | Looks up the value at the type.
57−-- >>> let x = lookup $ insert (11 :: Int) empty
58−-- >>> x :: Maybe Int
59−-- Just 11
60−-- >>> x :: Maybe ()
61−-- Nothing
62−lookup :: forall a f . Typeable a => TypeRepVector f -> Maybe (f a)
63−lookup tVect = fromAny . (anys tVect V.!)
64− <$> binarySearch (typeRepFingerprint (typeRep (Proxy :: Proxy a))) (fingerprintAs tVect) (fingerprintBs tVect)
65−
66−-- | Returns the size of the 'TypeRepVect'.
67−size :: TypeRepVector f -> Int
68−size = Unboxed.length . fingerprintAs
69−
70−data TF f where
71− TF :: Typeable a => f a -> TF f
72−
73−fromF :: Typeable a => f a -> Proxy a
74−fromF _ = Proxy
75−
76−fromList :: forall f . [TF f] -> TypeRepVector f
77−fromList tfs = TypeRepVect (Unboxed.fromList fpAs) (Unboxed.fromList fpBs) (V.fromList ans)
78− where
79− (fpAs, fpBs) = unzip $ fmap (\(Fingerprint a b) -> (a, b)) fps
80− (fps, ans) = unzip $ sortWith fst $ map (fp &&& an) tfs
81−
82− fp :: TF f -> Fingerprint
83− fp (TF x) = typeRepFingerprint $ typeRep $ fromF x
84−
85− an :: TF f -> Any
86− an (TF x) = unsafeCoerce x
87−
88−-- | Returns the index is found.
89−binarySearch :: Fingerprint -> Unboxed.Vector Word64 -> Unboxed.Vector Word64 -> Maybe Int
90−binarySearch (Fingerprint a b) fpAs fpBs =
91− let
92− !(I# len) = Unboxed.length fpAs
93− checkfpBs :: Int# -> Maybe Int
94− checkfpBs i =
95− case i <# len of
96− 0# -> Nothing
97− _ ->
98− if a /= Unboxed.unsafeIndex fpAs (I# i)
99− then Nothing
100− else if b == Unboxed.unsafeIndex fpBs (I# i)
101− then Just (I# i)
102− else checkfpBs (i +# 1#)
103− in
104− inline (checkfpBs (binSearchHelp (-1#) len))
105− where
106− binSearchHelp :: Int# -> Int# -> Int#
107− binSearchHelp l r = case l <# (r -# 1#) of
108− 0# -> r
109− _ ->
110− let m = uncheckedIShiftRA# (l +# r) 1# in
111− if Unboxed.unsafeIndex fpAs (I# m) < a
112− then binSearchHelp m r
113− else binSearchHelp l m
114−
test/Test/TypeRep/Map.hs+1−1
@@ -6,7 +6,7 @@ import Data.Functor.Identity (Identity (..))
66
77import Test.Tasty.Hspec
88
9−import Data.TypeRep.Map
9+import Data.TypeRep.CMap
1010
1111-- Simple test for 'lookup', 'insert' and 'size' functions.
1212spec_insertLookup :: Spec
test/Test/TypeRep/VectorOpt.hs+1−1
@@ -6,7 +6,7 @@ import Data.Functor.Identity (Identity (..))
66
77import Test.Tasty.Hspec
88
9−import Data.TypeRep.OptimalVector
9+import Data.TypeRep.Map (TF (..), fromList, lookup)
1010
1111-- Simple test for 'lookup', 'insert' and 'size' functions.
1212insertLookup :: Spec
typerep-map.cabal+6−5
@@ -18,9 +18,10 @@ tested-with: GHC == 8.0.2
1818
1919library
2020 hs-source-dirs: src
21− exposed-modules: Data.TypeRep.Map
22− , Data.TypeRep.Vector
23− , Data.TypeRep.OptimalVector
21+ exposed-modules: Data.TypeRep.CMap
22+ Data.TypeRep.Map
23+ Data.TypeRep.Vector
24+
2425 ghc-options: -Wall
2526 build-depends: base
2627 , containers
@@ -41,13 +42,13 @@ test-suite typerep-map-test
4142 , tasty-discover >= 4.1.1
4243 , tasty-hspec
4344 build-tool-depends: tasty-discover:tasty-discover
44− ghc-options: -Wall -Werror -threaded -rtsopts -with-rtsopts=-N
45+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
4546 default-language: Haskell2010
4647
4748benchmark typerep-map-benchmark
4849 type: exitcode-stdio-1.0
4950 default-language: Haskell2010
50− ghc-options: -Wall -Werror -O2 -threaded -rtsopts -with-rtsopts=-N -freduction-depth=0
51+ ghc-options: -Wall -O2 -threaded -rtsopts -with-rtsopts=-N -freduction-depth=0
5152 hs-source-dirs: benchmark
5253 main-is: Main.hs
5354 other-modules: Map