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