Skip to content

Commit 59e90f7

Browse files
andrewthadRyanGlScott
authored andcommitted
initial implementation of a more comprehensive test suite (#99)
* initial implementation of a more comprehensive test suite * fix laziness of Eq1 instance. Add Ord1 instance. * correct the definition of <*> * Improve compatibility with older versions of GHC and transformers * add tests for SmallArray and ByteArray. add Eq1, Ord1, and Show1 for SmallArray * fix implementation of <*> for SmallArray. The previous implementation did a pretty cool trick with a fixed-point combinator, but it didn't work. I couldn't figure out how to make it work, so I just copied the implementation used for Array and adapted it to SmallArray. * correct foldrByteArray, which fixes the IsList implementation for ByteArray. Also, improve the performance of ByteArray's fromListN function * improve compatibility with older transformers and base * add tagged as dependency of test suite so Data.Proxy is available for older GHCs * use spaces instead of tab in test cabal file * guard isListLaws with CPP everywhere * redefine fromList function for small array in test suite * remove the accidentally exported fromList functions from Data.Primitive.SmallArray * make fromListN safer for Array, SmallArray, and ByteArray * make compatible with transformers-0.3.0.0 again * document changes in changelog * Bump lower bound for transformers back down to 0.2. Explain the test suite a little in a test suite readme * allow future releases of quickcheck-classes to be accepted * document the SmallArray list conversion functions * add Read1 and Show1 instances for Array and SmallArray. Test Read and Show instances in test suite. * mention Read1 in changelog * Start testing Traversable laws. Test foldl1 and foldr1. Fix foldl1 implementation for Array and SmallArray. * derive Read1 when shimming SmallArray * For test suite, build quickcheck-classes without aeson and semigroupoids to accelerate travis builds * pass cabal flags to more places * remove double quotes from travis environment variable * try to make travis work again * fix cabal flags in travis file again * remove CABAL_FLAGS from travis
1 parent ea0734a commit 59e90f7

File tree

8 files changed

+399
-95
lines changed

8 files changed

+399
-95
lines changed

Data/Primitive/Array.hs

Lines changed: 104 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ import Data.Functor.Identity
6363

6464
import Text.ParserCombinators.ReadP
6565

66+
#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
67+
import Data.Functor.Classes (Eq1(..),Ord1(..),Show1(..),Read1(..))
68+
#endif
69+
6670
-- | Boxed arrays
6771
data Array a = Array
6872
{ array# :: Array# a }
@@ -288,26 +292,50 @@ createArray n x f = runST $ do
288292
die :: String -> String -> a
289293
die fun problem = error $ "Data.Primitive.Array." ++ fun ++ ": " ++ problem
290294

295+
arrayLiftEq :: (a -> b -> Bool) -> Array a -> Array b -> Bool
296+
arrayLiftEq p a1 a2 = sizeofArray a1 == sizeofArray a2 && loop (sizeofArray a1 - 1)
297+
where loop i | i < 0 = True
298+
| (# x1 #) <- indexArray## a1 i
299+
, (# x2 #) <- indexArray## a2 i
300+
, otherwise = p x1 x2 && loop (i-1)
301+
291302
instance Eq a => Eq (Array a) where
292-
a1 == a2 = sizeofArray a1 == sizeofArray a2 && loop (sizeofArray a1 - 1)
293-
where loop i | i < 0 = True
294-
| (# x1 #) <- indexArray## a1 i
295-
, (# x2 #) <- indexArray## a2 i
296-
= x1 == x2 && loop (i-1)
303+
a1 == a2 = arrayLiftEq (==) a1 a2
304+
305+
#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
306+
instance Eq1 Array where
307+
#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
308+
liftEq = arrayLiftEq
309+
#else
310+
eq1 = arrayLiftEq (==)
311+
#endif
312+
#endif
297313

298314
instance Eq (MutableArray s a) where
299315
ma1 == ma2 = isTrue# (sameMutableArray# (marray# ma1) (marray# ma2))
300316

317+
arrayLiftCompare :: (a -> b -> Ordering) -> Array a -> Array b -> Ordering
318+
arrayLiftCompare elemCompare a1 a2 = loop 0
319+
where
320+
mn = sizeofArray a1 `min` sizeofArray a2
321+
loop i
322+
| i < mn
323+
, (# x1 #) <- indexArray## a1 i
324+
, (# x2 #) <- indexArray## a2 i
325+
= elemCompare x1 x2 `mappend` loop (i+1)
326+
| otherwise = compare (sizeofArray a1) (sizeofArray a2)
327+
301328
instance Ord a => Ord (Array a) where
302-
compare a1 a2 = loop 0
303-
where
304-
mn = sizeofArray a1 `min` sizeofArray a2
305-
loop i
306-
| i < mn
307-
, (# x1 #) <- indexArray## a1 i
308-
, (# x2 #) <- indexArray## a2 i
309-
= compare x1 x2 `mappend` loop (i+1)
310-
| otherwise = compare (sizeofArray a1) (sizeofArray a2)
329+
compare a1 a2 = arrayLiftCompare compare a1 a2
330+
331+
#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
332+
instance Ord1 Array where
333+
#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
334+
liftCompare = arrayLiftCompare
335+
#else
336+
compare1 = arrayLiftCompare compare
337+
#endif
338+
#endif
311339

312340
instance Foldable Array where
313341
-- Note: we perform the array lookups eagerly so we won't
@@ -347,7 +375,7 @@ instance Foldable Array where
347375
go i =
348376
case indexArray## ary i of
349377
(# x #) | i == 0 -> x
350-
| otherwise -> f x (go (i - 1))
378+
| otherwise -> f (go (i - 1)) x
351379
in if sz < 0
352380
then die "foldl1" "empty array"
353381
else go sz
@@ -478,26 +506,35 @@ unsafeTraverseArray f = \ !ary ->
478506
go 0 mary
479507
{-# INLINE unsafeTraverseArray #-}
480508

509+
arrayFromListN :: Int -> [a] -> Array a
510+
arrayFromListN n l = runST $ do
511+
sma <- newArray n (die "fromListN" "uninitialized element")
512+
let go !ix [] = if ix == n
513+
then return ()
514+
else die "fromListN" "list length less than specified size"
515+
go !ix (x : xs) = if ix < n
516+
then do
517+
writeArray sma ix x
518+
go (ix+1) xs
519+
else die "fromListN" "list length greater than specified size"
520+
go 0 l
521+
unsafeFreezeArray sma
522+
523+
arrayFromList :: [a] -> Array a
524+
arrayFromList l = arrayFromListN (length l) l
525+
481526
#if MIN_VERSION_base(4,7,0)
482527
instance Exts.IsList (Array a) where
483528
type Item (Array a) = a
484-
fromListN n l =
485-
createArray n (die "fromListN" "mismatched size and list") $ \mi ->
486-
let go i (x:xs) = writeArray mi i x >> go (i+1) xs
487-
go _ [ ] = return ()
488-
in go 0 l
489-
fromList l = Exts.fromListN (length l) l
529+
fromListN = arrayFromListN
530+
fromList = arrayFromList
490531
toList = toList
491532
#else
492533
fromListN :: Int -> [a] -> Array a
493-
fromListN n l =
494-
createArray n (die "fromListN" "mismatched size and list") $ \mi ->
495-
let go i (x:xs) = writeArray mi i x >> go (i+1) xs
496-
go _ [ ] = return ()
497-
in go 0 l
534+
fromListN = arrayFromListN
498535

499536
fromList :: [a] -> Array a
500-
fromList l = fromListN (length l) l
537+
fromList = arrayFromList
501538
#endif
502539

503540
instance Functor Array where
@@ -526,6 +563,7 @@ instance Applicative Array where
526563
do
527564
x <- indexArrayM a j
528565
writeArray mb (off + j) (f x)
566+
go2 off f (j + 1)
529567
go1 0
530568
unsafeFreezeArray mb
531569
where szab = sizeofArray ab ; sza = sizeofArray a
@@ -649,19 +687,48 @@ instance Monoid (Array a) where
649687
in go 0 l
650688
where sz = sum . fmap sizeofArray $ l
651689

690+
arrayLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> Array a -> ShowS
691+
arrayLiftShowsPrec elemShowsPrec elemListShowsPrec p a = showParen (p > 10) $
692+
showString "fromListN " . shows (sizeofArray a) . showString " "
693+
. listLiftShowsPrec elemShowsPrec elemListShowsPrec 11 (toList a)
694+
695+
-- this need to be included for older ghcs
696+
listLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> [a] -> ShowS
697+
listLiftShowsPrec _ sl _ = sl
698+
652699
instance Show a => Show (Array a) where
653-
showsPrec p a = showParen (p > 10) $
654-
showString "fromListN " . shows (sizeofArray a) . showString " "
655-
. shows (toList a)
700+
showsPrec p a = arrayLiftShowsPrec showsPrec showList p a
701+
702+
#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
703+
instance Show1 Array where
704+
#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
705+
liftShowsPrec = arrayLiftShowsPrec
706+
#else
707+
showsPrec1 = arrayLiftShowsPrec showsPrec showList
708+
#endif
709+
#endif
710+
711+
arrayLiftReadsPrec :: (Int -> ReadS a) -> ReadS [a] -> Int -> ReadS (Array a)
712+
arrayLiftReadsPrec _ listReadsPrec p = readParen (p > 10) . readP_to_S $ do
713+
() <$ string "fromListN"
714+
skipSpaces
715+
n <- readS_to_P reads
716+
skipSpaces
717+
l <- readS_to_P listReadsPrec
718+
return $ arrayFromListN n l
656719

657720
instance Read a => Read (Array a) where
658-
readsPrec p = readParen (p > 10) . readP_to_S $ do
659-
() <$ string "fromListN"
660-
skipSpaces
661-
n <- readS_to_P reads
662-
skipSpaces
663-
l <- readS_to_P reads
664-
return $ fromListN n l
721+
readsPrec = arrayLiftReadsPrec readsPrec readList
722+
723+
#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
724+
instance Read1 Array where
725+
#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
726+
liftReadsPrec = arrayLiftReadsPrec
727+
#else
728+
readsPrec1 = arrayLiftReadsPrec readsPrec readList
729+
#endif
730+
#endif
731+
665732

666733
arrayDataType :: DataType
667734
arrayDataType = mkDataType "Data.Primitive.Array.Array" [fromListConstr]

Data/Primitive/ByteArray.hs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ module Data.Primitive.ByteArray (
4444

4545
import Control.Monad.Primitive
4646
import Control.Monad.ST
47-
import Control.Monad ( zipWithM_ )
4847
import Data.Primitive.Types
4948

5049
import Foreign.C.Types
@@ -181,12 +180,20 @@ foldrByteArray f z arr = go 0
181180
go i
182181
| sizeofByteArray arr > i * sz = f (indexByteArray arr i) (go (i+1))
183182
| otherwise = z
184-
sz = sizeofByteArray arr
183+
sz = sizeOf (undefined :: a)
185184

186185
fromListN :: Prim a => Int -> [a] -> ByteArray
187-
fromListN n xs = runST $ do
188-
marr <- newByteArray (n * sizeOf (head xs))
189-
zipWithM_ (writeByteArray marr) [0..n] xs
186+
fromListN n ys = runST $ do
187+
marr <- newByteArray (n * sizeOf (head ys))
188+
let go !ix [] = if ix == n
189+
then return ()
190+
else die "fromListN" "list length less than specified size"
191+
go !ix (x : xs) = if ix < n
192+
then do
193+
writeByteArray marr ix x
194+
go (ix + 1) xs
195+
else die "fromListN" "list length greater than specified size"
196+
go 0 ys
190197
unsafeFreezeByteArray marr
191198

192199
#if __GLASGOW_HASKELL__ >= 702
@@ -444,3 +451,7 @@ instance Exts.IsList ByteArray where
444451
fromList xs = fromListN (length xs) xs
445452
fromListN = fromListN
446453
#endif
454+
455+
die :: String -> String -> a
456+
die fun problem = error $ "Data.Primitive.ByteArray." ++ fun ++ ": " ++ problem
457+

0 commit comments

Comments
 (0)