File: Support.hs

package info (click to toggle)
haskell-bitvec 1.1.5.0-4
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 332 kB
  • sloc: haskell: 3,408; ansic: 397; makefile: 5
file content (176 lines) | stat: -rw-r--r-- 5,955 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
{-# LANGUAGE CPP                 #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE FlexibleInstances   #-}
{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE ScopedTypeVariables #-}

{-# OPTIONS_GHC -fno-warn-orphans #-}

module Support where

import Control.Monad.ST
import Data.Bit
import qualified Data.Bit.ThreadSafe as TS
import Data.Bits
import qualified Data.Vector.Generic as V
import qualified Data.Vector.Generic.Mutable as M
import qualified Data.Vector.Generic.New as N
import qualified Data.Vector.Unboxed as U
import Test.Tasty
import Test.Tasty.QuickCheck

#ifdef MIN_VERSION_quickcheck_classes_base
import Test.QuickCheck.Classes.Base
#endif
#ifdef MIN_VERSION_quickcheck_classes
import qualified Test.QuickCheck.Classes as QCC
#endif

instance Arbitrary Bit where
  arbitrary = Bit <$> arbitrary
  shrink    = fmap Bit . shrink . unBit

instance CoArbitrary Bit where
  coarbitrary = coarbitrary . unBit

instance Function Bit where
  function f = functionMap unBit Bit f

instance Arbitrary TS.Bit where
  arbitrary = TS.Bit <$> arbitrary
  shrink    = fmap TS.Bit . shrink . TS.unBit

instance CoArbitrary TS.Bit where
  coarbitrary = coarbitrary . TS.unBit

instance Function TS.Bit where
  function f = functionMap TS.unBit TS.Bit f

instance (Arbitrary a, U.Unbox a) => Arbitrary (U.Vector a) where
  arbitrary = frequency
    [ (10, U.fromList <$> arbitrary)
    , (2 , U.drop <$> arbitrary <*> arbitrary)
    , (2 , U.take <$> arbitrary <*> arbitrary)
    , (2 , slice <$> arbitrary <*> arbitrary <*> arbitrary)
    ]
   where
    slice s n v = let (s', n') = trimSlice s n (U.length v) in U.slice s' n' v
  shrink v = let len = U.length v in
    [ U.take (len - s) v | s <- [1 .. len] ] ++
    [ U.drop s         v | s <- [1 .. len] ] ++
    [ v U.// [(i, x)] | i <- [0 .. len - 1], x <- shrink (v U.! i) ]

instance {-# OVERLAPPING #-} Arbitrary (Large (U.Vector Bit)) where
  arbitrary = Large . castFromWords <$> arbitrary
  shrink (Large v) = Large <$> shrink v

instance {-# OVERLAPPING #-} Arbitrary (Large (U.Vector TS.Bit)) where
  arbitrary = Large . TS.castFromWords <$> arbitrary
  shrink (Large v) = Large <$> shrink v

instance Arbitrary F2Poly where
  arbitrary = toF2Poly <$> arbitrary
  shrink v = toF2Poly <$> shrink (unF2Poly v)

instance {-# OVERLAPPING #-} Arbitrary (Large F2Poly) where
  arbitrary = Large . toF2Poly . castFromWords <$> arbitrary
  shrink (Large v) = Large . toF2Poly <$> shrink (unF2Poly v)

instance (Show (v a), V.Vector v a) => Show (N.New v a) where
  showsPrec p = showsPrec p . V.new

newFromList :: forall a v . V.Vector v a => [a] -> N.New v a
newFromList xs = N.create (V.thaw (V.fromList xs :: v a))

-- this instance is designed to make sure that the arbitrary vectors we work with are not all nicely aligned; we need to deal with cases where the vector is a weird slice of some other vector.
instance (V.Vector v a, Arbitrary a) => Arbitrary (N.New v a) where
  arbitrary = frequency
    [ (10, newFromList <$> arbitrary)
    , (2 , N.drop <$> arbitrary <*> arbitrary)
    , (2 , N.take <$> arbitrary <*> arbitrary)
    , (2 , slice <$> arbitrary <*> arbitrary <*> arbitrary)
    ]
   where
    slice s n = N.apply
      $ \v -> let (s', n') = trimSlice s n (M.length v) in M.slice s' n' v
  shrink v =
    [ N.take s v | s <- [0 .. len - 1] ] ++
    [ N.drop s v | s <- [1 .. len] ]
    where len = runST (M.length <$> N.run v)

trimSlice :: Integral a => a -> a -> a -> (a, a)
trimSlice s n l = (s', n')
 where
  s' | l == 0    = 0
     | otherwise = s `mod` l
  n' | s' == 0   = 0
     | otherwise = n `mod` (l - s')

sliceList :: Int -> Int -> [a] -> [a]
sliceList s n = take n . drop s

wordSize :: Int
wordSize = finiteBitSize (0 :: Word)

packBitsToWord :: FiniteBits a => [Bit] -> (a, [Bit])
packBitsToWord = loop 0 zeroBits
 where
  loop _ w [] = (w, [])
  loop i w (x : xs)
    | i >= finiteBitSize w = (w, x : xs)
    | otherwise            = loop (i + 1) (if unBit x then setBit w i else w) xs

readWordL :: [Bit] -> Int -> Word
readWordL xs 0 = fst (packBitsToWord xs)
readWordL xs n = readWordL (drop n xs) 0

wordToBitList :: FiniteBits a => a -> [Bit]
wordToBitList w = [ Bit (testBit w i) | i <- [0 .. finiteBitSize w - 1] ]

writeWordL :: [Bit] -> Int -> Word -> [Bit]
writeWordL xs 0 w = zipWith const (wordToBitList w) xs ++ drop wordSize xs
writeWordL xs n w = pre ++ writeWordL post 0 w
  where (pre, post) = splitAt n xs

prop_writeWordL_preserves_length :: [Bit] -> NonNegative Int -> Word -> Property
prop_writeWordL_preserves_length xs (NonNegative n) w =
  length (writeWordL xs n w) === length xs

prop_writeWordL_preserves_prefix :: [Bit] -> NonNegative Int -> Word -> Property
prop_writeWordL_preserves_prefix xs (NonNegative n) w =
  take n (writeWordL xs n w) === take n xs

prop_writeWordL_preserves_suffix :: [Bit] -> NonNegative Int -> Word -> Property
prop_writeWordL_preserves_suffix xs (NonNegative n) w =
  drop (n + wordSize) (writeWordL xs n w) === drop (n + wordSize) xs

prop_writeWordL_readWordL :: [Bit] -> Int -> Property
prop_writeWordL_readWordL xs n = writeWordL xs n (readWordL xs n) === xs

withNonEmptyMVec
  :: (Eq t, Show t)
  => (U.Vector Bit -> t)
  -> (forall s . U.MVector s Bit -> ST s t)
  -> Property
withNonEmptyMVec f g = forAll arbitrary $ \xs ->
  let xs' = V.new xs in not (U.null xs') ==> f xs' === runST (N.run xs >>= g)

tenTimesLess :: TestTree -> TestTree
tenTimesLess = adjustOption $
  \(QuickCheckTests n) -> QuickCheckTests (max 100 (n `div` 10))

twoTimesMore :: TestTree -> TestTree
twoTimesMore = adjustOption $
  \(QuickCheckTests n) -> QuickCheckTests (n * 2)

#ifdef MIN_VERSION_quickcheck_classes_base
lawsToTest :: Laws -> TestTree
lawsToTest (Laws name props) =
  testGroup name $ map (uncurry testProperty) props
#endif

#ifdef MIN_VERSION_quickcheck_classes
lawsToTest' :: QCC.Laws -> TestTree
lawsToTest' (QCC.Laws name props) =
  testGroup name $ map (uncurry testProperty) props
#endif