@@ -1,69 +1,47 @@
1−{-# OPTIONS_GHC -Wno-missing-export-lists #-}
3−{-# LANGUAGE AllowAmbiguousTypes #-}
1+{-# LANGUAGE AllowAmbiguousTypes #-}
4−{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE BangPatterns #-}
6−{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE DataKinds #-}
7−{-# LANGUAGE GADTs #-}
4+{-# LANGUAGE GADTs #-}
8−{-# LANGUAGE InstanceSigs #-}
5+{-# LANGUAGE InstanceSigs #-}
6+{-# LANGUAGE KindSignatures #-}
9−{-# LANGUAGE MagicHash #-}
7+{-# LANGUAGE MagicHash #-}
10−{-# LANGUAGE PolyKinds #-}
8+{-# LANGUAGE PolyKinds #-}
11−{-# LANGUAGE Rank2Types #-}
9+{-# LANGUAGE Rank2Types #-}
12−{-# LANGUAGE TypeFamilies #-}
10+{-# LANGUAGE TypeFamilies #-}
13−{-# LANGUAGE TypeInType #-}
11+{-# LANGUAGE TypeInType #-}
14−{-# LANGUAGE ViewPatterns #-}
16−#if __GLASGOW_HASKELL__ >= 806
17−{-# LANGUAGE QuantifiedConstraints #-}
20-- {-# OPTIONS_GHC -ddump-simpl -dsuppress-idinfo -dsuppress-coercions -dsuppress-type-applications -dsuppress-uniques -dsuppress-module-prefixes #-}
13-- {-# OPTIONS_GHC -ddump-simpl -dsuppress-idinfo -dsuppress-coercions -dsuppress-type-applications -dsuppress-uniques -dsuppress-module-prefixes #-}
23−Copyright: (c) 2017-2020 Kowainik
24−SPDX-License-Identifier: MPL-2.0
25−Maintainer: Kowainik <xrom.xkov@gmail.com>
27−Internal API for 'TypeRepMap' and operations on it. The functions here do
15+-- | Internal API for 'TypeRepMap' and operations on it. The functions here do
28−not have any stability guarantees and can change between minor versions.
16+-- not have any stability guarantees and can change between minor versions.
30−If you need to use this module for purposes other than tests,
18+-- If you need to use this module for purposes other than tests,
31−create an issue.
19+-- create an issue.
36module Data.TypeRepMap.Internal where
21module Data.TypeRepMap.Internal where
38import Prelude hiding (lookup)
23import Prelude hiding (lookup)
40−import Control.DeepSeq
25+import Control.Arrow ((&&&))
41−import Control.Monad.ST (ST, runST)
42−import Control.Monad.Zip (mzip)
43import Data.Function (on)
26import Data.Function (on)
27+import Data.IntMap.Strict (IntMap)
44import Data.Kind (Type)
28import Data.Kind (Type)
45−import Data.Type.Equality ((:~:) (..), TestEquality (..))
29+import Data.List (nubBy)
46−import Data.List (intercalate, nubBy)
47−import Data.Maybe (fromMaybe)
30+import Data.Maybe (fromJust)
48−import Data.Primitive.Array (Array, MutableArray, indexArray, mapArray', sizeofArray,
31+import Data.Primitive.Array (Array, indexArray, mapArray')
49− thawArray, unsafeFreezeArray, writeArray)
50−import Data.Primitive.PrimArray (writePrimArray, newPrimArray, unsafeFreezePrimArray, primArrayToList, MutablePrimArray, primArrayFromListN, PrimArray, indexPrimArray, sizeofPrimArray)
32+import Data.Primitive.PrimArray (PrimArray, indexPrimArray, sizeofPrimArray)
51−import Data.Semigroup (Semigroup (..), All(..))
33+import Data.Proxy (Proxy (..))
34+import Data.Semigroup (Semigroup (..))
35+import Data.Typeable (Typeable, typeRep, typeRepFingerprint)
52import GHC.Base (Any, Int (..), Int#, (*#), (+#), (<#))
36import GHC.Base (Any, Int (..), Int#, (*#), (+#), (<#))
53−import GHC.Exts (IsList (..), inline, sortWith)
37+import GHC.Exts (inline, sortWith)
54import GHC.Fingerprint (Fingerprint (..))
38import GHC.Fingerprint (Fingerprint (..))
55−#if WORD_SIZE_IN_BITS >= 64
56import GHC.Prim (eqWord#, ltWord#)
39import GHC.Prim (eqWord#, ltWord#)
58−import GHC.IntWord64 (eqWord64#, ltWord64#)
59−#define eqWord eqWord64
60−#define ltWord ltWord64
62import GHC.Word (Word64 (..))
40import GHC.Word (Word64 (..))
63−import Type.Reflection (SomeTypeRep (..), TypeRep, Typeable, typeRep, withTypeable)
64−import Type.Reflection.Unsafe (typeRepFingerprint)
65import Unsafe.Coerce (unsafeCoerce)
41import Unsafe.Coerce (unsafeCoerce)
43+import qualified Data.IntMap.Strict as IM
44+import qualified Data.Map.Strict as Map
67import qualified GHC.Exts as GHC (fromList, toList)
45import qualified GHC.Exts as GHC (fromList, toList)
@@ -91,20 +69,13 @@ data TypeRepMap (f :: k -> Type) =
91 TypeRepMap
69 TypeRepMap
92 { fingerprintAs :: {-# UNPACK #-} !(PrimArray Word64) -- ^ first components of key fingerprints
70 { fingerprintAs :: {-# UNPACK #-} !(PrimArray Word64) -- ^ first components of key fingerprints
93 , fingerprintBs :: {-# UNPACK #-} !(PrimArray Word64) -- ^ second components of key fingerprints
71 , fingerprintBs :: {-# UNPACK #-} !(PrimArray Word64) -- ^ second components of key fingerprints
94− , trAnys :: {-# UNPACK #-} !(Array Any) -- ^ values stored in the map
72+ , anys :: {-# UNPACK #-} !(Array Any) -- ^ values stored in the map
95− , trKeys :: {-# UNPACK #-} !(Array Any) -- ^ typerep keys
97 -- ^ an unsafe constructor for 'TypeRepMap'
74 -- ^ an unsafe constructor for 'TypeRepMap'
99−instance NFData (TypeRepMap f) where
100− rnf x = rnf (keys x) `seq` ()
102−-- | Shows only keys.
76+-- | Shows only 'Fingerprint's.
103instance Show (TypeRepMap f) where
77instance Show (TypeRepMap f) where
104− show TypeRepMap{..} = "TypeRepMap [" ++ showKeys ++ "]"
78+ show = show . toFingerprints
107− showKeys = intercalate ", " $ toList $ mapArray' (show . anyToTypeRep) trKeys
109-- | Uses 'union' to combine 'TypeRepMap's.
80-- | Uses 'union' to combine 'TypeRepMap's.
110instance Semigroup (TypeRepMap f) where
81instance Semigroup (TypeRepMap f) where
@@ -113,36 +84,11 @@ instance Semigroup (TypeRepMap f) where
113 {-# INLINE (<>) #-}
84 {-# INLINE (<>) #-}
115instance Monoid (TypeRepMap f) where
86instance Monoid (TypeRepMap f) where
116− mempty = TypeRepMap mempty mempty mempty mempty
87+ mempty = TypeRepMap mempty mempty mempty
117 mappend = (<>)
88 mappend = (<>)
118 {-# INLINE mempty #-}
89 {-# INLINE mempty #-}
119 {-# INLINE mappend #-}
90 {-# INLINE mappend #-}
121−#if __GLASGOW_HASKELL__ >= 806
122−instance (forall a. Typeable a => Eq (f a)) => Eq (TypeRepMap f) where
123− tm1 == tm2 = size tm1 == size tm2 && go 0
127− | i == size tm1 = True
128− | otherwise = case testEquality tr1i tr2i of
130− Just Refl -> repEq tr1i (fromAny tv1i) (fromAny tv2i) && go (i + 1)
133− tr1i = anyToTypeRep $ indexArray (trKeys tm1) i
136− tr2i = anyToTypeRep $ indexArray (trKeys tm2) i
139− tv1i = indexArray (trAnys tm1) i
140− tv2i = indexArray (trAnys tm2) i
142− repEq :: TypeRep x -> f x -> f x -> Bool
143− repEq tr = withTypeable tr (==)
146-- | Returns the list of 'Fingerprint's from 'TypeRepMap'.
92-- | Returns the list of 'Fingerprint's from 'TypeRepMap'.
147toFingerprints :: TypeRepMap f -> [Fingerprint]
93toFingerprints :: TypeRepMap f -> [Fingerprint]
148toFingerprints TypeRepMap{..} =
94toFingerprints TypeRepMap{..} =
@@ -169,49 +115,33 @@ prop> member @a (one (x :: f a)) == True
171one :: forall a f . Typeable a => f a -> TypeRepMap f
117one :: forall a f . Typeable a => f a -> TypeRepMap f
172−one x = TypeRepMap (primArrayFromListN 1 [fa])
118+one x = insert x empty
173− (primArrayFromListN 1 [fb])
177− (Fingerprint fa fb, v, k) = (calcFp @a, toAny x, unsafeCoerce $ typeRep @a)
178{-# INLINE one #-}
119{-# INLINE one #-}
182Insert a value into a 'TypeRepMap'.
123Insert a value into a 'TypeRepMap'.
183−TypeRepMap optimizes for fast reads rather than inserts, as a trade-off inserts are @O(n)@.
185prop> size (insert v tm) >= size tm
125prop> size (insert v tm) >= size tm
186prop> member @a (insert (x :: f a) tm) == True
126prop> member @a (insert (x :: f a) tm) == True
189insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
129insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
190−insert x m
130+insert x = fromListPairs . addX . toPairList
191− | size m == 0 = one x
192− | otherwise = case cachedBinarySearch (typeFp @a) (fingerprintAs m) (fingerprintBs m) of
193− Nothing -> union m $ one x
194− Just i -> m {trAnys = changeAnyArr i (trAnys m)}
196− changeAnyArr :: Int -> Array Any -> Array Any
132+ pairX :: (Fingerprint, Any)
197− changeAnyArr i trAs = runST $ do
133+ pairX@(fpX, _) = (calcFp x, toAny x)
198− let n = sizeofArray trAs
134+
199− mutArr <- thawArray trAs 0 n
135+ addX :: [(Fingerprint, Any)] -> [(Fingerprint, Any)]
200− writeArray mutArr i $ toAny x
136+ addX l = pairX : deleteByFst fpX l
201− unsafeFreezeArray mutArr
202{-# INLINE insert #-}
137{-# INLINE insert #-}
204-- Extract the kind of a type. We use it to work around lack of syntax for
139-- Extract the kind of a type. We use it to work around lack of syntax for
205-- inferred type variables (which are not subject to type applications).
140-- inferred type variables (which are not subject to type applications).
206type KindOf (a :: k) = k
141type KindOf (a :: k) = k
208−type ArgKindOf (f :: k -> l) = k
210{- | Delete a value from a 'TypeRepMap'.
143{- | Delete a value from a 'TypeRepMap'.
212−TypeRepMap optimizes for fast reads rather than modifications, as a trade-off deletes are
213−@O(n)@, with an @O(log(n))@ optimization for when the element is already missing.
215prop> size (delete @a tm) <= size tm
145prop> size (delete @a tm) <= size tm
216prop> member @a (delete @a tm) == False
146prop> member @a (delete @a tm) == False
@@ -224,61 +154,9 @@ False
226delete :: forall a (f :: KindOf a -> Type) . Typeable a => TypeRepMap f -> TypeRepMap f
156delete :: forall a (f :: KindOf a -> Type) . Typeable a => TypeRepMap f -> TypeRepMap f
227−delete m
157+delete = fromListPairs . deleteByFst (typeFp @a) . toPairList
228− -- Lookups are fast, so check if we even have the element first.
229− | not (member @a m) = m
230− -- We know we have the element, If the map has exactly one element, we can return the empty map
231− | size m == 1 = empty
232− -- Otherwise, filter out the element in linear time.
233− | otherwise = fromSortedTriples . deleteFirst ((== typeFp @a) . fst3) . toSortedTriples $ m
234{-# INLINE delete #-}
158{-# INLINE delete #-}
236−deleteFirst :: (a -> Bool) -> [a] -> [a]
237−deleteFirst _ [] = []
238−deleteFirst p (x : xs) = if p x then xs else x : deleteFirst p xs
241−Update a value at a specific key with the result of the provided function.
242−When the key is not a member of the map, the original map is returned.
244−>>> trmap = fromList @(TypeRepMap Identity) [WrapTypeable $ Identity "a"]
245−>>> lookup @String $ adjust (fmap (++ "ww")) trmap
246−Just (Identity "aww")
248−adjust :: forall a f . Typeable a => (f a -> f a) -> TypeRepMap f -> TypeRepMap f
249−adjust fun = alter (fmap fun)
250−{-# INLINE adjust #-}
253−Updates a value at a specific key, whether or not it exists.
254−This can be used to insert, delete, or update a value of a given type in the map.
256−>>> func = (\case Nothing -> Just (Identity "new"); Just (Identity s) -> Just (Identity (reverse s)))
257−>>> lookup @String $ alter func empty
258−Just (Identity "new")
259−>>> trmap = fromList @(TypeRepMap Identity) [WrapTypeable $ Identity "helllo"]
260−>>> lookup @String $ alter func trmap
261−>>> Just (Identity "olleh")
263−alter :: forall a f . Typeable a => (Maybe (f a) -> Maybe (f a)) -> TypeRepMap f -> TypeRepMap f
264−alter fun tr = case cachedBinarySearch (typeFp @a) (fingerprintAs tr) (fingerprintBs tr) of
266− case (fun Nothing) of
268− Just v -> insert v tr
270− case fun (Just . fromAny $ indexArray (trAnys tr) i) of
271− Nothing -> delete @a tr
272− Just v -> tr{trAnys = replaceAnyAt i (toAny v) (trAnys tr)}
274− replaceAnyAt :: Int -> Any -> Array Any -> Array Any
275− replaceAnyAt i v trAs = runST $ do
276− let n = sizeofArray trAs
277− mutArr <- thawArray trAs 0 n
278− writeArray mutArr i v
279− unsafeFreezeArray mutArr
282{- | Map over the elements of a 'TypeRepMap'.
160{- | Map over the elements of a 'TypeRepMap'.
284>>> tm = insert (Identity True) $ one (Identity 'a')
162>>> tm = insert (Identity True) $ one (Identity 'a')
@@ -293,107 +171,27 @@ Just [True]
295hoist :: (forall x. f x -> g x) -> TypeRepMap f -> TypeRepMap g
173hoist :: (forall x. f x -> g x) -> TypeRepMap f -> TypeRepMap g
296−hoist f (TypeRepMap as bs ans ks) = TypeRepMap as bs (mapArray' (toAny . f . fromAny) ans) ks
174+hoist f (TypeRepMap as bs ans) = TypeRepMap as bs $ mapArray' (toAny . f . fromAny) ans
297{-# INLINE hoist #-}
175{-# INLINE hoist #-}
299−hoistA :: (Applicative t) => (forall x. f x -> t (g x)) -> TypeRepMap f -> t (TypeRepMap g)
300−hoistA f (TypeRepMap as bs (toList -> ans) ks) = (\l -> TypeRepMap as bs (fromList $ map toAny l) ks)
301− <$> traverse (f . fromAny) ans
302−{-# INLINE hoistA #-}
304−hoistWithKey :: forall f g. (forall x. Typeable x => f x -> g x) -> TypeRepMap f -> TypeRepMap g
305−hoistWithKey f (TypeRepMap as bs ans ks) = TypeRepMap as bs newAns ks
307− newAns = mapArray' mapAns (mzip ans ks)
308− mapAns (a, k) = toAny $ withTr (unsafeCoerce k) $ fromAny a
310− withTr :: forall x. TypeRep x -> f x -> g x
311− withTr t = withTypeable t f
312−{-# INLINE hoistWithKey #-}
314−-- | The union of two 'TypeRepMap's using a combining function for conflicting entries. @O(n + m)@
177+-- | The union of two 'TypeRepMap's using a combining function.
315−unionWith :: forall f. (forall x. Typeable x => f x -> f x -> f x) -> TypeRepMap f -> TypeRepMap f -> TypeRepMap f
178+unionWith :: (forall x. f x -> f x -> f x) -> TypeRepMap f -> TypeRepMap f -> TypeRepMap f
316−unionWith f ma mb = do
179+unionWith f m1 m2 = fromListPairs
317− fromSortedTriples $ mergeMaps (toSortedTriples ma) (toSortedTriples mb)
180+ $ Map.toList
181+ $ Map.unionWith combine
182+ (Map.fromList $ toPairList m1)
183+ (Map.fromList $ toPairList m2)
319− f' :: forall x. TypeRep x -> f x -> f x -> f x
320− f' tr = withTypeable tr f
322− combine :: (Fingerprint, Any, Any) -> (Fingerprint, Any, Any) -> (Fingerprint, Any, Any)
185+ combine :: Any -> Any -> Any
323− combine (fp, av, ak) (_, bv, _) = (fp, toAny $ f' (fromAny ak) (fromAny av) (fromAny bv), ak)
186+ combine a b = toAny $ f (fromAny a) (fromAny b)
325− -- Merges two typrepmaps into a sorted, dedup'd list of triples.
326− -- Using 'toSortedTriples' allows us to assume the triples are sorted by fingerprint,
327− -- Given O(n) performance from 'toSortedTriples', and given that we can merge-sort in
328− -- O(n + m) time, then can '.fromSortedTriples' back into cachedBinarySearch order in O(n + m)
329− -- that gives a total of O(n + m).
330− mergeMaps :: [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)]
331− -- We've addressed all elements from both maps
332− mergeMaps as [] = as
333− mergeMaps [] bs = bs
335− mergeMaps (a@(af, _, _) : as) (b@(bf, _, _) : bs) =
336− case compare af bf of
337− -- Fingerprints are equal, union the elements using our function
338− -- If the incoming maps were de-duped, there shouldn't be any other equivalent
340− EQ -> combine a b : mergeMaps as bs
341− -- First fingerprint must not be in the second map or we would have seen it by now
342− -- Add it to the result as-is
343− LT -> a : mergeMaps as (b : bs)
344− -- Second fingerprint must not be in the first map or we would have seen it by now
345− -- Add it to the result as-is
346− GT -> b : mergeMaps (a:as) bs
347{-# INLINE unionWith #-}
187{-# INLINE unionWith #-}
349−-- | The (left-biased) union of two 'TypeRepMap's in @O(n + m)@. It prefers the first map when
189+-- | The (left-biased) union of two 'TypeRepMap's. It prefers the first map when
350-- duplicate keys are encountered, i.e. @'union' == 'unionWith' const@.
190-- duplicate keys are encountered, i.e. @'union' == 'unionWith' const@.
351union :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
191union :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
352union = unionWith const
192union = unionWith const
353{-# INLINE union #-}
193{-# INLINE union #-}
355−-- | The 'intersection' of two 'TypeRepMap's using a combining function
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)
362− f' :: forall x. TypeRep x -> f x -> f x -> f x
363− f' tr = withTypeable tr f
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)
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.
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
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 #-}
388−-- | The intersection of two 'TypeRepMap's.
389−-- It keeps all values from the first map whose keys are present in the second.
392−intersection :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
393−intersection = intersectionWith const
394−{-# INLINE intersection #-}
397{- | Check if a value of the given type is present in a 'TypeRepMap'.
195{- | Check if a value of the given type is present in a 'TypeRepMap'.
399>>> member @Char $ one (Identity 'a')
197>>> member @Char $ one (Identity 'a')
@@ -416,7 +214,7 @@ Just (Identity 11)
418lookup :: forall a f . Typeable a => TypeRepMap f -> Maybe (f a)
216lookup :: forall a f . Typeable a => TypeRepMap f -> Maybe (f a)
419−lookup tVect = fromAny . (trAnys tVect `indexArray`)
217+lookup tVect = fromAny . (anys tVect `indexArray`)
420 <$> cachedBinarySearch (typeFp @a)
218 <$> cachedBinarySearch (typeFp @a)
421 (fingerprintAs tVect)
219 (fingerprintAs tVect)
422 (fingerprintBs tVect)
220 (fingerprintBs tVect)
@@ -427,24 +225,6 @@ size :: TypeRepMap f -> Int
427size = sizeofPrimArray . fingerprintAs
225size = sizeofPrimArray . fingerprintAs
428{-# INLINE size #-}
226{-# INLINE size #-}
430−-- | Return the list of 'SomeTypeRep' from the keys.
431−keys :: TypeRepMap f -> [SomeTypeRep]
432−keys = keysWith SomeTypeRep
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 #-}
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
444− withTypeRep :: TypeRep a -> f a -> r
445− withTypeRep tr an = withTypeable tr $ f an
446− toF (_, an, k) = withTypeRep (unsafeCoerce k) (fromAny an)
448-- | Binary searched based on this article
228-- | Binary searched based on this article
449-- http://bannalia.blogspot.com/2015/06/cache-friendly-binary-search.html
229-- http://bannalia.blogspot.com/2015/06/cache-friendly-binary-search.html
450-- with modification for our two-vector search case.
230-- with modification for our two-vector search case.
@@ -478,193 +258,71 @@ toAny = unsafeCoerce
478fromAny :: Any -> f a
258fromAny :: Any -> f a
479fromAny = unsafeCoerce
259fromAny = unsafeCoerce
481−anyToTypeRep :: Any -> TypeRep f
482−anyToTypeRep = unsafeCoerce
484typeFp :: forall a . Typeable a => Fingerprint
261typeFp :: forall a . Typeable a => Fingerprint
485−typeFp = typeRepFingerprint $ typeRep @a
262+typeFp = typeRepFingerprint $ typeRep $ Proxy @a
486{-# INLINE typeFp #-}
263{-# INLINE typeFp #-}
488−toTriples :: TypeRepMap f -> [(Fingerprint, Any, Any)]
265+toPairList :: TypeRepMap f -> [(Fingerprint, Any)]
489−toTriples tm = zip3 (toFingerprints tm) (GHC.toList $ trAnys tm) (GHC.toList $ trKeys tm)
266+toPairList tm = zip (toFingerprints tm) (GHC.toList $ anys tm)
491−-- | Efficiently get sorted triples from a map in O(n) time
268+deleteByFst :: Eq a => a -> [(a, b)] -> [(a, b)]
492−--
269+deleteByFst x = filter ((/= x) . fst)
493−-- We assume the incoming TypeRepMap is already sorted into 'cachedBinarySearch' order using fromSortedList.
494−-- Then we can construct the index mapping from the "cached" ordering into monotonically
495−-- increasing order using 'generateOrderMapping' with the length of the TRM. This takes @O(n).
496−-- We then pull those indexes from the source TRM to get the sorted triples in a total of @O(n).
497−toSortedTriples :: TypeRepMap f -> [(Fingerprint, Any, Any)]
498−toSortedTriples tm = trip <$> ordering
500− trip i = ( Fingerprint (indexPrimArray (fingerprintAs tm) i) (indexPrimArray (fingerprintBs tm) i)
501− , indexArray (trAnys tm) i
502− , indexArray (trKeys tm) i)
504− ordering = generateOrderMapping (size tm)
506−nubByFst :: (Eq a) => [(a, b, c)] -> [(a, b, c)]
507−nubByFst = nubBy ((==) `on` fst3)
509−fst3 :: (a, b, c) -> a
271+nubByFst :: (Eq a) => [(a, b)] -> [(a, b)]
510−fst3 (a, _, _) = a
272+nubByFst = nubBy ((==) `on` fst)
512----------------------------------------------------------------------------
274----------------------------------------------------------------------------
513-- Functions for testing and benchmarking
275-- Functions for testing and benchmarking
514----------------------------------------------------------------------------
276----------------------------------------------------------------------------
516-- | Existential wrapper around 'Typeable' indexed by @f@ type parameter.
278-- | Existential wrapper around 'Typeable' indexed by @f@ type parameter.
517−-- Useful for 'TypeRepMap' structure creation form list of 'WrapTypeable's.
279+-- Useful for 'TypeRepMap' structure creation form list of 'TF's.
518−data WrapTypeable f where
280+data TF f where
519− WrapTypeable :: Typeable a => f a -> WrapTypeable f
281+ TF :: Typeable a => f a -> TF f
521−instance Show (WrapTypeable f) where
283+instance Show (TF f) where
522− show (WrapTypeable (_ :: f a)) = show $ calcFp @a
284+ show (TF tf) = show $ calcFp tf
526−prop> fromList . toList == 'id'
528−Creates 'TypeRepMap' from a list of 'WrapTypeable's.
286+{- | Creates 'TypeRepMap' from a list of 'TF's.
530−>>> show $ fromList [WrapTypeable $ Identity True, WrapTypeable $ Identity 'a']
531−TypeRepMap [Bool, Char]
288+>>> size $ fromList [TF $ Identity True, TF $ Identity 'a']
535−instance IsList (TypeRepMap f) where
292+fromList :: forall f . [TF f] -> TypeRepMap f
536− type Item (TypeRepMap f) = WrapTypeable f
538− fromList :: [WrapTypeable f] -> TypeRepMap f
539− fromList = fromTriples . map (\x -> (fp x, an x, k x))
293+fromList = fromListPairs . map (fp &&& an)
541− fp :: WrapTypeable f -> Fingerprint
295+ fp :: TF f -> Fingerprint
542− fp (WrapTypeable (_ :: f a)) = calcFp @a
296+ fp (TF x) = calcFp x
544− an :: WrapTypeable f -> Any
545− an (WrapTypeable x) = toAny x
547− k :: WrapTypeable f -> Any
548− k (WrapTypeable (_ :: f a)) = unsafeCoerce $ typeRep @a
550− toList :: TypeRepMap f -> [WrapTypeable f]
298+ an :: TF f -> Any
551− toList = toListWith WrapTypeable
299+ an (TF x) = toAny x
553−calcFp :: forall a . Typeable a => Fingerprint
301+fromF :: Typeable a => f a -> Proxy a
554−calcFp = typeRepFingerprint $ typeRep @a
302+fromF _ = Proxy
556−fromTriples :: [(Fingerprint, Any, Any)] -> TypeRepMap f
304+calcFp :: Typeable a => f a -> Fingerprint
557−fromTriples = fromSortedTriples . sortWith fst3 . nubByFst
305+calcFp = typeRepFingerprint . typeRep . fromF
559−fromSortedTriples :: [(Fingerprint, Any, Any)] -> TypeRepMap f
307+fromListPairs :: [(Fingerprint, Any)] -> TypeRepMap f
560−fromSortedTriples kvs = TypeRepMap (GHC.fromList fpAs) (GHC.fromList fpBs) (GHC.fromList ans) (GHC.fromList ks)
308+fromListPairs kvs = TypeRepMap (GHC.fromList fpAs) (GHC.fromList fpBs) (GHC.fromList ans)
562 (fpAs, fpBs) = unzip $ map (\(Fingerprint a b) -> (a, b)) fps
310 (fpAs, fpBs) = unzip $ map (\(Fingerprint a b) -> (a, b)) fps
563− (fps, ans, ks) = unzip3 $ fromSortedList kvs
311+ (fps, ans) = unzip $ fromSortedList $ sortWith fst $ nubByFst kvs
565----------------------------------------------------------------------------
313----------------------------------------------------------------------------
566-- Tree-like conversion
314-- Tree-like conversion
567----------------------------------------------------------------------------
315----------------------------------------------------------------------------
569fromSortedList :: forall a . [a] -> [a]
317fromSortedList :: forall a . [a] -> [a]
570−fromSortedList l = runST $ do
318+fromSortedList l = IM.elems $ fst $ go 0 0 mempty (IM.fromList $ zip [0..] l)
572− let arrOrigin = fromListN n l
573− arrResult <- thawArray arrOrigin 0 n
574− go n arrResult arrOrigin
575− toList <$> unsafeFreezeArray arrResult
577 -- state monad could be used here, but it's another dependency
320 -- state monad could be used here, but it's another dependency
578− go :: forall s . Int -> MutableArray s a -> Array a -> ST s ()
321+ go :: Int -> Int -> IntMap a -> IntMap a -> (IntMap a, Int)
579− go len result origin = () <$ loop 0 0
322+ go i first result vector =
580− where
323+ if i >= IM.size vector
581− loop :: Int -> Int -> ST s Int
584− then pure first
324+ then (result, first)
586− newFirst <- loop (2 * i + 1) first
326+ let (newResult, newFirst) = go (2 * i + 1) first result vector
587− writeArray result i (indexArray origin newFirst)
327+ let withCur = IM.insert i (fromJust $ IM.lookup newFirst vector) newResult
588− loop (2 * i + 2) (newFirst + 1)
328+ go (2 * i + 2) (newFirst + 1) withCur vector
590−-- Returns a list of indexes which represents the "sorted" order of an array generated by
591−-- fromSortedList of the provided length.
592−-- I.e. fmap (fromSortedList [1, 2, 3, 4, 5, 6] !!) (generateOrderMapping 6) == [1, 2, 3, 4, 5, 6]
594−-- >>> generateOrderMapping 6
597−-- >>> generateOrderMapping 8
599−generateOrderMapping :: Int -> [Int]
600−generateOrderMapping len = runST $ do
601− orderMappingArr <- newPrimArray len
602− _ <- loop orderMappingArr 0 0
603− primArrayToList <$> unsafeFreezePrimArray orderMappingArr
605− loop :: MutablePrimArray s Int -> Int -> Int -> ST s Int
606− loop result i first =
610− newFirst <- loop result (2 * i + 1) first
611− writePrimArray result newFirst i
612− loop result (2 * i + 2) (newFirst + 1)
614−----------------------------------------------------------------------------
616−----------------------------------------------------------------------------
618−-- | Check that invariant of the structure holds.
619−-- The structure maintains the following invariant.
620−-- For each element @A@ at index @i@:
622−-- 1. if there is an element @B@ at index @2*i+1@,
625−-- 2. if there is an element @C@ at index @2*i+2@,
628−invariantCheck :: TypeRepMap f -> Bool
629−invariantCheck TypeRepMap{..} = getAll (check 0)
631− lastMay [] = Nothing
632− lastMay [x] = Just x
633− lastMay (_:xs) = lastMay xs
634− sz = sizeofPrimArray fingerprintAs
635− check i | i >= sz = All True
639− -- maximum value in the left branch
641− fmap (\j -> (indexPrimArray fingerprintAs j, indexPrimArray fingerprintBs j))
644− $ iterate (\j -> j*2+2) left
645− -- minimum value in the right branch
647− fmap (\j -> (indexPrimArray fingerprintAs j, indexPrimArray fingerprintBs j))
650− $ iterate (\j -> j*2+1) right
655− case indexPrimArray fingerprintAs i `compare` indexPrimArray fingerprintAs left of
657− EQ -> indexPrimArray fingerprintBs i >= indexPrimArray fingerprintBs left
663− case indexPrimArray fingerprintAs i `compare` indexPrimArray fingerprintAs right of
665− EQ -> indexPrimArray fingerprintBs i <= indexPrimArray fingerprintBs right
668− , All $ fromMaybe True $ (<=) <$> leftMax <*> rightMin