module Data.Symbol.Unsafe (
Symbol(..),
intern,
unintern
) where
import Control.Concurrent.MVar
import Control.DeepSeq
import Data.Data (Data)
#if __GLASGOW_HASKELL__ >= 608
import Data.String
#endif /* __GLASGOW_HASKELL__ >= 608 */
import Data.Typeable (Typeable)
import qualified Data.Map as Map
import System.IO.Unsafe (unsafePerformIO)
data Symbol =
Symbol !Int !String
#if defined(__GLASGOW_HASKELL__)
deriving (Data, Typeable)
#endif /* defined(__GLASGOW_HASKELL__) */
instance Eq Symbol where
(Symbol i1 _) == (Symbol i2 _) = i1 == i2
instance Ord Symbol where
compare (Symbol i1 _) (Symbol i2 _) = compare i1 i2
instance Show Symbol where
showsPrec d (Symbol _ s) = showsPrec d s
instance Read Symbol where
readsPrec d t = [(intern s, t') | (s, t') <- readList t]
#if __GLASGOW_HASKELL__ >= 608
instance IsString Symbol where
fromString = intern
#endif /* __GLASGOW_HASKELL__ >= 608 */
data SymbolEnv = SymbolEnv
{ uniq :: !Int
, symbols :: !(Map.Map String Symbol)
}
symbolEnv :: MVar SymbolEnv
symbolEnv = unsafePerformIO $ newMVar $ SymbolEnv 1 Map.empty
intern :: String -> Symbol
intern s = s `deepseq` unsafePerformIO $ modifyMVar symbolEnv $ \env -> do
case Map.lookup s (symbols env) of
Nothing -> do let sym = Symbol (uniq env) s
let env' = env { uniq = uniq env + 1,
symbols = Map.insert s sym
(symbols env)
}
env' `seq` return (env', sym)
Just sym -> return (env, sym)
unintern :: Symbol -> String
unintern (Symbol _ s) = s