packages feed

otel-effectful-1.0.0: src/System/Random/Extra.hs

-- |
-- Module      : System.Random.Extra
-- Copyright   : (c) 2026 Institute for Digital Autonomy
-- License     : EUPL-1.2
-- Maintainer  : IDA
--
-- Thread-safe, low-contention generation of random values.
module System.Random.Extra where

import Control.Concurrent (myThreadId, threadCapability)
import Data.IORef (IORef, atomicModifyIORef', newIORef)
import Data.Tuple (swap)
import Data.Vector (Vector)
import Data.Vector qualified as Vector
import GHC.Conc (getNumCapabilities)
import System.IO.Unsafe (unsafePerformIO)
import System.Random (StdGen, newStdGen)
import System.Random.Stateful (Uniform, runStateGen, uniformM)
import Prelude

-- | One 'StdGen' per capability, each seeded independently from the global one.
generators :: Vector (IORef StdGen)
generators = unsafePerformIO do
    capabilities <- getNumCapabilities
    Vector.replicateM capabilities $ newIORef =<< newStdGen
{-# NOINLINE generators #-}

-- | Draw a uniformly random value from the current capability's generator.
uniformIO :: (Uniform a) => IO a
uniformIO = do
    (capability, _pinned) <- threadCapability =<< myThreadId
    let generator = generators Vector.! (capability `mod` Vector.length generators)
    atomicModifyIORef' generator \g -> swap $ runStateGen g uniformM
{-# INLINE uniformIO #-}