Skip to content

Instantly share code, notes, and snippets.

@larskuhtz
Created April 26, 2017 16:15
Show Gist options
  • Save larskuhtz/7a828939d1561217d56bf66a407a963f to your computer and use it in GitHub Desktop.
Save larskuhtz/7a828939d1561217d56bf66a407a963f to your computer and use it in GitHub Desktop.
Efficiently Generate Random Haskell ByteString
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE BangPatterns #-}
module RandomByteString
( random
, randomGen
) where
import Control.Exception (bracketOnError)
import Data.ByteString (ByteString)
import Data.ByteString.Unsafe (unsafePackAddressLen)
import Data.Word (Word8, Word64)
import Foreign (mallocBytes, poke, plusPtr, free, castPtr)
import GHC.Ptr (Ptr(..))
import Numeric.Natural (Natural)
import System.Random.MWC (uniform, GenIO, create)
random ∷ Natural → IO ByteString
random n = do
gen ← create
randomGen gen n
randomGen ∷ GenIO → Natural → IO ByteString
randomGen gen n =
bracketOnError (mallocBytes len8) free $ \ptr@(Ptr !addr) → do
go ptr
unsafePackAddressLen len8 addr
where
len8, len64 ∷ Int
!len8 = fromIntegral n
!len64 = len8 `div` 8
go ∷ Ptr Word64 → IO ()
go !startPtr = loop64 startPtr
where
-- Generate 64bit values
fin64Ptr ∷ Ptr Word64
!fin64Ptr = startPtr `plusPtr` (len64 * 8)
loop64 ∷ Ptr Word64 → IO ()
loop64 !curPtr
| curPtr < fin64Ptr = do
!b ← uniform gen ∷ IO Word64
poke curPtr b
loop64 $ curPtr `plusPtr` 8
| otherwise = loop8 $ castPtr curPtr
-- Generate 8bit values
fin8Ptr ∷ Ptr Word8
!fin8Ptr = startPtr `plusPtr` len8
loop8 ∷ Ptr Word8 → IO ()
loop8 !curPtr
| curPtr < fin8Ptr = do
!b ← uniform gen ∷ IO Word8
poke curPtr b
loop8 $ curPtr `plusPtr` 1
| otherwise = return ()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment