Skip to content

Commit ceaaae0

Browse files
committed
Move out arbitrary Set and Map construction
1 parent 13c97ef commit ceaaae0

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
@@ -268,6 +268,9 @@ test-suite map-lazy-properties
268268
main-is: map-properties.hs
269269
type: exitcode-stdio-1.0
270270

271+
other-modules:
272+
Utils.ArbitrarySetMap
273+
271274
ghc-options: -O2
272275
other-extensions:
273276
BangPatterns
@@ -281,6 +284,9 @@ test-suite map-strict-properties
281284
type: exitcode-stdio-1.0
282285
cpp-options: -DSTRICT
283286

287+
other-modules:
288+
Utils.ArbitrarySetMap
289+
284290
ghc-options: -O2
285291
other-extensions:
286292
BangPatterns
@@ -304,6 +310,9 @@ test-suite set-properties
304310
main-is: set-properties.hs
305311
type: exitcode-stdio-1.0
306312

313+
other-modules:
314+
Utils.ArbitrarySetMap
315+
307316
ghc-options: -O2
308317
other-extensions:
309318
BangPatterns
@@ -402,6 +411,7 @@ test-suite map-strictness-properties
402411
CPP
403412

404413
other-modules:
414+
Utils.ArbitrarySetMap
405415
Utils.Strictness
406416

407417
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)
37-
import Control.Arrow (first)
37+
38+
import Utils.ArbitrarySetMap (mkArbMap)
3839

3940
default (Int)
4041

@@ -297,7 +298,7 @@ instance (IsInt k, Arbitrary v) => Arbitrary (Map k v) where
297298
middle <- choose (-positionFactor * (sz + 1), positionFactor * (sz + 1))
298299
let shift = (sz * (gapRange) + 1) `quot` 2
299300
start = middle - shift
300-
t <- evalStateT (mkArb step sz) start
301+
t <- evalStateT (mkArbMap step sz) start
301302
if valid t then pure t else error "Test generated invalid tree!")
302303
where
303304
step = do
@@ -307,39 +308,6 @@ instance (IsInt k, Arbitrary v) => Arbitrary (Map k v) where
307308
put i'
308309
pure (fromInt i')
309310

310-
class Monad m => MonadGen m where
311-
liftGen :: Gen a -> m a
312-
instance MonadGen Gen where
313-
liftGen = id
314-
instance MonadGen m => MonadGen (StateT s m) where
315-
liftGen = lift . liftGen
316-
317-
-- | Given an action that produces successively larger keys and
318-
-- a size, produce a map of arbitrary shape with exactly that size.
319-
mkArb :: (MonadGen m, Arbitrary v) => m k -> Int -> m (Map k v)
320-
mkArb step n
321-
| n <= 0 = return Tip
322-
| n == 1 = do
323-
k <- step
324-
v <- liftGen arbitrary
325-
return (singleton k v)
326-
| n == 2 = do
327-
dir <- liftGen arbitrary
328-
p <- step
329-
q <- step
330-
vOuter <- liftGen arbitrary
331-
vInner <- liftGen arbitrary
332-
if dir
333-
then return (Bin 2 q vOuter (singleton p vInner) Tip)
334-
else return (Bin 2 p vOuter Tip (singleton q vInner))
335-
| otherwise = do
336-
-- This assumes a balance factor of delta = 3
337-
let upper = (3*(n - 1)) `quot` 4
338-
let lower = (n + 2) `quot` 4
339-
ln <- liftGen $ choose (lower, upper)
340-
let rn = n - ln - 1
341-
liftM4 (\lt x v rt -> Bin n x v lt rt) (mkArb step ln) step (liftGen arbitrary) (mkArb step rn)
342-
343311
-- A type with a peculiar Eq instance designed to make sure keys
344312
-- come from where they're supposed to.
345313
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
@@ -222,7 +221,7 @@ instance IsInt a => Arbitrary (Set a) where
222221
middle <- choose (-positionFactor * (sz + 1), positionFactor * (sz + 1))
223222
let shift = (sz * (gapRange) + 1) `quot` 2
224223
start = middle - shift
225-
t <- evalStateT (mkArb step sz) start
224+
t <- evalStateT (mkArbSet step sz) start
226225
if valid t then pure t else error "Test generated invalid tree!")
227226
where
228227
step = do
@@ -232,47 +231,6 @@ instance IsInt a => Arbitrary (Set a) where
232231
put i'
233232
pure (fromInt i')
234233

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

278236
data TwoLists a = TwoLists [a] [a]

0 commit comments

Comments
 (0)