{-# 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
#ifdef NO_SPLITMIX
split (QCGen g) =
case split g of
(g1, g2) -> (QCGen g1, QCGen g2)
genRange (QCGen g) = genRange g
next = wrapQCGen next
#else
split (QCGen g) =
case splitSMGen g of
(g1, g2) -> (QCGen g1, QCGen g2)
genRange _ = (minBound, maxBound)
next = wrapQCGen nextInt
#ifndef OLD_RANDOM
genWord8 = wrapQCGen genWord8
genWord16 = wrapQCGen genWord16
genWord32 = wrapQCGen genWord32
genWord64 = wrapQCGen genWord64
genWord32R r = wrapQCGen (genWord32R r)
genWord64R r = wrapQCGen (genWord64R r)
genShortByteString n = wrapQCGen (genShortByteString n)
#endif
#endif
{-# INLINE wrapQCGen #-}
#ifdef NO_SPLITMIX
wrapQCGen :: (StdGen -> (a, StdGen)) -> (QCGen -> (a, QCGen))
#else
wrapQCGen :: (SMGen -> (a, SMGen)) -> (QCGen -> (a, QCGen))
#endif
wrapQCGen f (QCGen g) =
case f 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)