aboutsummaryrefslogtreecommitdiff
path: root/src/Data/StableName/Extra.hs
blob: cf37cfeb1d50e3eb7bd72e0e3343f0ac05625e67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# OPTIONS_GHC -fno-full-laziness -fno-cse #-}
module Data.StableName.Extra (
  StableName,
  makeStableName',
  showStableName,
) where

import Data.Hashable
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HM
import Data.IORef
import GHC.StableName
import System.IO.Unsafe


-- | This function evaluates its argument to WHNF and returns a stable name for
-- the evaluation result. This function is not referentially transparent and is
-- implemented using 'unsafePerformIO'.
{-# NOINLINE makeStableName' #-}
makeStableName' :: a -> StableName a
makeStableName' !x = unsafePerformIO (makeStableName x)


data SomeStableName = forall a. SomeStableName (StableName a)

instance Eq SomeStableName where
  SomeStableName a == SomeStableName b = eqStableName a b

instance Hashable SomeStableName where
  hashWithSalt salt (SomeStableName name) = hashWithSalt salt name

{-# NOINLINE showStableNameCache #-}
showStableNameCache :: IORef (HashMap SomeStableName Int, Int)
showStableNameCache = unsafePerformIO $ newIORef (mempty, 0)

{-# NOINLINE showStableName #-}
showStableName :: StableName a -> String
showStableName name =
  unsafePerformIO $ atomicModifyIORef' showStableNameCache $ \tup@(mp, nexti) ->
    case HM.lookup (SomeStableName name) mp of
      Just res -> (tup, '$' : show res)
      Nothing -> ((HM.insert (SomeStableName name) nexti mp, nexti + 1), '$' : show nexti)