{-# LANGUAGE DeriveDataTypeable #-}
module Data.Atom (
Atom,
newAtom,
share
) where
import Control.DeepSeq
import Data.ByteString (ByteString, pack, unpack)
import Data.ByteString.Internal (c2w, toForeignPtr, w2c)
import Data.IORef
import qualified Data.Map as M
import Data.String.Unicode (unicodeToUtf8)
import Data.String.UTF8Decoding (decodeUtf8)
import Data.Typeable
import System.IO.Unsafe (unsafePerformIO)
type Atoms = M.Map ByteString ByteString
newtype Atom = A { Atom -> ByteString
bs :: ByteString }
deriving (Typeable)
theAtoms :: IORef Atoms
theAtoms :: IORef Atoms
theAtoms = IO (IORef Atoms) -> IORef Atoms
forall a. IO a -> a
unsafePerformIO (Atoms -> IO (IORef Atoms)
forall a. a -> IO (IORef a)
newIORef Atoms
forall k a. Map k a
M.empty)
{-# NOINLINE theAtoms #-}
insertAtom :: ByteString -> Atoms -> (Atoms, Atom)
insertAtom :: ByteString -> Atoms -> (Atoms, Atom)
insertAtom ByteString
s Atoms
m = (Atoms, Atom)
-> (ByteString -> (Atoms, Atom))
-> Maybe ByteString
-> (Atoms, Atom)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (ByteString -> ByteString -> Atoms -> Atoms
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert ByteString
s ByteString
s Atoms
m, ByteString -> Atom
A ByteString
s)
(\ ByteString
s' -> (Atoms
m, ByteString -> Atom
A ByteString
s'))
(Maybe ByteString -> (Atoms, Atom))
-> (Atoms -> Maybe ByteString) -> Atoms -> (Atoms, Atom)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
ByteString -> Atoms -> Maybe ByteString
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup ByteString
s (Atoms -> (Atoms, Atom)) -> Atoms -> (Atoms, Atom)
forall a b. (a -> b) -> a -> b
$ Atoms
m
newAtom :: String -> Atom
newAtom :: String -> Atom
newAtom = IO Atom -> Atom
forall a. IO a -> a
unsafePerformIO (IO Atom -> Atom) -> (String -> IO Atom) -> String -> Atom
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO Atom
newAtom'
{-# NOINLINE newAtom #-}
newAtom' :: String -> IO Atom
newAtom' :: String -> IO Atom
newAtom' String
s = do
Atom
res <- IORef Atoms -> (Atoms -> (Atoms, Atom)) -> IO Atom
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef IORef Atoms
theAtoms Atoms -> (Atoms, Atom)
insert
Atom -> IO Atom
forall (m :: * -> *) a. Monad m => a -> m a
return Atom
res
where
insert :: Atoms -> (Atoms, Atom)
insert Atoms
m = let r :: (Atoms, Atom)
r = ByteString -> Atoms -> (Atoms, Atom)
insertAtom ([Word8] -> ByteString
pack([Word8] -> ByteString)
-> (String -> [Word8]) -> String -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Word8) -> String -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Word8
c2w (String -> [Word8]) -> (String -> String) -> String -> [Word8]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
unicodeToUtf8 (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ String
s) Atoms
m
in
(Atoms, Atom) -> Atoms
forall a b. (a, b) -> a
fst (Atoms, Atom)
r Atoms -> (Atoms, Atom) -> (Atoms, Atom)
`seq` (Atoms, Atom)
r
share :: String -> String
share :: String -> String
share = Atom -> String
forall a. Show a => a -> String
show (Atom -> String) -> (String -> Atom) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Atom
newAtom
instance Eq Atom where
Atom
a1 == :: Atom -> Atom -> Bool
== Atom
a2 = ForeignPtr Word8
fp1 ForeignPtr Word8 -> ForeignPtr Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== ForeignPtr Word8
fp2
where
(ForeignPtr Word8
fp1, Int
_, Int
_) = ByteString -> (ForeignPtr Word8, Int, Int)
toForeignPtr (ByteString -> (ForeignPtr Word8, Int, Int))
-> (Atom -> ByteString) -> Atom -> (ForeignPtr Word8, Int, Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Atom -> ByteString
bs (Atom -> (ForeignPtr Word8, Int, Int))
-> Atom -> (ForeignPtr Word8, Int, Int)
forall a b. (a -> b) -> a -> b
$ Atom
a1
(ForeignPtr Word8
fp2, Int
_, Int
_) = ByteString -> (ForeignPtr Word8, Int, Int)
toForeignPtr (ByteString -> (ForeignPtr Word8, Int, Int))
-> (Atom -> ByteString) -> Atom -> (ForeignPtr Word8, Int, Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Atom -> ByteString
bs (Atom -> (ForeignPtr Word8, Int, Int))
-> Atom -> (ForeignPtr Word8, Int, Int)
forall a b. (a -> b) -> a -> b
$ Atom
a2
instance Ord Atom where
compare :: Atom -> Atom -> Ordering
compare Atom
a1 Atom
a2
| Atom
a1 Atom -> Atom -> Bool
forall a. Eq a => a -> a -> Bool
== Atom
a2 = Ordering
EQ
| Bool
otherwise = ByteString -> ByteString -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Atom -> ByteString
bs Atom
a1) (Atom -> ByteString
bs Atom
a2)
instance Read Atom where
readsPrec :: Int -> ReadS Atom
readsPrec Int
p String
str = [ (String -> Atom
newAtom String
x, String
y) | (String
x, String
y) <- Int -> ReadS String
forall a. Read a => Int -> ReadS a
readsPrec Int
p String
str ]
instance Show Atom where
show :: Atom -> String
show = (String, [String]) -> String
forall a b. (a, b) -> a
fst ((String, [String]) -> String)
-> (Atom -> (String, [String])) -> Atom -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> (String, [String])
decodeUtf8 (String -> (String, [String]))
-> (Atom -> String) -> Atom -> (String, [String])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8 -> Char) -> [Word8] -> String
forall a b. (a -> b) -> [a] -> [b]
map Word8 -> Char
w2c ([Word8] -> String) -> (Atom -> [Word8]) -> Atom -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
unpack (ByteString -> [Word8]) -> (Atom -> ByteString) -> Atom -> [Word8]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Atom -> ByteString
bs
instance NFData Atom where
rnf :: Atom -> ()
rnf Atom
x = Atom -> () -> ()
seq Atom
x ()