1{-# LANGUAGE CPP #-}
2{-# LANGUAGE MagicHash #-}
3{-# LANGUAGE RankNTypes #-}
4{-# LANGUAGE TypeFamilies #-}
5{-# LANGUAGE UnboxedTuples #-}
6{-# LANGUAGE DeriveTraversable #-}
7{-# LANGUAGE DeriveDataTypeable #-}
8{-# LANGUAGE GeneralizedNewtypeDeriving #-}
9{-# LANGUAGE BangPatterns #-}
10
11-- |
12-- Module : Data.Primitive.SmallArray
13-- Copyright: (c) 2015 Dan Doel
14-- License: BSD3
15--
16-- Maintainer: libraries@haskell.org
17-- Portability: non-portable
18--
19-- Small arrays are boxed (im)mutable arrays.
20--
21-- The underlying structure of the 'Array' type contains a card table, allowing
22-- segments of the array to be marked as having been mutated. This allows the
23-- garbage collector to only re-traverse segments of the array that have been
24-- marked during certain phases, rather than having to traverse the entire
25-- array.
26--
27-- 'SmallArray' lacks this table. This means that it takes up less memory and
28-- has slightly faster writes. It is also more efficient during garbage
29-- collection so long as the card table would have a single entry covering the
30-- entire array. These advantages make them suitable for use as arrays that are
31-- known to be small.
32--
33-- The card size is 128, so for uses much larger than that, 'Array' would likely
34-- be superior.
35--
36-- The underlying type, 'SmallArray#', was introduced in GHC 7.10, so prior to
37-- that version, this module simply implements small arrays as 'Array'.
38
39module Data.Primitive.SmallArray
40  ( SmallArray(..)
41  , SmallMutableArray(..)
42  , newSmallArray
43  , readSmallArray
44  , writeSmallArray
45  , copySmallArray
46  , copySmallMutableArray
47  , indexSmallArray
48  , indexSmallArrayM
49  , indexSmallArray##
50  , cloneSmallArray
51  , cloneSmallMutableArray
52  , freezeSmallArray
53  , unsafeFreezeSmallArray
54  , thawSmallArray
55  , runSmallArray
56  , unsafeThawSmallArray
57  , sizeofSmallArray
58  , sizeofSmallMutableArray
59#if MIN_VERSION_base(4,14,0)
60  , shrinkSmallMutableArray
61#endif
62  , smallArrayFromList
63  , smallArrayFromListN
64  , mapSmallArray'
65  , traverseSmallArrayP
66  ) where
67
68
69#if (__GLASGOW_HASKELL__ >= 710)
70#define HAVE_SMALL_ARRAY 1
71#endif
72
73#if MIN_VERSION_base(4,7,0)
74import GHC.Exts hiding (toList)
75import qualified GHC.Exts
76#endif
77
78import Control.Applicative
79import Control.DeepSeq
80import Control.Monad
81import qualified Control.Monad.Fail as Fail
82import Control.Monad.Fix
83import Control.Monad.Primitive
84import Control.Monad.ST
85import Control.Monad.Zip
86import Data.Data
87import Data.Foldable as Foldable
88import Data.Functor.Identity
89#if !(MIN_VERSION_base(4,10,0))
90import Data.Monoid
91#endif
92#if MIN_VERSION_base(4,9,0)
93import qualified GHC.ST as GHCST
94import qualified Data.Semigroup as Sem
95#endif
96import Text.ParserCombinators.ReadP
97#if MIN_VERSION_base(4,10,0)
98import GHC.Exts (runRW#)
99#elif MIN_VERSION_base(4,9,0)
100import GHC.Base (runRW#)
101#endif
102
103#if !(HAVE_SMALL_ARRAY)
104import Data.Primitive.Array
105import Data.Traversable
106import qualified Data.Primitive.Array as Array
107#endif
108
109#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
110import Data.Functor.Classes (Eq1(..),Ord1(..),Show1(..),Read1(..))
111#endif
112
113#if HAVE_SMALL_ARRAY
114data SmallArray a = SmallArray (SmallArray# a)
115  deriving Typeable
116#else
117newtype SmallArray a = SmallArray (Array a) deriving
118  ( Eq
119  , Ord
120  , Show
121  , Read
122  , Foldable
123  , Traversable
124  , Functor
125  , Applicative
126  , Alternative
127  , Monad
128  , MonadPlus
129  , MonadZip
130  , MonadFix
131  , Monoid
132  , NFData
133#if MIN_VERSION_deepseq(1,4,3)
134  , NFData1
135#endif
136  , Typeable
137#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
138  , Eq1
139  , Ord1
140  , Show1
141  , Read1
142#endif
143  )
144
145#if MIN_VERSION_base(4,7,0)
146instance IsList (SmallArray a) where
147  type Item (SmallArray a) = a
148  fromListN n l = SmallArray (fromListN n l)
149  fromList l = SmallArray (fromList l)
150  toList a = Foldable.toList a
151#endif
152#endif
153
154#if HAVE_SMALL_ARRAY
155#if MIN_VERSION_deepseq(1,4,3)
156instance NFData1 SmallArray where
157  liftRnf r = foldl' (\_ -> r) ()
158#endif
159
160instance NFData a => NFData (SmallArray a) where
161  rnf = foldl' (\_ -> rnf) ()
162#endif
163
164#if HAVE_SMALL_ARRAY
165data SmallMutableArray s a = SmallMutableArray (SmallMutableArray# s a)
166  deriving Typeable
167#else
168newtype SmallMutableArray s a = SmallMutableArray (MutableArray s a)
169  deriving (Eq, Typeable)
170#endif
171
172-- | Create a new small mutable array.
173--
174-- /Note:/ this function does not check if the input is non-negative.
175newSmallArray
176  :: PrimMonad m
177  => Int -- ^ size
178  -> a   -- ^ initial contents
179  -> m (SmallMutableArray (PrimState m) a)
180#if HAVE_SMALL_ARRAY
181newSmallArray (I# i#) x = primitive $ \s ->
182  case newSmallArray# i# x s of
183    (# s', sma# #) -> (# s', SmallMutableArray sma# #)
184#else
185newSmallArray n e = SmallMutableArray `liftM` newArray n e
186#endif
187{-# INLINE newSmallArray #-}
188
189-- | Read the element at a given index in a mutable array.
190--
191-- /Note:/ this function does not do bounds checking.
192readSmallArray
193  :: PrimMonad m
194  => SmallMutableArray (PrimState m) a -- ^ array
195  -> Int                               -- ^ index
196  -> m a
197#if HAVE_SMALL_ARRAY
198readSmallArray (SmallMutableArray sma#) (I# i#) =
199  primitive $ readSmallArray# sma# i#
200#else
201readSmallArray (SmallMutableArray a) = readArray a
202#endif
203{-# INLINE readSmallArray #-}
204
205-- | Write an element at the given idex in a mutable array.
206--
207-- /Note:/ this function does not do bounds checking.
208writeSmallArray
209  :: PrimMonad m
210  => SmallMutableArray (PrimState m) a -- ^ array
211  -> Int                               -- ^ index
212  -> a                                 -- ^ new element
213  -> m ()
214#if HAVE_SMALL_ARRAY
215writeSmallArray (SmallMutableArray sma#) (I# i#) x =
216  primitive_ $ writeSmallArray# sma# i# x
217#else
218writeSmallArray (SmallMutableArray a) = writeArray a
219#endif
220{-# INLINE writeSmallArray #-}
221
222-- | Look up an element in an immutable array.
223--
224-- The purpose of returning a result using a monad is to allow the caller to
225-- avoid retaining references to the array. Evaluating the return value will
226-- cause the array lookup to be performed, even though it may not require the
227-- element of the array to be evaluated (which could throw an exception). For
228-- instance:
229--
230-- > data Box a = Box a
231-- > ...
232-- >
233-- > f sa = case indexSmallArrayM sa 0 of
234-- >   Box x -> ...
235--
236-- 'x' is not a closure that references 'sa' as it would be if we instead
237-- wrote:
238--
239-- > let x = indexSmallArray sa 0
240--
241-- And does not prevent 'sa' from being garbage collected.
242--
243-- Note that 'Identity' is not adequate for this use, as it is a newtype, and
244-- cannot be evaluated without evaluating the element.
245--
246-- /Note:/ this function does not do bounds checking.
247indexSmallArrayM
248  :: Monad m
249  => SmallArray a -- ^ array
250  -> Int          -- ^ index
251  -> m a
252#if HAVE_SMALL_ARRAY
253indexSmallArrayM (SmallArray sa#) (I# i#) =
254  case indexSmallArray# sa# i# of
255    (# x #) -> pure x
256#else
257indexSmallArrayM (SmallArray a) = indexArrayM a
258#endif
259{-# INLINE indexSmallArrayM #-}
260
261-- | Look up an element in an immutable array.
262--
263-- /Note:/ this function does not do bounds checking.
264indexSmallArray
265  :: SmallArray a -- ^ array
266  -> Int          -- ^ index
267  -> a
268#if HAVE_SMALL_ARRAY
269indexSmallArray sa i = runIdentity $ indexSmallArrayM sa i
270#else
271indexSmallArray (SmallArray a) = indexArray a
272#endif
273{-# INLINE indexSmallArray #-}
274
275-- | Read a value from the immutable array at the given index, returning
276-- the result in an unboxed unary tuple. This is currently used to implement
277-- folds.
278indexSmallArray## :: SmallArray a -> Int -> (# a #)
279#if HAVE_SMALL_ARRAY
280indexSmallArray## (SmallArray ary) (I# i) = indexSmallArray# ary i
281#else
282indexSmallArray## (SmallArray a) = indexArray## a
283#endif
284{-# INLINE indexSmallArray## #-}
285
286-- | Create a copy of a slice of an immutable array.
287--
288-- /Note:/ The provided Array should contain the full subrange
289-- specified by the two Ints, but this is not checked.
290cloneSmallArray
291  :: SmallArray a -- ^ source
292  -> Int          -- ^ offset
293  -> Int          -- ^ length
294  -> SmallArray a
295#if HAVE_SMALL_ARRAY
296cloneSmallArray (SmallArray sa#) (I# i#) (I# j#) =
297  SmallArray (cloneSmallArray# sa# i# j#)
298#else
299cloneSmallArray (SmallArray a) i j = SmallArray $ cloneArray a i j
300#endif
301{-# INLINE cloneSmallArray #-}
302
303-- | Create a copy of a slice of a mutable array.
304--
305-- /Note:/ The provided Array should contain the full subrange
306-- specified by the two Ints, but this is not checked.
307cloneSmallMutableArray
308  :: PrimMonad m
309  => SmallMutableArray (PrimState m) a -- ^ source
310  -> Int                               -- ^ offset
311  -> Int                               -- ^ length
312  -> m (SmallMutableArray (PrimState m) a)
313#if HAVE_SMALL_ARRAY
314cloneSmallMutableArray (SmallMutableArray sma#) (I# o#) (I# l#) =
315  primitive $ \s -> case cloneSmallMutableArray# sma# o# l# s of
316    (# s', smb# #) -> (# s', SmallMutableArray smb# #)
317#else
318cloneSmallMutableArray (SmallMutableArray ma) i j =
319  SmallMutableArray `liftM` cloneMutableArray ma i j
320#endif
321{-# INLINE cloneSmallMutableArray #-}
322
323-- | Create an immutable array corresponding to a slice of a mutable array.
324--
325-- This operation copies the portion of the array to be frozen.
326freezeSmallArray
327  :: PrimMonad m
328  => SmallMutableArray (PrimState m) a -- ^ source
329  -> Int                               -- ^ offset
330  -> Int                               -- ^ length
331  -> m (SmallArray a)
332#if HAVE_SMALL_ARRAY
333freezeSmallArray (SmallMutableArray sma#) (I# i#) (I# j#) =
334  primitive $ \s -> case freezeSmallArray# sma# i# j# s of
335    (# s', sa# #) -> (# s', SmallArray sa# #)
336#else
337freezeSmallArray (SmallMutableArray ma) i j =
338  SmallArray `liftM` freezeArray ma i j
339#endif
340{-# INLINE freezeSmallArray #-}
341
342-- | Render a mutable array immutable.
343--
344-- This operation performs no copying, so care must be taken not to modify the
345-- input array after freezing.
346unsafeFreezeSmallArray
347  :: PrimMonad m => SmallMutableArray (PrimState m) a -> m (SmallArray a)
348#if HAVE_SMALL_ARRAY
349unsafeFreezeSmallArray (SmallMutableArray sma#) =
350  primitive $ \s -> case unsafeFreezeSmallArray# sma# s of
351    (# s', sa# #) -> (# s', SmallArray sa# #)
352#else
353unsafeFreezeSmallArray (SmallMutableArray ma) =
354  SmallArray `liftM` unsafeFreezeArray ma
355#endif
356{-# INLINE unsafeFreezeSmallArray #-}
357
358-- | Create a mutable array corresponding to a slice of an immutable array.
359--
360-- This operation copies the portion of the array to be thawed.
361thawSmallArray
362  :: PrimMonad m
363  => SmallArray a -- ^ source
364  -> Int          -- ^ offset
365  -> Int          -- ^ length
366  -> m (SmallMutableArray (PrimState m) a)
367#if HAVE_SMALL_ARRAY
368thawSmallArray (SmallArray sa#) (I# o#) (I# l#) =
369  primitive $ \s -> case thawSmallArray# sa# o# l# s of
370    (# s', sma# #) -> (# s', SmallMutableArray sma# #)
371#else
372thawSmallArray (SmallArray a) off len =
373  SmallMutableArray `liftM` thawArray a off len
374#endif
375{-# INLINE thawSmallArray #-}
376
377-- | Render an immutable array mutable.
378--
379-- This operation performs no copying, so care must be taken with its use.
380unsafeThawSmallArray
381  :: PrimMonad m => SmallArray a -> m (SmallMutableArray (PrimState m) a)
382#if HAVE_SMALL_ARRAY
383unsafeThawSmallArray (SmallArray sa#) =
384  primitive $ \s -> case unsafeThawSmallArray# sa# s of
385    (# s', sma# #) -> (# s', SmallMutableArray sma# #)
386#else
387unsafeThawSmallArray (SmallArray a) = SmallMutableArray `liftM` unsafeThawArray a
388#endif
389{-# INLINE unsafeThawSmallArray #-}
390
391-- | Copy a slice of an immutable array into a mutable array.
392--
393-- /Note:/ this function does not do bounds or overlap checking.
394copySmallArray
395  :: PrimMonad m
396  => SmallMutableArray (PrimState m) a -- ^ destination
397  -> Int                               -- ^ destination offset
398  -> SmallArray a                      -- ^ source
399  -> Int                               -- ^ source offset
400  -> Int                               -- ^ length
401  -> m ()
402#if HAVE_SMALL_ARRAY
403copySmallArray
404  (SmallMutableArray dst#) (I# do#) (SmallArray src#) (I# so#) (I# l#) =
405    primitive_ $ copySmallArray# src# so# dst# do# l#
406#else
407copySmallArray (SmallMutableArray dst) i (SmallArray src) = copyArray dst i src
408#endif
409{-# INLINE copySmallArray #-}
410
411-- | Copy a slice of one mutable array into another.
412--
413-- /Note:/ this function does not do bounds or overlap checking.
414copySmallMutableArray
415  :: PrimMonad m
416  => SmallMutableArray (PrimState m) a -- ^ destination
417  -> Int                               -- ^ destination offset
418  -> SmallMutableArray (PrimState m) a -- ^ source
419  -> Int                               -- ^ source offset
420  -> Int                               -- ^ length
421  -> m ()
422#if HAVE_SMALL_ARRAY
423copySmallMutableArray
424  (SmallMutableArray dst#) (I# do#)
425  (SmallMutableArray src#) (I# so#)
426  (I# l#) =
427    primitive_ $ copySmallMutableArray# src# so# dst# do# l#
428#else
429copySmallMutableArray (SmallMutableArray dst) i (SmallMutableArray src) =
430  copyMutableArray dst i src
431#endif
432{-# INLINE copySmallMutableArray #-}
433
434sizeofSmallArray :: SmallArray a -> Int
435#if HAVE_SMALL_ARRAY
436sizeofSmallArray (SmallArray sa#) = I# (sizeofSmallArray# sa#)
437#else
438sizeofSmallArray (SmallArray a) = sizeofArray a
439#endif
440{-# INLINE sizeofSmallArray #-}
441
442sizeofSmallMutableArray :: SmallMutableArray s a -> Int
443#if HAVE_SMALL_ARRAY
444sizeofSmallMutableArray (SmallMutableArray sa#) =
445  I# (sizeofSmallMutableArray# sa#)
446#else
447sizeofSmallMutableArray (SmallMutableArray ma) = sizeofMutableArray ma
448#endif
449{-# INLINE sizeofSmallMutableArray #-}
450
451-- | This is the fastest, most straightforward way to traverse
452-- an array, but it only works correctly with a sufficiently
453-- "affine" 'PrimMonad' instance. In particular, it must only produce
454-- *one* result array. 'Control.Monad.Trans.List.ListT'-transformed
455-- monads, for example, will not work right at all.
456traverseSmallArrayP
457  :: PrimMonad m
458  => (a -> m b)
459  -> SmallArray a
460  -> m (SmallArray b)
461#if HAVE_SMALL_ARRAY
462traverseSmallArrayP f = \ !ary ->
463  let
464    !sz = sizeofSmallArray ary
465    go !i !mary
466      | i == sz
467      = unsafeFreezeSmallArray mary
468      | otherwise
469      = do
470          a <- indexSmallArrayM ary i
471          b <- f a
472          writeSmallArray mary i b
473          go (i + 1) mary
474  in do
475    mary <- newSmallArray sz badTraverseValue
476    go 0 mary
477#else
478traverseSmallArrayP f (SmallArray ar) = SmallArray `liftM` traverseArrayP f ar
479#endif
480{-# INLINE traverseSmallArrayP #-}
481
482-- | Strict map over the elements of the array.
483mapSmallArray' :: (a -> b) -> SmallArray a -> SmallArray b
484#if HAVE_SMALL_ARRAY
485mapSmallArray' f sa = createSmallArray (length sa) (die "mapSmallArray'" "impossible") $ \smb ->
486  fix ? 0 $ \go i ->
487    when (i < length sa) $ do
488      x <- indexSmallArrayM sa i
489      let !y = f x
490      writeSmallArray smb i y *> go (i+1)
491#else
492mapSmallArray' f (SmallArray ar) = SmallArray (mapArray' f ar)
493#endif
494{-# INLINE mapSmallArray' #-}
495
496#ifndef HAVE_SMALL_ARRAY
497runSmallArray
498  :: (forall s. ST s (SmallMutableArray s a))
499  -> SmallArray a
500runSmallArray m = SmallArray $ runArray $
501  m >>= \(SmallMutableArray mary) -> return mary
502
503#elif !MIN_VERSION_base(4,9,0)
504runSmallArray
505  :: (forall s. ST s (SmallMutableArray s a))
506  -> SmallArray a
507runSmallArray m = runST $ m >>= unsafeFreezeSmallArray
508
509#else
510-- This low-level business is designed to work with GHC's worker-wrapper
511-- transformation. A lot of the time, we don't actually need an Array
512-- constructor. By putting it on the outside, and being careful about
513-- how we special-case the empty array, we can make GHC smarter about this.
514-- The only downside is that separately created 0-length arrays won't share
515-- their Array constructors, although they'll share their underlying
516-- Array#s.
517runSmallArray
518  :: (forall s. ST s (SmallMutableArray s a))
519  -> SmallArray a
520runSmallArray m = SmallArray (runSmallArray# m)
521
522runSmallArray#
523  :: (forall s. ST s (SmallMutableArray s a))
524  -> SmallArray# a
525runSmallArray# m = case runRW# $ \s ->
526  case unST m s of { (# s', SmallMutableArray mary# #) ->
527  unsafeFreezeSmallArray# mary# s'} of (# _, ary# #) -> ary#
528
529unST :: ST s a -> State# s -> (# State# s, a #)
530unST (GHCST.ST f) = f
531
532#endif
533
534#if HAVE_SMALL_ARRAY
535-- See the comment on runSmallArray for why we use emptySmallArray#.
536createSmallArray
537  :: Int
538  -> a
539  -> (forall s. SmallMutableArray s a -> ST s ())
540  -> SmallArray a
541createSmallArray 0 _ _ = SmallArray (emptySmallArray# (# #))
542createSmallArray n x f = runSmallArray $ do
543  mary <- newSmallArray n x
544  f mary
545  pure mary
546
547emptySmallArray# :: (# #) -> SmallArray# a
548emptySmallArray# _ = case emptySmallArray of SmallArray ar -> ar
549{-# NOINLINE emptySmallArray# #-}
550
551die :: String -> String -> a
552die fun problem = error $ "Data.Primitive.SmallArray." ++ fun ++ ": " ++ problem
553
554emptySmallArray :: SmallArray a
555emptySmallArray =
556  runST $ newSmallArray 0 (die "emptySmallArray" "impossible")
557            >>= unsafeFreezeSmallArray
558{-# NOINLINE emptySmallArray #-}
559
560
561infixl 1 ?
562(?) :: (a -> b -> c) -> (b -> a -> c)
563(?) = flip
564{-# INLINE (?) #-}
565
566noOp :: a -> ST s ()
567noOp = const $ pure ()
568
569smallArrayLiftEq :: (a -> b -> Bool) -> SmallArray a -> SmallArray b -> Bool
570smallArrayLiftEq p sa1 sa2 = length sa1 == length sa2 && loop (length sa1 - 1)
571  where
572  loop i
573    | i < 0
574    = True
575    | (# x #) <- indexSmallArray## sa1 i
576    , (# y #) <- indexSmallArray## sa2 i
577    = p x y && loop (i-1)
578
579#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
580-- | @since 0.6.4.0
581instance Eq1 SmallArray where
582#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
583  liftEq = smallArrayLiftEq
584#else
585  eq1 = smallArrayLiftEq (==)
586#endif
587#endif
588
589instance Eq a => Eq (SmallArray a) where
590  sa1 == sa2 = smallArrayLiftEq (==) sa1 sa2
591
592instance Eq (SmallMutableArray s a) where
593  SmallMutableArray sma1# == SmallMutableArray sma2# =
594    isTrue# (sameSmallMutableArray# sma1# sma2#)
595
596smallArrayLiftCompare :: (a -> b -> Ordering) -> SmallArray a -> SmallArray b -> Ordering
597smallArrayLiftCompare elemCompare a1 a2 = loop 0
598  where
599  mn = length a1 `min` length a2
600  loop i
601    | i < mn
602    , (# x1 #) <- indexSmallArray## a1 i
603    , (# x2 #) <- indexSmallArray## a2 i
604    = elemCompare x1 x2 `mappend` loop (i+1)
605    | otherwise = compare (length a1) (length a2)
606
607#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
608-- | @since 0.6.4.0
609instance Ord1 SmallArray where
610#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
611  liftCompare = smallArrayLiftCompare
612#else
613  compare1 = smallArrayLiftCompare compare
614#endif
615#endif
616
617-- | Lexicographic ordering. Subject to change between major versions.
618instance Ord a => Ord (SmallArray a) where
619  compare sa1 sa2 = smallArrayLiftCompare compare sa1 sa2
620
621instance Foldable SmallArray where
622  -- Note: we perform the array lookups eagerly so we won't
623  -- create thunks to perform lookups even if GHC can't see
624  -- that the folding function is strict.
625  foldr f = \z !ary ->
626    let
627      !sz = sizeofSmallArray ary
628      go i
629        | i == sz = z
630        | (# x #) <- indexSmallArray## ary i
631        = f x (go (i+1))
632    in go 0
633  {-# INLINE foldr #-}
634  foldl f = \z !ary ->
635    let
636      go i
637        | i < 0 = z
638        | (# x #) <- indexSmallArray## ary i
639        = f (go (i-1)) x
640    in go (sizeofSmallArray ary - 1)
641  {-# INLINE foldl #-}
642  foldr1 f = \ !ary ->
643    let
644      !sz = sizeofSmallArray ary - 1
645      go i =
646        case indexSmallArray## ary i of
647          (# x #) | i == sz -> x
648                  | otherwise -> f x (go (i+1))
649    in if sz < 0
650       then die "foldr1" "Empty SmallArray"
651       else go 0
652  {-# INLINE foldr1 #-}
653  foldl1 f = \ !ary ->
654    let
655      !sz = sizeofSmallArray ary - 1
656      go i =
657        case indexSmallArray## ary i of
658          (# x #) | i == 0 -> x
659                  | otherwise -> f (go (i - 1)) x
660    in if sz < 0
661       then die "foldl1" "Empty SmallArray"
662       else go sz
663  {-# INLINE foldl1 #-}
664  foldr' f = \z !ary ->
665    let
666      go i !acc
667        | i == -1 = acc
668        | (# x #) <- indexSmallArray## ary i
669        = go (i-1) (f x acc)
670    in go (sizeofSmallArray ary - 1) z
671  {-# INLINE foldr' #-}
672  foldl' f = \z !ary ->
673    let
674      !sz = sizeofSmallArray ary
675      go i !acc
676        | i == sz = acc
677        | (# x #) <- indexSmallArray## ary i
678        = go (i+1) (f acc x)
679    in go 0 z
680  {-# INLINE foldl' #-}
681  null a = sizeofSmallArray a == 0
682  {-# INLINE null #-}
683  length = sizeofSmallArray
684  {-# INLINE length #-}
685  maximum ary | sz == 0   = die "maximum" "Empty SmallArray"
686              | (# frst #) <- indexSmallArray## ary 0
687              = go 1 frst
688   where
689     sz = sizeofSmallArray ary
690     go i !e
691       | i == sz = e
692       | (# x #) <- indexSmallArray## ary i
693       = go (i+1) (max e x)
694  {-# INLINE maximum #-}
695  minimum ary | sz == 0   = die "minimum" "Empty SmallArray"
696              | (# frst #) <- indexSmallArray## ary 0
697              = go 1 frst
698   where sz = sizeofSmallArray ary
699         go i !e
700           | i == sz = e
701           | (# x #) <- indexSmallArray## ary i
702           = go (i+1) (min e x)
703  {-# INLINE minimum #-}
704  sum = foldl' (+) 0
705  {-# INLINE sum #-}
706  product = foldl' (*) 1
707  {-# INLINE product #-}
708
709newtype STA a = STA {_runSTA :: forall s. SmallMutableArray# s a -> ST s (SmallArray a)}
710
711runSTA :: Int -> STA a -> SmallArray a
712runSTA !sz = \ (STA m) -> runST $ newSmallArray_ sz >>=
713                        \ (SmallMutableArray ar#) -> m ar#
714{-# INLINE runSTA #-}
715
716newSmallArray_ :: Int -> ST s (SmallMutableArray s a)
717newSmallArray_ !n = newSmallArray n badTraverseValue
718
719badTraverseValue :: a
720badTraverseValue = die "traverse" "bad indexing"
721{-# NOINLINE badTraverseValue #-}
722
723instance Traversable SmallArray where
724  traverse f = traverseSmallArray f
725  {-# INLINE traverse #-}
726
727traverseSmallArray
728  :: Applicative f
729  => (a -> f b) -> SmallArray a -> f (SmallArray b)
730traverseSmallArray f = \ !ary ->
731  let
732    !len = sizeofSmallArray ary
733    go !i
734      | i == len
735      = pure $ STA $ \mary -> unsafeFreezeSmallArray (SmallMutableArray mary)
736      | (# x #) <- indexSmallArray## ary i
737      = liftA2 (\b (STA m) -> STA $ \mary ->
738                  writeSmallArray (SmallMutableArray mary) i b >> m mary)
739               (f x) (go (i + 1))
740  in if len == 0
741     then pure emptySmallArray
742     else runSTA len <$> go 0
743{-# INLINE [1] traverseSmallArray #-}
744
745{-# RULES
746"traverse/ST" forall (f :: a -> ST s b). traverseSmallArray f = traverseSmallArrayP f
747"traverse/IO" forall (f :: a -> IO b). traverseSmallArray f = traverseSmallArrayP f
748"traverse/Id" forall (f :: a -> Identity b). traverseSmallArray f =
749   (coerce :: (SmallArray a -> SmallArray (Identity b))
750           -> SmallArray a -> Identity (SmallArray b)) (fmap f)
751 #-}
752
753
754instance Functor SmallArray where
755  fmap f sa = createSmallArray (length sa) (die "fmap" "impossible") $ \smb ->
756    fix ? 0 $ \go i ->
757      when (i < length sa) $ do
758        x <- indexSmallArrayM sa i
759        writeSmallArray smb i (f x) *> go (i+1)
760  {-# INLINE fmap #-}
761
762  x <$ sa = createSmallArray (length sa) x noOp
763
764instance Applicative SmallArray where
765  pure x = createSmallArray 1 x noOp
766
767  sa *> sb = createSmallArray (la*lb) (die "*>" "impossible") $ \smb ->
768    fix ? 0 $ \go i ->
769      when (i < la) $
770        copySmallArray smb 0 sb 0 lb *> go (i+1)
771   where
772   la = length sa ; lb = length sb
773
774  a <* b = createSmallArray (sza*szb) (die "<*" "impossible") $ \ma ->
775    let fill off i e = when (i < szb) $
776                         writeSmallArray ma (off+i) e >> fill off (i+1) e
777        go i = when (i < sza) $ do
778                 x <- indexSmallArrayM a i
779                 fill (i*szb) 0 x
780                 go (i+1)
781     in go 0
782   where sza = sizeofSmallArray a ; szb = sizeofSmallArray b
783
784  ab <*> a = createSmallArray (szab*sza) (die "<*>" "impossible") $ \mb ->
785    let go1 i = when (i < szab) $
786            do
787              f <- indexSmallArrayM ab i
788              go2 (i*sza) f 0
789              go1 (i+1)
790        go2 off f j = when (j < sza) $
791            do
792              x <- indexSmallArrayM a j
793              writeSmallArray mb (off + j) (f x)
794              go2 off f (j + 1)
795    in go1 0
796   where szab = sizeofSmallArray ab ; sza = sizeofSmallArray a
797
798instance Alternative SmallArray where
799  empty = emptySmallArray
800
801  sl <|> sr =
802    createSmallArray (length sl + length sr) (die "<|>" "impossible") $ \sma ->
803      copySmallArray sma 0 sl 0 (length sl)
804        *> copySmallArray sma (length sl) sr 0 (length sr)
805
806  many sa | null sa   = pure []
807          | otherwise = die "many" "infinite arrays are not well defined"
808
809  some sa | null sa   = emptySmallArray
810          | otherwise = die "some" "infinite arrays are not well defined"
811
812data ArrayStack a
813  = PushArray !(SmallArray a) !(ArrayStack a)
814  | EmptyStack
815-- TODO: This isn't terribly efficient. It would be better to wrap
816-- ArrayStack with a type like
817--
818-- data NES s a = NES !Int !(SmallMutableArray s a) !(ArrayStack a)
819--
820-- We'd copy incoming arrays into the mutable array until we would
821-- overflow it. Then we'd freeze it, push it on the stack, and continue.
822-- Any sufficiently large incoming arrays would go straight on the stack.
823-- Such a scheme would make the stack much more compact in the case
824-- of many small arrays.
825
826instance Monad SmallArray where
827  return = pure
828  (>>) = (*>)
829
830  sa >>= f = collect 0 EmptyStack (la-1)
831   where
832   la = length sa
833   collect sz stk i
834     | i < 0 = createSmallArray sz (die ">>=" "impossible") $ fill 0 stk
835     | (# x #) <- indexSmallArray## sa i
836     , let sb = f x
837           lsb = length sb
838       -- If we don't perform this check, we could end up allocating
839       -- a stack full of empty arrays if someone is filtering most
840       -- things out. So we refrain from pushing empty arrays.
841     = if lsb == 0
842       then collect sz stk (i-1)
843       else collect (sz + lsb) (PushArray sb stk) (i-1)
844
845   fill _ EmptyStack _ = return ()
846   fill off (PushArray sb sbs) smb =
847     copySmallArray smb off sb 0 (length sb)
848       *> fill (off + length sb) sbs smb
849
850#if !(MIN_VERSION_base(4,13,0))
851  fail = Fail.fail
852#endif
853
854instance Fail.MonadFail SmallArray where
855  fail _ = emptySmallArray
856
857instance MonadPlus SmallArray where
858  mzero = empty
859  mplus = (<|>)
860
861zipW :: String -> (a -> b -> c) -> SmallArray a -> SmallArray b -> SmallArray c
862zipW nm = \f sa sb -> let mn = length sa `min` length sb in
863  createSmallArray mn (die nm "impossible") $ \mc ->
864    fix ? 0 $ \go i -> when (i < mn) $ do
865      x <- indexSmallArrayM sa i
866      y <- indexSmallArrayM sb i
867      writeSmallArray mc i (f x y)
868      go (i+1)
869{-# INLINE zipW #-}
870
871instance MonadZip SmallArray where
872  mzip = zipW "mzip" (,)
873  mzipWith = zipW "mzipWith"
874  {-# INLINE mzipWith #-}
875  munzip sab = runST $ do
876    let sz = length sab
877    sma <- newSmallArray sz $ die "munzip" "impossible"
878    smb <- newSmallArray sz $ die "munzip" "impossible"
879    fix ? 0 $ \go i ->
880      when (i < sz) $ case indexSmallArray sab i of
881        (x, y) -> do writeSmallArray sma i x
882                     writeSmallArray smb i y
883                     go $ i+1
884    (,) <$> unsafeFreezeSmallArray sma
885        <*> unsafeFreezeSmallArray smb
886
887instance MonadFix SmallArray where
888  mfix f = createSmallArray (sizeofSmallArray (f err))
889                            (die "mfix" "impossible") $ flip fix 0 $
890    \r !i !mary -> when (i < sz) $ do
891                      writeSmallArray mary i (fix (\xi -> f xi `indexSmallArray` i))
892                      r (i + 1) mary
893    where
894      sz = sizeofSmallArray (f err)
895      err = error "mfix for Data.Primitive.SmallArray applied to strict function."
896
897#if MIN_VERSION_base(4,9,0)
898-- | @since 0.6.3.0
899instance Sem.Semigroup (SmallArray a) where
900  (<>) = (<|>)
901  sconcat = mconcat . toList
902#endif
903
904instance Monoid (SmallArray a) where
905  mempty = empty
906#if !(MIN_VERSION_base(4,11,0))
907  mappend = (<|>)
908#endif
909  mconcat l = createSmallArray n (die "mconcat" "impossible") $ \ma ->
910    let go !_  [    ] = return ()
911        go off (a:as) =
912          copySmallArray ma off a 0 (sizeofSmallArray a) >> go (off + sizeofSmallArray a) as
913     in go 0 l
914   where n = sum . fmap length $ l
915
916instance IsList (SmallArray a) where
917  type Item (SmallArray a) = a
918  fromListN = smallArrayFromListN
919  fromList = smallArrayFromList
920  toList = Foldable.toList
921
922smallArrayLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> SmallArray a -> ShowS
923smallArrayLiftShowsPrec elemShowsPrec elemListShowsPrec p sa = showParen (p > 10) $
924  showString "fromListN " . shows (length sa) . showString " "
925    . listLiftShowsPrec elemShowsPrec elemListShowsPrec 11 (toList sa)
926
927-- this need to be included for older ghcs
928listLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> [a] -> ShowS
929listLiftShowsPrec _ sl _ = sl
930
931instance Show a => Show (SmallArray a) where
932  showsPrec p sa = smallArrayLiftShowsPrec showsPrec showList p sa
933
934#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
935-- | @since 0.6.4.0
936instance Show1 SmallArray where
937#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
938  liftShowsPrec = smallArrayLiftShowsPrec
939#else
940  showsPrec1 = smallArrayLiftShowsPrec showsPrec showList
941#endif
942#endif
943
944smallArrayLiftReadsPrec :: (Int -> ReadS a) -> ReadS [a] -> Int -> ReadS (SmallArray a)
945smallArrayLiftReadsPrec _ listReadsPrec p = readParen (p > 10) . readP_to_S $ do
946  () <$ string "fromListN"
947  skipSpaces
948  n <- readS_to_P reads
949  skipSpaces
950  l <- readS_to_P listReadsPrec
951  return $ smallArrayFromListN n l
952
953instance Read a => Read (SmallArray a) where
954  readsPrec = smallArrayLiftReadsPrec readsPrec readList
955
956#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
957-- | @since 0.6.4.0
958instance Read1 SmallArray where
959#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
960  liftReadsPrec = smallArrayLiftReadsPrec
961#else
962  readsPrec1 = smallArrayLiftReadsPrec readsPrec readList
963#endif
964#endif
965
966
967
968smallArrayDataType :: DataType
969smallArrayDataType =
970  mkDataType "Data.Primitive.SmallArray.SmallArray" [fromListConstr]
971
972fromListConstr :: Constr
973fromListConstr = mkConstr smallArrayDataType "fromList" [] Prefix
974
975instance Data a => Data (SmallArray a) where
976  toConstr _ = fromListConstr
977  dataTypeOf _ = smallArrayDataType
978  gunfold k z c = case constrIndex c of
979    1 -> k (z fromList)
980    _ -> die "gunfold" "SmallArray"
981  gfoldl f z m = z fromList `f` toList m
982
983instance (Typeable s, Typeable a) => Data (SmallMutableArray s a) where
984  toConstr _ = die "toConstr" "SmallMutableArray"
985  gunfold _ _ = die "gunfold" "SmallMutableArray"
986  dataTypeOf _ = mkNoRepType "Data.Primitive.SmallArray.SmallMutableArray"
987#endif
988
989-- | Create a 'SmallArray' from a list of a known length. If the length
990--   of the list does not match the given length, this throws an exception.
991smallArrayFromListN :: Int -> [a] -> SmallArray a
992#if HAVE_SMALL_ARRAY
993smallArrayFromListN n l =
994  createSmallArray n
995      (die "smallArrayFromListN" "uninitialized element") $ \sma ->
996  let go !ix [] = if ix == n
997        then return ()
998        else die "smallArrayFromListN" "list length less than specified size"
999      go !ix (x : xs) = if ix < n
1000        then do
1001          writeSmallArray sma ix x
1002          go (ix+1) xs
1003        else die "smallArrayFromListN" "list length greater than specified size"
1004  in go 0 l
1005#else
1006smallArrayFromListN n l = SmallArray (Array.fromListN n l)
1007#endif
1008
1009-- | Create a 'SmallArray' from a list.
1010smallArrayFromList :: [a] -> SmallArray a
1011smallArrayFromList l = smallArrayFromListN (length l) l
1012
1013#if MIN_VERSION_base(4,14,0)
1014-- | Shrink the mutable array in place. The size given must be equal to
1015-- or less than the current size of the array. This is not checked.
1016shrinkSmallMutableArray :: PrimMonad m
1017  => SmallMutableArray (PrimState m) a
1018  -> Int
1019  -> m ()
1020{-# inline shrinkSmallMutableArray #-}
1021shrinkSmallMutableArray (SmallMutableArray x) (I# n) = primitive
1022  (\s0 -> case GHC.Exts.shrinkSmallMutableArray# x n s0 of
1023    s1 -> (# s1, () #)
1024  )
1025#endif
1026