-- Copyright 2013 Kevin Backhouse.
module Main where
import Control.Monad.ST2
import Control.Monad.State.Strict
import Control.Monad.Writer.Strict
import Data.Bits
import Test.Framework as TF ( defaultMain, testGroup, Test )
import Test.Framework.Providers.QuickCheck2 ( testProperty )
import Test.QuickCheck as QC
import Test.QuickCheck.Property ( morallyDubiousIOProperty )
-- | 'TestST2' is a trivial wrapper around 'PureST2'. Its only purpose
-- is to define a 'QC.Testable' instance for 'PureST2'.
newtype TestST2 a
= TestST2 (PureST2 a)
instance QC.Testable a => QC.Testable (TestST2 a) where
property (TestST2 (PureST2 m)) = morallyDubiousIOProperty (st2ToIO m)
main :: IO ()
main = defaultMain tests
tests :: [TF.Test]
tests =
[ testGroup "Control.Monad.ST2"
[ testProperty "CreateWriteRead" prop_CreateWriteRead
, testProperty "ST2RArray" prop_ST2RArray
, testProperty "parallelST2" prop_parallelST2
]
]
-- | This property creates an array, initialises its elements, then
-- reads the elements to check that it worked correctly.
prop_CreateWriteRead :: Int -> TestST2 Bool
prop_CreateWriteRead n0 =
let n = n0 `mod` 0x100 in
let ks = [0 .. n-1] in
TestST2 $ PureST2 $
do xs <- newST2Array_ (0,n-1)
sequence_
[ writeST2Array xs k k
| k <- ks
]
ks' <- mapM (readST2Array xs) ks
return (ks == ks')
-- | This property is a demonstration of how a read-only array can be
-- returned through 'readOnlyST2'. The type checker rejects this code if
-- prop_ST2RArray_helper returns an 'ST2Array' rather than an
-- 'ST2RArray'.
prop_ST2RArray :: Int -> TestST2 Bool
prop_ST2RArray n0 =
let n = n0 `mod` 0x100 in
let ks = [0 .. n-1] in
TestST2 $ PureST2 $
do xs <- readOnlyST2 (prop_ST2RArray_helper n)
ks' <- mapM (readST2RArray xs) ks
return (ks == ks')
prop_ST2RArray_helper :: Int -> ST2 r w (ST2RArray r Int Int)
prop_ST2RArray_helper n =
do xs <- newST2Array_ (0,n-1)
sequence_
[ writeST2Array xs i i
| i <- [0 .. n-1]
]
return (mkST2RArray xs)
prop_parallelST2 :: Int -> TestST2 Bool
prop_parallelST2 k0 =
let nShift = 12 in
let k = k0 `mod` (nShift+1) in
let n = (1 :: Int) `shiftL` nShift in
TestST2 $ PureST2 $
do let bnds = (0,n-1)
xs <- newST2Array_ bnds
let n' = n `shiftR` k
let bnds' = (0,n'-1)
-- Initialise the array, using multiple threads.
parallelST2 bnds' $ \i ->
sequence_
[ let j' = (i `shiftL` k) .|. j in
writeST2Array xs j' j'
| j <- [0 .. (1 `shiftL` k) - 1]
]
-- Compute sub-totals, using multiple threads.
ys <- newST2Array_ bnds'
parallelST2 bnds' $ \i ->
do Sum total <-
execWriterT $
sequence_
[ do x <- lift $ readST2Array xs ((i `shiftL` k) .|. j)
tell (Sum x)
| j <- [0 .. (1 `shiftL` k) - 1]
]
writeST2Array ys i total
-- Sum the sub-totals.
Sum total <-
execWriterT $
sequence_
[ do y <- lift $ readST2Array ys i
tell (Sum y)
| i <- [0 .. n' - 1]
]
-- Check the answer.
return (total == (n * (n-1)) `div` 2)