@@ -75,7 +75,7 @@ import Control.Monad.ST
7575import Control.Monad.Zip
7676#endif
7777import Data.Data
78- import Data.Foldable
78+ import Data.Foldable as Foldable
7979import Data.Functor.Identity
8080#if !(MIN_VERSION_base(4,11,0))
8181import Data.Monoid
@@ -121,7 +121,7 @@ instance IsList (SmallArray a) where
121121 type Item (SmallArray a ) = a
122122 fromListN n l = SmallArray (fromListN n l)
123123 fromList l = SmallArray (fromList l)
124- toList ( SmallArray a) = toList a
124+ toList a = Foldable. toList a
125125#endif
126126#endif
127127
@@ -419,19 +419,27 @@ instance Eq a => Eq (SmallArray a) where
419419 sa1 == sa2 = length sa1 == length sa2 && loop (length sa1 - 1 )
420420 where
421421 loop i
422- | i < 0 = True
423- | otherwise = indexSmallArray sa1 i == indexSmallArray sa2 i && loop (i- 1 )
422+ | i < 0
423+ = True
424+ | (# x # ) <- indexSmallArray## sa1 i
425+ , (# y # ) <- indexSmallArray## sa2 i
426+ = x == y && loop (i- 1 )
424427
425428instance Eq (SmallMutableArray s a ) where
426429 SmallMutableArray sma1# == SmallMutableArray sma2# =
427430 isTrue# (sameSmallMutableArray# sma1# sma2# )
428431
429432instance Ord a => Ord (SmallArray a ) where
430- compare sl sr = fix ? 0 $ \ go i ->
431- if i < l
432- then compare (indexSmallArray sl i) (indexSmallArray sr i) <> go (i+ 1 )
433- else compare (length sl) (length sr)
434- where l = length sl `min` length sr
433+ compare a1 a2 = loop 0
434+ where
435+ mn = length a1 `min` length a2
436+ loop i
437+ | i < mn
438+ , (# x1 # ) <- indexSmallArray## a1 i
439+ , (# x2 # ) <- indexSmallArray## a2 i
440+ = compare x1 x2 `mappend` loop (i+ 1 )
441+ | otherwise = compare (length a1) (length a2)
442+
435443
436444instance Foldable SmallArray where
437445 -- Note: we perform the array lookups eagerly so we won't
@@ -532,8 +540,9 @@ instance Traversable SmallArray where
532540instance Functor SmallArray where
533541 fmap f sa = createSmallArray (length sa) (die " fmap" " impossible" ) $ \ smb ->
534542 fix ? 0 $ \ go i ->
535- when (i < length sa) $
536- writeSmallArray smb i (f $ indexSmallArray sa i) *> go (i+ 1 )
543+ when (i < length sa) $ do
544+ x <- indexSmallArrayM sa i
545+ writeSmallArray smb i (f x) *> go (i+ 1 )
537546 {-# INLINE fmap #-}
538547
539548 x <$ sa = createSmallArray (length sa) x noOp
@@ -548,22 +557,23 @@ instance Applicative SmallArray where
548557 where
549558 la = length sa ; lb = length sb
550559
551- sa <* sb = createSmallArray (la * lb ) (indexSmallArray sa $ la - 1 ) $ \ sma ->
552- fix ? 0 $ \ outer i -> when (i < la - 1 ) $ do
553- let a = indexSmallArray sa i
554- fix ? 0 $ \ inner j ->
555- when (j < lb) $
556- writeSmallArray sma (la * i + j) a *> inner (j + 1 )
557- outer $ i+ 1
558- where
559- la = length sa ; lb = length sb
560+ a <* b = createSmallArray (sza * szb ) (die " <* " " impossible " ) $ \ ma ->
561+ let fill off i e = when (i < szb ) $
562+ writeSmallArray ma (off + i) e >> fill off (i + 1 ) e
563+ go i = when (i < sza) $ do
564+ x <- indexSmallArrayM a i
565+ fill (i * szb) 0 x
566+ go ( i+ 1 )
567+ in go 0
568+ where sza = sizeofSmallArray a ; szb = sizeofSmallArray b
560569
561570 sf <*> sx = createSmallArray (lf* lx) (die " <*>" " impossible" ) $ \ smb ->
562571 fix ? 0 $ \ outer i -> when (i < lf) $ do
563- let f = indexSmallArray sf i
572+ f <- indexSmallArrayM sf i
564573 fix ? 0 $ \ inner j ->
565- when (j < lx) $
566- writeSmallArray smb (lf* i + j) (f $ indexSmallArray sx j)
574+ when (j < lx) $ do
575+ x <- indexSmallArrayM sx j
576+ writeSmallArray smb (lf* i + j) (f x)
567577 *> inner (j+ 1 )
568578 outer $ i+ 1
569579 where
@@ -583,20 +593,41 @@ instance Alternative SmallArray where
583593 some sa | null sa = emptySmallArray
584594 | otherwise = die " some" " infinite arrays are not well defined"
585595
596+ data ArrayStack a
597+ = PushArray ! (SmallArray a ) ! (ArrayStack a )
598+ | EmptyStack
599+ -- TODO: This isn't terribly efficient. It would be better to wrap
600+ -- ArrayStack with a type like
601+ --
602+ -- data NES s a = NES !Int !(SmallMutableArray s a) !(ArrayStack a)
603+ --
604+ -- We'd copy incoming arrays into the mutable array until we would
605+ -- overflow it. Then we'd freeze it, push it on the stack, and continue.
606+ -- Any sufficiently large incoming arrays would go straight on the stack.
607+ -- Such a scheme would make the stack much more compact in the case
608+ -- of many small arrays.
609+
586610instance Monad SmallArray where
587611 return = pure
588612 (>>) = (*>)
589613
590- sa >>= f = collect 0 [] (la- 1 )
614+ sa >>= f = collect 0 EmptyStack (la- 1 )
591615 where
592616 la = length sa
593617 collect sz stk i
594618 | i < 0 = createSmallArray sz (die " >>=" " impossible" ) $ fill 0 stk
595- | otherwise = let sb = f $ indexSmallArray sa i in
596- collect (sz + length sb) (sb: stk) (i- 1 )
597-
598- fill _ [ ] _ = return ()
599- fill off (sb: sbs) smb =
619+ | (# x # ) <- indexSmallArray## sa i
620+ , let sb = f x
621+ lsb = length sb
622+ -- If we don't perform this check, we could end up allocating
623+ -- a stack full of empty arrays if someone is filtering most
624+ -- things out. So we refrain from pushing empty arrays.
625+ = if lsb == 0
626+ then collect sz stk (i- 1 )
627+ else collect (sz + lsb) (PushArray sb stk) (i- 1 )
628+
629+ fill _ EmptyStack _ = return ()
630+ fill off (PushArray sb sbs) smb =
600631 copySmallArray smb off sb 0 (length sb)
601632 *> fill (off + length sb) sbs smb
602633
@@ -609,9 +640,11 @@ instance MonadPlus SmallArray where
609640zipW :: String -> (a -> b -> c ) -> SmallArray a -> SmallArray b -> SmallArray c
610641zipW nm = \ f sa sb -> let mn = length sa `min` length sb in
611642 createSmallArray mn (die nm " impossible" ) $ \ mc ->
612- fix ? 0 $ \ go i -> when (i < mn) $
613- writeSmallArray mc i (f (indexSmallArray sa i) (indexSmallArray sb i))
614- *> go (i+ 1 )
643+ fix ? 0 $ \ go i -> when (i < mn) $ do
644+ x <- indexSmallArrayM sa i
645+ y <- indexSmallArrayM sb i
646+ writeSmallArray mc i (f x y)
647+ go (i+ 1 )
615648{-# INLINE zipW #-}
616649
617650instance MonadZip SmallArray where
@@ -631,7 +664,14 @@ instance MonadZip SmallArray where
631664 <*> unsafeFreezeSmallArray smb
632665
633666instance MonadFix SmallArray where
634- mfix f = fromList . mfix $ toList . f
667+ mfix f = createSmallArray (sizeofSmallArray (f err))
668+ (die " mfix" " impossible" ) $ flip fix 0 $
669+ \ r ! i ! mary -> when (i < sz) $ do
670+ writeSmallArray mary i (fix (\ xi -> f xi `indexSmallArray` i))
671+ r (i + 1 ) mary
672+ where
673+ sz = sizeofSmallArray (f err)
674+ err = error " mfix for Data.Primitive.SmallArray applied to strict function."
635675
636676#if MIN_VERSION_base(4,9,0)
637677instance Sem. Semigroup (SmallArray a ) where
@@ -658,7 +698,7 @@ instance IsList (SmallArray a) where
658698 [] -> pure ()
659699 x: xs -> writeSmallArray sma i x *> go (i+ 1 ) xs
660700 fromList l = fromListN (length l) l
661- toList sa = indexSmallArray sa <$> [ 0 .. length sa - 1 ]
701+ toList = Foldable. toList
662702
663703instance Show a => Show (SmallArray a ) where
664704 showsPrec p sa = showParen (p > 10 ) $
0 commit comments