    -- |
    -- /SplitMix/ is a splittable pseudorandom number generator (PRNG) that is quite fast.
    --
    -- This is 32bit variant (original one is 32 bit).
    --
    -- You __really don't want to use this one__.
    --
    --  Note: This module supports all GHCs since GHC-7.0.4,
    --  but GHC-7.0 and GHC-7.2 have slow implementation, as there
    --  are no native 'popCount'.
    --
    {-# LANGUAGE CPP         #-}
    #if __GLASGOW_HASKELL__ >= 702
    {-# LANGUAGE Trustworthy #-}
    #endif
    module System.Random.SplitMix32 (
        SMGen,
        nextWord32,
        nextWord64,
        nextTwoWord32,
        nextInt,
        nextDouble,
        nextFloat,
        nextInteger,
        splitSMGen,
        -- * Generation
        bitmaskWithRejection32,
        bitmaskWithRejection32',
        bitmaskWithRejection64,
        bitmaskWithRejection64',
        -- * Initialisation
        mkSMGen,
        initSMGen,
        newSMGen,
        seedSMGen,
        seedSMGen',
        unseedSMGen,
        ) where

    import Data.Bits             (complement, shiftL, shiftR, xor, (.&.), (.|.))
    import Data.Bits.Compat
           (countLeadingZeros, finiteBitSize, popCount, zeroBits)
    import Data.IORef            (IORef, atomicModifyIORef, newIORef)
    import Data.Word             (Word32, Word64)
    import System.IO.Unsafe      (unsafePerformIO)

    import System.Random.SplitMix.Init

    #if defined(__HUGS__) || !MIN_VERSION_base(4,8,0)
    import Data.Word (Word)
    #endif

    #ifndef __HUGS__
    import Control.DeepSeq (NFData (..))
    #endif

    -- $setup
    -- >>> import Text.Read (readMaybe)
    -- >>> import Data.List (unfoldr)
    -- >>> import Text.Printf (printf)

    -------------------------------------------------------------------------------
    -- Generator
    -------------------------------------------------------------------------------

    -- | SplitMix generator state.
    data SMGen = SMGen {-# UNPACK #-} !Word32 {-# UNPACK #-} !Word32 -- seed and gamma; gamma is odd
      deriving Int -> SMGen -> ShowS
    [SMGen] -> ShowS
    SMGen -> String
    (Int -> SMGen -> ShowS)
    -> (SMGen -> String) -> ([SMGen] -> ShowS) -> Show SMGen
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> SMGen -> ShowS
    showsPrec :: Int -> SMGen -> ShowS
    $cshow :: SMGen -> String
    show :: SMGen -> String
    $cshowList :: [SMGen] -> ShowS
    showList :: [SMGen] -> ShowS
    Show

    #ifndef __HUGS__
    instance NFData SMGen where
        rnf :: SMGen -> ()
    rnf (SMGen Word32
    _ Word32
    _) = ()
    #endif

    -- |
    --
    -- >>> readMaybe "SMGen 1 1" :: Maybe SMGen
    -- Just (SMGen 1 1)
    --
    -- >>> readMaybe "SMGen 1 2" :: Maybe SMGen
    -- Nothing
    --
    -- >>> readMaybe (show (mkSMGen 42)) :: Maybe SMGen
    -- Just (SMGen 142593372 1604540297)
    --
    instance Read SMGen where
        readsPrec :: Int -> ReadS SMGen
    readsPrec Int
    d String
    r =  Bool -> ReadS SMGen -> ReadS SMGen
    forall a. Bool -> ReadS a -> ReadS a
    readParen (Int
    d Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    10) (\String
    r0 ->
            [ (Word32 -> Word32 -> SMGen
    SMGen Word32
    seed Word32
    gamma, String
    r3)
            | (String
    "SMGen", String
    r1) <- ReadS String
    lex String
    r0
            , (Word32
    seed, String
    r2) <- Int -> ReadS Word32
    forall a. Read a => Int -> ReadS a
    readsPrec Int
    11 String
    r1
            , (Word32
    gamma, String
    r3) <- Int -> ReadS Word32
    forall a. Read a => Int -> ReadS a
    readsPrec Int
    11 String
    r2
            , Word32 -> Bool
    forall a. Integral a => a -> Bool
    odd Word32
    gamma
            ]) String
    r

    -------------------------------------------------------------------------------
    -- Operations
    -------------------------------------------------------------------------------

    -- | Generate a 'Word32'.
    --
    -- >>> take 3 $ map (printf "%x") $ unfoldr (Just . nextWord32) (mkSMGen 1337) :: [String]
    -- ["e0cfe722","a6ced0f0","c3a6d889"]
    --
    nextWord32 :: SMGen -> (Word32, SMGen)
    nextWord32 :: SMGen -> (Word32, SMGen)
    nextWord32 (SMGen Word32
    seed Word32
    gamma) = (Word32 -> Word32
    mix32 Word32
    seed', Word32 -> Word32 -> SMGen
    SMGen Word32
    seed' Word32
    gamma)
      where
        seed' :: Word32
    seed' = Word32
    seed Word32 -> Word32 -> Word32
    forall a. Num a => a -> a -> a
    + Word32
    gamma

    -- | Generate a 'Word64', by generating to 'Word32's.
    nextWord64 :: SMGen -> (Word64, SMGen)
    nextWord64 :: SMGen -> (Word64, SMGen)
    nextWord64 SMGen
    s0 = (Word32 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word32
    w0 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    32 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. Word32 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word32
    w1,  SMGen
    s2)
      where
        (Word32
    w0, SMGen
    s1) = SMGen -> (Word32, SMGen)
    nextWord32 SMGen
    s0
        (Word32
    w1, SMGen
    s2) = SMGen -> (Word32, SMGen)
    nextWord32 SMGen
    s1

    -- | Generate two 'Word32'.
    nextTwoWord32 :: SMGen -> (Word32, Word32, SMGen)
    nextTwoWord32 :: SMGen -> (Word32, Word32, SMGen)
    nextTwoWord32 SMGen
    s0 = (Word32
    w0, Word32
    w1, SMGen
    s2) where
        (Word32
    w0, SMGen
    s1) = SMGen -> (Word32, SMGen)
    nextWord32 SMGen
    s0
        (Word32
    w1, SMGen
    s2) = SMGen -> (Word32, SMGen)
    nextWord32 SMGen
    s1

    -- | Generate an 'Int'.
    nextInt :: SMGen -> (Int, SMGen)
    nextInt :: SMGen -> (Int, SMGen)
    nextInt SMGen
    g | Bool
    isBigInt  = (Int, SMGen)
    int64
              | Bool
    otherwise = (Int, SMGen)
    int32
      where
        int32 :: (Int, SMGen)
    int32 = case SMGen -> (Word32, SMGen)
    nextWord32 SMGen
    g of
            (Word32
    w, SMGen
    g') -> (Word32 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word32
    w, SMGen
    g')
        int64 :: (Int, SMGen)
    int64 = case SMGen -> (Word64, SMGen)
    nextWord64 SMGen
    g of
            (Word64
    w, SMGen
    g') -> (Word64 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word64
    w, SMGen
    g')

    isBigInt :: Bool
    isBigInt :: Bool
    isBigInt = Int -> Int
    forall b. FiniteBits b => b -> Int
    finiteBitSize (Int
    forall a. HasCallStack => a
    undefined :: Int) Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    32

    -- | Generate a 'Double' in @[0, 1)@ range.
    --
    -- >>> take 8 $ map (printf "%0.3f") $ unfoldr (Just . nextDouble) (mkSMGen 1337) :: [String]
    -- ["0.878","0.764","0.063","0.845","0.262","0.490","0.176","0.544"]
    --
    nextDouble :: SMGen -> (Double, SMGen)
    nextDouble :: SMGen -> (Double, SMGen)
    nextDouble SMGen
    g = case SMGen -> (Word64, SMGen)
    nextWord64 SMGen
    g of
        (Word64
    w64, SMGen
    g') -> (Word64 -> Double
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64
    w64 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    11) Double -> Double -> Double
    forall a. Num a => a -> a -> a
    * Double
    doubleUlp, SMGen
    g')

    -- | Generate a 'Float' in @[0, 1)@ range.
    --
    -- >>> take 8 $ map (printf "%0.3f") $ unfoldr (Just . nextFloat) (mkSMGen 1337) :: [String]
    -- ["0.878","0.652","0.764","0.631","0.063","0.180","0.845","0.645"]
    --
    nextFloat :: SMGen -> (Float, SMGen)
    nextFloat :: SMGen -> (Float, SMGen)
    nextFloat SMGen
    g = case SMGen -> (Word32, SMGen)
    nextWord32 SMGen
    g of
        (Word32
    w32, SMGen
    g') -> (Word32 -> Float
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word32
    w32 Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    8) Float -> Float -> Float
    forall a. Num a => a -> a -> a
    * Float
    floatUlp, SMGen
    g')

    -- | Generate an 'Integer' in closed @[x, y]@ range.
    nextInteger :: Integer -> Integer -> SMGen -> (Integer, SMGen)
    nextInteger :: Integer -> Integer -> SMGen -> (Integer, SMGen)
    nextInteger Integer
    lo Integer
    hi SMGen
    g = case Integer -> Integer -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare Integer
    lo Integer
    hi of
        Ordering
    LT -> let (Integer
    i, SMGen
    g') = Integer -> SMGen -> (Integer, SMGen)
    nextInteger' (Integer
    hi Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    lo) SMGen
    g in (Integer
    i Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    + Integer
    lo, SMGen
    g')
        Ordering
    EQ -> (Integer
    lo, SMGen
    g)
        Ordering
    GT -> let (Integer
    i, SMGen
    g') = Integer -> SMGen -> (Integer, SMGen)
    nextInteger' (Integer
    lo Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    hi) SMGen
    g in (Integer
    i Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    + Integer
    hi, SMGen
    g')

    -- invariant: first argument is positive
    -- Essentially bitmaskWithRejection but for Integers.
    --
    nextInteger' :: Integer -> SMGen -> (Integer, SMGen)
    nextInteger' :: Integer -> SMGen -> (Integer, SMGen)
    nextInteger' Integer
    range = SMGen -> (Integer, SMGen)
    loop
      where
        leadMask :: Word32
        restDigits :: Word
        (Word32
    leadMask, Word
    restDigits) = Word -> Integer -> (Word32, Word)
    go Word
    0 Integer
    range where
            go :: Word -> Integer -> (Word32, Word)
            go :: Word -> Integer -> (Word32, Word)
    go Word
    n Integer
    x | Integer
    x Integer -> Integer -> Bool
    forall a. Ord a => a -> a -> Bool
    < Integer
    two32 = (Word32 -> Word32
    forall a. Bits a => a -> a
    complement Word32
    forall a. Bits a => a
    zeroBits Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    `shiftR` Word32 -> Int
    forall b. FiniteBits b => b -> Int
    countLeadingZeros (Integer -> Word32
    forall a. Num a => Integer -> a
    fromInteger Integer
    x :: Word32), Word
    n)
                   | Bool
    otherwise = Word -> Integer -> (Word32, Word)
    go (Word
    n Word -> Word -> Word
    forall a. Num a => a -> a -> a
    + Word
    1) (Integer
    x Integer -> Int -> Integer
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    32)

        generate :: SMGen -> (Integer, SMGen)
        generate :: SMGen -> (Integer, SMGen)
    generate SMGen
    g0 =
            let (Word32
    x, SMGen
    g') = SMGen -> (Word32, SMGen)
    nextWord32 SMGen
    g0
                x' :: Word32
    x' = Word32
    x Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .&. Word32
    leadMask
            in Integer -> Word -> SMGen -> (Integer, SMGen)
    go (Word32 -> Integer
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word32
    x') Word
    restDigits SMGen
    g'
          where
            go :: Integer -> Word -> SMGen -> (Integer, SMGen)
            go :: Integer -> Word -> SMGen -> (Integer, SMGen)
    go Integer
    acc Word
    0 SMGen
    g = Integer
    acc Integer -> (Integer, SMGen) -> (Integer, SMGen)
    forall a b. a -> b -> b
    `seq` (Integer
    acc, SMGen
    g)
            go Integer
    acc Word
    n SMGen
    g =
                let (Word32
    x, SMGen
    g') = SMGen -> (Word32, SMGen)
    nextWord32 SMGen
    g
                in Integer -> Word -> SMGen -> (Integer, SMGen)
    go (Integer
    acc Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Integer
    two32 Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    + Word32 -> Integer
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word32
    x) (Word
    n Word -> Word -> Word
    forall a. Num a => a -> a -> a
    - Word
    1) SMGen
    g'

        loop :: SMGen -> (Integer, SMGen)
    loop SMGen
    g = let (Integer
    x, SMGen
    g') = SMGen -> (Integer, SMGen)
    generate SMGen
    g
                 in if Integer
    x Integer -> Integer -> Bool
    forall a. Ord a => a -> a -> Bool
    > Integer
    range
                    then SMGen -> (Integer, SMGen)
    loop SMGen
    g'
                    else (Integer
    x, SMGen
    g')

    two32 :: Integer
    two32 :: Integer
    two32 = Integer
    2 Integer -> Int -> Integer
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ (Int
    32 :: Int)

    -------------------------------------------------------------------------------
    -- Splitting
    -------------------------------------------------------------------------------

    -- | Split a generator into a two uncorrelated generators.
    splitSMGen :: SMGen -> (SMGen, SMGen)
    splitSMGen :: SMGen -> (SMGen, SMGen)
    splitSMGen (SMGen Word32
    seed Word32
    gamma) =
        (Word32 -> Word32 -> SMGen
    SMGen Word32
    seed'' Word32
    gamma, Word32 -> Word32 -> SMGen
    SMGen (Word32 -> Word32
    mix32 Word32
    seed') (Word32 -> Word32
    mixGamma Word32
    seed''))
      where
        seed' :: Word32
    seed'  = Word32
    seed Word32 -> Word32 -> Word32
    forall a. Num a => a -> a -> a
    + Word32
    gamma
        seed'' :: Word32
    seed'' = Word32
    seed' Word32 -> Word32 -> Word32
    forall a. Num a => a -> a -> a
    + Word32
    gamma

    -------------------------------------------------------------------------------
    -- Algorithm
    -------------------------------------------------------------------------------

    -- | (1 + sqrt 5) / 2 * (2 ^^ bits)
    goldenGamma :: Word32
    goldenGamma :: Word32
    goldenGamma = Word32
    0x9e3779b9

    floatUlp :: Float
    floatUlp :: Float
    floatUlp =  Float
    1.0 Float -> Float -> Float
    forall a. Fractional a => a -> a -> a
    / Word32 -> Float
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word32
    1 Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    24 :: Word32)

    doubleUlp :: Double
    doubleUlp :: Double
    doubleUlp =  Double
    1.0 Double -> Double -> Double
    forall a. Fractional a => a -> a -> a
    / Word64 -> Double
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64
    1 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    53 :: Word64)

    #if defined(__GHCJS__) && defined(OPTIMISED_MIX32)
    -- JavaScript Foreign Function Interface
    -- https://github.com/ghcjs/ghcjs/blob/master/doc/foreign-function-interface.md

    foreign import javascript unsafe
        "var x0 = $1 ^ $1 >>> 16; var x1 = x0 & 0xffff; var x2 = (((x0 >>> 16 & 0xffff) * 0x0000ca6b + x1 * 0x000085eb & 0xffff) << 16) + x1 * 0x0000ca6b; var x3 = x2 ^ x2 >>> 13; var x4 = x3 & 0xffff; var x5 = (((x3 >>> 16 & 0xffff) * 0x0000ae35 + x4 * 0x0000c2b2 & 0xffff) << 16) + x4 * 0x0000ae35; $r = (x5 ^ x5 >>> 16) | 0;"
        mix32 :: Word32 -> Word32

    foreign import javascript unsafe
        "var x0 = $1 ^ $1 >>> 16; var x1 = x0 & 0xffff; var x2 = (((x0 >>> 16 & 0xffff) * 0x00006ccb + x1 * 0x000069ad & 0xffff) << 16) + x1 * 0x00006ccb; var x3 = x2 ^ x2 >>> 13; var x4 = x3 & 0xffff; var x5 = (((x3 >>> 16 & 0xffff) * 0x0000b5b3 + x4 * 0x0000cd9a & 0xffff) << 16) + x4 * 0x0000b5b3; $r = (x5 ^ x5 >>> 16) | 0;"
        mix32variant13 :: Word32 -> Word32

    #else
    mix32 :: Word32 -> Word32
    mix32 :: Word32 -> Word32
    mix32 Word32
    z0 =
       -- MurmurHash3Mixer 32bit
        let z1 :: Word32
    z1 = Int -> Word32 -> Word32 -> Word32
    shiftXorMultiply Int
    16 Word32
    0x85ebca6b Word32
    z0
            z2 :: Word32
    z2 = Int -> Word32 -> Word32 -> Word32
    shiftXorMultiply Int
    13 Word32
    0xc2b2ae35 Word32
    z1
            z3 :: Word32
    z3 = Int -> Word32 -> Word32
    shiftXor Int
    16 Word32
    z2
        in Word32
    z3

    -- used only in mixGamma
    mix32variant13 :: Word32 -> Word32
    mix32variant13 :: Word32 -> Word32
    mix32variant13 Word32
    z0 =
       -- See avalanche "executable"
        let z1 :: Word32
    z1 = Int -> Word32 -> Word32 -> Word32
    shiftXorMultiply Int
    16 Word32
    0x69ad6ccb Word32
    z0
            z2 :: Word32
    z2 = Int -> Word32 -> Word32 -> Word32
    shiftXorMultiply Int
    13 Word32
    0xcd9ab5b3 Word32
    z1
            z3 :: Word32
    z3 = Int -> Word32 -> Word32
    shiftXor Int
    16 Word32
    z2
        in Word32
    z3

    shiftXor :: Int -> Word32 -> Word32
    shiftXor :: Int -> Word32 -> Word32
    shiftXor Int
    n Word32
    w = Word32
    w Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    `xor` (Word32
    w Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    n)

    shiftXorMultiply :: Int -> Word32 -> Word32 -> Word32
    shiftXorMultiply :: Int -> Word32 -> Word32 -> Word32
    shiftXorMultiply Int
    n Word32
    k Word32
    w = Int -> Word32 -> Word32
    shiftXor Int
    n Word32
    w Word32 -> Word32 -> Word32
    forall a. Num a => a -> a -> a
    * Word32
    k
    #endif

    mixGamma :: Word32 -> Word32
    mixGamma :: Word32 -> Word32
    mixGamma Word32
    z0 =
        let z1 :: Word32
    z1 = Word32 -> Word32
    mix32variant13 Word32
    z0 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .|. Word32
    1             -- force to be odd
            n :: Int
    n  = Word32 -> Int
    forall a. Bits a => a -> Int
    popCount (Word32
    z1 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    `xor` (Word32
    z1 Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    1))
        -- see: http://www.pcg-random.org/posts/bugs-in-splitmix.html
        -- let's trust the text of the paper, not the code.
        in if Int
    n Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Int
    12
            then Word32
    z1
            else Word32
    z1 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    `xor` Word32
    0xaaaaaaaa

    -------------------------------------------------------------------------------
    -- Generation
    -------------------------------------------------------------------------------

    -- | /Bitmask with rejection/ method of generating subrange of 'Word32'.
    --
    -- @bitmaskWithRejection32 w32@ generates random numbers in closed-open
    -- range of @[0, w32)@.
    --
    bitmaskWithRejection32 :: Word32 -> SMGen -> (Word32, SMGen)
    bitmaskWithRejection32 :: Word32 -> SMGen -> (Word32, SMGen)
    bitmaskWithRejection32 Word32
    0 = String -> SMGen -> (Word32, SMGen)
    forall a. HasCallStack => String -> a
    error String
    "bitmaskWithRejection32 0"
    bitmaskWithRejection32 Word32
    n = Word32 -> SMGen -> (Word32, SMGen)
    bitmaskWithRejection32' (Word32
    n Word32 -> Word32 -> Word32
    forall a. Num a => a -> a -> a
    - Word32
    1)
    {-# INLINEABLE bitmaskWithRejection32 #-}

    -- | /Bitmask with rejection/ method of generating subrange of 'Word64'.
    --
    -- @bitmaskWithRejection64 w64@ generates random numbers in closed-open
    -- range of @[0, w64)@.
    --
    -- >>> take 20 $ unfoldr (Just . bitmaskWithRejection64 5) (mkSMGen 1337)
    -- [0,2,4,2,1,4,2,4,2,2,3,0,3,2,2,2,3,1,2,2]
    --
    bitmaskWithRejection64 :: Word64 -> SMGen -> (Word64, SMGen)
    bitmaskWithRejection64 :: Word64 -> SMGen -> (Word64, SMGen)
    bitmaskWithRejection64 Word64
    0 = String -> SMGen -> (Word64, SMGen)
    forall a. HasCallStack => String -> a
    error String
    "bitmaskWithRejection64 0"
    bitmaskWithRejection64 Word64
    n = Word64 -> SMGen -> (Word64, SMGen)
    bitmaskWithRejection64' (Word64
    n Word64 -> Word64 -> Word64
    forall a. Num a => a -> a -> a
    - Word64
    1)
    {-# INLINEABLE bitmaskWithRejection64 #-}

    -- | /Bitmask with rejection/ method of generating subrange of 'Word32'.
    --
    -- @bitmaskWithRejection32' w32@ generates random numbers in closed-closed
    -- range of @[0, w32]@.
    --
    -- @since 0.0.4
    bitmaskWithRejection32' :: Word32 -> SMGen -> (Word32, SMGen)
    bitmaskWithRejection32' :: Word32 -> SMGen -> (Word32, SMGen)
    bitmaskWithRejection32' Word32
    range = SMGen -> (Word32, SMGen)
    go where
        mask :: Word32
    mask = Word32 -> Word32
    forall a. Bits a => a -> a
    complement Word32
    forall a. Bits a => a
    zeroBits Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    `shiftR` Word32 -> Int
    forall b. FiniteBits b => b -> Int
    countLeadingZeros (Word32
    range Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .|. Word32
    1)
        go :: SMGen -> (Word32, SMGen)
    go SMGen
    g = let (Word32
    x, SMGen
    g') = SMGen -> (Word32, SMGen)
    nextWord32 SMGen
    g
                   x' :: Word32
    x' = Word32
    x Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .&. Word32
    mask
               in if Word32
    x' Word32 -> Word32 -> Bool
    forall a. Ord a => a -> a -> Bool
    > Word32
    range
                  then SMGen -> (Word32, SMGen)
    go SMGen
    g'
                  else (Word32
    x', SMGen
    g')
    {-# INLINEABLE bitmaskWithRejection32' #-}

    -- | /Bitmask with rejection/ method of generating subrange of 'Word64'.
    --
    -- @bitmaskWithRejection64' w64@ generates random numbers in closed-closed
    -- range of @[0, w64]@.
    --
    -- >>> take 20 $ unfoldr (Just . bitmaskWithRejection64' 5) (mkSMGen 1337)
    -- [0,2,4,2,1,4,2,4,5,5,2,2,5,3,5,0,3,2,2,2]
    --
    -- @since 0.0.4
    bitmaskWithRejection64' :: Word64 -> SMGen -> (Word64, SMGen)
    bitmaskWithRejection64' :: Word64 -> SMGen -> (Word64, SMGen)
    bitmaskWithRejection64' Word64
    range = SMGen -> (Word64, SMGen)
    go where
        mask :: Word64
    mask = Word64 -> Word64
    forall a. Bits a => a -> a
    complement Word64
    forall a. Bits a => a
    zeroBits Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftR` Word64 -> Int
    forall b. FiniteBits b => b -> Int
    countLeadingZeros (Word64
    range Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. Word64
    1)
        go :: SMGen -> (Word64, SMGen)
    go SMGen
    g = let (Word64
    x, SMGen
    g') = SMGen -> (Word64, SMGen)
    nextWord64 SMGen
    g
                   x' :: Word64
    x' = Word64
    x Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .&. Word64
    mask
               in if Word64
    x' Word64 -> Word64 -> Bool
    forall a. Ord a => a -> a -> Bool
    > Word64
    range
                  then SMGen -> (Word64, SMGen)
    go SMGen
    g'
                  else (Word64
    x', SMGen
    g')
    {-# INLINEABLE bitmaskWithRejection64' #-}

    -------------------------------------------------------------------------------
    -- Initialisation
    -------------------------------------------------------------------------------

    -- | Create 'SMGen' using seed and gamma.
    --
    -- >>> seedSMGen 2 2
    -- SMGen 2 3
    --
    seedSMGen
        :: Word32 -- ^ seed
        -> Word32 -- ^ gamma
        -> SMGen
    seedSMGen :: Word32 -> Word32 -> SMGen
    seedSMGen Word32
    seed Word32
    gamma = Word32 -> Word32 -> SMGen
    SMGen Word32
    seed (Word32
    gamma Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .|. Word32
    1)

    -- | Like 'seedSMGen' but takes a pair.
    seedSMGen' :: (Word32, Word32) -> SMGen
    seedSMGen' :: (Word32, Word32) -> SMGen
    seedSMGen' = (Word32 -> Word32 -> SMGen) -> (Word32, Word32) -> SMGen
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry Word32 -> Word32 -> SMGen
    seedSMGen

    -- | Extract current state of 'SMGen'.
    unseedSMGen :: SMGen -> (Word32, Word32)
    unseedSMGen :: SMGen -> (Word32, Word32)
    unseedSMGen (SMGen Word32
    seed Word32
    gamma) = (Word32
    seed, Word32
    gamma)

    -- | Preferred way to deterministically construct 'SMGen'.
    --
    -- >>> mkSMGen 42
    -- SMGen 142593372 1604540297
    --
    mkSMGen :: Word32 -> SMGen
    mkSMGen :: Word32 -> SMGen
    mkSMGen Word32
    s = Word32 -> Word32 -> SMGen
    SMGen (Word32 -> Word32
    mix32 Word32
    s) (Word32 -> Word32
    mixGamma (Word32
    s Word32 -> Word32 -> Word32
    forall a. Num a => a -> a -> a
    + Word32
    goldenGamma))

    -- | Initialize 'SMGen' using entropy available on the system (time, ...)
    initSMGen :: IO SMGen
    initSMGen :: IO SMGen
    initSMGen = (Word32 -> SMGen) -> IO Word32 -> IO SMGen
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Word32 -> SMGen
    mkSMGen IO Word32
    initialSeed'

    -- | Derive a new generator instance from the global 'SMGen' using 'splitSMGen'.
    newSMGen :: IO SMGen
    newSMGen :: IO SMGen
    newSMGen = IORef SMGen -> (SMGen -> (SMGen, SMGen)) -> IO SMGen
    forall a b. IORef a -> (a -> (a, b)) -> IO b
    atomicModifyIORef IORef SMGen
    theSMGen SMGen -> (SMGen, SMGen)
    splitSMGen

    theSMGen :: IORef SMGen
    theSMGen :: IORef SMGen
    theSMGen = IO (IORef SMGen) -> IORef SMGen
    forall a. IO a -> a
    unsafePerformIO (IO (IORef SMGen) -> IORef SMGen)
    -> IO (IORef SMGen) -> IORef SMGen
    forall a b. (a -> b) -> a -> b
    $ IO SMGen
    initSMGen IO SMGen -> (SMGen -> IO (IORef SMGen)) -> IO (IORef SMGen)
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= SMGen -> IO (IORef SMGen)
    forall a. a -> IO (IORef a)
    newIORef
    {-# NOINLINE theSMGen #-}

    initialSeed' :: IO Word32
    initialSeed' :: IO Word32
    initialSeed' = do
        Word64
    w64 <- IO Word64
    initialSeed
        Word32 -> IO Word32
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Word64 -> Word32
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    shiftR Word64
    w64 Int
    32) Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word32
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word64
    w64)