blob: d14ef28e5dc12df5b73b62a47ac7f36e8244185c [file]
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DisambiguateRecordFields #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE ImplicitParams #-}
{- LANGUAGE ImplicitPrelude #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE PartialTypeSignatures #-}
{- LANGUAGE RebindableSyntax #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{- LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# OPTIONS_GHC -Wno-missing-fields #-}
{- OPTIONS_GHC -F -pgmFderive -optF-F #-}
module WordArray where
import Control.Exception (bracket)
import Control.Lens hiding (elements)
-- import Control.Monad.State
import Control.Monad (void)
import Control.Monad.Trans.Class (lift)
import Data.Array.IArray
import Data.Array.IO hiding (newArray)
import Data.Either.Extra -- extra-1.6
-- import Data.Function
import Data.Functor.Classes
import Data.Ix
import Data.List (genericDrop, genericTake)
import qualified Data.Set as S
-- import qualified Data.Set.Internal as S
import Enumerate
import Foreign hiding (void)
import Foreign.C.String hiding (CString)
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Marshal.Alloc
import Foreign.Marshal.Unsafe (unsafeLocalState)
import Foreign.Ptr
import Foreign.Storable
import GHC.Generics
import Prelude as P
-- import QuickCheck.GenT
import Test.QuickCheck hiding (Success)
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Function
import Test.QuickCheck.Gen
import Test.QuickCheck.Monadic
import CogentMonad
import Corres
import Wa_FFI_Types
import Wa_FFI_Types_Abs
import Wa_FFI
import Util
-- import Debug.Trace
{- |
To run the REPL:
> cabal v1-repl wa-example --ghc-options=" wa_example/build/wa.o"
-}
-- * Haskell specification
-- | The Haskell type for wordarrays
type WordArray e = Array Word32 e
data O = O_mallocFail
| O_zeroLengthFail
| O_good
deriving (Show, Generic, Enumerable)
empty_array :: WordArray e
empty_array = array (0, 0) []
hs_wordarray_create :: (?o :: O, Integral e) => Word32 -> Maybe (WordArray e)
hs_wordarray_create 0
| O_zeroLengthFail <- ?o = Nothing
| otherwise = Just (array (1,0) [])
hs_wordarray_create l
| O_mallocFail <- ?o = Nothing
| otherwise = Just (listArray (0, l-1) (repeat 0))
hs_wordarray_create_nd :: (Integral e) => Word32 -> CogentMonad (Maybe (WordArray e))
hs_wordarray_create_nd 0 = return Nothing <|> return (Just $ array (1,0) []) -- either nothing or empty array
hs_wordarray_create_nd l = return Nothing <|> return (Just $ listArray (0, l-1) (repeat 0))
hs_wordarray_create_nz :: (Integral e, ?o :: O) => Word32 -> Maybe (WordArray e)
hs_wordarray_create_nz 0
| O_zeroLengthFail <- ?o = Nothing
| otherwise = Just (array (1,0) [])
hs_wordarray_create_nz l
| O_mallocFail <- ?o = Nothing
| otherwise = Just (array (0, l-1) [(i,v) | i <- [0..l-1], v <- [0]])
hs_wordarray_free :: WordArray e -> ()
hs_wordarray_free _ = ()
hs_wordarray_get_bounded :: Integral e => WordArray e -> Word32 -> Maybe e
hs_wordarray_get_bounded xs i =
if i `is_inbound` xs then Just $ xs ! i else Nothing
is_inbound :: Word32 -> WordArray e -> Bool
is_inbound i xs = case bounds xs of (l,u) -> l <= i && i <= u
hs_wordarray_modify :: WordArray e
-> Word32
-> ((e, acc, obsv) -> (e, acc))
-> acc
-> obsv
-> (WordArray e, acc)
hs_wordarray_modify xs i f acc obsv
| i `is_inbound` xs =
let (e',acc') = f (xs ! i, acc, obsv)
in (xs // [(i, e')], acc')
| otherwise = (xs, acc)
-- | __NOTE__: We also need to specify all inner functions used. As on the Cogent
-- side, due to the way higher-order function calls are made, we cannot generate
-- random functions for testing. The way we test higher-order functions is
-- to show that for all callable inner functions, the outer function behaves
-- correctly.
--
-- In the case of @wordarray_modify@, @modify_bofy_f@ is the only callable
-- function. This can be seem in the @dispatch@ functions generated in the .h file. / zilinc
hs_modify_body_f :: (Word8, Word8, Bool) -> (Word8, Word8)
hs_modify_body_f (e, acc, obsv) =
if obsv then (e + acc, e + acc) else (e, acc)
hs_wordarray_put :: WordArray e -> Word32 -> e -> Either (WordArray e) (WordArray e)
hs_wordarray_put xs i _ | not (i `is_inbound` xs) = Left xs
hs_wordarray_put xs i a = Right $ xs // [(i,a)]
hs_wordarray_length :: WordArray e -> Word32
hs_wordarray_length = fromIntegral . length
hs_wordarray_clone :: (?o :: O) => WordArray e -> Maybe (WordArray e)
hs_wordarray_clone xs
| O_mallocFail <- ?o = Nothing
| otherwise = Just xs
hs_wordarray_set :: WordArray a -> Word32 -> Word32 -> a -> WordArray a
hs_wordarray_set arr frm n a =
let len = hs_wordarray_length arr
to = min (frm + n) len - 1
in if frm >= len then arr
else arr // (zip [frm .. to] (repeat a))
hs_wordarray_copy :: WordArray e -> WordArray e -> Word32 -> Word32 -> Word32 -> WordArray e
hs_wordarray_copy dst src dst_offs src_offs n =
let len_dst = fromIntegral $ length dst
len_src = fromIntegral $ length src
dst_avl = len_dst - dst_offs
src_avl = len_src - src_offs
n' = minimum [n, dst_avl, src_avl]
src_cpy = genericTake n' . genericDrop src_offs $ elems src
in if dst_offs > len_dst - 1 || src_offs > len_src - 1 then dst
else dst // zip [dst_offs .. dst_offs + n' - 1] src_cpy
hs_wordarray_map :: WordArray e
-> (e -> e)
-> WordArray e
hs_wordarray_map xs f = fmap f xs
hs_map_body_f = (+1)
hs_map_body_g = (*2)
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Testing @wordarray_create@.
prop_corres_wordarray_create_u8 :: Property
prop_corres_wordarray_create_u8 =
forAll (pure O_good) $ \o -> let ?o = o in
monadicIO $ forAllM gen_c_wordarray_create_u8_arg $ \ic -> run $ do
oa <- hs_wordarray_create @ Word8 <$> abs_wordarray_create_u8_arg ic
bracket (cogent_wordarray_create_u8 ic)
(\oc -> do Ct8 tag err suc <- peek oc
if | fromEnum tag == fromEnum tagEnumError -> return ()
| fromEnum tag == fromEnum tagEnumSuccess -> do
psuc <- new suc
cogent_wordarray_free_u8 psuc
return ()
| otherwise -> fail "impossible")
(\oc -> corresM' rel_wordarray_create_u8_ret oa oc)
prop_corres_wordarray_create_u8_nd :: Property
prop_corres_wordarray_create_u8_nd = monadicIO $
forAllM gen_c_wordarray_create_u8_arg $ \ic -> run $ do
oa <- hs_wordarray_create_nd @ Word8 <$> abs_wordarray_create_u8_arg ic
bracket (cogent_wordarray_create_u8 ic)
(\oc -> do Ct8 tag err suc <- peek oc
if | fromEnum tag == fromEnum tagEnumError -> return ()
| fromEnum tag == fromEnum tagEnumSuccess -> do
psuc <- new suc
cogent_wordarray_free_u8 psuc
return ()
| otherwise -> fail "impossible")
(\oc -> corresM rel_wordarray_create_u8_ret oa oc)
prop_equiv_wordarray_create_u8 :: Property
prop_equiv_wordarray_create_u8 =
forAll (choose (0, 4095) :: Gen Word32) $ \l ->
let d_os = flip map (enumerated :: [O]) $ \o ->
let ?o = o
in hs_wordarray_create @ Word8 l
nd_os = hs_wordarray_create_nd l
in liftEq eq (S.fromList d_os) (S.fromList nd_os)
where eq :: Maybe (WordArray Word8) -> Maybe (WordArray Word8) -> Bool
eq Nothing Nothing = True
eq (Just a1) (Just a2) = length a1 == length a2
eq _ _ = False
gen_c_wordarray_create_u8_arg :: Gen (Ptr Ct7)
gen_c_wordarray_create_u8_arg = do
let p1 = unsafeLocalState pDummyCSysState
ct6 <- Ct7 p1 <$> choose (0, 4095)
return $ unsafeLocalState $ new ct6
abs_wordarray_create_u8_arg :: Ptr Ct7 -> IO Word32
abs_wordarray_create_u8_arg ia = do
Ct7 _ p2 <- peek ia
return $ fromIntegral p2
rel_wordarray_create_u8_ret :: Maybe (WordArray Word8) -> Ptr Ct8 -> IO Bool
rel_wordarray_create_u8_ret oa oc = do
Ct8 tag err suc <- peek oc
if | fromEnum tag == fromEnum tagEnumError , Nothing <- oa -> return True
| fromEnum tag == fromEnum tagEnumSuccess, Just _ <- oa -> return True -- nothing that we can check about the values of the wordarrays
| otherwise -> return False
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Testing @wordarray_create_nz@
prop_corres_wordarray_create_nz_u8 :: Property
prop_corres_wordarray_create_nz_u8 =
forAll (pure O_good) $ \o -> let ?o = o in
monadicIO $ forAllM gen_c_wordarray_create_nz_u8_arg $ \ic -> run $ do
oa <- hs_wordarray_create_nz @ Word8 <$> abs_wordarray_create_nz_u8_arg ic
bracket (cogent_wordarray_create_nz_u8 ic)
(\oc -> do Ct8 tag err suc <- peek oc
if | fromEnum tag == fromEnum tagEnumError -> return ()
| fromEnum tag == fromEnum tagEnumSuccess -> do
psuc <- new suc
cogent_wordarray_free_u8 psuc
return ()
| otherwise -> fail "impossible")
(\oc -> corresM' rel_wordarray_create_nz_u8_ret oa oc)
gen_c_wordarray_create_nz_u8_arg :: Gen (Ptr Ct7)
gen_c_wordarray_create_nz_u8_arg = gen_c_wordarray_create_u8_arg
abs_wordarray_create_nz_u8_arg :: Ptr Ct7 -> IO Word32
abs_wordarray_create_nz_u8_arg = abs_wordarray_create_u8_arg
rel_wordarray_create_nz_u8_ret :: Maybe (WordArray Word8) -> Ptr Ct8 -> IO Bool
rel_wordarray_create_nz_u8_ret oa oc = do
Ct8 tag err suc <- peek oc
if | fromEnum tag == fromEnum tagEnumError , Nothing <- oa -> return True
| fromEnum tag == fromEnum tagEnumSuccess, Just hs_arr <- oa -> do
let Ct6 _ parr = suc
rel_wordarray_u8 hs_arr parr
| otherwise -> return False
rel_wordarray_u8 :: WordArray Word8 -> Ptr (CWordArray_u8) -> IO Bool
rel_wordarray_u8 hs_arr c_arr = do
CWordArray_u8 len pvalues <- peek c_arr
arr <- peekArray (fromIntegral len) pvalues
return $ map fromIntegral (elems hs_arr) == arr
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Testing @wordarray_get_bounded@
prop_corres_wordarray_get_bounded_u8 :: Property
prop_corres_wordarray_get_bounded_u8 = monadicIO $
forAllM gen_c_wordarray_get_bounded_u8_arg $ \ic -> run $ do
(arr, idx) <- abs_wordarray_get_bounded_u8_arg ic
let oa = hs_wordarray_get_bounded @ Word8 arr idx
oc <- cogent_wordarray_get_bounded_u8 ic
bracket (return ic)
(\ic -> do Ct2 parr _ <- peek ic
CWordArray_u8 _ pvalues <- peek parr
free pvalues
free parr)
(\_ -> corresM' rel_wordarray_get_bounded_u8_ret oa oc)
prop_corres_wordarray_get_bounded_u8' :: Property
prop_corres_wordarray_get_bounded_u8' = monadicIO $
forAllM gen_c_wordarray_get_bounded_u8_arg' $ \(elems,idx) -> run $ do
let (arr,idx') = mk_hs_wordarray_get_bounded_u8_arg (elems,idx)
oa = hs_wordarray_get_bounded @ Word8 arr idx'
bracket (mk_c_wordarray_get_bounded_u8_arg (elems,idx))
(\ic -> do Ct2 parr _ <- peek ic
free_CWordArray_u8 parr)
(\ic -> do oc <- cogent_wordarray_get_bounded_u8 ic
corresM' rel_wordarray_get_bounded_u8_ret oa oc)
-- NOTE: length can't be 0. Otherwise segfault. / zilinc
gen_c_wordarray_get_bounded_u8_arg :: Gen (Ptr Ct2)
gen_c_wordarray_get_bounded_u8_arg = do
l <- choose (1, 200) :: Gen CInt
arr <- gen_CWordArray_u8 (fromIntegral l)
let parr = unsafeLocalState $ new arr
idx <- frequency [(1, fmap (+l) $ getPositive <$> (arbitrary :: Gen (Positive CInt))), (3, choose (0, l))]
return $ unsafeLocalState $ new (Ct2 parr (fromIntegral idx))
gen_CWordArray_u8 :: Int -> Gen CWordArray_u8
gen_CWordArray_u8 l = do
let parr = unsafeLocalState (mallocArray l) :: Ptr Cu8
elems <- vector l :: Gen [Cu8]
unit <- return . unsafeLocalState $ pokeArray parr elems
return $ unit `seq` CWordArray_u8 (fromIntegral l) parr
gen_c_wordarray_get_bounded_u8_arg' :: Gen ([Word8], Word32)
gen_c_wordarray_get_bounded_u8_arg' = do
l <- choose (1, 200) :: Gen Int
elems <- vector l :: Gen [Word8]
idx <- frequency [(1, fmap (+l) $ getNonNegative <$> arbitrary), (3, choose (0, l-1))]
return (elems, fromIntegral idx)
mk_c_wordarray_u8 :: [Word8] -> IO (Ptr CWordArray_u8)
mk_c_wordarray_u8 elems = do
let l = length elems
pvalues <- newArray (map fromIntegral elems :: [Cu8])
new $ CWordArray_u8 (fromIntegral l) pvalues
mk_c_wordarray_get_bounded_u8_arg :: ([Word8], Word32) -> IO (Ptr Ct2)
mk_c_wordarray_get_bounded_u8_arg (elems, idx) = do
parr <- mk_c_wordarray_u8 elems
new $ Ct2 parr (fromIntegral idx)
mk_hs_wordarray_get_bounded_u8_arg :: ([Word8], Word32) -> (WordArray Word8, Word32)
mk_hs_wordarray_get_bounded_u8_arg (elems, idx) =
let arr = listWordArray elems
in (arr, idx)
abs_wordarray_get_bounded_u8_arg :: Ptr Ct2 -> IO (WordArray Word8, Word32)
abs_wordarray_get_bounded_u8_arg ia = do
Ct2 carr cidx <- peek ia
arr <- abs_CWordArray_u8 =<< peek carr
let idx = fromIntegral cidx
return (arr, idx)
abs_CWordArray_u8 :: CWordArray_u8 -> IO (WordArray Word8)
abs_CWordArray_u8 (CWordArray_u8 len values) = do
elems <- peekArray (fromIntegral len) values
return $ listArray (0, fromIntegral len - 1) (map fromIntegral elems)
rel_wordarray_get_bounded_u8_ret :: Maybe Word8 -> Ptr Ct16 -> IO Bool
rel_wordarray_get_bounded_u8_ret oa oc = do
Ct16 tag err suc <- peek oc
if | fromEnum tag == fromEnum tagEnumError , Nothing <- oa -> return True
| fromEnum tag == fromEnum tagEnumSuccess, Just a <- oa -> do
return $ fromIntegral a == suc
| otherwise -> return False
free_CWordArray_u8 :: Ptr CWordArray_u8 -> IO ()
free_CWordArray_u8 parr = do
CWordArray_u8 _ pvalues <- peek parr
free pvalues
free parr
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Testing @wordarray_put@
prop_corres_wordarray_put_u8 :: Property
prop_corres_wordarray_put_u8 = monadicIO $
forAllM gen_wordarray_put_u8_arg' $ \args -> run $ do
let ia = mk_hs_wordarray_put_u8_arg args
oa = uncurry3 hs_wordarray_put ia
bracket (mk_c_wordarray_put_u8_arg args)
(\ic -> do Ct9 parr _ _ <- peek ic
free_CWordArray_u8 parr)
(\ic -> do oc <- cogent_wordarray_put_u8 ic
corresM' rel_wordarray_put_u8_ret oa oc)
gen_wordarray_put_u8_arg' :: Gen ([Word8], Word32, Word8)
gen_wordarray_put_u8_arg' = do
l <- choose (1, 200) :: Gen Word32
arr <- vector $ fromIntegral l
idx <- frequency [(1, fmap (+l) $ getNonNegative <$> arbitrary), (3, choose (0, l-1))]
a <- arbitrary :: Gen Word8
return (arr, idx, a)
mk_hs_wordarray_put_u8_arg :: ([Word8], Word32, Word8) -> (WordArray Word8, Word32, Word8)
mk_hs_wordarray_put_u8_arg (elems, idx, a) =
let arr = listWordArray elems
in (arr, idx, a)
mk_c_wordarray_put_u8_arg :: ([Word8], Word32, Word8) -> IO (Ptr Ct9)
mk_c_wordarray_put_u8_arg (elems, idx, a) = do
parr <- mk_c_wordarray_u8 elems
new $ Ct9 parr (fromIntegral idx) (fromIntegral a)
rel_wordarray_put_u8_ret :: Either (WordArray Word8) (WordArray Word8) -> Ptr Ct10 -> IO Bool
rel_wordarray_put_u8_ret oa oc = do
Ct10 tag err suc <- peek oc
if | Left arr <- oa, fromEnum tag == fromEnum tagEnumError -> rel_wordarray_u8 arr err
| Right arr <- oa, fromEnum tag == fromEnum tagEnumSuccess -> rel_wordarray_u8 arr suc
| otherwise -> return False
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Testing @wordarray_set@
prop_corres_wordarray_set_u8 :: Property
prop_corres_wordarray_set_u8 = monadicIO $
forAllM gen_wordarray_set_u8_arg' $ \args -> run $ do
let ia = mk_hs_wordarray_set_u8_arg args
oa = uncurry4 hs_wordarray_set ia
bracket (mk_c_wordarray_set_u8_arg args)
(\ic -> do Ct5 parr _ _ _ <- peek ic
free_CWordArray_u8 parr)
(\ic -> do oc <- cogent_wordarray_set_u8 ic
corresM' rel_wordarray_u8 oa oc)
gen_wordarray_set_u8_arg' :: Gen ([Word8], Word32, Word32, Word8)
gen_wordarray_set_u8_arg' = do
l <- choose (1, 200) :: Gen Word32
arr <- vector $ fromIntegral l
frm <- choose (0, 250)
n <- choose (0, 150)
a <- arbitrary :: Gen Word8
return (arr, frm, n, a)
mk_hs_wordarray_set_u8_arg :: ([Word8], Word32, Word32, Word8)
-> (WordArray Word8, Word32, Word32, Word8)
mk_hs_wordarray_set_u8_arg (arr, frm, n, a) =
let arr' = listWordArray arr
in (arr', frm, n, a)
mk_c_wordarray_set_u8_arg :: ([Word8], Word32, Word32, Word8) -> IO (Ptr Ct5)
mk_c_wordarray_set_u8_arg (arr, frm, n, a) = do
p_arr <- mk_c_wordarray_u8 arr
new $ Ct5 p_arr (fromIntegral frm) (fromIntegral n) (fromIntegral a)
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Testing @wordarray_copy@
prop_corres_wordarray_copy_u8 :: Property
prop_corres_wordarray_copy_u8 = monadicIO $
forAllM gen_wordarray_copy_u8_arg' $ \args -> run $ do
let ia = mk_hs_wordarray_copy_u8_arg args
oa = uncurry5 hs_wordarray_copy ia
bracket (mk_c_wordarray_copy_u8_arg args)
(\ic -> do Ct1 pdst psrc _ _ _ <- peek ic
free_CWordArray_u8 pdst
free_CWordArray_u8 psrc)
(\ic -> do oc <- cogent_wordarray_copy_u8 ic
corresM' rel_wordarray_u8 oa oc)
gen_wordarray_copy_u8_arg' :: Gen ([Word8], [Word8], Word32, Word32, Word32)
gen_wordarray_copy_u8_arg' = do
l_dst <- choose (1, 200) :: Gen Word32
l_src <- choose (1, 200) :: Gen Word32
dst <- vector $ fromIntegral l_dst
src <- vector $ fromIntegral l_src
idx_dst <- choose (0, 199)
idx_src <- choose (0, 199)
len <- choose (0, 99)
return (dst, src, idx_dst, idx_src, len)
mk_hs_wordarray_copy_u8_arg :: ([Word8], [Word8], Word32, Word32, Word32)
-> (WordArray Word8, WordArray Word8, Word32, Word32, Word32)
mk_hs_wordarray_copy_u8_arg (dst, src, idx_dst, idx_src, len) =
let arr_dst = listWordArray dst
arr_src = listWordArray src
in (arr_dst, arr_src, idx_dst, idx_src, len)
mk_c_wordarray_copy_u8_arg :: ([Word8], [Word8], Word32, Word32, Word32) -> IO (Ptr Ct1)
mk_c_wordarray_copy_u8_arg (dst, src, idx_dst, idx_src, len) = do
p_dst <- mk_c_wordarray_u8 dst
p_src <- mk_c_wordarray_u8 src
new $ Ct1 p_dst p_src (fromIntegral idx_dst) (fromIntegral idx_src) (fromIntegral len)
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Testing @wordarray_modify@
prop_corres_wordarray_modify_u8 :: Property
prop_corres_wordarray_modify_u8 = monadicIO $
forAllM gen_wordarray_modify_u8_arg' $ \args -> run $ do
let ia = mk_hs_wordarray_modify_u8_arg args
oa = uncurry5 hs_wordarray_modify ia
bracket (mk_c_wordarray_modify_u8_arg args)
(\ic -> do Ct14 parr _ _ _ _ <- peek ic
free_CWordArray_u8 parr)
(\ic -> do oc <- cogent_wordarray_modify_u8 ic
corresM' rel_wordarray_modify_u8_ret oa oc)
gen_wordarray_modify_u8_arg' :: Gen ([Word8], Word32, Int, Word8, Bool)
gen_wordarray_modify_u8_arg' = do
l <- choose (1, 200) :: Gen Word32
arr <- vector $ fromIntegral l
idx <- frequency [(1, fmap (+l) $ getNonNegative <$> arbitrary), (3, choose (0, l-1))]
f <- elements [1] -- funcEnum
acc <- arbitrary
obsv <- arbitrary
return (arr, idx, f, acc, obsv)
mk_hs_wordarray_modify_u8_arg :: ([Word8], Word32, Int, Word8, Bool)
-> (WordArray Word8, Word32, (Word8, Word8, Bool) -> (Word8, Word8), Word8, Bool)
mk_hs_wordarray_modify_u8_arg (elems, idx, f, acc, obsv) =
let arr = listWordArray elems
f' = case f of 1 -> hs_modify_body_f
in (arr, idx, f', acc, obsv)
mk_c_wordarray_modify_u8_arg :: ([Word8], Word32, Int, Word8, Bool)
-> IO (Ptr Ct14)
mk_c_wordarray_modify_u8_arg (elems, idx, f, acc, obsv) = do
parr <- mk_c_wordarray_u8 elems
new $ Ct14 parr (fromIntegral idx) (toEnum f) (fromIntegral acc) (mk_c_bool obsv)
mk_c_bool :: Bool -> Cbool_t
mk_c_bool b = Cbool_t $ fromIntegral $ if b then 1 else 0
rel_wordarray_modify_u8_ret :: (WordArray Word8, Word8) -> Ptr Ct15 -> IO Bool
rel_wordarray_modify_u8_ret (hs_arr, hs_acc) oc = do
Ct15 c_arr c_acc <- peek oc
barr <- rel_wordarray_u8 hs_arr c_arr
return $ barr && (fromIntegral hs_acc == c_acc)
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Testing @wordarray_map@
prop_corres_wordarray_map_u8 :: Property
prop_corres_wordarray_map_u8 = monadicIO $
forAllM gen_wordarray_map_u8_arg' $ \args -> run $ do
let ia = mk_hs_wordarray_map_u8_arg args
oa = uncurry hs_wordarray_map ia
bracket (mk_c_wordarray_map_u8_arg args)
(\ic -> do Ct4 parr _ <- peek ic
free_CWordArray_u8 parr)
(\ic -> do oc <- cogent_wordarray_map_u8 ic
corresM' rel_wordarray_u8 oa oc)
gen_wordarray_map_u8_arg' :: Gen ([Word8], Int)
gen_wordarray_map_u8_arg' = do
l <- choose (1, 200) :: Gen Word32
arr <- vector $ fromIntegral l
f <- elements [0, 1] -- funcEnum
return (arr, f)
mk_hs_wordarray_map_u8_arg :: ([Word8], Int) -> (WordArray Word8, Word8 -> Word8)
mk_hs_wordarray_map_u8_arg (elems, f) =
let arr = listWordArray elems
f' = case f of 0 -> hs_map_body_f
1 -> hs_map_body_g
in (arr, f')
mk_c_wordarray_map_u8_arg :: ([Word8], Int) -> IO (Ptr Ct4)
mk_c_wordarray_map_u8_arg (elems, f) = do
parr <- mk_c_wordarray_u8 elems
new $ Ct4 parr (toEnum f)
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Properties atop the Haskell spec.
prop_wordarray_get_put =
forAll (choose (1, 200)) $ \len ->
forAll (vector len :: Gen [Word8]) $ \elems ->
forAll (choose (0, 2 * fromIntegral len)) $ \idx ->
forAll (arbitrary :: Gen Word8) $ \val ->
let arr = listWordArray elems
r = hs_wordarray_put arr idx val
in if | idx < fromIntegral len, Right arr' <- r ->
let Just val' = hs_wordarray_get_bounded arr' idx
in val == val'
| idx >= fromIntegral len, Left arr' <- r ->
arr' == arr
| otherwise -> False
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Helper functions
listWordArray :: [a] -> WordArray a
listWordArray arr = listArray (0, fromIntegral (length arr - 1)) arr
-- /////////////////////////////////////////////////////////////////////////////
--
-- * Main function
return []
main = $quickCheckAll