on 1b739d8 help sign in
8 files changed+22−173
since splitsnapshots
unifiedsplit
.github/workflows/ci.yml+4−3 CHANGELOG.md+1−1 README.md+1−1 src/Data/TMap.hs+1−33 src/Data/TypeRepMap.hs+1−5 src/Data/TypeRepMap/Internal.hs+8−59 test/Test/TypeRep/TypeRepMap.hs+4−62 test/Test/TypeRep/TypeRepMapProperty.hs+2−9
.github/workflows/ci.yml+4−3
@@ -1,10 +1,11 @@
11name: CI
22
3−# Trigger the workflow on push or pull request, but only for the main branch
43on:
4+ # Trigger the workflow on push or pull request,
5+ # but only for the master branch
56 push:
67 branches:
7− - main
8+ - master
89 pull_request:
910
1011jobs:
@@ -23,7 +24,7 @@ jobs:
2324
2425 steps:
2526 - uses: actions/checkout@v2
26− if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/main'
27+ if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/master'
2728
2829 - uses: actions/setup-haskell@v1
2930 name: Setup Haskell
CHANGELOG.md+1−1
@@ -53,4 +53,4 @@ The changelog is available [on GitHub][2].
5353* Initially created.
5454
5555[1]: https://pvp.haskell.org
56−[2]: https://github.com/kowainik/typerep-map/releases
56+[2]: https://github.com/kowainik/typerep-map/blob/master/CHANGELOG.md
README.md+1−1
@@ -4,7 +4,7 @@
44
55[![GitHub CI](https://github.com/kowainik/typerep-map/workflows/CI/badge.svg)](https://github.com/kowainik/typerep-map/actions)
66[![Build status](https://img.shields.io/travis/kowainik/typerep-map.svg?logo=travis)](https://travis-ci.org/kowainik/typerep-map)
7−[![Windows build status](https://ci.appveyor.com/api/projects/status/github/kowainik/typerep-map?branch=main&svg=true)](https://ci.appveyor.com/project/kowainik/typerep-map)
7+[![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)
88[![Hackage](https://img.shields.io/hackage/v/typerep-map.svg?logo=haskell)](https://hackage.haskell.org/package/typerep-map)
99[![Stackage LTS](http://stackage.org/package/typerep-map/badge/lts)](http://stackage.org/lts/package/typerep-map)
1010[![Stackage Nightly](http://stackage.org/package/typerep-map/badge/nightly)](http://stackage.org/nightly/package/typerep-map)
src/Data/TMap.hs+1−33
@@ -37,8 +37,6 @@ module Data.TMap
3737 , delete
3838 , unionWith
3939 , union
40− , intersectionWith
41− , intersection
4240 , map
4341 , adjust
4442 , alter
@@ -48,8 +46,6 @@ module Data.TMap
4846 , member
4947 , size
5048 , keys
51− , keysWith
52− , toListWith
5349 ) where
5450
5551import Prelude hiding (lookup, map)
@@ -57,7 +53,7 @@ import Prelude hiding (lookup, map)
5753import Data.Functor.Identity (Identity (..))
5854import Data.Typeable (Typeable)
5955import GHC.Exts (coerce)
60−import Type.Reflection (SomeTypeRep, TypeRep)
56+import Type.Reflection (SomeTypeRep)
6157
6258import qualified Data.TypeRepMap as F
6359
@@ -136,24 +132,6 @@ union :: TMap -> TMap -> TMap
136132union = F.union
137133{-# INLINE union #-}
138134
139−-- | The intersection of two 'TMap's using a combining function.
140−--
141−-- @O(n + m)@
142−intersectionWith :: (forall x. Typeable x => x -> x -> x) -> TMap -> TMap -> TMap
143−intersectionWith f = F.intersectionWith fId
144− where
145− fId :: forall y . Typeable y => Identity y -> Identity y -> Identity y
146− fId y1 y2 = f (coerce y1) (coerce y2)
147−{-# INLINE intersectionWith #-}
148−
149−-- | The intersection of two 'TMap's.
150−-- It keeps all values from the first map whose keys are present in the second.
151−--
152−-- @O(n + m)@
153−intersection :: TMap -> TMap -> TMap
154−intersection = F.intersection
155−{-# INLINE intersection #-}
156−
157135{- | Lookup a value of the given type in a 'TMap'.
158136
159137>>> x = lookup $ insert (11 :: Int) empty
@@ -187,16 +165,6 @@ keys :: TMap -> [SomeTypeRep]
187165keys = F.keys
188166{-# INLINE keys #-}
189167
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−
200168-- | Map a function over the values.
201169map :: (forall a. Typeable a => a -> a) -> TMap -> TMap
202170map f = F.hoistWithKey (liftToIdentity f)
src/Data/TypeRepMap.hs+1−5
@@ -5,7 +5,7 @@ Copyright: (c) 2017-2020 Kowainik
55SPDX-License-Identifier: MPL-2.0
66Maintainer: Kowainik <xrom.xkov@gmail.com>
77
8−A version of 'Data.TMap.TMap' parametrized by an interpretation @f@. This
8+ A version of 'Data.TMap.TMap' parametrized by an interpretation @f@. This
99sort of parametrization may be familiar to users of @vinyl@ records.
1010
1111@'TypeRepMap' f@ is a more efficient replacement for @DMap
@@ -63,16 +63,12 @@ module Data.TypeRepMap
6363 , hoistWithKey
6464 , unionWith
6565 , union
66− , intersectionWith
67− , intersection
6866
6967 -- * Query
7068 , lookup
7169 , member
7270 , size
7371 , keys
74− , keysWith
75− , toListWith
7672
7773 -- * 'IsList'
7874 , WrapTypeable (..)
src/Data/TypeRepMap/Internal.hs+8−59
@@ -205,8 +205,6 @@ insert x m
205205-- inferred type variables (which are not subject to type applications).
206206type KindOf (a :: k) = k
207207
208−type ArgKindOf (f :: k -> l) = k
209−
210208{- | Delete a value from a 'TypeRepMap'.
211209
212210TypeRepMap optimizes for fast reads rather than modifications, as a trade-off deletes are
@@ -352,48 +350,6 @@ union :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
352350union = unionWith const
353351{-# INLINE union #-}
354352
355−-- | The 'intersection' of two 'TypeRepMap's using a combining function
356−--
357−-- @O(n + m)@
358−intersectionWith :: forall f. (forall x. Typeable x => f x -> f x -> f x) -> TypeRepMap f -> TypeRepMap f -> TypeRepMap f
359−intersectionWith f ma mb =
360− fromSortedTriples $ mergeMaps (toSortedTriples ma) (toSortedTriples mb)
361− where
362− f' :: forall x. TypeRep x -> f x -> f x -> f x
363− f' tr = withTypeable tr f
364−
365− combine :: (Fingerprint, Any, Any) -> (Fingerprint, Any, Any) -> (Fingerprint, Any, Any)
366− combine (fp, av, ak) (_, bv, _) = (fp, toAny $ f' (fromAny ak) (fromAny av) (fromAny bv), ak)
367−
368− -- Merges two typrepmaps into a sorted, dedup'd list of triples.
369− mergeMaps :: [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)]
370− -- If either list is empty, the intersection must be finished.
371− mergeMaps _ [] = []
372− mergeMaps [] _ = []
373− -- Merge the two maps considering one element at a time.
374− mergeMaps (a@(af, _, _) : as) (b@(bf, _, _) : bs) =
375− case compare af bf of
376− -- Fingerprints are equal, union the elements using our function
377− -- If the incoming maps were de-duped, there shouldn't be any other equivalent
378− -- fingerprints
379− EQ -> combine a b : mergeMaps as bs
380− -- First fingerprint must not be in the second map or we would have seen it by now
381− -- Skip it an move on
382− LT -> mergeMaps as (b : bs)
383− -- Second fingerprint must not be in the first map or we would have seen it by now
384− -- Skip it an move on
385− GT -> mergeMaps (a:as) bs
386−{-# INLINE intersectionWith #-}
387−
388−-- | The intersection of two 'TypeRepMap's.
389−-- It keeps all values from the first map whose keys are present in the second.
390−--
391−-- @O(n + m)@
392−intersection :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
393−intersection = intersectionWith const
394−{-# INLINE intersection #-}
395−
396−
397353{- | Check if a value of the given type is present in a 'TypeRepMap'.
398354
399355>>> member @Char $ one (Identity 'a')
@@ -429,22 +385,9 @@ size = sizeofPrimArray . fingerprintAs
429385
430386-- | Return the list of 'SomeTypeRep' from the keys.
431387keys :: TypeRepMap f -> [SomeTypeRep]
432−keys = keysWith SomeTypeRep
388+keys TypeRepMap{..} = SomeTypeRep . anyToTypeRep <$> toList trKeys
433389{-# INLINE keys #-}
434390
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−
448391-- | Binary searched based on this article
449392-- http://bannalia.blogspot.com/2015/06/cache-friendly-binary-search.html
450393-- with modification for our two-vector search case.
@@ -521,6 +464,9 @@ data WrapTypeable f where
521464instance Show (WrapTypeable f) where
522465 show (WrapTypeable (_ :: f a)) = show $ calcFp @a
523466
467+wrapTypeable :: TypeRep a -> f a -> WrapTypeable f
468+wrapTypeable tr = withTypeable tr WrapTypeable
469+
524470{- |
525471
526472prop> fromList . toList == 'id'
@@ -548,7 +494,10 @@ instance IsList (TypeRepMap f) where
548494 k (WrapTypeable (_ :: f a)) = unsafeCoerce $ typeRep @a
549495
550496 toList :: TypeRepMap f -> [WrapTypeable f]
551− toList = toListWith WrapTypeable
497+ toList = map toWrapTypeable . toTriples
498+ where
499+ toWrapTypeable :: (Fingerprint, Any, Any) -> WrapTypeable f
500+ toWrapTypeable (_, an, k) = wrapTypeable (unsafeCoerce k) (fromAny an)
552501
553502calcFp :: forall a . Typeable a => Fingerprint
554503calcFp = typeRepFingerprint $ typeRep @a
test/Test/TypeRep/TypeRepMap.hs+4−62
@@ -5,18 +5,14 @@ module Test.TypeRep.TypeRepMap
55import Prelude hiding (lookup)
66
77import Data.Functor.Identity (Identity (..))
8−import Data.List (sortBy)
9−import Data.Ord (comparing)
10−import Data.Typeable (cast)
11−import GHC.Exts (fromList, toList)
12−import Type.Reflection (SomeTypeRep(..), typeRep)
13−import Test.Hspec (Spec, describe, it, shouldBe, shouldMatchList, shouldSatisfy, expectationFailure)
8+import GHC.Exts (fromList)
9+import Test.Hspec (Spec, describe, it, shouldBe)
1410
15−import Data.TMap (TMap, empty, insert, lookup, one, size, union, keys)
11+import Data.TMap (TMap, empty, insert, lookup, one, size, union)
1612import Data.TypeRepMap.Internal (WrapTypeable (..))
1713
1814
19−-- Simple test for 'lookup', 'insert', 'size', 'keys', 'toList' functions.
15+-- Simple test for 'lookup', 'insert' and 'size' functions.
2016typeRepMapSpec :: Spec
2117typeRepMapSpec = describe "TypeRepMap" $ do
2218 describe "Lookup Test" $ do
@@ -43,60 +39,6 @@ typeRepMapSpec = describe "TypeRepMap" $ do
4339 lookup m `shouldBe` Just True
4440 lookup @Int m `shouldBe` Nothing
4541
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
10042
10143mapOf10 :: TMap
10244mapOf10 = insert True
test/Test/TypeRep/TypeRepMapProperty.hs+2−9
@@ -20,8 +20,8 @@ import Test.Hspec (Arg, Expectation, Spec, SpecWith, describe, it)
2020import Test.Hspec.Hedgehog (hedgehog)
2121
2222import Data.TypeRepMap.Internal (TypeRepMap (..), WrapTypeable (..), delete, insert, invariantCheck,
23− lookup, member, union, generateOrderMapping, fromSortedList,
24− adjust, alter, intersection)
23+ lookup, member, generateOrderMapping, fromSortedList, alter,
24+ adjust)
2525
2626import qualified Hedgehog.Gen as Gen
2727import qualified Hedgehog.Range as Range
@@ -39,7 +39,6 @@ typeRepMapPropertySpec = describe "TypeRepMap Property tests" $ do
3939 alterDeleteSpec
4040 alterAdjustSpec
4141 alterModifySpec
42− intersectionSpec
4342 describe "Internal helpers" $ do
4443 generateOrderMappingInvariantSpec
4544 describe "Instance Laws" $ do
@@ -119,12 +118,6 @@ alterModifySpec = it "lookup k (alter f) == f (lookup k m)" $ hedgehog $ do
119118 | otherwise = Just $ IntProxy p (n * 10)
120119 lookup @n @IntProxy (alter @n f m) === f (lookup @n @IntProxy m)
121120
122−intersectionSpec :: Property
123−intersectionSpec = it "m `intersection` (m `union` n) == m" $ hedgehog $ do
124− m <- forAll genMap
125− n <- forAll genMap
126− m `intersection` (m `union` n) === m
127−
128121----------------------------------------------------------------------------
129122-- Internal helpers
130123----------------------------------------------------------------------------