{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE CPP #-}
#ifndef NO_SAFE_HASKELL
{-# LANGUAGE Trustworthy #-}
#endif
module Test.QuickCheck.Random where
import System.Random
#ifndef NO_SPLITMIX
import System.Random.SplitMix
#endif
import Data.Bits
#ifdef NO_SPLITMIX
newtype QCGen = QCGen StdGen
#else
newtype QCGen = QCGen SMGen
#endif
instance Show QCGen where
showsPrec n (QCGen g) s = showsPrec n g s
instance Read QCGen where
readsPrec n xs = [(QCGen g, ys) | (g, ys) <- readsPrec n xs]
instance RandomGen QCGen where
split (QCGen g) =
case split g of
(g1, g2) -> (QCGen g1, QCGen g2)
genRange (QCGen g) = genRange g
next (QCGen g) =
case next g of
(x, g') -> (x, QCGen g')
newQCGen :: IO QCGen
#ifdef NO_SPLITMIX
newQCGen = fmap QCGen newStdGen
#else
newQCGen = fmap QCGen newSMGen
#endif
mkQCGen :: Int -> QCGen
#ifdef NO_SPLITMIX
mkQCGen n = QCGen (mkStdGen n)
#else
mkQCGen n = QCGen (mkSMGen (fromIntegral n))
#endif
class Splittable a where
left, right :: a -> a
instance Splittable QCGen where
left = fst . split
right = snd . split
{-# INLINE integerVariant #-}
integerVariant :: Splittable a => Integer -> a -> a
integerVariant n g
| n >= 1 = gamma n $! left g
| otherwise = gamma (1-n) $! right g
where
gamma n =
encode k . zeroes k
where
k = ilog2 n
encode (-1) g = g
encode k g
| testBit n k =
encode (k-1) $! right g
| otherwise =
encode (k-1) $! left g
zeroes 0 g = g
zeroes k g = zeroes (k-1) $! left g
ilog2 1 = 0
ilog2 n = 1 + ilog2 (n `div` 2)