Skip to content

Commit 7f4d14e

Browse files
committed
Move out arbitrary Set and Map construction
1 parent 953bc1f commit 7f4d14e

File tree

5 files changed

+157
-83
lines changed

5 files changed

+157
-83
lines changed

containers-tests/containers-tests.cabal

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ test-suite map-lazy-properties
269269
main-is: map-properties.hs
270270
type: exitcode-stdio-1.0
271271

272+
other-modules:
273+
Utils.ArbitrarySetMap
274+
272275
ghc-options: -O2
273276
other-extensions:
274277
BangPatterns
@@ -282,6 +285,9 @@ test-suite map-strict-properties
282285
type: exitcode-stdio-1.0
283286
cpp-options: -DSTRICT
284287

288+
other-modules:
289+
Utils.ArbitrarySetMap
290+
285291
ghc-options: -O2
286292
other-extensions:
287293
BangPatterns
@@ -305,6 +311,9 @@ test-suite set-properties
305311
main-is: set-properties.hs
306312
type: exitcode-stdio-1.0
307313

314+
other-modules:
315+
Utils.ArbitrarySetMap
316+
308317
ghc-options: -O2
309318
other-extensions:
310319
BangPatterns
@@ -403,6 +412,7 @@ test-suite map-strictness-properties
403412
CPP
404413

405414
other-modules:
415+
Utils.ArbitrarySetMap
406416
Utils.Strictness
407417

408418
if impl(ghc >= 8.6)
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
module Utils.ArbitrarySetMap
2+
(
3+
-- MonadGen
4+
MonadGen(..)
5+
6+
-- Set
7+
, mkArbSet
8+
, setFromList
9+
10+
-- Map
11+
, mkArbMap
12+
, mapFromKeysList
13+
) where
14+
15+
import Control.Monad (liftM, liftM3, liftM4)
16+
import Control.Monad.Trans.State.Strict
17+
import Control.Monad.Trans.Class
18+
import Test.QuickCheck
19+
20+
import Data.Set (Set)
21+
import qualified Data.Set.Internal as S
22+
import Data.Map (Map)
23+
import qualified Data.Map.Internal as M
24+
25+
{--------------------------------------------------------------------
26+
MonadGen
27+
--------------------------------------------------------------------}
28+
29+
class Monad m => MonadGen m where
30+
liftGen :: Gen a -> m a
31+
instance MonadGen Gen where
32+
liftGen = id
33+
instance MonadGen m => MonadGen (StateT s m) where
34+
liftGen = lift . liftGen
35+
36+
{--------------------------------------------------------------------
37+
Set
38+
--------------------------------------------------------------------}
39+
40+
-- | Given an action that produces successively larger elements and
41+
-- a size, produce a set of arbitrary shape with exactly that size.
42+
mkArbSet :: MonadGen m => m a -> Int -> m (Set a)
43+
mkArbSet step n
44+
| n <= 0 = return S.Tip
45+
| n == 1 = S.singleton `liftM` step
46+
| n == 2 = do
47+
dir <- liftGen arbitrary
48+
p <- step
49+
q <- step
50+
if dir
51+
then return (S.Bin 2 q (S.singleton p) S.Tip)
52+
else return (S.Bin 2 p S.Tip (S.singleton q))
53+
| otherwise = do
54+
-- This assumes a balance factor of delta = 3
55+
let upper = (3*(n - 1)) `quot` 4
56+
let lower = (n + 2) `quot` 4
57+
ln <- liftGen $ choose (lower, upper)
58+
let rn = n - ln - 1
59+
liftM3
60+
(\lt x rt -> S.Bin n x lt rt)
61+
(mkArbSet step ln)
62+
step
63+
(mkArbSet step rn)
64+
{-# INLINABLE mkArbSet #-}
65+
66+
-- | Given a strictly increasing list of elements, produce an arbitrarily
67+
-- shaped set with exactly those elements.
68+
setFromList :: [a] -> Gen (Set a)
69+
setFromList xs = flip evalStateT xs $ mkArbSet step (length xs)
70+
where
71+
step = do
72+
xxs <- get
73+
case xxs of
74+
x : xs -> do
75+
put xs
76+
pure x
77+
[] -> error "setFromList"
78+
79+
{--------------------------------------------------------------------
80+
Map
81+
--------------------------------------------------------------------}
82+
83+
-- | Given an action that produces successively larger keys and
84+
-- a size, produce a map of arbitrary shape with exactly that size.
85+
mkArbMap :: (MonadGen m, Arbitrary v) => m k -> Int -> m (Map k v)
86+
mkArbMap step n
87+
| n <= 0 = return M.Tip
88+
| n == 1 = do
89+
k <- step
90+
v <- liftGen arbitrary
91+
return (M.singleton k v)
92+
| n == 2 = do
93+
dir <- liftGen arbitrary
94+
p <- step
95+
q <- step
96+
vOuter <- liftGen arbitrary
97+
vInner <- liftGen arbitrary
98+
if dir
99+
then return (M.Bin 2 q vOuter (M.singleton p vInner) M.Tip)
100+
else return (M.Bin 2 p vOuter M.Tip (M.singleton q vInner))
101+
| otherwise = do
102+
-- This assumes a balance factor of delta = 3
103+
let upper = (3*(n - 1)) `quot` 4
104+
let lower = (n + 2) `quot` 4
105+
ln <- liftGen $ choose (lower, upper)
106+
let rn = n - ln - 1
107+
liftM4
108+
(\lt x v rt -> M.Bin n x v lt rt)
109+
(mkArbMap step ln)
110+
step
111+
(liftGen arbitrary)
112+
(mkArbMap step rn)
113+
{-# INLINABLE mkArbMap #-}
114+
115+
-- | Given a strictly increasing list of keys, produce an arbitrarily
116+
-- shaped map with exactly those keys.
117+
mapFromKeysList :: Arbitrary a => [k] -> Gen (Map k a)
118+
mapFromKeysList xs = flip evalStateT xs $ mkArbMap step (length xs)
119+
where
120+
step = do
121+
xxs <- get
122+
case xxs of
123+
x : xs -> do
124+
put xs
125+
pure x
126+
[] -> error "mapFromKeysList"
127+
{-# INLINABLE mapFromKeysList #-}

containers-tests/tests/map-properties.hs

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import Data.Map.Merge.Strict
77
import Data.Map.Lazy as Data.Map hiding (showTree, showTreeWith)
88
import Data.Map.Merge.Lazy
99
#endif
10-
import Data.Map.Internal (Map (..), link2, link, bin)
10+
import Data.Map.Internal (Map, link2, link)
1111
import Data.Map.Internal.Debug (showTree, showTreeWith, balanced)
1212

1313
import Control.Applicative (Const(Const, getConst), pure, (<$>), (<*>))
1414
import Control.Monad.Trans.State.Strict
1515
import Control.Monad.Trans.Class
16-
import Control.Monad (liftM4, (<=<))
16+
import Control.Monad ((<=<))
1717
import Data.Functor.Identity (Identity(Identity, runIdentity))
1818
import Data.Monoid
1919
import Data.Maybe hiding (mapMaybe)
@@ -34,7 +34,8 @@ import Test.Tasty.HUnit
3434
import Test.Tasty.QuickCheck
3535
import Test.QuickCheck.Function (apply)
3636
import Test.QuickCheck.Poly (A, B, OrdA)
37-
import Control.Arrow (first)
37+
38+
import Utils.ArbitrarySetMap (mkArbMap)
3839

3940
default (Int)
4041

@@ -299,7 +300,7 @@ instance (IsInt k, Arbitrary v) => Arbitrary (Map k v) where
299300
middle <- choose (-positionFactor * (sz + 1), positionFactor * (sz + 1))
300301
let shift = (sz * (gapRange) + 1) `quot` 2
301302
start = middle - shift
302-
t <- evalStateT (mkArb step sz) start
303+
t <- evalStateT (mkArbMap step sz) start
303304
if valid t then pure t else error "Test generated invalid tree!")
304305
where
305306
step = do
@@ -309,39 +310,6 @@ instance (IsInt k, Arbitrary v) => Arbitrary (Map k v) where
309310
put i'
310311
pure (fromInt i')
311312

312-
class Monad m => MonadGen m where
313-
liftGen :: Gen a -> m a
314-
instance MonadGen Gen where
315-
liftGen = id
316-
instance MonadGen m => MonadGen (StateT s m) where
317-
liftGen = lift . liftGen
318-
319-
-- | Given an action that produces successively larger keys and
320-
-- a size, produce a map of arbitrary shape with exactly that size.
321-
mkArb :: (MonadGen m, Arbitrary v) => m k -> Int -> m (Map k v)
322-
mkArb step n
323-
| n <= 0 = return Tip
324-
| n == 1 = do
325-
k <- step
326-
v <- liftGen arbitrary
327-
return (singleton k v)
328-
| n == 2 = do
329-
dir <- liftGen arbitrary
330-
p <- step
331-
q <- step
332-
vOuter <- liftGen arbitrary
333-
vInner <- liftGen arbitrary
334-
if dir
335-
then return (Bin 2 q vOuter (singleton p vInner) Tip)
336-
else return (Bin 2 p vOuter Tip (singleton q vInner))
337-
| otherwise = do
338-
-- This assumes a balance factor of delta = 3
339-
let upper = (3*(n - 1)) `quot` 4
340-
let lower = (n + 2) `quot` 4
341-
ln <- liftGen $ choose (lower, upper)
342-
let rn = n - ln - 1
343-
liftM4 (\lt x v rt -> Bin n x v lt rt) (mkArb step ln) step (liftGen arbitrary) (mkArb step rn)
344-
345313
-- A type with a peculiar Eq instance designed to make sure keys
346314
-- come from where they're supposed to.
347315
data OddEq a = OddEq a Bool deriving (Show)

containers-tests/tests/map-strictness.hs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ import Data.Map.Merge.Lazy (WhenMatched, WhenMissing)
3030
import qualified Data.Map.Merge.Lazy as LMerge
3131
import Data.Set (Set)
3232
import qualified Data.Set as Set
33+
import Data.Containers.ListUtils (nubOrd)
3334

35+
import Utils.ArbitrarySetMap (setFromList, mapFromKeysList)
3436
import Utils.Strictness
3537
(Bot(..), Func(..), Func2(..), Func3(..), applyFunc, applyFunc2, applyFunc3)
3638

@@ -40,10 +42,19 @@ import Utils.NoThunks
4042

4143
instance (Arbitrary k, Arbitrary v, Ord k) =>
4244
Arbitrary (Map k v) where
43-
arbitrary = M.fromList `fmap` arbitrary
45+
arbitrary = do
46+
Sorted xs <- arbitrary
47+
m <- mapFromKeysList $ nubOrd xs
48+
49+
-- Force the values to WHNF. Should use liftRnf2 when that's available.
50+
let !_ = foldr seq () m
51+
52+
pure m
4453

4554
instance (Arbitrary a, Ord a) => Arbitrary (Set a) where
46-
arbitrary = Set.fromList <$> arbitrary
55+
arbitrary = do
56+
Sorted xs <- arbitrary
57+
setFromList $ nubOrd xs
4758

4859
apply2 :: Fun (a, b) c -> a -> b -> c
4960
apply2 f a b = apply f (a, b)

containers-tests/tests/set-properties.hs

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import qualified Data.IntSet as IntSet
33
import Data.List (nub,sort)
44
import qualified Data.List as List
5-
import Data.Monoid (mempty)
65
import Data.Maybe
76
import Data.Set
87
import Prelude hiding (lookup, null, map, filter, foldr, foldl, foldl', all, take, drop, splitAt)
@@ -12,11 +11,11 @@ import Test.Tasty.QuickCheck
1211
import Test.QuickCheck.Function (apply)
1312
import Control.Monad.Trans.State.Strict
1413
import Control.Monad.Trans.Class
15-
import Control.Monad (liftM, liftM3)
1614
import Data.Functor.Identity
1715
import Data.Foldable (all)
1816
import Control.Applicative (liftA2)
1917

18+
import Utils.ArbitrarySetMap (mkArbSet, setFromList)
2019
#if __GLASGOW_HASKELL__ >= 806
2120
import Utils.NoThunks (whnfHasNoThunks)
2221
#endif
@@ -224,7 +223,7 @@ instance IsInt a => Arbitrary (Set a) where
224223
middle <- choose (-positionFactor * (sz + 1), positionFactor * (sz + 1))
225224
let shift = (sz * (gapRange) + 1) `quot` 2
226225
start = middle - shift
227-
t <- evalStateT (mkArb step sz) start
226+
t <- evalStateT (mkArbSet step sz) start
228227
if valid t then pure t else error "Test generated invalid tree!")
229228
where
230229
step = do
@@ -234,47 +233,6 @@ instance IsInt a => Arbitrary (Set a) where
234233
put i'
235234
pure (fromInt i')
236235

237-
class Monad m => MonadGen m where
238-
liftGen :: Gen a -> m a
239-
instance MonadGen Gen where
240-
liftGen = id
241-
instance MonadGen m => MonadGen (StateT s m) where
242-
liftGen = lift . liftGen
243-
244-
-- | Given an action that produces successively larger elements and
245-
-- a size, produce a set of arbitrary shape with exactly that size.
246-
mkArb :: MonadGen m => m a -> Int -> m (Set a)
247-
mkArb step n
248-
| n <= 0 = return Tip
249-
| n == 1 = singleton `liftM` step
250-
| n == 2 = do
251-
dir <- liftGen arbitrary
252-
p <- step
253-
q <- step
254-
if dir
255-
then return (Bin 2 q (singleton p) Tip)
256-
else return (Bin 2 p Tip (singleton q))
257-
| otherwise = do
258-
-- This assumes a balance factor of delta = 3
259-
let upper = (3*(n - 1)) `quot` 4
260-
let lower = (n + 2) `quot` 4
261-
ln <- liftGen $ choose (lower, upper)
262-
let rn = n - ln - 1
263-
liftM3 (\lt x rt -> Bin n x lt rt) (mkArb step ln) step (mkArb step rn)
264-
265-
-- | Given a strictly increasing list of elements, produce an arbitrarily
266-
-- shaped set with exactly those elements.
267-
setFromList :: [a] -> Gen (Set a)
268-
setFromList xs = flip evalStateT xs $ mkArb step (length xs)
269-
where
270-
step = do
271-
xxs <- get
272-
case xxs of
273-
x : xs -> do
274-
put xs
275-
pure x
276-
[] -> error "setFromList"
277-
278236
data TwoSets = TwoSets (Set Int) (Set Int) deriving (Show)
279237

280238
data TwoLists a = TwoLists [a] [a]

0 commit comments

Comments
 (0)