{-# LANGUAGE CPP #-}
module System.Random.TF.Init
(newTFGen, mkTFGen, mkSeedTime, mkSeedUnix, initTFGen)
where
import System.Random.TF.Gen (TFGen, seedTFGen, split)
import Control.Monad (when)
import Data.Bits (bitSize)
import Data.IORef
import Data.Word
import Foreign (allocaBytes, peekArray)
import Data.Ratio (numerator, denominator)
import Data.Time
import System.CPUTime
import System.IO
import System.IO.Unsafe (unsafePerformIO)
mkSeedTime :: IO (Word64, Word64, Word64, Word64)
mkSeedTime = do
utcTm <- getCurrentTime
cpu <- getCPUTime
let daytime = toRational $ utctDayTime utcTm
t1, t2 :: Word64
t1 = fromIntegral $ numerator daytime
t2 = fromIntegral $ denominator daytime
day = toModifiedJulianDay $ utctDay utcTm
d1 :: Word64
d1 = fromIntegral day
c1 :: Word64
c1 = fromIntegral cpu
return (t1, t2, d1, c1)
mkSeedUnix :: IO (Word64, Word64, Word64, Word64)
mkSeedUnix = do
let bytes = 32
rfile = "/dev/urandom"
l <- allocaBytes bytes $ \buf -> do
nread <- withBinaryFile rfile ReadMode $ \h ->
hGetBuf h buf bytes
when (nread /= bytes) $
fail $ "mkSeedUnix: Failed to read " ++
show bytes ++ " from " ++ rfile
peekArray 4 buf
let [x1, x2, x3, x4] = l
return (x1, x2, x3, x4)
initTFGen :: IO TFGen
initTFGen = do
#ifdef UNIX
s <- mkSeedUnix
#else
s <- mkSeedTime
#endif
return $ seedTFGen s
newTFGen :: IO TFGen
newTFGen = atomicModifyIORef theTFGen split
{-# NOINLINE theTFGen #-}
theTFGen :: IORef TFGen
theTFGen = unsafePerformIO $ do
rng <- initTFGen
newIORef rng
mkTFGen :: Int -> TFGen
mkTFGen n
| bitSize n > 64 = error "mkTFGen: case where size of Int > 64 not implemented"
| otherwise = seedTFGen (fromIntegral n, 0, 0, 0)