packages feed

primitive 0.6.3.0 → 0.6.4.0

raw patch · 16 files changed

+3387/−372 lines, 16 filesdep −primitivedep ~basedep ~ghc-prim

Dependencies removed: primitive

Dependency ranges changed: base, ghc-prim

Files

Control/Monad/Primitive.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE CPP, MagicHash, UnboxedTuples, TypeFamilies #-} {-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-warn-deprecations #-}  -- | -- Module      : Control.Monad.Primitive@@ -77,6 +78,8 @@ -- Unlike 'PrimMonad', this typeclass requires that the @Monad@ be fully -- expressed as a state transformer, therefore disallowing other monad -- transformers on top of the base @IO@ or @ST@.+--+-- @since 0.6.0.0 class PrimMonad m => PrimBase m where   -- | Expose the internal structure of the monad   internal :: m a -> State# (PrimState m) -> (# State# (PrimState m), a #)@@ -97,41 +100,52 @@   internal (IO p) = p   {-# INLINE internal #-} +-- | @since 0.6.3.0 instance PrimMonad m => PrimMonad (ContT r m) where   type PrimState (ContT r m) = PrimState m   primitive = lift . primitive   {-# INLINE primitive #-}+ instance PrimMonad m => PrimMonad (IdentityT m) where   type PrimState (IdentityT m) = PrimState m   primitive = lift . primitive   {-# INLINE primitive #-}++-- | @since 0.6.2.0 instance PrimBase m => PrimBase (IdentityT m) where   internal (IdentityT m) = internal m   {-# INLINE internal #-}+ instance PrimMonad m => PrimMonad (ListT m) where   type PrimState (ListT m) = PrimState m   primitive = lift . primitive   {-# INLINE primitive #-}+ instance PrimMonad m => PrimMonad (MaybeT m) where   type PrimState (MaybeT m) = PrimState m   primitive = lift . primitive   {-# INLINE primitive #-}+ instance (Error e, PrimMonad m) => PrimMonad (ErrorT e m) where   type PrimState (ErrorT e m) = PrimState m   primitive = lift . primitive   {-# INLINE primitive #-}+ instance PrimMonad m => PrimMonad (ReaderT r m) where   type PrimState (ReaderT r m) = PrimState m   primitive = lift . primitive   {-# INLINE primitive #-}+ instance PrimMonad m => PrimMonad (StateT s m) where   type PrimState (StateT s m) = PrimState m   primitive = lift . primitive   {-# INLINE primitive #-}+ instance (Monoid w, PrimMonad m) => PrimMonad (WriterT w m) where   type PrimState (WriterT w m) = PrimState m   primitive = lift . primitive   {-# INLINE primitive #-}+ instance (Monoid w, PrimMonad m) => PrimMonad (RWST r w s m) where   type PrimState (RWST r w s m) = PrimState m   primitive = lift . primitive@@ -145,6 +159,7 @@ #endif  #if MIN_VERSION_transformers(0,5,3)+-- | @since 0.6.3.0 instance ( Monoid w          , PrimMonad m # if !(MIN_VERSION_base(4,8,0))@@ -164,10 +179,12 @@   type PrimState (Strict.StateT s m) = PrimState m   primitive = lift . primitive   {-# INLINE primitive #-}+ instance (Monoid w, PrimMonad m) => PrimMonad (Strict.WriterT w m) where   type PrimState (Strict.WriterT w m) = PrimState m   primitive = lift . primitive   {-# INLINE primitive #-}+ instance (Monoid w, PrimMonad m) => PrimMonad (Strict.RWST r w s m) where   type PrimState (Strict.RWST r w s m) = PrimState m   primitive = lift . primitive@@ -205,11 +222,15 @@ primToST = primToPrim  -- | Convert an 'IO' action to a 'PrimMonad'.+-- +-- @since 0.6.2.0 ioToPrim :: (PrimMonad m, PrimState m ~ RealWorld) => IO a -> m a {-# INLINE ioToPrim #-} ioToPrim = primToPrim  -- | Convert an 'ST' action to a 'PrimMonad'.+--+-- @since 0.6.2.0 stToPrim :: PrimMonad m => ST (PrimState m) a -> m a {-# INLINE stToPrim #-} stToPrim = primToPrim@@ -233,12 +254,16 @@  -- | Convert an 'ST' action with an arbitraty state token to any 'PrimMonad'. -- This operation is highly unsafe!+-- +-- @since 0.6.2.0 unsafeSTToPrim :: PrimMonad m => ST s a -> m a {-# INLINE unsafeSTToPrim #-} unsafeSTToPrim = unsafePrimToPrim  -- | Convert an 'IO' action to any 'PrimMonad'. This operation is highly -- unsafe!+--+-- @since 0.6.2.0 unsafeIOToPrim :: PrimMonad m => IO a -> m a {-# INLINE unsafeIOToPrim #-} unsafeIOToPrim = unsafePrimToPrim@@ -261,6 +286,8 @@         $ (primitive (\s -> case touch# x s of { s' -> (# s', () #) }) :: IO ())  -- | Create an action to force a value; generalizes 'Control.Exception.evaluate'+--+-- @since 0.6.2.0 evalPrim :: forall a m . PrimMonad m => a -> m a #if MIN_VERSION_base(4,4,0) evalPrim a = primitive (\s -> seq# a s)
Data/Primitive.hs view
@@ -11,15 +11,75 @@ -- Reexports all primitive operations -- module Data.Primitive (-  module Data.Primitive.Types,-  module Data.Primitive.Array,-  module Data.Primitive.ByteArray,-  module Data.Primitive.Addr,--  sizeOf, alignment+  -- * Re-exports+  module Data.Primitive.Types+  ,module Data.Primitive.Array+  ,module Data.Primitive.ByteArray+  ,module Data.Primitive.Addr+  ,module Data.Primitive.SmallArray+  ,module Data.Primitive.UnliftedArray+  ,module Data.Primitive.PrimArray+  ,module Data.Primitive.MutVar+  -- * Naming Conventions+  -- $namingConventions ) where  import Data.Primitive.Types import Data.Primitive.Array import Data.Primitive.ByteArray import Data.Primitive.Addr+import Data.Primitive.SmallArray+import Data.Primitive.UnliftedArray+import Data.Primitive.PrimArray+import Data.Primitive.MutVar++{- $namingConventions+For historical reasons, this library embraces the practice of suffixing+the name of a function with the type it operates on. For example, three+of the variants of the array indexing function are:++> indexArray      ::           Array      a -> Int -> a+> indexSmallArray ::           SmallArray a -> Int -> a+> indexPrimArray  :: Prim a => PrimArray  a -> Int -> a++In a few places, where the language sounds more natural, the array type+is instead used as a prefix. For example, @Data.Primitive.SmallArray@+exports @smallArrayFromList@, which would sound unnatural if it used+@SmallArray@ as a suffix instead.++This library provides several functions traversing, building, and filtering+arrays. These functions are suffixed with an additional character to+indicate their the nature of their effectfulness:++* No suffix: A non-effectful pass over the array.+* @-A@ suffix: An effectful pass over the array, where the effect is 'Applicative'.+* @-P@ suffix: An effectful pass over the array, where the effect is 'PrimMonad'.++Additionally, an apostrophe can be used to indicate strictness in the elements.+The variants with an apostrophe are used in @Data.Primitive.Array@ but not+in @Data.Primitive.PrimArray@ since the array type it provides is always strict in the element.+For example, there are three variants of the function that filters elements+from a primitive array.++> filterPrimArray  :: (Prim a               ) => (a ->   Bool) -> PrimArray a ->    PrimArray a+> filterPrimArrayA :: (Prim a, Applicative f) => (a -> f Bool) -> PrimArray a -> f (PrimArray a)+> filterPrimArrayP :: (Prim a, PrimMonad   m) => (a -> m Bool) -> PrimArray a -> m (PrimArray a)++As long as the effectful context is a monad that is sufficiently affine+the behaviors of the 'Applicative' and 'PrimMonad' variants produce the same results+and differ only in their strictness. Monads that are sufficiently affine+include:++* 'IO' and 'ST'+* Any combination of 'MaybeT', 'ExceptT', 'StateT' and 'Writer' on top+  of another sufficiently affine monad.++There is one situation where the names deviate from effectful suffix convention+described above. Throughout the haskell ecosystem, the 'Applicative' variant of+'map' is known as 'traverse', not @mapA@. Consequently, we adopt the following+naming convention for mapping:++> mapPrimArray :: (Prim a, Prim b) => (a -> b) -> PrimArray a -> PrimArray b+> traversePrimArray :: (Applicative f, Prim a, Prim b) => (a -> f b) -> PrimArray a -> f (PrimArray b)+> traversePrimArrayP :: (PrimMonad m, Prim a, Prim b) => (a -> m b) -> PrimArray a -> m (PrimArray b)+-}
Data/Primitive/Addr.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE MagicHash, UnboxedTuples #-}+{-# LANGUAGE MagicHash, UnboxedTuples, CPP #-}  -- | -- Module      : Data.Primitive.Addr@@ -22,11 +22,21 @@   indexOffAddr, readOffAddr, writeOffAddr,    -- * Block operations-  copyAddr, moveAddr, setAddr+  copyAddr,+#if __GLASGOW_HASKELL__ >= 708+  copyAddrToByteArray,+#endif+  moveAddr, setAddr,++  -- * Conversion+  addrToInt ) where  import Control.Monad.Primitive import Data.Primitive.Types+#if __GLASGOW_HASKELL__ >= 708+import Data.Primitive.ByteArray+#endif  import GHC.Base ( Int(..) ) import GHC.Prim@@ -84,6 +94,23 @@ copyAddr (Addr dst#) (Addr src#) n   = unsafePrimToPrim $ copyBytes (Ptr dst#) (Ptr src#) n +#if __GLASGOW_HASKELL__ >= 708+-- | Copy the given number of bytes from the 'Addr' to the 'MutableByteArray'.+--   The areas may not overlap. This function is only available when compiling+--   with GHC 7.8 or newer.+--   +--   @since 0.6.4.0+copyAddrToByteArray :: PrimMonad m+  => MutableByteArray (PrimState m) -- ^ destination+  -> Int -- ^ offset into the destination array+  -> Addr -- ^ source+  -> Int -- ^ number of bytes to copy+  -> m ()+{-# INLINE copyAddrToByteArray #-}+copyAddrToByteArray (MutableByteArray marr) (I# off) (Addr addr) (I# len) =+  primitive_ $ copyAddrToByteArray# addr marr off len+#endif+ -- | Copy the given number of bytes from the second 'Addr' to the first. The -- areas may overlap. moveAddr :: PrimMonad m => Addr         -- ^ destination address@@ -100,3 +127,7 @@ {-# INLINE setAddr #-} setAddr (Addr addr#) (I# n#) x = primitive_ (setOffAddr# addr# 0# n# x) +-- | Convert an 'Addr' to an 'Int'.+addrToInt :: Addr -> Int+{-# INLINE addrToInt #-}+addrToInt (Addr addr#) = I# (addr2Int# addr#)
Data/Primitive/Array.hs view
@@ -16,13 +16,15 @@ module Data.Primitive.Array (   Array(..), MutableArray(..), -  newArray, readArray, writeArray, indexArray, indexArrayM,-  freezeArray, thawArray,+  newArray, readArray, writeArray, indexArray, indexArrayM, indexArray##,+  freezeArray, thawArray, runArray,   unsafeFreezeArray, unsafeThawArray, sameMutableArray,   copyArray, copyMutableArray,   cloneArray, cloneMutableArray,   sizeofArray, sizeofMutableArray,-  fromListN, fromList+  fromListN, fromList,+  mapArray',+  traverseArrayP ) where  import Control.Monad.Primitive@@ -42,7 +44,7 @@ import Control.Monad.ST(ST,runST)  import Control.Applicative-import Control.Monad (MonadPlus(..))+import Control.Monad (MonadPlus(..), when) import Control.Monad.Fix #if MIN_VERSION_base(4,4,0) import Control.Monad.Zip@@ -53,31 +55,35 @@ import Data.Monoid #endif #if MIN_VERSION_base(4,9,0)+import qualified GHC.ST as GHCST import qualified Data.Foldable as F import Data.Semigroup #endif+#if MIN_VERSION_base(4,8,0)+import Data.Functor.Identity+#endif+#if MIN_VERSION_base(4,10,0)+import GHC.Exts (runRW#)+#elif MIN_VERSION_base(4,9,0)+import GHC.Base (runRW#)+#endif  import Text.ParserCombinators.ReadP +#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+import Data.Functor.Classes (Eq1(..),Ord1(..),Show1(..),Read1(..))+#endif+ -- | Boxed arrays data Array a = Array-             { array# :: Array# a-#if (__GLASGOW_HASKELL__ < 702)-             , sizeofArray :: {-# UNPACK #-} !Int-#endif-             }+  { array# :: Array# a }   deriving ( Typeable )  -- | Mutable boxed arrays associated with a primitive state token. data MutableArray s a = MutableArray-                      { marray# :: MutableArray# s a-#if (__GLASGOW_HASKELL__ < 702)-                      , sizeofMutableArray :: {-# UNPACK #-} !Int-#endif-                      }+  { marray# :: MutableArray# s a }   deriving ( Typeable ) -#if (__GLASGOW_HASKELL__ >= 702) sizeofArray :: Array a -> Int sizeofArray a = I# (sizeofArray# (array# a)) {-# INLINE sizeofArray #-}@@ -85,7 +91,6 @@ sizeofMutableArray :: MutableArray s a -> Int sizeofMutableArray a = I# (sizeofMutableArray# (marray# a)) {-# INLINE sizeofMutableArray #-}-#endif  -- | Create a new mutable array of the specified size and initialise all -- elements with the given value.@@ -95,9 +100,6 @@    (\s# -> case newArray# n# x s# of              (# s'#, arr# #) ->                let ma = MutableArray arr#-#if (__GLASGOW_HASKELL__ < 702)-                          (I# n#)-#endif                in (# s'# , ma #))  -- | Read a value from the array at the given index.@@ -115,6 +117,13 @@ {-# INLINE indexArray #-} indexArray arr (I# i#) = case indexArray# (array# arr) i# of (# x #) -> x +-- | Read a value from the immutable array at the given index, returning+-- the result in an unboxed unary tuple. This is currently used to implement+-- folds.+indexArray## :: Array a -> Int -> (# a #)+indexArray## arr (I# i) = indexArray# (array# arr) i+{-# INLINE indexArray## #-}+ -- | Monadically read a value from the immutable array at the given index. -- This allows us to be strict in the array while remaining lazy in the read -- element which is very useful for collective operations. Suppose we want to@@ -154,16 +163,9 @@   -> Int                          -- ^ length   -> m (Array a) {-# INLINE freezeArray #-}-#if (__GLASGOW_HASKELL__ >= 702) freezeArray (MutableArray ma#) (I# off#) (I# len#) =   primitive $ \s -> case freezeArray# ma# off# len# s of     (# s', a# #) -> (# s', Array a# #)-#else-freezeArray src off len = do-  dst <- newArray len (die "freezeArray" "impossible")-  copyMutableArray dst 0 src off len-  unsafeFreezeArray dst-#endif  -- | Convert a mutable array to an immutable one without copying. The -- array should not be modified after the conversion.@@ -173,9 +175,6 @@   = primitive (\s# -> case unsafeFreezeArray# (marray# arr) s# of                         (# s'#, arr'# #) ->                           let a = Array arr'#-#if (__GLASGOW_HASKELL__ < 702)-                                    (sizeofMutableArray arr)-#endif                           in (# s'#, a #))  -- | Create a mutable array from a slice of an immutable array.@@ -189,16 +188,9 @@   -> Int     -- ^ length   -> m (MutableArray (PrimState m) a) {-# INLINE thawArray #-}-#if (__GLASGOW_HASKELL__ >= 702) thawArray (Array a#) (I# off#) (I# len#) =   primitive $ \s -> case thawArray# a# off# len# s of     (# s', ma# #) -> (# s', MutableArray ma# #)-#else-thawArray src off len = do-  dst <- newArray len (die "thawArray" "impossible")-  copyArray dst 0 src off len-  return dst-#endif  -- | Convert an immutable array to an mutable one without copying. The -- immutable array should not be used after the conversion.@@ -208,9 +200,6 @@   = primitive (\s# -> case unsafeThawArray# (array# a) s# of                         (# s'#, arr'# #) ->                           let ma = MutableArray arr'#-#if (__GLASGOW_HASKELL__ < 702)-                                     (sizeofArray a)-#endif                           in (# s'#, ma #))  -- | Check whether the two arrays refer to the same memory block.@@ -275,15 +264,8 @@            -> Int     -- ^ number of elements to copy            -> Array a {-# INLINE cloneArray #-}-#if __GLASGOW_HASKELL__ >= 702 cloneArray (Array arr#) (I# off#) (I# len#)   = case cloneArray# arr# off# len# of arr'# -> Array arr'#-#else-cloneArray arr off len = runST $ do-    marr2 <- newArray len $ die "cloneArray" "impossible"-    copyArray marr2 0 arr off len-    unsafeFreezeArray marr2-#endif  -- | Return a newly allocated MutableArray. with the specified subrange of -- the provided MutableArray. The provided MutableArray should contain the@@ -294,112 +276,209 @@         -> Int                          -- ^ number of elements to copy         -> m (MutableArray (PrimState m) a) {-# INLINE cloneMutableArray #-}-#if __GLASGOW_HASKELL__ >= 702 cloneMutableArray (MutableArray arr#) (I# off#) (I# len#) = primitive    (\s# -> case cloneMutableArray# arr# off# len# s# of              (# s'#, arr'# #) -> (# s'#, MutableArray arr'# #))-#else-cloneMutableArray marr off len = do-        marr2 <- newArray len $ die "cloneMutableArray" "impossible"-        let go !i !j c-                | c >= len = return marr2-                | otherwise = do-                    b <- readArray marr i-                    writeArray marr2 j b-                    go (i+1) (j+1) (c+1)-        go off 0 0-#endif  emptyArray :: Array a emptyArray =   runST $ newArray 0 (die "emptyArray" "impossible") >>= unsafeFreezeArray {-# NOINLINE emptyArray #-} +#if !MIN_VERSION_base(4,9,0) createArray   :: Int   -> a   -> (forall s. MutableArray s a -> ST s ())   -> Array a createArray 0 _ _ = emptyArray-createArray n x f = runST $ do-  ma <- newArray n x-  f ma-  unsafeFreezeArray ma+createArray n x f = runArray $ do+  mary <- newArray n x+  f mary+  pure mary +runArray+  :: (forall s. ST s (MutableArray s a))+  -> Array a+runArray m = runST $ m >>= unsafeFreezeArray++#else /* Below, runRW# is available. */++-- This low-level business is designed to work with GHC's worker-wrapper+-- transformation. A lot of the time, we don't actually need an Array+-- constructor. By putting it on the outside, and being careful about+-- how we special-case the empty array, we can make GHC smarter about this.+-- The only downside is that separately created 0-length arrays won't share+-- their Array constructors, although they'll share their underlying+-- Array#s.+createArray+  :: Int+  -> a+  -> (forall s. MutableArray s a -> ST s ())+  -> Array a+createArray 0 _ _ = Array (emptyArray# (# #))+createArray n x f = runArray $ do+  mary <- newArray n x+  f mary+  pure mary++runArray+  :: (forall s. ST s (MutableArray s a))+  -> Array a+runArray m = Array (runArray# m)++runArray#+  :: (forall s. ST s (MutableArray s a))+  -> Array# a+runArray# m = case runRW# $ \s ->+  case unST m s of { (# s', MutableArray mary# #) ->+  unsafeFreezeArray# mary# s'} of (# _, ary# #) -> ary#++unST :: ST s a -> State# s -> (# State# s, a #)+unST (GHCST.ST f) = f++emptyArray# :: (# #) -> Array# a+emptyArray# _ = case emptyArray of Array ar -> ar+{-# NOINLINE emptyArray# #-}+#endif++ die :: String -> String -> a die fun problem = error $ "Data.Primitive.Array." ++ fun ++ ": " ++ problem +arrayLiftEq :: (a -> b -> Bool) -> Array a -> Array b -> Bool+arrayLiftEq p a1 a2 = sizeofArray a1 == sizeofArray a2 && loop (sizeofArray a1 - 1)+  where loop i | i < 0     = True+               | (# x1 #) <- indexArray## a1 i+               , (# x2 #) <- indexArray## a2 i+               , otherwise = p x1 x2 && loop (i-1)+ instance Eq a => Eq (Array a) where-  a1 == a2 = sizeofArray a1 == sizeofArray a2 && loop (sizeofArray a1 - 1)-   where loop i | i < 0     = True-                | otherwise = indexArray a1 i == indexArray a2 i && loop (i-1)+  a1 == a2 = arrayLiftEq (==) a1 a2 +#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+-- | @since 0.6.4.0+instance Eq1 Array where+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)+  liftEq = arrayLiftEq+#else+  eq1 = arrayLiftEq (==)+#endif+#endif+ instance Eq (MutableArray s a) where   ma1 == ma2 = isTrue# (sameMutableArray# (marray# ma1) (marray# ma2)) +arrayLiftCompare :: (a -> b -> Ordering) -> Array a -> Array b -> Ordering+arrayLiftCompare elemCompare a1 a2 = loop 0+  where+  mn = sizeofArray a1 `min` sizeofArray a2+  loop i+    | i < mn+    , (# x1 #) <- indexArray## a1 i+    , (# x2 #) <- indexArray## a2 i+    = elemCompare x1 x2 `mappend` loop (i+1)+    | otherwise = compare (sizeofArray a1) (sizeofArray a2)++-- | Lexicographic ordering. Subject to change between major versions. instance Ord a => Ord (Array a) where-  compare a1 a2 = loop 0-   where-   mn = sizeofArray a1 `min` sizeofArray a2-   loop i-     | i < mn    = compare (indexArray a1 i) (indexArray a2 i) `mappend` loop (i+1)-     | otherwise = compare (sizeofArray a1) (sizeofArray a2)+  compare a1 a2 = arrayLiftCompare compare a1 a2 +#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+-- | @since 0.6.4.0+instance Ord1 Array where+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)+  liftCompare = arrayLiftCompare+#else+  compare1 = arrayLiftCompare compare+#endif+#endif+ instance Foldable Array where-  foldr f z a = go 0-   where go i | i < sizeofArray a = f (indexArray a i) (go $ i+1)-              | otherwise         = z+  -- Note: we perform the array lookups eagerly so we won't+  -- create thunks to perform lookups even if GHC can't see+  -- that the folding function is strict.+  foldr f = \z !ary ->+    let+      !sz = sizeofArray ary+      go i+        | i == sz = z+        | (# x #) <- indexArray## ary i+        = f x (go (i+1))+    in go 0   {-# INLINE foldr #-}-  foldl f z a = go (sizeofArray a - 1)-   where go i | i < 0     = z-              | otherwise = f (go $ i-1) (indexArray a i)+  foldl f = \z !ary ->+    let+      go i+        | i < 0 = z+        | (# x #) <- indexArray## ary i+        = f (go (i-1)) x+    in go (sizeofArray ary - 1)   {-# INLINE foldl #-}-  foldr1 f a | sz < 0    = die "foldr1" "empty array"-             | otherwise = go 0-   where sz = sizeofArray a - 1-         z = indexArray a sz-         go i | i < sz    = f (indexArray a i) (go $ i+1)-              | otherwise = z+  foldr1 f = \ !ary ->+    let+      !sz = sizeofArray ary - 1+      go i =+        case indexArray## ary i of+          (# x #) | i == sz -> x+                  | otherwise -> f x (go (i+1))+    in if sz < 0+       then die "foldr1" "empty array"+       else go 0   {-# INLINE foldr1 #-}-  foldl1 f a | sz == 0   = die "foldl1" "empty array"-             | otherwise = go $ sz-1-   where sz = sizeofArray a-         z = indexArray a 0-         go i | i < 1     = f (go $ i-1) (indexArray a i)-              | otherwise = z+  foldl1 f = \ !ary ->+    let+      !sz = sizeofArray ary - 1+      go i =+        case indexArray## ary i of+          (# x #) | i == 0 -> x+                  | otherwise -> f (go (i - 1)) x+    in if sz < 0+       then die "foldl1" "empty array"+       else go sz   {-# INLINE foldl1 #-} #if MIN_VERSION_base(4,6,0)-  foldr' f z a = go (sizeofArray a - 1) z-   where go i !acc | i < 0     = acc-                   | otherwise = go (i-1) (f (indexArray a i) acc)+  foldr' f = \z !ary ->+    let+      go i !acc+        | i == -1 = acc+        | (# x #) <- indexArray## ary i+        = go (i-1) (f x acc)+    in go (sizeofArray ary - 1) z   {-# INLINE foldr' #-}-  foldl' f z a = go 0 z-   where go i !acc | i < sizeofArray a = go (i+1) (f acc $ indexArray a i)-                   | otherwise         = acc+  foldl' f = \z !ary ->+    let+      !sz = sizeofArray ary+      go i !acc+        | i == sz = acc+        | (# x #) <- indexArray## ary i+        = go (i+1) (f acc x)+    in go 0 z   {-# INLINE foldl' #-} #endif #if MIN_VERSION_base(4,8,0)-  toList a = Exts.build $ \c z -> let-      sz = sizeofArray a-      go i | i < sz    = c (indexArray a i) (go $ i+1)-           | otherwise = z-    in go 0-  {-# INLINE toList #-}   null a = sizeofArray a == 0   {-# INLINE null #-}   length = sizeofArray   {-# INLINE length #-}-  maximum a | sz == 0   = die "maximum" "empty array"-            | otherwise = go 1 (indexArray a 0)-   where sz = sizeofArray a-         go i !e | i < sz    = go (i+1) (max e $ indexArray a i)-                 | otherwise = e+  maximum ary | sz == 0   = die "maximum" "empty array"+              | (# frst #) <- indexArray## ary 0+              = go 1 frst+   where+     sz = sizeofArray ary+     go i !e+       | i == sz = e+       | (# x #) <- indexArray## ary i+       = go (i+1) (max e x)   {-# INLINE maximum #-}-  minimum a | sz == 0   = die "minimum" "empty array"-            | otherwise = go 1 (indexArray a 0)-   where sz = sizeofArray a-         go i !e | i < sz    = go (i+1) (min e $ indexArray a i)-                 | otherwise = e+  minimum ary | sz == 0   = die "minimum" "empty array"+              | (# frst #) <- indexArray## ary 0+              = go 1 frst+   where sz = sizeofArray ary+         go i !e+           | i == sz = e+           | (# x #) <- indexArray## ary i+           = go (i+1) (min e x)   {-# INLINE minimum #-}   sum = foldl' (+) 0   {-# INLINE sum #-}@@ -407,56 +486,155 @@   {-# INLINE product #-} #endif +newtype STA a = STA {_runSTA :: forall s. MutableArray# s a -> ST s (Array a)}++runSTA :: Int -> STA a -> Array a+runSTA !sz = \ (STA m) -> runST $ newArray_ sz >>= \ ar -> m (marray# ar)+{-# INLINE runSTA #-}++newArray_ :: Int -> ST s (MutableArray s a)+newArray_ !n = newArray n badTraverseValue++badTraverseValue :: a+badTraverseValue = die "traverse" "bad indexing"+{-# NOINLINE badTraverseValue #-}+ instance Traversable Array where-  traverse f a =-    fromListN (sizeofArray a)-      <$> traverse (f . indexArray a) [0 .. sizeofArray a - 1]+  traverse f = traverseArray f+  {-# INLINE traverse #-} +traverseArray+  :: Applicative f+  => (a -> f b)+  -> Array a+  -> f (Array b)+traverseArray f = \ !ary ->+  let+    !len = sizeofArray ary+    go !i+      | i == len = pure $ STA $ \mary -> unsafeFreezeArray (MutableArray mary)+      | (# x #) <- indexArray## ary i+      = liftA2 (\b (STA m) -> STA $ \mary ->+                  writeArray (MutableArray mary) i b >> m mary)+               (f x) (go (i + 1))+  in if len == 0+     then pure emptyArray+     else runSTA len <$> go 0+{-# INLINE [1] traverseArray #-}++{-# RULES+"traverse/ST" forall (f :: a -> ST s b). traverseArray f =+   traverseArrayP f+"traverse/IO" forall (f :: a -> IO b). traverseArray f =+   traverseArrayP f+ #-}+#if MIN_VERSION_base(4,8,0)+{-# RULES+"traverse/Id" forall (f :: a -> Identity b). traverseArray f =+   (coerce :: (Array a -> Array (Identity b))+           -> Array a -> Identity (Array b)) (fmap f)+ #-}+#endif++-- | This is the fastest, most straightforward way to traverse+-- an array, but it only works correctly with a sufficiently+-- "affine" 'PrimMonad' instance. In particular, it must only produce+-- *one* result array. 'Control.Monad.Trans.List.ListT'-transformed+-- monads, for example, will not work right at all.+traverseArrayP+  :: PrimMonad m+  => (a -> m b)+  -> Array a+  -> m (Array b)+traverseArrayP f = \ !ary ->+  let+    !sz = sizeofArray ary+    go !i !mary+      | i == sz+      = unsafeFreezeArray mary+      | otherwise+      = do+          a <- indexArrayM ary i+          b <- f a+          writeArray mary i b+          go (i + 1) mary+  in do+    mary <- newArray sz badTraverseValue+    go 0 mary+{-# INLINE traverseArrayP #-}++-- | Strict map over the elements of the array.+mapArray' :: (a -> b) -> Array a -> Array b+mapArray' f a =+  createArray (sizeofArray a) (die "mapArray'" "impossible") $ \mb ->+    let go i | i == sizeofArray a+             = return ()+             | otherwise+             = do x <- indexArrayM a i+                  -- We use indexArrayM here so that we will perform the+                  -- indexing eagerly even if f is lazy.+                  let !y = f x+                  writeArray mb i y >> go (i+1)+     in go 0+{-# INLINE mapArray' #-}++arrayFromListN :: Int -> [a] -> Array a+arrayFromListN n l =+  createArray n (die "fromListN" "uninitialized element") $ \sma ->+    let go !ix [] = if ix == n+          then return ()+          else die "fromListN" "list length less than specified size"+        go !ix (x : xs) = if ix < n+          then do+            writeArray sma ix x+            go (ix+1) xs+          else die "fromListN" "list length greater than specified size"+    in go 0 l++arrayFromList :: [a] -> Array a+arrayFromList l = arrayFromListN (length l) l+ #if MIN_VERSION_base(4,7,0) instance Exts.IsList (Array a) where   type Item (Array a) = a-  fromListN n l =-    createArray n (die "fromListN" "mismatched size and list") $ \mi ->-      let go i (x:xs) = writeArray mi i x >> go (i+1) xs-          go _ [    ] = return ()-       in go 0 l-  fromList l = Exts.fromListN (length l) l+  fromListN = arrayFromListN+  fromList = arrayFromList   toList = toList #else fromListN :: Int -> [a] -> Array a-fromListN n l =-  createArray n (die "fromListN" "mismatched size and list") $ \mi ->-    let go i (x:xs) = writeArray mi i x >> go (i+1) xs-        go _ [    ] = return ()-     in go 0 l+fromListN = arrayFromListN  fromList :: [a] -> Array a-fromList l = fromListN (length l) l+fromList = arrayFromList #endif  instance Functor Array where   fmap f a =     createArray (sizeofArray a) (die "fmap" "impossible") $ \mb ->-      let go i | i < sizeofArray a = return ()-               | otherwise         = writeArray mb i (f $ indexArray a i)-                                  >> go (i+1)+      let go i | i == sizeofArray a+               = return ()+               | otherwise+               = do x <- indexArrayM a i+                    writeArray mb i (f x) >> go (i+1)        in go 0 #if MIN_VERSION_base(4,8,0)-  e <$ a = runST $ newArray (sizeofArray a) e >>= unsafeFreezeArray+  e <$ a = createArray (sizeofArray a) e (\ !_ -> pure ()) #endif  instance Applicative Array where-  pure x = runST $ newArray 1 x >>= unsafeFreezeArray-  ab <*> a = runST $ do-    mb <- newArray (szab*sza) $ die "<*>" "impossible"-    let go1 i-          | i < szab  = go2 (i*sza) (indexArray ab i) 0 >> go1 (i+1)-          | otherwise = return ()-        go2 off f j-          | j < sza   = writeArray mb (off + j) (f $ indexArray a j)-          | otherwise = return ()-    go1 0-    unsafeFreezeArray mb+  pure x = runArray $ newArray 1 x+  ab <*> a = createArray (szab*sza) (die "<*>" "impossible") $ \mb ->+    let go1 i = when (i < szab) $+            do+              f <- indexArrayM ab i+              go2 (i*sza) f 0+              go1 (i+1)+        go2 off f j = when (j < sza) $+            do+              x <- indexArrayM a j+              writeArray mb (off + j) (f x)+              go2 off f (j + 1)+    in go1 0    where szab = sizeofArray ab ; sza = sizeofArray a   a *> b = createArray (sza*szb) (die "*>" "impossible") $ \mb ->     let go i | i < sza   = copyArray mb (i * szb) b 0 szb@@ -466,7 +644,9 @@   a <* b = createArray (sza*szb) (die "<*" "impossible") $ \ma ->     let fill off i e | i < szb   = writeArray ma (off+i) e >> fill off (i+1) e                      | otherwise = return ()-        go i | i < sza   = fill (i*szb) 0 (indexArray a i) >> go (i+1)+        go i | i < sza+             = do x <- indexArrayM a i+                  fill (i*szb) 0 x >> go (i+1)              | otherwise = return ()      in go 0    where sza = sizeofArray a ; szb = sizeofArray b@@ -481,20 +661,36 @@   many a | sizeofArray a == 0 = pure []          | otherwise = die "many" "infinite arrays are not well defined" +data ArrayStack a+  = PushArray !(Array a) !(ArrayStack a)+  | EmptyStack+-- See the note in SmallArray about how we might improve this.+ instance Monad Array where   return = pure   (>>) = (*>)-  a >>= f = push 0 [] (sizeofArray a - 1)++  ary >>= f = collect 0 EmptyStack (la-1)    where-   push !sz bs i-     | i < 0 = build sz bs-     | otherwise = let b = f $ indexArray a i-                    in push (sz + sizeofArray b) (b:bs) (i+1)+   la = sizeofArray ary+   collect sz stk i+     | i < 0 = createArray sz (die ">>=" "impossible") $ fill 0 stk+     | (# x #) <- indexArray## ary i+     , let sb = f x+           lsb = sizeofArray sb+       -- If we don't perform this check, we could end up allocating+       -- a stack full of empty arrays if someone is filtering most+       -- things out. So we refrain from pushing empty arrays.+     = if lsb == 0+       then collect sz stk (i - 1)+       else collect (sz + lsb) (PushArray sb stk) (i-1) -   build sz stk = createArray sz (die ">>=" "impossible") $ \mb ->-     let go off (b:bs) = copyArray mb off b 0 (sizeofArray b) >> go (off + sizeofArray b) bs-         go _   [    ] = return ()-      in go 0 stk+   fill _   EmptyStack         _   = return ()+   fill off (PushArray sb sbs) smb+     | let lsb = sizeofArray sb+     = copyArray smb off sb 0 (lsb)+         *> fill (off + lsb) sbs smb+   fail _ = empty  instance MonadPlus Array where@@ -503,10 +699,13 @@  zipW :: String -> (a -> b -> c) -> Array a -> Array b -> Array c zipW s f aa ab = createArray mn (die s "impossible") $ \mc ->-  let go i-        | i < mn    = writeArray mc i (f (indexArray aa i) (indexArray ab i))-                   >> go (i+1)-        | otherwise = return ()+  let go i | i < mn+           = do+               x <- indexArrayM aa i+               y <- indexArrayM ab i+               writeArray mc i (f x y)+               go (i+1)+           | otherwise = return ()    in go 0  where mn = sizeofArray aa `min` sizeofArray ab {-# INLINE zipW #-}@@ -520,7 +719,7 @@     ma <- newArray sz (die "munzip" "impossible")     mb <- newArray sz (die "munzip" "impossible")     let go i | i < sz = do-          let (a, b) = indexArray aab i+          (a, b) <- indexArrayM aab i           writeArray ma i a           writeArray mb i b           go (i+1)@@ -530,9 +729,17 @@ #endif  instance MonadFix Array where-  mfix f = let l = mfix (toList . f) in fromListN (length l) l+  mfix f = createArray (sizeofArray (f err))+                       (die "mfix" "impossible") $ flip fix 0 $+    \r !i !mary -> when (i < sz) $ do+                      writeArray mary i (fix (\xi -> f xi `indexArray` i))+                      r (i + 1) mary+    where+      sz = sizeofArray (f err)+      err = error "mfix for Data.Primitive.Array applied to strict function."  #if MIN_VERSION_base(4,9,0)+-- | @since 0.6.3.0 instance Semigroup (Array a) where   (<>) = (<|>)   sconcat = mconcat . F.toList@@ -550,19 +757,50 @@      in go 0 l    where sz = sum . fmap sizeofArray $ l +arrayLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> Array a -> ShowS+arrayLiftShowsPrec elemShowsPrec elemListShowsPrec p a = showParen (p > 10) $+  showString "fromListN " . shows (sizeofArray a) . showString " "+    . listLiftShowsPrec elemShowsPrec elemListShowsPrec 11 (toList a)++-- this need to be included for older ghcs+listLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> [a] -> ShowS+listLiftShowsPrec _ sl _ = sl+ instance Show a => Show (Array a) where-  showsPrec p a = showParen (p > 10) $-    showString "fromListN " . shows (sizeofArray a) . showString " "-      . shows (toList a)+  showsPrec p a = arrayLiftShowsPrec showsPrec showList p a +#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+-- | @since 0.6.4.0+instance Show1 Array where+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)+  liftShowsPrec = arrayLiftShowsPrec+#else+  showsPrec1 = arrayLiftShowsPrec showsPrec showList+#endif+#endif++arrayLiftReadsPrec :: (Int -> ReadS a) -> ReadS [a] -> Int -> ReadS (Array a)+arrayLiftReadsPrec _ listReadsPrec p = readParen (p > 10) . readP_to_S $ do+  () <$ string "fromListN"+  skipSpaces+  n <- readS_to_P reads+  skipSpaces+  l <- readS_to_P listReadsPrec+  return $ arrayFromListN n l+ instance Read a => Read (Array a) where-  readsPrec p = readParen (p > 10) . readP_to_S $ do-    () <$ string "fromListN"-    skipSpaces-    n <- readS_to_P reads-    skipSpaces-    l <- readS_to_P reads-    return $ fromListN n l+  readsPrec = arrayLiftReadsPrec readsPrec readList++#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+-- | @since 0.6.4.0+instance Read1 Array where+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)+  liftReadsPrec = arrayLiftReadsPrec+#else+  readsPrec1 = arrayLiftReadsPrec readsPrec readList+#endif+#endif+  arrayDataType :: DataType arrayDataType = mkDataType "Data.Primitive.Array.Array" [fromListConstr]
Data/Primitive/ByteArray.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, MagicHash, UnboxedTuples, UnliftedFFITypes, DeriveDataTypeable #-}+{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples, UnliftedFFITypes, DeriveDataTypeable #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} @@ -19,10 +19,14 @@    -- * Allocation   newByteArray, newPinnedByteArray, newAlignedPinnedByteArray,+  resizeMutableByteArray,    -- * Element access   readByteArray, writeByteArray, indexByteArray, +  -- * Constructing+  byteArrayFromList, byteArrayFromListN,+   -- * Folding   foldrByteArray, @@ -30,17 +34,25 @@   unsafeFreezeByteArray, unsafeThawByteArray,    -- * Block operations-  copyByteArray, copyMutableByteArray, moveByteArray,+  copyByteArray, copyMutableByteArray,+#if __GLASGOW_HASKELL__ >= 708+  copyByteArrayToAddr, copyMutableByteArrayToAddr,+#endif+  moveByteArray,   setByteArray, fillByteArray,    -- * Information-  sizeofByteArray, sizeofMutableByteArray, sameMutableByteArray,+  sizeofByteArray,+  sizeofMutableByteArray, getSizeofMutableByteArray, sameMutableByteArray,+#if __GLASGOW_HASKELL__ >= 802+  isByteArrayPinned, isMutableByteArrayPinned,+#endif   byteArrayContents, mutableByteArrayContents+ ) where  import Control.Monad.Primitive import Control.Monad.ST-import Control.Monad ( zipWithM_ ) import Data.Primitive.Types  import Foreign.C.Types@@ -58,8 +70,26 @@ import Data.Data ( Data(..) ) import Data.Primitive.Internal.Compat ( isTrue#, mkNoRepType ) import Numeric-import System.IO.Unsafe +#if MIN_VERSION_base(4,9,0)+import qualified Data.Semigroup as SG+import qualified Data.Foldable as F+#endif++#if !(MIN_VERSION_base(4,8,0))+import Data.Monoid (Monoid(..))+#endif++#if __GLASGOW_HASKELL__ >= 802+import GHC.Exts as Exts (isByteArrayPinned#,isMutableByteArrayPinned#)+#endif++#if __GLASGOW_HASKELL__ >= 804+import GHC.Exts (compareByteArrays#)+#else+import System.IO.Unsafe (unsafeDupablePerformIO)+#endif+ -- | Byte arrays data ByteArray = ByteArray ByteArray# deriving ( Typeable ) @@ -83,9 +113,12 @@                         (# s'#, arr# #) -> (# s'#, MutableByteArray arr# #))  -- | Create a /pinned/ byte array of the specified size in bytes and with the--- give alignment. The garbage collector is guaranteed not to move it.+-- given alignment. The garbage collector is guaranteed not to move it. newAlignedPinnedByteArray-  :: PrimMonad m => Int -> Int -> m (MutableByteArray (PrimState m))+  :: PrimMonad m+  => Int  -- ^ size+  -> Int  -- ^ alignment+  -> m (MutableByteArray (PrimState m)) {-# INLINE newAlignedPinnedByteArray #-} newAlignedPinnedByteArray (I# n#) (I# k#)   = primitive (\s# -> case newAlignedPinnedByteArray# n# k# s# of@@ -112,6 +145,47 @@ sameMutableByteArray (MutableByteArray arr#) (MutableByteArray brr#)   = isTrue# (sameMutableByteArray# arr# brr#) +-- | Resize a mutable byte array. The new size is given in bytes.+--+-- This will either resize the array in-place or, if not possible, allocate the+-- contents into a new, unpinned array and copy the original array's contents.+--+-- To avoid undefined behaviour, the original 'MutableByteArray' shall not be+-- accessed anymore after a 'resizeMutableByteArray' has been performed.+-- Moreover, no reference to the old one should be kept in order to allow+-- garbage collection of the original 'MutableByteArray' in case a new+-- 'MutableByteArray' had to be allocated.+--+-- @since 0.6.4.0+resizeMutableByteArray+  :: PrimMonad m => MutableByteArray (PrimState m) -> Int+                 -> m (MutableByteArray (PrimState m))+{-# INLINE resizeMutableByteArray #-}+#if __GLASGOW_HASKELL__ >= 710+resizeMutableByteArray (MutableByteArray arr#) (I# n#)+  = primitive (\s# -> case resizeMutableByteArray# arr# n# s# of+                        (# s'#, arr'# #) -> (# s'#, MutableByteArray arr'# #))+#else+resizeMutableByteArray arr n+  = do arr' <- newByteArray n+       copyMutableByteArray arr' 0 arr 0 (min (sizeofMutableByteArray arr) n)+       return arr'+#endif++-- | Get the size of a byte array in bytes. Unlike 'sizeofMutableByteArray',+-- this function ensures sequencing in the presence of resizing.+getSizeofMutableByteArray+  :: PrimMonad m => MutableByteArray (PrimState m) -> m Int+{-# INLINE getSizeofMutableByteArray #-}+#if __GLASGOW_HASKELL__ >= 801+getSizeofMutableByteArray (MutableByteArray arr#)+  = primitive (\s# -> case getSizeofMutableByteArray# arr# s# of+                        (# s'#, n# #) -> (# s'#, I# n# #))+#else+getSizeofMutableByteArray arr+  = return (sizeofMutableByteArray arr)+#endif+ -- | Convert a mutable byte array to an immutable one without copying. The -- array should not be modified after the conversion. unsafeFreezeByteArray@@ -134,11 +208,35 @@ {-# INLINE sizeofByteArray #-} sizeofByteArray (ByteArray arr#) = I# (sizeofByteArray# arr#) --- | Size of the mutable byte array in bytes.+-- | Size of the mutable byte array in bytes. This function\'s behavior +-- is undefined if 'resizeMutableByteArray' is ever called on the mutable+-- byte array given as the argument. Consequently, use of this function+-- is discouraged. Prefer 'getSizeofMutableByteArray', which ensures correct+-- sequencing in the presence of resizing. sizeofMutableByteArray :: MutableByteArray s -> Int {-# INLINE sizeofMutableByteArray #-} sizeofMutableByteArray (MutableByteArray arr#) = I# (sizeofMutableByteArray# arr#) +#if __GLASGOW_HASKELL__ >= 802+-- | Check whether or not the byte array is pinned. Pinned byte arrays cannot+--   be moved by the garbage collector. It is safe to use 'byteArrayContents'+--   on such byte arrays. This function is only available when compiling with+--   GHC 8.2 or newer.+--+--   @since 0.6.4.0+isByteArrayPinned :: ByteArray -> Bool+{-# INLINE isByteArrayPinned #-}+isByteArrayPinned (ByteArray arr#) = isTrue# (Exts.isByteArrayPinned# arr#)++-- | Check whether or not the mutable byte array is pinned. This function is+--   only available when compiling with GHC 8.2 or newer.+--+--   @since 0.6.4.0+isMutableByteArrayPinned :: MutableByteArray s -> Bool+{-# INLINE isMutableByteArrayPinned #-}+isMutableByteArrayPinned (MutableByteArray marr#) = isTrue# (Exts.isMutableByteArrayPinned# marr#)+#endif+ -- | Read a primitive value from the byte array. The offset is given in -- elements of type @a@ rather than in bytes. indexByteArray :: Prim a => ByteArray -> Int -> a@@ -168,18 +266,27 @@     go i       | sizeofByteArray arr > i * sz = f (indexByteArray arr i) (go (i+1))       | otherwise                    = z-    sz = sizeofByteArray arr+    sz = sizeOf (undefined :: a) -fromListN :: Prim a => Int -> [a] -> ByteArray-fromListN n xs = runST $ do-    marr <- newByteArray (n * sizeOf (head xs))-    zipWithM_ (writeByteArray marr) [0..n] xs+byteArrayFromList :: Prim a => [a] -> ByteArray+byteArrayFromList xs = byteArrayFromListN (length xs) xs++byteArrayFromListN :: Prim a => Int -> [a] -> ByteArray+byteArrayFromListN n ys = runST $ do+    marr <- newByteArray (n * sizeOf (head ys))+    let go !ix [] = if ix == n+          then return ()+          else die "byteArrayFromListN" "list length less than specified size"+        go !ix (x : xs) = if ix < n+          then do+            writeByteArray marr ix x+            go (ix + 1) xs+          else die "byteArrayFromListN" "list length greater than specified size"+    go 0 ys     unsafeFreezeByteArray marr -#if __GLASGOW_HASKELL__ >= 702 unI# :: Int -> Int# unI# (I# n#) = n#-#endif  -- | Copy a slice of an immutable byte array to a mutable byte array. copyByteArray@@ -192,13 +299,7 @@                  -> m () {-# INLINE copyByteArray #-} copyByteArray (MutableByteArray dst#) doff (ByteArray src#) soff sz-#if __GLASGOW_HASKELL__ >= 702   = primitive_ (copyByteArray# src# (unI# soff) dst# (unI# doff) (unI# sz))-#else-  = unsafePrimToPrim-  $ memcpy_ba dst# (fromIntegral doff) src# (fromIntegral soff)-                 (fromIntegral sz)-#endif  -- | Copy a slice of a mutable byte array into another array. The two slices -- may not overlap.@@ -214,12 +315,40 @@ {-# INLINE copyMutableByteArray #-} copyMutableByteArray (MutableByteArray dst#) doff                      (MutableByteArray src#) soff sz-#if __GLASGOW_HASKELL__ >= 702   = primitive_ (copyMutableByteArray# src# (unI# soff) dst# (unI# doff) (unI# sz))-#else-  = unsafePrimToPrim-  $ memcpy_mba dst# (fromIntegral doff) src# (fromIntegral soff)-                    (fromIntegral sz)++#if __GLASGOW_HASKELL__ >= 708+-- | Copy a slice of a byte array to an unmanaged address. These must not+--   overlap. This function is only available when compiling with GHC 7.8+--   or newer.+--+--   @since 0.6.4.0+copyByteArrayToAddr+  :: PrimMonad m+  => Addr -- ^ destination+  -> ByteArray -- ^ source array+  -> Int -- ^ offset into source array+  -> Int -- ^ number of bytes to copy+  -> m ()+{-# INLINE copyByteArrayToAddr #-}+copyByteArrayToAddr (Addr dst#) (ByteArray src#) soff sz+  = primitive_ (copyByteArrayToAddr# src# (unI# soff) dst# (unI# sz))++-- | Copy a slice of a mutable byte array to an unmanaged address. These must+--   not overlap. This function is only available when compiling with GHC 7.8+--   or newer.+--+--   @since 0.6.4.0+copyMutableByteArrayToAddr+  :: PrimMonad m+  => Addr -- ^ destination+  -> MutableByteArray (PrimState m) -- ^ source array+  -> Int -- ^ offset into source array+  -> Int -- ^ number of bytes to copy+  -> m ()+{-# INLINE copyMutableByteArrayToAddr #-}+copyMutableByteArrayToAddr (Addr dst#) (MutableByteArray src#) soff sz+  = primitive_ (copyMutableByteArrayToAddr# src# (unI# soff) dst# (unI# sz)) #endif  -- | Copy a slice of a mutable byte array into another, potentially@@ -263,18 +392,6 @@ {-# INLINE fillByteArray #-} fillByteArray = setByteArray -#if __GLASGOW_HASKELL__ < 702-foreign import ccall unsafe "primitive-memops.h hsprimitive_memcpy"-  memcpy_mba :: MutableByteArray# s -> CInt-             -> MutableByteArray# s -> CInt-             -> CSize -> IO ()--foreign import ccall unsafe "primitive-memops.h hsprimitive_memcpy"-  memcpy_ba :: MutableByteArray# s -> CInt-            -> ByteArray# -> CInt-            -> CSize -> IO ()-#endif- foreign import ccall unsafe "primitive-memops.h hsprimitive_memmove"   memmove_mba :: MutableByteArray# s -> CInt               -> MutableByteArray# s -> CInt@@ -290,6 +407,7 @@   gunfold _ _ = error "gunfold"   dataTypeOf _ = mkNoRepType "Data.Primitive.ByteArray.MutableByteArray" +-- | @since 0.6.3.0 instance Show ByteArray where   showsPrec _ ba =       showString "[" . go 0@@ -301,9 +419,25 @@           comma | i == 0    = id                 | otherwise = showString ", " ++compareByteArrays :: ByteArray -> ByteArray -> Int -> Ordering+{-# INLINE compareByteArrays #-}+#if __GLASGOW_HASKELL__ >= 804+compareByteArrays (ByteArray ba1#) (ByteArray ba2#) (I# n#) =+  compare (I# (compareByteArrays# ba1# 0# ba2# 0# n#)) 0+#else+-- Emulate GHC 8.4's 'GHC.Prim.compareByteArrays#'+compareByteArrays (ByteArray ba1#) (ByteArray ba2#) (I# n#)+    = compare (fromCInt (unsafeDupablePerformIO (memcmp_ba ba1# ba2# n))) 0+  where+    n = fromIntegral (I# n#) :: CSize+    fromCInt = fromIntegral :: CInt -> Int+ foreign import ccall unsafe "primitive-memops.h hsprimitive_memcmp"   memcmp_ba :: ByteArray# -> ByteArray# -> CSize -> IO CInt+#endif + sameByteArray :: ByteArray# -> ByteArray# -> Bool sameByteArray ba1 ba2 =     case reallyUnsafePtrEquality# (unsafeCoerce# ba1 :: ()) (unsafeCoerce# ba2 :: ()) of@@ -314,33 +448,102 @@       0# -> False #endif +-- | @since 0.6.3.0 instance Eq ByteArray where   ba1@(ByteArray ba1#) == ba2@(ByteArray ba2#)-    | sameByteArray ba1# ba2#                    = True-    | sizeofByteArray ba1 /= sizeofByteArray ba2 = False-    | otherwise =-        case unsafeDupablePerformIO $ memcmp_ba ba1# ba2# (fromIntegral $ sizeofByteArray ba1) of-          0 -> True-          _ -> False+    | sameByteArray ba1# ba2# = True+    | n1 /= n2 = False+    | otherwise = compareByteArrays ba1 ba2 n1 == EQ+    where+      n1 = sizeofByteArray ba1+      n2 = sizeofByteArray ba2 +-- | Non-lexicographic ordering. This compares the lengths of+-- the byte arrays first and uses a lexicographic ordering if+-- the lengths are equal. Subject to change between major versions.+-- +-- @since 0.6.3.0 instance Ord ByteArray where   ba1@(ByteArray ba1#) `compare` ba2@(ByteArray ba2#)     | sameByteArray ba1# ba2# = EQ-    | n1 /= n2                = n1 `compare` n2-    | otherwise =-        case unsafeDupablePerformIO $ memcmp_ba ba1# ba2# (fromIntegral n1) of-          x | x >  0 -> GT-            | x == 0 -> EQ-            | otherwise -> LT+    | n1 /= n2 = n1 `compare` n2+    | otherwise = compareByteArrays ba1 ba2 n1     where       n1 = sizeofByteArray ba1       n2 = sizeofByteArray ba2+-- Note: On GHC 8.4, the primop compareByteArrays# performs a check for pointer+-- equality as a shortcut, so the check here is actually redundant. However, it+-- is included here because it is likely better to check for pointer equality+-- before checking for length equality. Getting the length requires deferencing+-- the pointers, which could cause accesses to memory that is not in the cache.+-- By contrast, a pointer equality check is always extremely cheap. +appendByteArray :: ByteArray -> ByteArray -> ByteArray+appendByteArray a b = runST $ do+  marr <- newByteArray (sizeofByteArray a + sizeofByteArray b)+  copyByteArray marr 0 a 0 (sizeofByteArray a)+  copyByteArray marr (sizeofByteArray a) b 0 (sizeofByteArray b)+  unsafeFreezeByteArray marr++concatByteArray :: [ByteArray] -> ByteArray+concatByteArray arrs = runST $ do+  let len = calcLength arrs 0+  marr <- newByteArray len+  pasteByteArrays marr 0 arrs+  unsafeFreezeByteArray marr++pasteByteArrays :: MutableByteArray s -> Int -> [ByteArray] -> ST s ()+pasteByteArrays !_ !_ [] = return ()+pasteByteArrays !marr !ix (x : xs) = do+  copyByteArray marr ix x 0 (sizeofByteArray x)+  pasteByteArrays marr (ix + sizeofByteArray x) xs++calcLength :: [ByteArray] -> Int -> Int+calcLength [] !n = n+calcLength (x : xs) !n = calcLength xs (sizeofByteArray x + n)++emptyByteArray :: ByteArray+emptyByteArray = runST (newByteArray 0 >>= unsafeFreezeByteArray)++replicateByteArray :: Int -> ByteArray -> ByteArray+replicateByteArray n arr = runST $ do+  marr <- newByteArray (n * sizeofByteArray arr)+  let go i = if i < n+        then do+          copyByteArray marr (i * sizeofByteArray arr) arr 0 (sizeofByteArray arr)+          go (i + 1)+        else return ()+  go 0+  unsafeFreezeByteArray marr++#if MIN_VERSION_base(4,9,0)+instance SG.Semigroup ByteArray where+  (<>) = appendByteArray+  sconcat = mconcat . F.toList+  stimes i arr+    | itgr < 1 = emptyByteArray+    | itgr <= (fromIntegral (maxBound :: Int)) = replicateByteArray (fromIntegral itgr) arr+    | otherwise = error "Data.Primitive.ByteArray#stimes: cannot allocate the requested amount of memory"+    where itgr = toInteger i :: Integer+#endif++instance Monoid ByteArray where+  mempty = emptyByteArray+#if !(MIN_VERSION_base(4,11,0))+  mappend = appendByteArray+#endif+  mconcat = concatByteArray+ #if __GLASGOW_HASKELL__ >= 708+-- | @since 0.6.3.0 instance Exts.IsList ByteArray where   type Item ByteArray = Word8    toList = foldrByteArray (:) []-  fromList xs = fromListN (length xs) xs-  fromListN = fromListN+  fromList xs = byteArrayFromListN (length xs) xs+  fromListN = byteArrayFromListN #endif++die :: String -> String -> a+die fun problem = error $ "Data.Primitive.ByteArray." ++ fun ++ ": " ++ problem+
+ Data/Primitive/MVar.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}++-- |+-- Module      : Data.Primitive.MVar+-- License     : BSD2+-- Portability : non-portable+--+-- Primitive operations on @MVar@. This module provides a similar interface+-- to "Control.Concurrent.MVar". However, the functions are generalized to+-- work in any 'PrimMonad' instead of only working in 'IO'. Note that all+-- of the functions here are completely deterministic. Users of 'MVar' are+-- responsible for designing abstractions that guarantee determinism in+-- the presence of multi-threading.+--+-- @since 0.6.4.0+module Data.Primitive.MVar+  ( MVar(..)+  , newMVar+  , isEmptyMVar+  , newEmptyMVar+  , putMVar+  , readMVar+  , takeMVar+  , tryPutMVar+  , tryReadMVar+  , tryTakeMVar+  ) where++import Control.Monad.Primitive+import Data.Primitive.Internal.Compat (isTrue#)+import GHC.Exts (MVar#,newMVar#,takeMVar#,sameMVar#,putMVar#,tryTakeMVar#,+  isEmptyMVar#,tryPutMVar#,(/=#))++#if __GLASGOW_HASKELL__ >= 708+import GHC.Exts (readMVar#,tryReadMVar#)+#endif++data MVar s a = MVar (MVar# s a)++instance Eq (MVar s a) where+  MVar mvar1# == MVar mvar2# = isTrue# (sameMVar# mvar1# mvar2#)++-- | Create a new 'MVar' that is initially empty.+newEmptyMVar :: PrimMonad m => m (MVar (PrimState m) a)+newEmptyMVar = primitive $ \ s# ->+  case newMVar# s# of+    (# s2#, svar# #) -> (# s2#, MVar svar# #)+++-- | Create a new 'MVar' that holds the supplied argument.+newMVar :: PrimMonad m => a -> m (MVar (PrimState m) a)+newMVar value =+  newEmptyMVar >>= \ mvar ->+  putMVar mvar value >>+  return mvar++-- | Return the contents of the 'MVar'.  If the 'MVar' is currently+-- empty, 'takeMVar' will wait until it is full.  After a 'takeMVar',+-- the 'MVar' is left empty.+takeMVar :: PrimMonad m => MVar (PrimState m) a -> m a+takeMVar (MVar mvar#) = primitive $ \ s# -> takeMVar# mvar# s#++-- | Atomically read the contents of an 'MVar'.  If the 'MVar' is+-- currently empty, 'readMVar' will wait until it is full.+-- 'readMVar' is guaranteed to receive the next 'putMVar'.+--+-- /Multiple Wakeup:/ 'readMVar' is multiple-wakeup, so when multiple readers+-- are blocked on an 'MVar', all of them are woken up at the same time.+--+-- /Compatibility note:/ On GHCs prior to 7.8, 'readMVar' is a combination+-- of 'takeMVar' and 'putMVar'. Consequently, its behavior differs in the+-- following ways:+--+-- * It is single-wakeup instead of multiple-wakeup.+-- * It might not receive the value from the next call to 'putMVar' if+--   there is already a pending thread blocked on 'takeMVar'.+-- * If another thread puts a value in the 'MVar' in between the+--   calls to 'takeMVar' and 'putMVar', that value may be overridden.+readMVar :: PrimMonad m => MVar (PrimState m) a -> m a+#if __GLASGOW_HASKELL__ >= 708+readMVar (MVar mvar#) = primitive $ \ s# -> readMVar# mvar# s#+#else+readMVar mv = do+  a <- takeMVar mv+  putMVar mv a+  return a+#endif++-- |Put a value into an 'MVar'.  If the 'MVar' is currently full,+-- 'putMVar' will wait until it becomes empty.+putMVar :: PrimMonad m => MVar (PrimState m) a -> a -> m ()+putMVar (MVar mvar#) x = primitive_ (putMVar# mvar# x)++-- |A non-blocking version of 'takeMVar'.  The 'tryTakeMVar' function+-- returns immediately, with 'Nothing' if the 'MVar' was empty, or+-- @'Just' a@ if the 'MVar' was full with contents @a@.  After 'tryTakeMVar',+-- the 'MVar' is left empty.+tryTakeMVar :: PrimMonad m => MVar (PrimState m) a -> m (Maybe a)+tryTakeMVar (MVar m) = primitive $ \ s ->+  case tryTakeMVar# m s of+    (# s', 0#, _ #) -> (# s', Nothing #) -- MVar is empty+    (# s', _,  a #) -> (# s', Just a  #) -- MVar is full+++-- |A non-blocking version of 'putMVar'.  The 'tryPutMVar' function+-- attempts to put the value @a@ into the 'MVar', returning 'True' if+-- it was successful, or 'False' otherwise.+tryPutMVar :: PrimMonad m => MVar (PrimState m) a -> a -> m Bool+tryPutMVar (MVar mvar#) x = primitive $ \ s# ->+    case tryPutMVar# mvar# x s# of+        (# s, 0# #) -> (# s, False #)+        (# s, _  #) -> (# s, True #)++-- | A non-blocking version of 'readMVar'.  The 'tryReadMVar' function+-- returns immediately, with 'Nothing' if the 'MVar' was empty, or+-- @'Just' a@ if the 'MVar' was full with contents @a@.+--+-- /Compatibility note:/ On GHCs prior to 7.8, 'tryReadMVar' is a combination+-- of 'tryTakeMVar' and 'putMVar'. Consequently, its behavior differs in the+-- following ways:+--+-- * It is single-wakeup instead of multiple-wakeup.+-- * In the presence of other threads calling 'putMVar', 'tryReadMVar'+--   may block.+-- * If another thread puts a value in the 'MVar' in between the+--   calls to 'tryTakeMVar' and 'putMVar', that value may be overridden.+tryReadMVar :: PrimMonad m => MVar (PrimState m) a -> m (Maybe a)+#if __GLASGOW_HASKELL__ >= 708+tryReadMVar (MVar m) = primitive $ \ s ->+    case tryReadMVar# m s of+        (# s', 0#, _ #) -> (# s', Nothing #)      -- MVar is empty+        (# s', _,  a #) -> (# s', Just a  #)      -- MVar is full+#else+tryReadMVar mv = do+  ma <- tryTakeMVar mv+  case ma of+    Just a -> do+      putMVar mv a+      return (Just a)+    Nothing -> return Nothing+#endif++-- | Check whether a given 'MVar' is empty.+--+-- Notice that the boolean value returned  is just a snapshot of+-- the state of the MVar. By the time you get to react on its result,+-- the MVar may have been filled (or emptied) - so be extremely+-- careful when using this operation.   Use 'tryTakeMVar' instead if possible.+isEmptyMVar :: PrimMonad m => MVar (PrimState m) a -> m Bool+isEmptyMVar (MVar mv#) = primitive $ \ s# ->+  case isEmptyMVar# mv# s# of+    (# s2#, flg #) -> (# s2#, isTrue# (flg /=# 0#) #)
+ Data/Primitive/PrimArray.hs view
@@ -0,0 +1,969 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UnboxedTuples #-}++{-# OPTIONS_GHC -Wall #-}++-- |+-- Module      : Data.Primitive.PrimArray+-- Copyright   : (c) Roman Leshchinskiy 2009-2012+-- License     : BSD-style+--+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>+-- Portability : non-portable+--+-- Arrays of unboxed primitive types. The function provided by this module+-- match the behavior of those provided by @Data.Primitive.ByteArray@, and+-- the underlying types and primops that back them are the same.+-- However, the type constructors 'PrimArray' and 'MutablePrimArray' take one additional+-- argument than their respective counterparts 'ByteArray' and 'MutableByteArray'.+-- This argument is used to designate the type of element in the array.+-- Consequently, all function this modules accepts length and incides in+-- terms of elements, not bytes.+--+-- @since 0.6.4.0+module Data.Primitive.PrimArray+  ( -- * Types+    PrimArray(..)+  , MutablePrimArray(..)+    -- * Allocation+  , newPrimArray+  , resizeMutablePrimArray+#if __GLASGOW_HASKELL__ >= 710+  , shrinkMutablePrimArray+#endif+    -- * Element Access+  , readPrimArray+  , writePrimArray+  , indexPrimArray+    -- * Freezing and Thawing+  , unsafeFreezePrimArray+  , unsafeThawPrimArray+    -- * Block Operations+  , copyPrimArray+  , copyMutablePrimArray+#if __GLASGOW_HASKELL__ >= 708+  , copyPrimArrayToPtr+  , copyMutablePrimArrayToPtr+#endif+  , setPrimArray+    -- * Information+  , sameMutablePrimArray+  , getSizeofMutablePrimArray+  , sizeofMutablePrimArray+  , sizeofPrimArray+    -- * List Conversion+  , primArrayToList+  , primArrayFromList+  , primArrayFromListN+    -- * Folding+  , foldrPrimArray+  , foldrPrimArray'+  , foldlPrimArray+  , foldlPrimArray'+  , foldlPrimArrayM'+    -- * Effectful Folding+  , traversePrimArray_+  , itraversePrimArray_+    -- * Map/Create+  , mapPrimArray+  , imapPrimArray+  , generatePrimArray+  , replicatePrimArray+  , filterPrimArray+  , mapMaybePrimArray+    -- * Effectful Map/Create+    -- $effectfulMapCreate+    -- ** Lazy Applicative+  , traversePrimArray+  , itraversePrimArray+  , generatePrimArrayA+  , replicatePrimArrayA+  , filterPrimArrayA+  , mapMaybePrimArrayA+    -- ** Strict Primitive Monadic+  , traversePrimArrayP+  , itraversePrimArrayP+  , generatePrimArrayP+  , replicatePrimArrayP+  , filterPrimArrayP+  , mapMaybePrimArrayP+  ) where++import GHC.Prim+import GHC.Base ( Int(..) )+import GHC.Exts (build)+import GHC.Ptr+import Data.Primitive.Internal.Compat (isTrue#)+import Data.Primitive.Types+import Data.Primitive.ByteArray (ByteArray(..))+import Data.Monoid (Monoid(..),(<>))+import Control.Applicative+import Control.Monad.Primitive+import Control.Monad.ST+import qualified Data.List as L+import qualified Data.Primitive.ByteArray as PB+import qualified Data.Primitive.Types as PT++#if MIN_VERSION_base(4,7,0)+import GHC.Exts (IsList(..))+#endif++#if MIN_VERSION_base(4,9,0)+import Data.Semigroup (Semigroup)+import qualified Data.Semigroup as SG+#endif++-- | Arrays of unboxed elements. This accepts types like 'Double', 'Char',+-- 'Int', and 'Word', as well as their fixed-length variants ('Word8',+-- 'Word16', etc.). Since the elements are unboxed, a 'PrimArray' is strict+-- in its elements. This differs from the behavior of 'Array', which is lazy+-- in its elements.+data PrimArray a = PrimArray ByteArray#++-- | Mutable primitive arrays associated with a primitive state token.+-- These can be written to and read from in a monadic context that supports+-- sequencing such as 'IO' or 'ST'. Typically, a mutable primitive array will+-- be built and then convert to an immutable primitive array using+-- 'unsafeFreezePrimArray'. However, it is also acceptable to simply discard+-- a mutable primitive array since it lives in managed memory and will be+-- garbage collected when no longer referenced.+data MutablePrimArray s a = MutablePrimArray (MutableByteArray# s)++sameByteArray :: ByteArray# -> ByteArray# -> Bool+sameByteArray ba1 ba2 =+    case reallyUnsafePtrEquality# (unsafeCoerce# ba1 :: ()) (unsafeCoerce# ba2 :: ()) of+#if __GLASGOW_HASKELL__ >= 708+      r -> isTrue# r+#else+      1# -> True+      _ -> False+#endif++-- | @since 0.6.4.0+instance (Eq a, Prim a) => Eq (PrimArray a) where+  a1@(PrimArray ba1#) == a2@(PrimArray ba2#)+    | sameByteArray ba1# ba2# = True+    | sz1 /= sz2 = False+    | otherwise = loop (quot sz1 (sizeOf (undefined :: a)) - 1)+    where+    -- Here, we take the size in bytes, not in elements. We do this+    -- since it allows us to defer performing the division to+    -- calculate the size in elements.+    sz1 = PB.sizeofByteArray (ByteArray ba1#)+    sz2 = PB.sizeofByteArray (ByteArray ba2#)+    loop !i+      | i < 0 = True+      | otherwise = indexPrimArray a1 i == indexPrimArray a2 i && loop (i-1)++-- | Lexicographic ordering. Subject to change between major versions.+-- +--   @since 0.6.4.0+instance (Ord a, Prim a) => Ord (PrimArray a) where+  compare a1@(PrimArray ba1#) a2@(PrimArray ba2#)+    | sameByteArray ba1# ba2# = EQ+    | otherwise = loop 0+    where+    sz1 = PB.sizeofByteArray (ByteArray ba1#)+    sz2 = PB.sizeofByteArray (ByteArray ba2#)+    sz = quot (min sz1 sz2) (sizeOf (undefined :: a))+    loop !i+      | i < sz = compare (indexPrimArray a1 i) (indexPrimArray a2 i) <> loop (i+1)+      | otherwise = compare sz1 sz2++#if MIN_VERSION_base(4,7,0)+-- | @since 0.6.4.0+instance Prim a => IsList (PrimArray a) where+  type Item (PrimArray a) = a+  fromList = primArrayFromList+  fromListN = primArrayFromListN+  toList = primArrayToList+#endif++-- | @since 0.6.4.0+instance (Show a, Prim a) => Show (PrimArray a) where+  showsPrec p a = showParen (p > 10) $+    showString "fromListN " . shows (sizeofPrimArray a) . showString " "+      . shows (primArrayToList a)++die :: String -> String -> a+die fun problem = error $ "Data.Primitive.PrimArray." ++ fun ++ ": " ++ problem++primArrayFromList :: Prim a => [a] -> PrimArray a+primArrayFromList vs = primArrayFromListN (L.length vs) vs++primArrayFromListN :: forall a. Prim a => Int -> [a] -> PrimArray a+primArrayFromListN len vs = runST run where+  run :: forall s. ST s (PrimArray a)+  run = do+    arr <- newPrimArray len+    let go :: [a] -> Int -> ST s ()+        go [] !ix = if ix == len+          then return ()+          else die "fromListN" "list length less than specified size"+        go (a : as) !ix = if ix < len+          then do+            writePrimArray arr ix a+            go as (ix + 1)+          else die "fromListN" "list length greater than specified size"+    go vs 0+    unsafeFreezePrimArray arr++-- | Convert the primitive array to a list.+{-# INLINE primArrayToList #-}+primArrayToList :: forall a. Prim a => PrimArray a -> [a]+primArrayToList xs = build (\c n -> foldrPrimArray c n xs)++primArrayToByteArray :: PrimArray a -> PB.ByteArray+primArrayToByteArray (PrimArray x) = PB.ByteArray x++byteArrayToPrimArray :: ByteArray -> PrimArray a+byteArrayToPrimArray (PB.ByteArray x) = PrimArray x++#if MIN_VERSION_base(4,9,0)+-- | @since 0.6.4.0+instance Semigroup (PrimArray a) where+  x <> y = byteArrayToPrimArray (primArrayToByteArray x SG.<> primArrayToByteArray y)+  sconcat = byteArrayToPrimArray . SG.sconcat . fmap primArrayToByteArray+  stimes i arr = byteArrayToPrimArray (SG.stimes i (primArrayToByteArray arr))+#endif++-- | @since 0.6.4.0+instance Monoid (PrimArray a) where+  mempty = emptyPrimArray+#if !(MIN_VERSION_base(4,11,0))+  mappend x y = byteArrayToPrimArray (mappend (primArrayToByteArray x) (primArrayToByteArray y))+#endif+  mconcat = byteArrayToPrimArray . mconcat . map primArrayToByteArray++-- | The empty primitive array.+emptyPrimArray :: PrimArray a+{-# NOINLINE emptyPrimArray #-}+emptyPrimArray = runST $ primitive $ \s0# -> case newByteArray# 0# s0# of+  (# s1#, arr# #) -> case unsafeFreezeByteArray# arr# s1# of+    (# s2#, arr'# #) -> (# s2#, PrimArray arr'# #)++-- | Create a new mutable primitive array of the given length. The+-- underlying memory is left uninitialized.+newPrimArray :: forall m a. (PrimMonad m, Prim a) => Int -> m (MutablePrimArray (PrimState m) a)+{-# INLINE newPrimArray #-}+newPrimArray (I# n#)+  = primitive (\s# -> +      case newByteArray# (n# *# sizeOf# (undefined :: a)) s# of+        (# s'#, arr# #) -> (# s'#, MutablePrimArray arr# #)+    )++-- | Resize a mutable primitive array. The new size is given in elements.+--+-- This will either resize the array in-place or, if not possible, allocate the+-- contents into a new, unpinned array and copy the original array\'s contents.+--+-- To avoid undefined behaviour, the original 'MutablePrimArray' shall not be+-- accessed anymore after a 'resizeMutablePrimArray' has been performed.+-- Moreover, no reference to the old one should be kept in order to allow+-- garbage collection of the original 'MutablePrimArray' in case a new+-- 'MutablePrimArray' had to be allocated.+resizeMutablePrimArray :: forall m a. (PrimMonad m, Prim a)+  => MutablePrimArray (PrimState m) a+  -> Int -- ^ new size+  -> m (MutablePrimArray (PrimState m) a)+{-# INLINE resizeMutablePrimArray #-}+#if __GLASGOW_HASKELL__ >= 710+resizeMutablePrimArray (MutablePrimArray arr#) (I# n#)+  = primitive (\s# -> case resizeMutableByteArray# arr# (n# *# sizeOf# (undefined :: a)) s# of+                        (# s'#, arr'# #) -> (# s'#, MutablePrimArray arr'# #))+#else+resizeMutablePrimArray arr n+  = do arr' <- newPrimArray n+       copyMutablePrimArray arr' 0 arr 0 (min (sizeofMutablePrimArray arr) n)+       return arr'+#endif++-- Although it is possible to shim resizeMutableByteArray for old GHCs, this+-- is not the case with shrinkMutablePrimArray.+#if __GLASGOW_HASKELL__ >= 710+-- | Shrink a mutable primitive array. The new size is given in elements.+-- It must be smaller than the old size. The array will be resized in place.+-- This function is only available when compiling with GHC 7.10 or newer.+shrinkMutablePrimArray :: forall m a. (PrimMonad m, Prim a)+  => MutablePrimArray (PrimState m) a+  -> Int -- ^ new size+  -> m ()+{-# INLINE shrinkMutablePrimArray #-}+shrinkMutablePrimArray (MutablePrimArray arr#) (I# n#)+  = primitive_ (shrinkMutableByteArray# arr# (n# *# sizeOf# (undefined :: a)))+#endif++readPrimArray :: (Prim a, PrimMonad m) => MutablePrimArray (PrimState m) a -> Int -> m a+{-# INLINE readPrimArray #-}+readPrimArray (MutablePrimArray arr#) (I# i#)+  = primitive (readByteArray# arr# i#)++-- | Write an element to the given index.+writePrimArray ::+     (Prim a, PrimMonad m)+  => MutablePrimArray (PrimState m) a -- ^ array+  -> Int -- ^ index+  -> a -- ^ element+  -> m ()+{-# INLINE writePrimArray #-}+writePrimArray (MutablePrimArray arr#) (I# i#) x+  = primitive_ (writeByteArray# arr# i# x)++-- | Copy part of a mutable array into another mutable array.+--   In the case that the destination and+--   source arrays are the same, the regions may overlap.+copyMutablePrimArray :: forall m a.+     (PrimMonad m, Prim a)+  => MutablePrimArray (PrimState m) a -- ^ destination array+  -> Int -- ^ offset into destination array+  -> MutablePrimArray (PrimState m) a -- ^ source array+  -> Int -- ^ offset into source array+  -> Int -- ^ number of elements to copy+  -> m ()+{-# INLINE copyMutablePrimArray #-}+copyMutablePrimArray (MutablePrimArray dst#) (I# doff#) (MutablePrimArray src#) (I# soff#) (I# n#)+  = primitive_ (copyMutableByteArray#+      src# +      (soff# *# (sizeOf# (undefined :: a)))+      dst#+      (doff# *# (sizeOf# (undefined :: a)))+      (n# *# (sizeOf# (undefined :: a)))+    )++-- | Copy part of an array into another mutable array.+copyPrimArray :: forall m a.+     (PrimMonad m, Prim a)+  => MutablePrimArray (PrimState m) a -- ^ destination array+  -> Int -- ^ offset into destination array+  -> PrimArray a -- ^ source array+  -> Int -- ^ offset into source array+  -> Int -- ^ number of elements to copy+  -> m ()+{-# INLINE copyPrimArray #-}+copyPrimArray (MutablePrimArray dst#) (I# doff#) (PrimArray src#) (I# soff#) (I# n#)+  = primitive_ (copyByteArray#+      src# +      (soff# *# (sizeOf# (undefined :: a)))+      dst#+      (doff# *# (sizeOf# (undefined :: a)))+      (n# *# (sizeOf# (undefined :: a)))+    )++#if __GLASGOW_HASKELL__ >= 708+-- | Copy a slice of an immutable primitive array to an address.+--   The offset and length are given in elements of type @a@.+--   This function assumes that the 'Prim' instance of @a@+--   agrees with the 'Storable' instance. This function is only+--   available when building with GHC 7.8 or newer.+copyPrimArrayToPtr :: forall m a. (PrimMonad m, Prim a)+  => Ptr a -- ^ destination pointer+  -> PrimArray a -- ^ source array+  -> Int -- ^ offset into source array+  -> Int -- ^ number of prims to copy+  -> m ()+{-# INLINE copyPrimArrayToPtr #-}+copyPrimArrayToPtr (Ptr addr#) (PrimArray ba#) (I# soff#) (I# n#) =+    primitive (\ s# ->+        let s'# = copyByteArrayToAddr# ba# (soff# *# siz#) addr# (n# *# siz#) s#+        in (# s'#, () #))+  where siz# = sizeOf# (undefined :: a)++-- | Copy a slice of an immutable primitive array to an address.+--   The offset and length are given in elements of type @a@.+--   This function assumes that the 'Prim' instance of @a@+--   agrees with the 'Storable' instance. This function is only+--   available when building with GHC 7.8 or newer.+copyMutablePrimArrayToPtr :: forall m a. (PrimMonad m, Prim a)+  => Ptr a -- ^ destination pointer+  -> MutablePrimArray (PrimState m) a -- ^ source array+  -> Int -- ^ offset into source array+  -> Int -- ^ number of prims to copy+  -> m ()+{-# INLINE copyMutablePrimArrayToPtr #-}+copyMutablePrimArrayToPtr (Ptr addr#) (MutablePrimArray mba#) (I# soff#) (I# n#) =+    primitive (\ s# ->+        let s'# = copyMutableByteArrayToAddr# mba# (soff# *# siz#) addr# (n# *# siz#) s#+        in (# s'#, () #))+  where siz# = sizeOf# (undefined :: a)+#endif++-- | Fill a slice of a mutable primitive array with a value.+setPrimArray+  :: (Prim a, PrimMonad m)+  => MutablePrimArray (PrimState m) a -- ^ array to fill+  -> Int -- ^ offset into array+  -> Int -- ^ number of values to fill+  -> a -- ^ value to fill with+  -> m ()+{-# INLINE setPrimArray #-}+setPrimArray (MutablePrimArray dst#) (I# doff#) (I# sz#) x+  = primitive_ (PT.setByteArray# dst# doff# sz# x)++-- | Get the size of a mutable primitive array in elements. Unlike 'sizeofMutablePrimArray',+-- this function ensures sequencing in the presence of resizing.+getSizeofMutablePrimArray :: forall m a. (PrimMonad m, Prim a)+  => MutablePrimArray (PrimState m) a -- ^ array+  -> m Int+{-# INLINE getSizeofMutablePrimArray #-}+#if __GLASGOW_HASKELL__ >= 801+getSizeofMutablePrimArray (MutablePrimArray arr#)+  = primitive (\s# -> +      case getSizeofMutableByteArray# arr# s# of+        (# s'#, sz# #) -> (# s'#, I# (quotInt# sz# (sizeOf# (undefined :: a))) #)+    )+#else+-- On older GHCs, it is not possible to resize a byte array, so+-- this provides behavior consistent with the implementation for+-- newer GHCs.+getSizeofMutablePrimArray arr+  = return (sizeofMutablePrimArray arr)+#endif++-- | Size of the mutable primitive array in elements. This function shall not+--   be used on primitive arrays that are an argument to or a result of+--   'resizeMutablePrimArray' or 'shrinkMutablePrimArray'.+sizeofMutablePrimArray :: forall s a. Prim a => MutablePrimArray s a -> Int+{-# INLINE sizeofMutablePrimArray #-}+sizeofMutablePrimArray (MutablePrimArray arr#) =+  I# (quotInt# (sizeofMutableByteArray# arr#) (sizeOf# (undefined :: a)))++-- | Check if the two arrays refer to the same memory block.+sameMutablePrimArray :: MutablePrimArray s a -> MutablePrimArray s a -> Bool+{-# INLINE sameMutablePrimArray #-}+sameMutablePrimArray (MutablePrimArray arr#) (MutablePrimArray brr#)+  = isTrue# (sameMutableByteArray# arr# brr#)++-- | Convert a mutable byte array to an immutable one without copying. The+-- array should not be modified after the conversion.+unsafeFreezePrimArray+  :: PrimMonad m => MutablePrimArray (PrimState m) a -> m (PrimArray a)+{-# INLINE unsafeFreezePrimArray #-}+unsafeFreezePrimArray (MutablePrimArray arr#)+  = primitive (\s# -> case unsafeFreezeByteArray# arr# s# of+                        (# s'#, arr'# #) -> (# s'#, PrimArray arr'# #))++-- | Convert an immutable array to a mutable one without copying. The+-- original array should not be used after the conversion.+unsafeThawPrimArray+  :: PrimMonad m => PrimArray a -> m (MutablePrimArray (PrimState m) a)+{-# INLINE unsafeThawPrimArray #-}+unsafeThawPrimArray (PrimArray arr#)+  = primitive (\s# -> (# s#, MutablePrimArray (unsafeCoerce# arr#) #))++-- | Read a primitive value from the primitive array.+indexPrimArray :: forall a. Prim a => PrimArray a -> Int -> a+{-# INLINE indexPrimArray #-}+indexPrimArray (PrimArray arr#) (I# i#) = indexByteArray# arr# i#++-- | Get the size, in elements, of the primitive array.+sizeofPrimArray :: forall a. Prim a => PrimArray a -> Int+{-# INLINE sizeofPrimArray #-}+sizeofPrimArray (PrimArray arr#) = I# (quotInt# (sizeofByteArray# arr#) (sizeOf# (undefined :: a)))++-- | Lazy right-associated fold over the elements of a 'PrimArray'.+{-# INLINE foldrPrimArray #-}+foldrPrimArray :: forall a b. Prim a => (a -> b -> b) -> b -> PrimArray a -> b+foldrPrimArray f z arr = go 0+  where+    !sz = sizeofPrimArray arr+    go !i+      | sz > i = f (indexPrimArray arr i) (go (i+1))+      | otherwise = z++-- | Strict right-associated fold over the elements of a 'PrimArray'.+{-# INLINE foldrPrimArray' #-}+foldrPrimArray' :: forall a b. Prim a => (a -> b -> b) -> b -> PrimArray a -> b+foldrPrimArray' f z0 arr = go (sizeofPrimArray arr - 1) z0+  where+    go !i !acc+      | i < 0 = acc+      | otherwise = go (i - 1) (f (indexPrimArray arr i) acc)++-- | Lazy left-associated fold over the elements of a 'PrimArray'.+{-# INLINE foldlPrimArray #-}+foldlPrimArray :: forall a b. Prim a => (b -> a -> b) -> b -> PrimArray a -> b+foldlPrimArray f z arr = go (sizeofPrimArray arr - 1)+  where+    go !i+      | i < 0 = z+      | otherwise = f (go (i - 1)) (indexPrimArray arr i)++-- | Strict left-associated fold over the elements of a 'PrimArray'.+{-# INLINE foldlPrimArray' #-}+foldlPrimArray' :: forall a b. Prim a => (b -> a -> b) -> b -> PrimArray a -> b+foldlPrimArray' f z0 arr = go 0 z0+  where+    !sz = sizeofPrimArray arr+    go !i !acc+      | i < sz = go (i + 1) (f acc (indexPrimArray arr i))+      | otherwise = acc++-- | Strict left-associated fold over the elements of a 'PrimArray'.+{-# INLINE foldlPrimArrayM' #-}+foldlPrimArrayM' :: (Prim a, Monad m) => (b -> a -> m b) -> b -> PrimArray a -> m b+foldlPrimArrayM' f z0 arr = go 0 z0+  where+    !sz = sizeofPrimArray arr+    go !i !acc1+      | i < sz = do+          acc2 <- f acc1 (indexPrimArray arr i)+          go (i + 1) acc2+      | otherwise = return acc1++-- | Traverse a primitive array. The traversal forces the resulting values and+-- writes them to the new primitive array as it performs the monadic effects.+-- Consequently:+--+-- >>> traversePrimArrayP (\x -> print x $> bool x undefined (x == 2)) (fromList [1, 2, 3 :: Int])+-- 1+-- 2+-- *** Exception: Prelude.undefined+--+-- In many situations, 'traversePrimArrayP' can replace 'traversePrimArray',+-- changing the strictness characteristics of the traversal but typically improving+-- the performance. Consider the following short-circuiting traversal:+--+-- > incrPositiveA :: PrimArray Int -> Maybe (PrimArray Int)+-- > incrPositiveA xs = traversePrimArray (\x -> bool Nothing (Just (x + 1)) (x > 0)) xs+--+-- This can be rewritten using 'traversePrimArrayP'. To do this, we must+-- change the traversal context to @MaybeT (ST s)@, which has a 'PrimMonad'+-- instance:+--+-- > incrPositiveB :: PrimArray Int -> Maybe (PrimArray Int)+-- > incrPositiveB xs = runST $ runMaybeT $ traversePrimArrayP+-- >   (\x -> bool (MaybeT (return Nothing)) (MaybeT (return (Just (x + 1)))) (x > 0))+-- >   xs+-- +-- Benchmarks demonstrate that the second implementation runs 150 times+-- faster than the first. It also results in fewer allocations.+{-# INLINE traversePrimArrayP #-}+traversePrimArrayP :: (PrimMonad m, Prim a, Prim b)+  => (a -> m b)+  -> PrimArray a+  -> m (PrimArray b)+traversePrimArrayP f arr = do+  let !sz = sizeofPrimArray arr+  marr <- newPrimArray sz+  let go !ix = if ix < sz+        then do+          b <- f (indexPrimArray arr ix)+          writePrimArray marr ix b+          go (ix + 1)+        else return ()+  go 0+  unsafeFreezePrimArray marr++-- | Filter the primitive array, keeping the elements for which the monadic+-- predicate evaluates true.+{-# INLINE filterPrimArrayP #-}+filterPrimArrayP :: (PrimMonad m, Prim a)+  => (a -> m Bool)+  -> PrimArray a+  -> m (PrimArray a)+filterPrimArrayP f arr = do+  let !sz = sizeofPrimArray arr+  marr <- newPrimArray sz+  let go !ixSrc !ixDst = if ixSrc < sz+        then do+          let a = indexPrimArray arr ixSrc+          b <- f a+          if b+            then do+              writePrimArray marr ixDst a+              go (ixSrc + 1) (ixDst + 1)+            else go (ixSrc + 1) ixDst+        else return ixDst+  lenDst <- go 0 0+  marr' <- resizeMutablePrimArray marr lenDst+  unsafeFreezePrimArray marr'++-- | Map over the primitive array, keeping the elements for which the monadic+-- predicate provides a 'Just'.+{-# INLINE mapMaybePrimArrayP #-}+mapMaybePrimArrayP :: (PrimMonad m, Prim a, Prim b)+  => (a -> m (Maybe b))+  -> PrimArray a+  -> m (PrimArray b)+mapMaybePrimArrayP f arr = do+  let !sz = sizeofPrimArray arr+  marr <- newPrimArray sz+  let go !ixSrc !ixDst = if ixSrc < sz+        then do+          let a = indexPrimArray arr ixSrc+          mb <- f a+          case mb of+            Just b -> do+              writePrimArray marr ixDst b+              go (ixSrc + 1) (ixDst + 1)+            Nothing -> go (ixSrc + 1) ixDst+        else return ixDst+  lenDst <- go 0 0+  marr' <- resizeMutablePrimArray marr lenDst+  unsafeFreezePrimArray marr'++-- | Generate a primitive array by evaluating the monadic generator function+-- at each index.+{-# INLINE generatePrimArrayP #-}+generatePrimArrayP :: (PrimMonad m, Prim a)+  => Int -- ^ length+  -> (Int -> m a) -- ^ generator+  -> m (PrimArray a)+generatePrimArrayP sz f = do+  marr <- newPrimArray sz+  let go !ix = if ix < sz+        then do+          b <- f ix+          writePrimArray marr ix b+          go (ix + 1)+        else return ()+  go 0+  unsafeFreezePrimArray marr++-- | Execute the monadic action the given number of times and store the+-- results in a primitive array.+{-# INLINE replicatePrimArrayP #-}+replicatePrimArrayP :: (PrimMonad m, Prim a)+  => Int+  -> m a+  -> m (PrimArray a)+replicatePrimArrayP sz f = do+  marr <- newPrimArray sz+  let go !ix = if ix < sz+        then do+          b <- f+          writePrimArray marr ix b+          go (ix + 1)+        else return ()+  go 0+  unsafeFreezePrimArray marr+++-- | Map over the elements of a primitive array.+{-# INLINE mapPrimArray #-}+mapPrimArray :: (Prim a, Prim b)+  => (a -> b)+  -> PrimArray a+  -> PrimArray b+mapPrimArray f arr = runST $ do+  let !sz = sizeofPrimArray arr+  marr <- newPrimArray sz+  let go !ix = if ix < sz+        then do+          let b = f (indexPrimArray arr ix)+          writePrimArray marr ix b+          go (ix + 1)+        else return ()+  go 0+  unsafeFreezePrimArray marr++-- | Indexed map over the elements of a primitive array.+{-# INLINE imapPrimArray #-}+imapPrimArray :: (Prim a, Prim b)+  => (Int -> a -> b)+  -> PrimArray a+  -> PrimArray b+imapPrimArray f arr = runST $ do+  let !sz = sizeofPrimArray arr+  marr <- newPrimArray sz+  let go !ix = if ix < sz+        then do+          let b = f ix (indexPrimArray arr ix)+          writePrimArray marr ix b+          go (ix + 1)+        else return ()+  go 0+  unsafeFreezePrimArray marr++-- | Filter elements of a primitive array according to a predicate.+{-# INLINE filterPrimArray #-}+filterPrimArray :: Prim a+  => (a -> Bool)+  -> PrimArray a+  -> PrimArray a+filterPrimArray p arr = runST $ do+  let !sz = sizeofPrimArray arr+  marr <- newPrimArray sz+  let go !ixSrc !ixDst = if ixSrc < sz+        then do+          let !a = indexPrimArray arr ixSrc+          if p a+            then do+              writePrimArray marr ixDst a+              go (ixSrc + 1) (ixDst + 1)+            else go (ixSrc + 1) ixDst+        else return ixDst+  dstLen <- go 0 0+  marr' <- resizeMutablePrimArray marr dstLen+  unsafeFreezePrimArray marr'++-- | Filter the primitive array, keeping the elements for which the monadic+-- predicate evaluates true.+filterPrimArrayA ::+     (Applicative f, Prim a)+  => (a -> f Bool) -- ^ mapping function+  -> PrimArray a -- ^ primitive array+  -> f (PrimArray a)+filterPrimArrayA f = \ !ary ->+  let+    !len = sizeofPrimArray ary+    go !ixSrc+      | ixSrc == len = pure $ IxSTA $ \ixDst _ -> return ixDst+      | otherwise = let x = indexPrimArray ary ixSrc in+          liftA2+            (\keep (IxSTA m) -> IxSTA $ \ixDst mary -> if keep+              then writePrimArray (MutablePrimArray mary) ixDst x >> m (ixDst + 1) mary+              else m ixDst mary+            )+            (f x)+            (go (ixSrc + 1))+  in if len == 0+     then pure emptyPrimArray+     else runIxSTA len <$> go 0++-- | Map over the primitive array, keeping the elements for which the applicative+-- predicate provides a 'Just'.+mapMaybePrimArrayA ::+     (Applicative f, Prim a, Prim b)+  => (a -> f (Maybe b)) -- ^ mapping function+  -> PrimArray a -- ^ primitive array+  -> f (PrimArray b)+mapMaybePrimArrayA f = \ !ary ->+  let+    !len = sizeofPrimArray ary+    go !ixSrc+      | ixSrc == len = pure $ IxSTA $ \ixDst _ -> return ixDst+      | otherwise = let x = indexPrimArray ary ixSrc in+          liftA2+            (\mb (IxSTA m) -> IxSTA $ \ixDst mary -> case mb of+              Just b -> writePrimArray (MutablePrimArray mary) ixDst b >> m (ixDst + 1) mary+              Nothing -> m ixDst mary+            )+            (f x)+            (go (ixSrc + 1))+  in if len == 0+     then pure emptyPrimArray+     else runIxSTA len <$> go 0++-- | Map over a primitive array, optionally discarding some elements. This+--   has the same behavior as @Data.Maybe.mapMaybe@.+{-# INLINE mapMaybePrimArray #-}+mapMaybePrimArray :: (Prim a, Prim b)+  => (a -> Maybe b)+  -> PrimArray a+  -> PrimArray b+mapMaybePrimArray p arr = runST $ do+  let !sz = sizeofPrimArray arr+  marr <- newPrimArray sz+  let go !ixSrc !ixDst = if ixSrc < sz+        then do+          let !a = indexPrimArray arr ixSrc+          case p a of+            Just b -> do+              writePrimArray marr ixDst b+              go (ixSrc + 1) (ixDst + 1)+            Nothing -> go (ixSrc + 1) ixDst+        else return ixDst+  dstLen <- go 0 0+  marr' <- resizeMutablePrimArray marr dstLen+  unsafeFreezePrimArray marr'+++-- | Traverse a primitive array. The traversal performs all of the applicative+-- effects /before/ forcing the resulting values and writing them to the new+-- primitive array. Consequently:+--+-- >>> traversePrimArray (\x -> print x $> bool x undefined (x == 2)) (fromList [1, 2, 3 :: Int])+-- 1+-- 2+-- 3+-- *** Exception: Prelude.undefined+--+-- The function 'traversePrimArrayP' always outperforms this function, but it+-- requires a 'PrimAffineMonad' constraint, and it forces the values as+-- it performs the effects.+traversePrimArray ::+     (Applicative f, Prim a, Prim b)+  => (a -> f b) -- ^ mapping function+  -> PrimArray a -- ^ primitive array+  -> f (PrimArray b)+traversePrimArray f = \ !ary ->+  let+    !len = sizeofPrimArray ary+    go !i+      | i == len = pure $ STA $ \mary -> unsafeFreezePrimArray (MutablePrimArray mary)+      | x <- indexPrimArray ary i+      = liftA2 (\b (STA m) -> STA $ \mary ->+                  writePrimArray (MutablePrimArray mary) i b >> m mary)+               (f x) (go (i + 1))+  in if len == 0+     then pure emptyPrimArray+     else runSTA len <$> go 0++-- | Traverse a primitive array with the index of each element.+itraversePrimArray ::+     (Applicative f, Prim a, Prim b)+  => (Int -> a -> f b)+  -> PrimArray a+  -> f (PrimArray b)+itraversePrimArray f = \ !ary ->+  let+    !len = sizeofPrimArray ary+    go !i+      | i == len = pure $ STA $ \mary -> unsafeFreezePrimArray (MutablePrimArray mary)+      | x <- indexPrimArray ary i+      = liftA2 (\b (STA m) -> STA $ \mary ->+                  writePrimArray (MutablePrimArray mary) i b >> m mary)+               (f i x) (go (i + 1))+  in if len == 0+     then pure emptyPrimArray+     else runSTA len <$> go 0++-- | Traverse a primitive array with the indices. The traversal forces the+-- resulting values and writes them to the new primitive array as it performs+-- the monadic effects.+{-# INLINE itraversePrimArrayP #-}+itraversePrimArrayP :: (Prim a, Prim b, PrimMonad m)+  => (Int -> a -> m b)+  -> PrimArray a+  -> m (PrimArray b)+itraversePrimArrayP f arr = do+  let !sz = sizeofPrimArray arr+  marr <- newPrimArray sz+  let go !ix+        | ix < sz = do+            writePrimArray marr ix =<< f ix (indexPrimArray arr ix)+            go (ix + 1)+        | otherwise = return ()+  go 0+  unsafeFreezePrimArray marr++-- | Generate a primitive array.+{-# INLINE generatePrimArray #-}+generatePrimArray :: Prim a+  => Int -- ^ length+  -> (Int -> a) -- ^ element from index+  -> PrimArray a+generatePrimArray len f = runST $ do+  marr <- newPrimArray len+  let go !ix = if ix < len+        then do+          writePrimArray marr ix (f ix)+          go (ix + 1)+        else return ()+  go 0+  unsafeFreezePrimArray marr++-- | Create a primitive array by copying the element the given+-- number of times.+{-# INLINE replicatePrimArray #-}+replicatePrimArray :: Prim a+  => Int -- ^ length+  -> a -- ^ element+  -> PrimArray a+replicatePrimArray len a = runST $ do+  marr <- newPrimArray len+  setPrimArray marr 0 len a+  unsafeFreezePrimArray marr++-- | Generate a primitive array by evaluating the applicative generator+-- function at each index.+{-# INLINE generatePrimArrayA #-}+generatePrimArrayA ::+     (Applicative f, Prim a)+  => Int -- ^ length+  -> (Int -> f a) -- ^ element from index+  -> f (PrimArray a)+generatePrimArrayA len f =+  let+    go !i+      | i == len = pure $ STA $ \mary -> unsafeFreezePrimArray (MutablePrimArray mary)+      | otherwise+      = liftA2 (\b (STA m) -> STA $ \mary ->+                  writePrimArray (MutablePrimArray mary) i b >> m mary)+               (f i) (go (i + 1))+  in if len == 0+     then pure emptyPrimArray+     else runSTA len <$> go 0++-- | Execute the applicative action the given number of times and store the+-- results in a vector.+{-# INLINE replicatePrimArrayA #-}+replicatePrimArrayA ::+     (Applicative f, Prim a)+  => Int -- ^ length+  -> f a -- ^ applicative element producer+  -> f (PrimArray a)+replicatePrimArrayA len f =+  let+    go !i+      | i == len = pure $ STA $ \mary -> unsafeFreezePrimArray (MutablePrimArray mary)+      | otherwise+      = liftA2 (\b (STA m) -> STA $ \mary ->+                  writePrimArray (MutablePrimArray mary) i b >> m mary)+               f (go (i + 1))+  in if len == 0+     then pure emptyPrimArray+     else runSTA len <$> go 0++-- | Traverse the primitive array, discarding the results. There+-- is no 'PrimMonad' variant of this function since it would not provide+-- any performance benefit.+traversePrimArray_ ::+     (Applicative f, Prim a)+  => (a -> f b)+  -> PrimArray a+  -> f ()+traversePrimArray_ f a = go 0 where+  !sz = sizeofPrimArray a+  go !ix = if ix < sz+    then f (indexPrimArray a ix) *> go (ix + 1)+    else pure ()++-- | Traverse the primitive array with the indices, discarding the results.+-- There is no 'PrimMonad' variant of this function since it would not+-- provide any performance benefit.+itraversePrimArray_ ::+     (Applicative f, Prim a)+  => (Int -> a -> f b)+  -> PrimArray a+  -> f ()+itraversePrimArray_ f a = go 0 where+  !sz = sizeofPrimArray a+  go !ix = if ix < sz+    then f ix (indexPrimArray a ix) *> go (ix + 1)+    else pure ()++newtype IxSTA a = IxSTA {_runIxSTA :: forall s. Int -> MutableByteArray# s -> ST s Int}++runIxSTA :: forall a. Prim a+  => Int -- maximum possible size+  -> IxSTA a+  -> PrimArray a+runIxSTA !szUpper = \ (IxSTA m) -> runST $ do+  ar :: MutablePrimArray s a <- newPrimArray szUpper+  sz <- m 0 (unMutablePrimArray ar)+  ar' <- resizeMutablePrimArray ar sz+  unsafeFreezePrimArray ar'+{-# INLINE runIxSTA #-}++newtype STA a = STA {_runSTA :: forall s. MutableByteArray# s -> ST s (PrimArray a)}++runSTA :: forall a. Prim a => Int -> STA a -> PrimArray a+runSTA !sz = \ (STA m) -> runST $ newPrimArray sz >>= \ (ar :: MutablePrimArray s a) -> m (unMutablePrimArray ar)+{-# INLINE runSTA #-}++unMutablePrimArray :: MutablePrimArray s a -> MutableByteArray# s+unMutablePrimArray (MutablePrimArray m) = m++{- $effectfulMapCreate+The naming conventions adopted in this section are explained in the+documentation of the @Data.Primitive@ module.+-}++
+ Data/Primitive/Ptr.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- |+-- Module      : Data.Primitive.Ptr+-- Copyright   : (c) Roman Leshchinskiy 2009-2012+-- License     : BSD-style+--+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>+-- Portability : non-portable+--+-- Primitive operations on machine addresses+--+-- @since 0.6.4.0++module Data.Primitive.Ptr (+  -- * Types+  Ptr(..),++  -- * Address arithmetic+  nullPtr, advancePtr, subtractPtr,++  -- * Element access+  indexOffPtr, readOffPtr, writeOffPtr,++  -- * Block operations+  copyPtr, movePtr, setPtr++#if __GLASGOW_HASKELL__ >= 708+  , copyPtrToMutablePrimArray+#endif+) where++import Control.Monad.Primitive+import Data.Primitive.Types+#if __GLASGOW_HASKELL__ >= 708+import Data.Primitive.PrimArray (MutablePrimArray(..))+#endif++import GHC.Base ( Int(..) )+import GHC.Prim++import GHC.Ptr+import Foreign.Marshal.Utils+++-- | Offset a pointer by the given number of elements.+advancePtr :: forall a. Prim a => Ptr a -> Int -> Ptr a+{-# INLINE advancePtr #-}+advancePtr (Ptr a#) (I# i#) = Ptr (plusAddr# a# (i# *# sizeOf# (undefined :: a)))++-- | Subtract a pointer from another pointer. The result represents+--   the number of elements of type @a@ that fit in the contiguous+--   memory range bounded by these two pointers.+subtractPtr :: forall a. Prim a => Ptr a -> Ptr a -> Int+{-# INLINE subtractPtr #-}+subtractPtr (Ptr a#) (Ptr b#) = I# (quotInt# (minusAddr# a# b#) (sizeOf# (undefined :: a)))++-- | Read a value from a memory position given by a pointer and an offset.+-- The memory block the address refers to must be immutable. The offset is in+-- elements of type @a@ rather than in bytes.+indexOffPtr :: Prim a => Ptr a -> Int -> a+{-# INLINE indexOffPtr #-}+indexOffPtr (Ptr addr#) (I# i#) = indexOffAddr# addr# i#++-- | Read a value from a memory position given by an address and an offset.+-- The offset is in elements of type @a@ rather than in bytes.+readOffPtr :: (Prim a, PrimMonad m) => Ptr a -> Int -> m a+{-# INLINE readOffPtr #-}+readOffPtr (Ptr addr#) (I# i#) = primitive (readOffAddr# addr# i#)++-- | Write a value to a memory position given by an address and an offset.+-- The offset is in elements of type @a@ rather than in bytes.+writeOffPtr :: (Prim a, PrimMonad m) => Ptr a -> Int -> a -> m ()+{-# INLINE writeOffPtr #-}+writeOffPtr (Ptr addr#) (I# i#) x = primitive_ (writeOffAddr# addr# i# x)++-- | Copy the given number of elements from the second 'Ptr' to the first. The+-- areas may not overlap.+copyPtr :: forall m a. (PrimMonad m, Prim a)+  => Ptr a -- ^ destination pointer+  -> Ptr a -- ^ source pointer+  -> Int -- ^ number of elements+  -> m ()+{-# INLINE copyPtr #-}+copyPtr (Ptr dst#) (Ptr src#) n+  = unsafePrimToPrim $ copyBytes (Ptr dst#) (Ptr src#) (n * sizeOf (undefined :: a))++-- | Copy the given number of elements from the second 'Ptr' to the first. The+-- areas may overlap.+movePtr :: forall m a. (PrimMonad m, Prim a)+  => Ptr a -- ^ destination address+  -> Ptr a -- ^ source address+  -> Int -- ^ number of elements+  -> m ()+{-# INLINE movePtr #-}+movePtr (Ptr dst#) (Ptr src#) n+  = unsafePrimToPrim $ moveBytes (Ptr dst#) (Ptr src#) (n * sizeOf (undefined :: a))++-- | Fill a memory block with the given value. The length is in+-- elements of type @a@ rather than in bytes.+setPtr :: (Prim a, PrimMonad m) => Ptr a -> Int -> a -> m ()+{-# INLINE setPtr #-}+setPtr (Ptr addr#) (I# n#) x = primitive_ (setOffAddr# addr# 0# n# x)+++#if __GLASGOW_HASKELL__ >= 708+-- | Copy from a pointer to a mutable primitive array.+-- The offset and length are given in elements of type @a@.+-- This function is only available when building with GHC 7.8+-- or newer.+copyPtrToMutablePrimArray :: forall m a. (PrimMonad m, Prim a)+  => MutablePrimArray (PrimState m) a -- ^ destination array+  -> Int -- ^ destination offset+  -> Ptr a -- ^ source pointer+  -> Int -- ^ number of elements+  -> m ()+{-# INLINE copyPtrToMutablePrimArray #-}+copyPtrToMutablePrimArray (MutablePrimArray ba#) (I# doff#) (Ptr addr#) (I# n#) = +  primitive_ (copyAddrToByteArray# addr# ba# (doff# *# siz#) (n# *# siz#))+  where+  siz# = sizeOf# (undefined :: a)+#endif
Data/Primitive/SmallArray.hs view
@@ -6,6 +6,7 @@ {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE BangPatterns #-}  -- | -- Module : Data.Primitive.SmallArray@@ -45,14 +46,20 @@   , copySmallMutableArray   , indexSmallArray   , indexSmallArrayM+  , indexSmallArray##   , cloneSmallArray   , cloneSmallMutableArray   , freezeSmallArray   , unsafeFreezeSmallArray   , thawSmallArray+  , runSmallArray   , unsafeThawSmallArray   , sizeofSmallArray   , sizeofSmallMutableArray+  , smallArrayFromList+  , smallArrayFromListN+  , mapSmallArray'+  , traverseSmallArrayP   ) where  @@ -70,25 +77,34 @@ import Control.Monad.Fix import Control.Monad.Primitive import Control.Monad.ST-#if MIN_VERSION_base(4,4,0) import Control.Monad.Zip-#endif import Data.Data-import Data.Foldable+import Data.Foldable as Foldable import Data.Functor.Identity+#if !(MIN_VERSION_base(4,10,0)) import Data.Monoid+#endif #if MIN_VERSION_base(4,9,0)+import qualified GHC.ST as GHCST import qualified Data.Semigroup as Sem #endif-import Text.ParserCombinators.ReadPrec-import Text.Read-import Text.Read.Lex+import Text.ParserCombinators.ReadP+#if MIN_VERSION_base(4,10,0)+import GHC.Exts (runRW#)+#elif MIN_VERSION_base(4,9,0)+import GHC.Base (runRW#)+#endif  #if !(HAVE_SMALL_ARRAY) import Data.Primitive.Array import Data.Traversable+import qualified Data.Primitive.Array as Array #endif +#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+import Data.Functor.Classes (Eq1(..),Ord1(..),Show1(..),Read1(..))+#endif+ #if HAVE_SMALL_ARRAY data SmallArray a = SmallArray (SmallArray# a)   deriving Typeable@@ -105,12 +121,16 @@   , Alternative   , Monad   , MonadPlus-#if MIN_VERSION_base(4,4,0)   , MonadZip-#endif   , MonadFix   , Monoid   , Typeable+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+  , Eq1+  , Ord1+  , Show1+  , Read1+#endif   )  #if MIN_VERSION_base(4,7,0)@@ -118,7 +138,7 @@   type Item (SmallArray a) = a   fromListN n l = SmallArray (fromListN n l)   fromList l = SmallArray (fromList l)-  toList (SmallArray a) = toList a+  toList a = Foldable.toList a #endif #endif @@ -223,6 +243,17 @@ #endif {-# INLINE indexSmallArray #-} +-- | Read a value from the immutable array at the given index, returning+-- the result in an unboxed unary tuple. This is currently used to implement+-- folds.+indexSmallArray## :: SmallArray a -> Int -> (# a #)+#if HAVE_SMALL_ARRAY+indexSmallArray## (SmallArray ary) (I# i) = indexSmallArray# ary i+#else+indexSmallArray## (SmallArray a) = indexArray## a+#endif+{-# INLINE indexSmallArray## #-}+ -- | Create a copy of a slice of an immutable array. cloneSmallArray   :: SmallArray a -- ^ source@@ -378,7 +409,106 @@ #endif {-# INLINE sizeofSmallMutableArray #-} +-- | This is the fastest, most straightforward way to traverse+-- an array, but it only works correctly with a sufficiently+-- "affine" 'PrimMonad' instance. In particular, it must only produce+-- *one* result array. 'Control.Monad.Trans.List.ListT'-transformed+-- monads, for example, will not work right at all.+traverseSmallArrayP+  :: PrimMonad m+  => (a -> m b)+  -> SmallArray a+  -> m (SmallArray b) #if HAVE_SMALL_ARRAY+traverseSmallArrayP f = \ !ary ->+  let+    !sz = sizeofSmallArray ary+    go !i !mary+      | i == sz+      = unsafeFreezeSmallArray mary+      | otherwise+      = do+          a <- indexSmallArrayM ary i+          b <- f a+          writeSmallArray mary i b+          go (i + 1) mary+  in do+    mary <- newSmallArray sz badTraverseValue+    go 0 mary+#else+traverseSmallArrayP f (SmallArray ar) = SmallArray `liftM` traverseArrayP f ar+#endif+{-# INLINE traverseSmallArrayP #-}++-- | Strict map over the elements of the array.+mapSmallArray' :: (a -> b) -> SmallArray a -> SmallArray b+#if HAVE_SMALL_ARRAY+mapSmallArray' f sa = createSmallArray (length sa) (die "mapSmallArray'" "impossible") $ \smb ->+  fix ? 0 $ \go i ->+    when (i < length sa) $ do+      x <- indexSmallArrayM sa i+      let !y = f x+      writeSmallArray smb i y *> go (i+1)+#else+mapSmallArray' f (SmallArray ar) = SmallArray (mapArray' f ar)+#endif+{-# INLINE mapSmallArray' #-}++#ifndef HAVE_SMALL_ARRAY+runSmallArray+  :: (forall s. ST s (SmallMutableArray s a))+  -> SmallArray a+runSmallArray m = SmallArray $ runArray $+  m >>= \(SmallMutableArray mary) -> return mary++#elif !MIN_VERSION_base(4,9,0)+runSmallArray+  :: (forall s. ST s (SmallMutableArray s a))+  -> SmallArray a+runSmallArray m = runST $ m >>= unsafeFreezeSmallArray++#else+-- This low-level business is designed to work with GHC's worker-wrapper+-- transformation. A lot of the time, we don't actually need an Array+-- constructor. By putting it on the outside, and being careful about+-- how we special-case the empty array, we can make GHC smarter about this.+-- The only downside is that separately created 0-length arrays won't share+-- their Array constructors, although they'll share their underlying+-- Array#s.+runSmallArray+  :: (forall s. ST s (SmallMutableArray s a))+  -> SmallArray a+runSmallArray m = SmallArray (runSmallArray# m)++runSmallArray#+  :: (forall s. ST s (SmallMutableArray s a))+  -> SmallArray# a+runSmallArray# m = case runRW# $ \s ->+  case unST m s of { (# s', SmallMutableArray mary# #) ->+  unsafeFreezeSmallArray# mary# s'} of (# _, ary# #) -> ary#++unST :: ST s a -> State# s -> (# State# s, a #)+unST (GHCST.ST f) = f++#endif++#if HAVE_SMALL_ARRAY+-- See the comment on runSmallArray for why we use emptySmallArray#.+createSmallArray+  :: Int+  -> a+  -> (forall s. SmallMutableArray s a -> ST s ())+  -> SmallArray a+createSmallArray 0 _ _ = SmallArray (emptySmallArray# (# #))+createSmallArray n x f = runSmallArray $ do+  mary <- newSmallArray n x+  f mary+  pure mary++emptySmallArray# :: (# #) -> SmallArray# a+emptySmallArray# _ = case emptySmallArray of SmallArray ar -> ar+{-# NOINLINE emptySmallArray# #-}+ die :: String -> String -> a die fun problem = error $ "Data.Primitive.SmallArray." ++ fun ++ ": " ++ problem @@ -388,12 +518,6 @@             >>= unsafeFreezeSmallArray {-# NOINLINE emptySmallArray #-} -createSmallArray-  :: Int -> a -> (forall s. SmallMutableArray s a -> ST s ()) -> SmallArray a-createSmallArray 0 _ _ = emptySmallArray-createSmallArray i x k =-  runST $ newSmallArray i x >>= \sa -> k sa *> unsafeFreezeSmallArray sa-{-# INLINE createSmallArray #-}  infixl 1 ? (?) :: (a -> b -> c) -> (b -> a -> c)@@ -403,82 +527,197 @@ noOp :: a -> ST s () noOp = const $ pure () +smallArrayLiftEq :: (a -> b -> Bool) -> SmallArray a -> SmallArray b -> Bool+smallArrayLiftEq p sa1 sa2 = length sa1 == length sa2 && loop (length sa1 - 1)+  where+  loop i+    | i < 0+    = True+    | (# x #) <- indexSmallArray## sa1 i+    , (# y #) <- indexSmallArray## sa2 i+    = p x y && loop (i-1)++#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+-- | @since 0.6.4.0+instance Eq1 SmallArray where+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)+  liftEq = smallArrayLiftEq+#else+  eq1 = smallArrayLiftEq (==)+#endif+#endif+ instance Eq a => Eq (SmallArray a) where-  sa1 == sa2 = length sa1 == length sa2 && loop (length sa1 - 1)-   where-   loop i-     | i < 0     = True-     | otherwise = indexSmallArray sa1 i == indexSmallArray sa2 i && loop (i-1)+  sa1 == sa2 = smallArrayLiftEq (==) sa1 sa2  instance Eq (SmallMutableArray s a) where   SmallMutableArray sma1# == SmallMutableArray sma2# =     isTrue# (sameSmallMutableArray# sma1# sma2#) +smallArrayLiftCompare :: (a -> b -> Ordering) -> SmallArray a -> SmallArray b -> Ordering+smallArrayLiftCompare elemCompare a1 a2 = loop 0+  where+  mn = length a1 `min` length a2+  loop i+    | i < mn+    , (# x1 #) <- indexSmallArray## a1 i+    , (# x2 #) <- indexSmallArray## a2 i+    = elemCompare x1 x2 `mappend` loop (i+1)+    | otherwise = compare (length a1) (length a2)++#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+-- | @since 0.6.4.0+instance Ord1 SmallArray where+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)+  liftCompare = smallArrayLiftCompare+#else+  compare1 = smallArrayLiftCompare compare+#endif+#endif++-- | Lexicographic ordering. Subject to change between major versions. instance Ord a => Ord (SmallArray a) where-  compare sl sr = fix ? 0 $ \go i ->-    if i < l-      then compare (indexSmallArray sl i) (indexSmallArray sr i) <> go (i+1)-      else compare (length sl) (length sr)-   where l = length sl `min` length sr+  compare sa1 sa2 = smallArrayLiftCompare compare sa1 sa2  instance Foldable SmallArray where-  foldr f z sa = fix ? 0 $ \go i ->-    if i < length sa-      then f (indexSmallArray sa i) (go $ i+1)-      else z+  -- Note: we perform the array lookups eagerly so we won't+  -- create thunks to perform lookups even if GHC can't see+  -- that the folding function is strict.+  foldr f = \z !ary ->+    let+      !sz = sizeofSmallArray ary+      go i+        | i == sz = z+        | (# x #) <- indexSmallArray## ary i+        = f x (go (i+1))+    in go 0   {-# INLINE foldr #-}--  foldr' f z sa = fix ? z ? length sa - 1 $ \go acc i ->-    if i < 0-      then acc-      else go (f (indexSmallArray sa i) acc) (i-1)-  {-# INLINE foldr' #-}--  foldl f z sa = fix ? length sa - 1 $ \go i ->-    if i < 0-      then z-      else f (go $ i-1) $ indexSmallArray sa i+  foldl f = \z !ary ->+    let+      go i+        | i < 0 = z+        | (# x #) <- indexSmallArray## ary i+        = f (go (i-1)) x+    in go (sizeofSmallArray ary - 1)   {-# INLINE foldl #-}--  foldl' f z sa = fix ? z ? 0 $ \go acc i ->-    if i < length sa-      then go (f acc $ indexSmallArray sa i) (i+1)-      else acc-  {-# INLINE foldl' #-}--  foldr1 f sa-    | sz == 0   = die "foldr1" "empty list"-    | otherwise = fix ? 0 $ \go i ->-        if i < sz-1-          then f (indexSmallArray sa i) (go $ i+1)-          else indexSmallArray sa $ sz-1-   where sz = sizeofSmallArray sa+  foldr1 f = \ !ary ->+    let+      !sz = sizeofSmallArray ary - 1+      go i =+        case indexSmallArray## ary i of+          (# x #) | i == sz -> x+                  | otherwise -> f x (go (i+1))+    in if sz < 0+       then die "foldr1" "Empty SmallArray"+       else go 0   {-# INLINE foldr1 #-}--  foldl1 f sa-    | sz == 0   = die "foldl1" "empty list"-    | otherwise = fix ? sz-1 $ \go i ->-        if i < 1-        then indexSmallArray sa 0-        else f (go $ i-1) (indexSmallArray sa i)-   where sz = sizeofSmallArray sa+  foldl1 f = \ !ary ->+    let+      !sz = sizeofSmallArray ary - 1+      go i =+        case indexSmallArray## ary i of+          (# x #) | i == 0 -> x+                  | otherwise -> f (go (i - 1)) x+    in if sz < 0+       then die "foldl1" "Empty SmallArray"+       else go sz   {-# INLINE foldl1 #-}--  null sa = sizeofSmallArray sa == 0+  foldr' f = \z !ary ->+    let+      go i !acc+        | i == -1 = acc+        | (# x #) <- indexSmallArray## ary i+        = go (i-1) (f x acc)+    in go (sizeofSmallArray ary - 1) z+  {-# INLINE foldr' #-}+  foldl' f = \z !ary ->+    let+      !sz = sizeofSmallArray ary+      go i !acc+        | i == sz = acc+        | (# x #) <- indexSmallArray## ary i+        = go (i+1) (f acc x)+    in go 0 z+  {-# INLINE foldl' #-}+  null a = sizeofSmallArray a == 0   {-# INLINE null #-}-   length = sizeofSmallArray   {-# INLINE length #-}+  maximum ary | sz == 0   = die "maximum" "Empty SmallArray"+              | (# frst #) <- indexSmallArray## ary 0+              = go 1 frst+   where+     sz = sizeofSmallArray ary+     go i !e+       | i == sz = e+       | (# x #) <- indexSmallArray## ary i+       = go (i+1) (max e x)+  {-# INLINE maximum #-}+  minimum ary | sz == 0   = die "minimum" "Empty SmallArray"+              | (# frst #) <- indexSmallArray## ary 0+              = go 1 frst+   where sz = sizeofSmallArray ary+         go i !e+           | i == sz = e+           | (# x #) <- indexSmallArray## ary i+           = go (i+1) (min e x)+  {-# INLINE minimum #-}+  sum = foldl' (+) 0+  {-# INLINE sum #-}+  product = foldl' (*) 1+  {-# INLINE product #-} +newtype STA a = STA {_runSTA :: forall s. SmallMutableArray# s a -> ST s (SmallArray a)}++runSTA :: Int -> STA a -> SmallArray a+runSTA !sz = \ (STA m) -> runST $ newSmallArray_ sz >>=+                        \ (SmallMutableArray ar#) -> m ar#+{-# INLINE runSTA #-}++newSmallArray_ :: Int -> ST s (SmallMutableArray s a)+newSmallArray_ !n = newSmallArray n badTraverseValue++badTraverseValue :: a+badTraverseValue = die "traverse" "bad indexing"+{-# NOINLINE badTraverseValue #-}+ instance Traversable SmallArray where-  traverse f sa = fromListN l <$> traverse (f . indexSmallArray sa) [0..l-1]-   where l = length sa+  traverse f = traverseSmallArray f+  {-# INLINE traverse #-} +traverseSmallArray+  :: Applicative f+  => (a -> f b) -> SmallArray a -> f (SmallArray b)+traverseSmallArray f = \ !ary ->+  let+    !len = sizeofSmallArray ary+    go !i+      | i == len+      = pure $ STA $ \mary -> unsafeFreezeSmallArray (SmallMutableArray mary)+      | (# x #) <- indexSmallArray## ary i+      = liftA2 (\b (STA m) -> STA $ \mary ->+                  writeSmallArray (SmallMutableArray mary) i b >> m mary)+               (f x) (go (i + 1))+  in if len == 0+     then pure emptySmallArray+     else runSTA len <$> go 0+{-# INLINE [1] traverseSmallArray #-}++{-# RULES+"traverse/ST" forall (f :: a -> ST s b). traverseSmallArray f = traverseSmallArrayP f+"traverse/IO" forall (f :: a -> IO b). traverseSmallArray f = traverseSmallArrayP f+"traverse/Id" forall (f :: a -> Identity b). traverseSmallArray f =+   (coerce :: (SmallArray a -> SmallArray (Identity b))+           -> SmallArray a -> Identity (SmallArray b)) (fmap f)+ #-}++ instance Functor SmallArray where   fmap f sa = createSmallArray (length sa) (die "fmap" "impossible") $ \smb ->     fix ? 0 $ \go i ->-      when (i < length sa) $-        writeSmallArray smb i (f $ indexSmallArray sa i) *> go (i+1)+      when (i < length sa) $ do+        x <- indexSmallArrayM sa i+        writeSmallArray smb i (f x) *> go (i+1)   {-# INLINE fmap #-}    x <$ sa = createSmallArray (length sa) x noOp@@ -493,26 +732,29 @@    where    la = length sa ; lb = length sb -  sa <* sb = createSmallArray (la*lb) (indexSmallArray sa $ la-1) $ \sma ->-    fix ? 0 $ \outer i -> when (i < la-1) $ do-      let a = indexSmallArray sa i-      fix ? 0 $ \inner j ->-        when (j < lb) $-          writeSmallArray sma (la*i + j) a *> inner (j+1)-      outer $ i+1-   where-   la = length sa ; lb = length sb+  a <* b = createSmallArray (sza*szb) (die "<*" "impossible") $ \ma ->+    let fill off i e = when (i < szb) $+                         writeSmallArray ma (off+i) e >> fill off (i+1) e+        go i = when (i < sza) $ do+                 x <- indexSmallArrayM a i+                 fill (i*szb) 0 x+                 go (i+1)+     in go 0+   where sza = sizeofSmallArray a ; szb = sizeofSmallArray b -  sf <*> sx = createSmallArray (lf*lx) (die "<*>" "impossible") $ \smb ->-    fix ? 0 $ \outer i -> when (i < lf) $ do-      let f = indexSmallArray sf i-      fix ? 0 $ \inner j ->-        when (j < lx) $-          writeSmallArray smb (lf*i + j) (f $ indexSmallArray sx j)-            *> inner (j+1)-      outer $ i+1-   where-   lf = length sf ; lx = length sx+  ab <*> a = createSmallArray (szab*sza) (die "<*>" "impossible") $ \mb ->+    let go1 i = when (i < szab) $+            do+              f <- indexSmallArrayM ab i+              go2 (i*sza) f 0+              go1 (i+1)+        go2 off f j = when (j < sza) $+            do+              x <- indexSmallArrayM a j+              writeSmallArray mb (off + j) (f x)+              go2 off f (j + 1)+    in go1 0+   where szab = sizeofSmallArray ab ; sza = sizeofSmallArray a  instance Alternative SmallArray where   empty = emptySmallArray@@ -528,20 +770,41 @@   some sa | null sa   = emptySmallArray           | otherwise = die "some" "infinite arrays are not well defined" +data ArrayStack a+  = PushArray !(SmallArray a) !(ArrayStack a)+  | EmptyStack+-- TODO: This isn't terribly efficient. It would be better to wrap+-- ArrayStack with a type like+--+-- data NES s a = NES !Int !(SmallMutableArray s a) !(ArrayStack a)+--+-- We'd copy incoming arrays into the mutable array until we would+-- overflow it. Then we'd freeze it, push it on the stack, and continue.+-- Any sufficiently large incoming arrays would go straight on the stack.+-- Such a scheme would make the stack much more compact in the case+-- of many small arrays.+ instance Monad SmallArray where   return = pure   (>>) = (*>) -  sa >>= f = collect 0 [] (la-1)+  sa >>= f = collect 0 EmptyStack (la-1)    where    la = length sa    collect sz stk i      | i < 0 = createSmallArray sz (die ">>=" "impossible") $ fill 0 stk-     | otherwise = let sb = f $ indexSmallArray sa i in-         collect (sz + length sb) (sb:stk) (i-1)+     | (# x #) <- indexSmallArray## sa i+     , let sb = f x+           lsb = length sb+       -- If we don't perform this check, we could end up allocating+       -- a stack full of empty arrays if someone is filtering most+       -- things out. So we refrain from pushing empty arrays.+     = if lsb == 0+       then collect sz stk (i-1)+       else collect (sz + lsb) (PushArray sb stk) (i-1) -   fill _   [      ] _   = return ()-   fill off (sb:sbs) smb =+   fill _ EmptyStack _ = return ()+   fill off (PushArray sb sbs) smb =      copySmallArray smb off sb 0 (length sb)        *> fill (off + length sb) sbs smb @@ -554,9 +817,11 @@ zipW :: String -> (a -> b -> c) -> SmallArray a -> SmallArray b -> SmallArray c zipW nm = \f sa sb -> let mn = length sa `min` length sb in   createSmallArray mn (die nm "impossible") $ \mc ->-    fix ? 0 $ \go i -> when (i < mn) $-      writeSmallArray mc i (f (indexSmallArray sa i) (indexSmallArray sb i))-        *> go (i+1)+    fix ? 0 $ \go i -> when (i < mn) $ do+      x <- indexSmallArrayM sa i+      y <- indexSmallArrayM sb i+      writeSmallArray mc i (f x y)+      go (i+1) {-# INLINE zipW #-}  instance MonadZip SmallArray where@@ -576,9 +841,17 @@         <*> unsafeFreezeSmallArray smb  instance MonadFix SmallArray where-  mfix f = fromList . mfix $ toList . f+  mfix f = createSmallArray (sizeofSmallArray (f err))+                            (die "mfix" "impossible") $ flip fix 0 $+    \r !i !mary -> when (i < sz) $ do+                      writeSmallArray mary i (fix (\xi -> f xi `indexSmallArray` i))+                      r (i + 1) mary+    where+      sz = sizeofSmallArray (f err)+      err = error "mfix for Data.Primitive.SmallArray applied to strict function."  #if MIN_VERSION_base(4,9,0)+-- | @since 0.6.3.0 instance Sem.Semigroup (SmallArray a) where   (<>) = (<|>)   sconcat = mconcat . toList@@ -589,34 +862,65 @@ #if !(MIN_VERSION_base(4,11,0))   mappend = (<|>) #endif-  mconcat sas = createSmallArray n (die "mconcat" "impossible") $ \sma ->-    fix ? 0 ? sas $ \go off l -> case l of-      [] -> return ()-      sa:stk -> copySmallArray sma off sa 0 (length sa) *> go (off+1) stk-   where n = sum . fmap length $ sas+  mconcat l = createSmallArray n (die "mconcat" "impossible") $ \ma ->+    let go !_  [    ] = return ()+        go off (a:as) =+          copySmallArray ma off a 0 (sizeofSmallArray a) >> go (off + sizeofSmallArray a) as+     in go 0 l+   where n = sum . fmap length $ l  instance IsList (SmallArray a) where   type Item (SmallArray a) = a-  fromListN n l =-    createSmallArray n (die "fromListN" "mismatched size and list") $ \sma ->-      fix ? 0 ? l $ \go i li -> case li of-        [] -> pure ()-        x:xs -> writeSmallArray sma i x *> go (i+1) xs-  fromList l = fromListN (length l) l-  toList sa = indexSmallArray sa <$> [0 .. length sa - 1]+  fromListN = smallArrayFromListN+  fromList = smallArrayFromList+  toList = Foldable.toList +smallArrayLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> SmallArray a -> ShowS+smallArrayLiftShowsPrec elemShowsPrec elemListShowsPrec p sa = showParen (p > 10) $+  showString "fromListN " . shows (length sa) . showString " "+    . listLiftShowsPrec elemShowsPrec elemListShowsPrec 11 (toList sa)++-- this need to be included for older ghcs+listLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> [a] -> ShowS+listLiftShowsPrec _ sl _ = sl+ instance Show a => Show (SmallArray a) where-  showsPrec p sa = showParen (p > 10) $-    showString "fromListN " . shows (length sa) . showString " "-      . shows (toList sa)+  showsPrec p sa = smallArrayLiftShowsPrec showsPrec showList p sa +#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+-- | @since 0.6.4.0+instance Show1 SmallArray where+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)+  liftShowsPrec = smallArrayLiftShowsPrec+#else+  showsPrec1 = smallArrayLiftShowsPrec showsPrec showList+#endif+#endif++smallArrayLiftReadsPrec :: (Int -> ReadS a) -> ReadS [a] -> Int -> ReadS (SmallArray a)+smallArrayLiftReadsPrec _ listReadsPrec p = readParen (p > 10) . readP_to_S $ do+  () <$ string "fromListN"+  skipSpaces+  n <- readS_to_P reads+  skipSpaces+  l <- readS_to_P listReadsPrec+  return $ smallArrayFromListN n l+ instance Read a => Read (SmallArray a) where-  readPrec = parens . prec 10 $ do-    Symbol "fromListN" <- lexP-    Number nu <- lexP-    n <- maybe empty pure $ numberToInteger nu-    fromListN (fromIntegral n) <$> readPrec+  readsPrec = smallArrayLiftReadsPrec readsPrec readList +#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+-- | @since 0.6.4.0+instance Read1 SmallArray where+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)+  liftReadsPrec = smallArrayLiftReadsPrec+#else+  readsPrec1 = smallArrayLiftReadsPrec readsPrec readList+#endif+#endif+++ smallArrayDataType :: DataType smallArrayDataType =   mkDataType "Data.Primitive.SmallArray.SmallArray" [fromListConstr]@@ -637,3 +941,27 @@   gunfold _ _ = die "gunfold" "SmallMutableArray"   dataTypeOf _ = mkNoRepType "Data.Primitive.SmallArray.SmallMutableArray" #endif++-- | Create a 'SmallArray' from a list of a known length. If the length+--   of the list does not match the given length, this throws an exception.+smallArrayFromListN :: Int -> [a] -> SmallArray a+#if HAVE_SMALL_ARRAY+smallArrayFromListN n l =+  createSmallArray n+      (die "smallArrayFromListN" "uninitialized element") $ \sma ->+  let go !ix [] = if ix == n+        then return ()+        else die "smallArrayFromListN" "list length less than specified size"+      go !ix (x : xs) = if ix < n+        then do+          writeSmallArray sma ix x+          go (ix+1) xs+        else die "smallArrayFromListN" "list length greater than specified size"+  in go 0 l+#else+smallArrayFromListN n l = SmallArray (Array.fromListN n l)+#endif++-- | Create a 'SmallArray' from a list.+smallArrayFromList :: [a] -> SmallArray a+smallArrayFromList l = smallArrayFromListN (length l) l
Data/Primitive/Types.hs view
@@ -1,5 +1,12 @@ {-# LANGUAGE CPP, UnboxedTuples, MagicHash, DeriveDataTypeable #-}+{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving #-}+{-# LANGUAGE ScopedTypeVariables #-}+#if __GLASGOW_HASKELL__ >= 800+{-# LANGUAGE TypeInType #-}+#endif +#include "HsBaseConfig.h"+ -- | -- Module      : Data.Primitive.Types -- Copyright   : (c) Roman Leshchinskiy 2009-2012@@ -13,14 +20,17 @@  module Data.Primitive.Types (   Prim(..),-  sizeOf, alignment,+  sizeOf, alignment, defaultSetByteArray#, defaultSetOffAddr#,    Addr(..),+  PrimStorable(..) ) where  import Control.Monad.Primitive import Data.Primitive.MachDeps import Data.Primitive.Internal.Operations+import Foreign.C.Types+import System.Posix.Types  import GHC.Base (     Int(..), Char(..),@@ -47,10 +57,18 @@ import Data.Typeable ( Typeable ) import Data.Data ( Data(..) ) import Data.Primitive.Internal.Compat ( isTrue#, mkNoRepType )+import Foreign.Storable (Storable)+import Numeric +import qualified Foreign.Storable as FS+ -- | A machine address data Addr = Addr Addr# deriving ( Typeable ) +instance Show Addr where+  showsPrec _ (Addr a) =+    showString "0x" . showHex (fromIntegral (I# (addr2Int# a)) :: Word)+ instance Eq Addr where   Addr a# == Addr b# = isTrue# (eqAddr# a# b#)   Addr a# /= Addr b# = isTrue# (neAddr# a# b#)@@ -110,13 +128,87 @@   setOffAddr# :: Addr# -> Int# -> Int# -> a -> State# s -> State# s  -- | Size of values of type @a@. The argument is not used.+--+-- This function has existed since 0.1, but was moved from 'Data.Primitive'+-- to 'Data.Primitive.Types' in version 0.6.3.0 sizeOf :: Prim a => a -> Int sizeOf x = I# (sizeOf# x)  -- | Alignment of values of type @a@. The argument is not used.+--+-- This function has existed since 0.1, but was moved from 'Data.Primitive'+-- to 'Data.Primitive.Types' in version 0.6.3.0 alignment :: Prim a => a -> Int alignment x = I# (alignment# x) +-- | An implementation of 'setByteArray#' that calls 'writeByteArray#'+-- to set each element. This is helpful when writing a 'Prim' instance+-- for a multi-word data type for which there is no cpu-accelerated way+-- to broadcast a value to contiguous memory. It is typically used+-- alongside 'defaultSetOffAddr#'. For example:+--+-- > data Trip = Trip Int Int Int+-- >+-- > instance Prim Trip+-- >   sizeOf# _ = 3# *# sizeOf# (undefined :: Int)+-- >   alignment# _ = alignment# (undefined :: Int)+-- >   indexByteArray# arr# i# = ...+-- >   readByteArray# arr# i# = ...+-- >   writeByteArray# arr# i# (Trip a b c) =+-- >     \s0 -> case writeByteArray# arr# (3# *# i#) a s0 of+-- >        s1 -> case writeByteArray# arr# ((3# *# i#) +# 1#) b s1 of+-- >          s2 -> case writeByteArray# arr# ((3# *# i#) +# 2# ) c s2 of+-- >            s3 -> s3+-- >   setByteArray# = defaultSetByteArray#+-- >   indexOffAddr# addr# i# = ...+-- >   readOffAddr# addr# i# = ...+-- >   writeOffAddr# addr# i# (Trip a b c) =+-- >     \s0 -> case writeOffAddr# addr# (3# *# i#) a s0 of+-- >        s1 -> case writeOffAddr# addr# ((3# *# i#) +# 1#) b s1 of+-- >          s2 -> case writeOffAddr# addr# ((3# *# i#) +# 2# ) c s2 of+-- >            s3 -> s3+-- >   setOffAddr# = defaultSetOffAddr#+defaultSetByteArray# :: Prim a => MutableByteArray# s -> Int# -> Int# -> a -> State# s -> State# s+defaultSetByteArray# arr# i# len# ident = go 0#+  where+  go ix# s0 = if isTrue# (ix# <# len#)+    then case writeByteArray# arr# (i# +# ix#) ident s0 of+      s1 -> go (ix# +# 1#) s1+    else s0++-- | An implementation of 'setOffAddr#' that calls 'writeOffAddr#'+-- to set each element. The documentation of 'defaultSetByteArray#'+-- provides an example of how to use this.+defaultSetOffAddr# :: Prim a => Addr# -> Int# -> Int# -> a -> State# s -> State# s+defaultSetOffAddr# addr# i# len# ident = go 0#+  where+  go ix# s0 = if isTrue# (ix# <# len#)+    then case writeOffAddr# addr# (i# +# ix#) ident s0 of+      s1 -> go (ix# +# 1#) s1+    else s0++-- | Newtype that uses a 'Prim' instance to give rise to a 'Storable' instance.+-- This type is intended to be used with the @DerivingVia@ extension available+-- in GHC 8.6 and up. For example, consider a user-defined 'Prim' instance for+-- a multi-word data type.+--+-- > data Uuid = Uuid Word64 Word64+-- >   deriving Storable via (PrimStorable Uuid)+-- > instance Prim Uuid where ...+--+-- Writing the 'Prim' instance is tedious and unavoidable, but the 'Storable'+-- instance comes for free once the 'Prim' instance is written.+newtype PrimStorable a = PrimStorable { getPrimStorable :: a }++instance Prim a => Storable (PrimStorable a) where+  sizeOf _ = sizeOf (undefined :: a)+  alignment _ = alignment (undefined :: a)+  peekElemOff (Ptr addr#) (I# i#) =+    primitive $ \s0# -> case readOffAddr# addr# i# s0# of+      (# s1, x #) -> (# s1, PrimStorable x #)+  pokeElemOff (Ptr addr#) (I# i#) (PrimStorable a) = primitive_ $ \s# ->+    writeOffAddr# addr# i# a s#+ #define derivePrim(ty, ctr, sz, align, idx_arr, rd_arr, wr_arr, set_arr, idx_addr, rd_addr, wr_addr, set_addr) \ instance Prim (ty) where {                                      \   sizeOf# _ = unI# sz                                           \@@ -205,3 +297,99 @@ derivePrim(FunPtr a, FunPtr, sIZEOF_PTR, aLIGNMENT_PTR,            indexAddrArray#, readAddrArray#, writeAddrArray#, setAddrArray#,            indexAddrOffAddr#, readAddrOffAddr#, writeAddrOffAddr#, setAddrOffAddr#)++-- Prim instances for newtypes in Foreign.C.Types+deriving instance Prim CChar+deriving instance Prim CSChar+deriving instance Prim CUChar+deriving instance Prim CShort+deriving instance Prim CUShort+deriving instance Prim CInt+deriving instance Prim CUInt+deriving instance Prim CLong+deriving instance Prim CULong+deriving instance Prim CPtrdiff+deriving instance Prim CSize+deriving instance Prim CWchar+deriving instance Prim CSigAtomic+deriving instance Prim CLLong+deriving instance Prim CULLong+#if MIN_VERSION_base(4,10,0)+deriving instance Prim CBool+#endif+deriving instance Prim CIntPtr+deriving instance Prim CUIntPtr+deriving instance Prim CIntMax+deriving instance Prim CUIntMax+deriving instance Prim CClock+deriving instance Prim CTime+deriving instance Prim CUSeconds+deriving instance Prim CSUSeconds+deriving instance Prim CFloat+deriving instance Prim CDouble++-- Prim instances for newtypes in System.Posix.Types+#if defined(HTYPE_DEV_T)+deriving instance Prim CDev+#endif+#if defined(HTYPE_INO_T)+deriving instance Prim CIno+#endif+#if defined(HTYPE_MODE_T)+deriving instance Prim CMode+#endif+#if defined(HTYPE_OFF_T)+deriving instance Prim COff+#endif+#if defined(HTYPE_PID_T)+deriving instance Prim CPid+#endif+#if defined(HTYPE_SSIZE_T)+deriving instance Prim CSsize+#endif+#if defined(HTYPE_GID_T)+deriving instance Prim CGid+#endif+#if defined(HTYPE_NLINK_T)+deriving instance Prim CNlink+#endif+#if defined(HTYPE_UID_T)+deriving instance Prim CUid+#endif+#if defined(HTYPE_CC_T)+deriving instance Prim CCc+#endif+#if defined(HTYPE_SPEED_T)+deriving instance Prim CSpeed+#endif+#if defined(HTYPE_TCFLAG_T)+deriving instance Prim CTcflag+#endif+#if defined(HTYPE_RLIM_T)+deriving instance Prim CRLim+#endif+#if defined(HTYPE_BLKSIZE_T)+deriving instance Prim CBlkSize+#endif+#if defined(HTYPE_BLKCNT_T)+deriving instance Prim CBlkCnt+#endif+#if defined(HTYPE_CLOCKID_T)+deriving instance Prim CClockId+#endif+#if defined(HTYPE_FSBLKCNT_T)+deriving instance Prim CFsBlkCnt+#endif+#if defined(HTYPE_FSFILCNT_T)+deriving instance Prim CFsFilCnt+#endif+#if defined(HTYPE_ID_T)+deriving instance Prim CId+#endif+#if defined(HTYPE_KEY_T)+deriving instance Prim CKey+#endif+#if defined(HTYPE_TIMER_T)+deriving instance Prim CTimer+#endif+deriving instance Prim Fd
Data/Primitive/UnliftedArray.hs view
@@ -1,6 +1,11 @@+{-# Language BangPatterns #-}+{-# Language CPP #-}+{-# Language DeriveDataTypeable #-} {-# Language MagicHash #-}+{-# Language RankNTypes #-}+{-# Language ScopedTypeVariables #-}+{-# Language TypeFamilies #-} {-# Language UnboxedTuples #-}-{-# Language DeriveDataTypeable #-}  -- | -- Module      : Data.Primitive.UnliftedArray@@ -39,9 +44,11 @@ -- that are eligible to be stored.  module Data.Primitive.UnliftedArray-  ( UnliftedArray(..)+  ( -- * Types+    UnliftedArray(..)   , MutableUnliftedArray(..)   , PrimUnlifted(..)+    -- * Operations   , unsafeNewUnliftedArray   , newUnliftedArray   , setUnliftedArray@@ -54,33 +61,68 @@   , unsafeFreezeUnliftedArray   , freezeUnliftedArray   , thawUnliftedArray+  , runUnliftedArray   , sameMutableUnliftedArray   , copyUnliftedArray   , copyMutableUnliftedArray   , cloneUnliftedArray   , cloneMutableUnliftedArray+    -- * List Conversion+  , unliftedArrayToList+  , unliftedArrayFromList+  , unliftedArrayFromListN+    -- * Folding+  , foldrUnliftedArray+  , foldrUnliftedArray'+  , foldlUnliftedArray+  , foldlUnliftedArray'+    -- * Mapping+  , mapUnliftedArray -- Missing operations: --  , unsafeThawUnliftedArray   ) where  import Data.Typeable+import Control.Applicative  import GHC.Prim-import GHC.Base (Int(..))+import GHC.Base (Int(..),build)  import Control.Monad.Primitive -import Control.Monad.ST (runST)+import Control.Monad.ST (runST,ST) +import Data.Monoid (Monoid,mappend) import Data.Primitive.Internal.Compat ( isTrue# ) +import qualified Data.List as L import           Data.Primitive.Array (Array) import qualified Data.Primitive.Array as A import           Data.Primitive.ByteArray (ByteArray) import qualified Data.Primitive.ByteArray as BA+import qualified Data.Primitive.PrimArray as PA import qualified Data.Primitive.SmallArray as SA import qualified Data.Primitive.MutVar as MV+import qualified Data.Monoid+import qualified GHC.MVar as GM (MVar(..))+import qualified GHC.Conc as GC (TVar(..))+import qualified GHC.Stable as GSP (StablePtr(..))+import qualified GHC.Weak as GW (Weak(..))+import qualified GHC.Conc.Sync as GCS (ThreadId(..))+import qualified GHC.Exts as E+import qualified GHC.ST as GHCST +#if MIN_VERSION_base(4,9,0)+import Data.Semigroup (Semigroup)+import qualified Data.Semigroup+#endif++#if MIN_VERSION_base(4,10,0)+import GHC.Exts (runRW#)+#elif MIN_VERSION_base(4,9,0)+import GHC.Base (runRW#)+#endif+ -- | Immutable arrays that efficiently store types that are simple wrappers -- around unlifted primitive types. The values of the unlifted type are -- stored directly, eliminating a layer of indirection.@@ -125,6 +167,16 @@   toArrayArray# (BA.MutableByteArray mba#) = unsafeCoerce# mba#   fromArrayArray# aa# = BA.MutableByteArray (unsafeCoerce# aa#) +-- | @since 0.6.4.0+instance PrimUnlifted (PA.PrimArray a) where+  toArrayArray# (PA.PrimArray ba#) = unsafeCoerce# ba#+  fromArrayArray# aa# = PA.PrimArray (unsafeCoerce# aa#)++-- | @since 0.6.4.0+instance PrimUnlifted (PA.MutablePrimArray s a) where+  toArrayArray# (PA.MutablePrimArray mba#) = unsafeCoerce# mba#+  fromArrayArray# aa# = PA.MutablePrimArray (unsafeCoerce# aa#)+ instance PrimUnlifted (SA.SmallArray a) where   toArrayArray# (SA.SmallArray sa#) = unsafeCoerce# sa#   fromArrayArray# aa# = SA.SmallArray (unsafeCoerce# aa#)@@ -137,8 +189,38 @@   toArrayArray# (MV.MutVar mv#) = unsafeCoerce# mv#   fromArrayArray# aa# = MV.MutVar (unsafeCoerce# aa#) --- | Creates a new 'MutableUnliftedArray'. This function is unsafe, because it--- allows access to the raw contents of the underlying 'ArrayArray#'.+-- | @since 0.6.4.0+instance PrimUnlifted (GM.MVar a) where+  toArrayArray# (GM.MVar mv#) = unsafeCoerce# mv#+  fromArrayArray# mv# = GM.MVar (unsafeCoerce# mv#)++-- | @since 0.6.4.0+instance PrimUnlifted (GC.TVar a) where+  toArrayArray# (GC.TVar tv#) = unsafeCoerce# tv#+  fromArrayArray# tv# = GC.TVar (unsafeCoerce# tv#)++-- | @since 0.6.4.0+instance PrimUnlifted (GSP.StablePtr a) where+  toArrayArray# (GSP.StablePtr tv#) = unsafeCoerce# tv#+  fromArrayArray# tv# = GSP.StablePtr (unsafeCoerce# tv#)++-- | @since 0.6.4.0+instance PrimUnlifted (GW.Weak a) where+  toArrayArray# (GW.Weak tv#) = unsafeCoerce# tv#+  fromArrayArray# tv# = GW.Weak (unsafeCoerce# tv#)++-- | @since 0.6.4.0+instance PrimUnlifted GCS.ThreadId where+  toArrayArray# (GCS.ThreadId tv#) = unsafeCoerce# tv#+  fromArrayArray# tv# = GCS.ThreadId (unsafeCoerce# tv#)++die :: String -> String -> a+die fun problem = error $ "Data.Primitive.UnliftedArray." ++ fun ++ ": " ++ problem++-- | Creates a new 'MutableUnliftedArray'. This function is unsafe because it+-- initializes all elements of the array as pointers to the array itself. Attempting+-- to read one of these elements before writing to it is in effect an unsafe+-- coercion from the @MutableUnliftedArray s a@ to the element type. unsafeNewUnliftedArray   :: (PrimMonad m)   => Int -- ^ size@@ -329,6 +411,63 @@   return dst {-# inline thawUnliftedArray #-} +#if !MIN_VERSION_base(4,9,0)+unsafeCreateUnliftedArray+  :: Int+  -> (forall s. MutableUnliftedArray s a -> ST s ())+  -> UnliftedArray a+unsafeCreateUnliftedArray 0 _ = emptyUnliftedArray+unsafeCreateUnliftedArray n f = runUnliftedArray $ do+  mary <- unsafeNewUnliftedArray n+  f mary+  pure mary++-- | Execute a stateful computation and freeze the resulting array.+runUnliftedArray+  :: (forall s. ST s (MutableUnliftedArray s a))+  -> UnliftedArray a+runUnliftedArray m = runST $ m >>= unsafeFreezeUnliftedArray++#else /* Below, runRW# is available. */++-- This low-level business is designed to work with GHC's worker-wrapper+-- transformation. A lot of the time, we don't actually need an Array+-- constructor. By putting it on the outside, and being careful about+-- how we special-case the empty array, we can make GHC smarter about this.+-- The only downside is that separately created 0-length arrays won't share+-- their Array constructors, although they'll share their underlying+-- Array#s.+unsafeCreateUnliftedArray+  :: Int+  -> (forall s. MutableUnliftedArray s a -> ST s ())+  -> UnliftedArray a+unsafeCreateUnliftedArray 0 _ = UnliftedArray (emptyArrayArray# (# #))+unsafeCreateUnliftedArray n f = runUnliftedArray $ do+  mary <- unsafeNewUnliftedArray n+  f mary+  pure mary++-- | Execute a stateful computation and freeze the resulting array.+runUnliftedArray+  :: (forall s. ST s (MutableUnliftedArray s a))+  -> UnliftedArray a+runUnliftedArray m = UnliftedArray (runUnliftedArray# m)++runUnliftedArray#+  :: (forall s. ST s (MutableUnliftedArray s a))+  -> ArrayArray#+runUnliftedArray# m = case runRW# $ \s ->+  case unST m s of { (# s', MutableUnliftedArray mary# #) ->+  unsafeFreezeArrayArray# mary# s'} of (# _, ary# #) -> ary#++unST :: ST s a -> State# s -> (# State# s, a #)+unST (GHCST.ST f) = f++emptyArrayArray# :: (# #) -> ArrayArray#+emptyArrayArray# _ = case emptyUnliftedArray of UnliftedArray ar -> ar+{-# NOINLINE emptyArrayArray# #-}+#endif+ -- | Creates a copy of a portion of an 'UnliftedArray' cloneUnliftedArray   :: UnliftedArray a -- ^ source@@ -336,7 +475,7 @@   -> Int -- ^ length   -> UnliftedArray a cloneUnliftedArray src off len =-  runST $ thawUnliftedArray src off len >>= unsafeFreezeUnliftedArray+  runUnliftedArray (thawUnliftedArray src off len) {-# inline cloneUnliftedArray #-}  -- | Creates a new 'MutableUnliftedArray' containing a copy of a portion of@@ -363,3 +502,137 @@    loop i      | i < 0 = True      | otherwise = indexUnliftedArray aa1 i == indexUnliftedArray aa2 i && loop (i-1)++-- | Lexicographic ordering. Subject to change between major versions.+--+--   @since 0.6.4.0+instance (Ord a, PrimUnlifted a) => Ord (UnliftedArray a) where+  compare a1 a2 = loop 0+    where+    mn = sizeofUnliftedArray a1 `min` sizeofUnliftedArray a2+    loop i+      | i < mn+      , x1 <- indexUnliftedArray a1 i+      , x2 <- indexUnliftedArray a2 i+      = compare x1 x2 `mappend` loop (i+1)+      | otherwise = compare (sizeofUnliftedArray a1) (sizeofUnliftedArray a2)++-- | @since 0.6.4.0+instance (Show a, PrimUnlifted a) => Show (UnliftedArray a) where+  showsPrec p a = showParen (p > 10) $+    showString "fromListN " . shows (sizeofUnliftedArray a) . showString " "+      . shows (unliftedArrayToList a)++#if MIN_VERSION_base(4,9,0)+-- | @since 0.6.4.0+instance PrimUnlifted a => Semigroup (UnliftedArray a) where+  (<>) = concatUnliftedArray+#endif++-- | @since 0.6.4.0+instance PrimUnlifted a => Monoid (UnliftedArray a) where+  mempty = emptyUnliftedArray+#if !(MIN_VERSION_base(4,11,0))+  mappend = concatUnliftedArray+#endif++emptyUnliftedArray :: UnliftedArray a+emptyUnliftedArray = runUnliftedArray (unsafeNewUnliftedArray 0)+{-# NOINLINE emptyUnliftedArray #-}++concatUnliftedArray :: UnliftedArray a -> UnliftedArray a -> UnliftedArray a+concatUnliftedArray x y = unsafeCreateUnliftedArray (sizeofUnliftedArray x + sizeofUnliftedArray y) $ \m -> do+  copyUnliftedArray m 0 x 0 (sizeofUnliftedArray x)+  copyUnliftedArray m (sizeofUnliftedArray x) y 0 (sizeofUnliftedArray y)++-- | Lazy right-associated fold over the elements of an 'UnliftedArray'.+{-# INLINE foldrUnliftedArray #-}+foldrUnliftedArray :: forall a b. PrimUnlifted a => (a -> b -> b) -> b -> UnliftedArray a -> b+foldrUnliftedArray f z arr = go 0+  where+    !sz = sizeofUnliftedArray arr+    go !i+      | sz > i = f (indexUnliftedArray arr i) (go (i+1))+      | otherwise = z++-- | Strict right-associated fold over the elements of an 'UnliftedArray.+{-# INLINE foldrUnliftedArray' #-}+foldrUnliftedArray' :: forall a b. PrimUnlifted a => (a -> b -> b) -> b -> UnliftedArray a -> b+foldrUnliftedArray' f z0 arr = go (sizeofUnliftedArray arr - 1) z0+  where+    go !i !acc+      | i < 0 = acc+      | otherwise = go (i - 1) (f (indexUnliftedArray arr i) acc)++-- | Lazy left-associated fold over the elements of an 'UnliftedArray'.+{-# INLINE foldlUnliftedArray #-}+foldlUnliftedArray :: forall a b. PrimUnlifted a => (b -> a -> b) -> b -> UnliftedArray a -> b+foldlUnliftedArray f z arr = go (sizeofUnliftedArray arr - 1)+  where+    go !i+      | i < 0 = z+      | otherwise = f (go (i - 1)) (indexUnliftedArray arr i)++-- | Strict left-associated fold over the elements of an 'UnliftedArray'.+{-# INLINE foldlUnliftedArray' #-}+foldlUnliftedArray' :: forall a b. PrimUnlifted a => (b -> a -> b) -> b -> UnliftedArray a -> b+foldlUnliftedArray' f z0 arr = go 0 z0+  where+    !sz = sizeofUnliftedArray arr+    go !i !acc+      | i < sz = go (i + 1) (f acc (indexUnliftedArray arr i))+      | otherwise = acc++-- | Map over the elements of an 'UnliftedArray'.+{-# INLINE mapUnliftedArray #-}+mapUnliftedArray :: (PrimUnlifted a, PrimUnlifted b)+  => (a -> b)+  -> UnliftedArray a+  -> UnliftedArray b+mapUnliftedArray f arr = unsafeCreateUnliftedArray sz $ \marr -> do+  let go !ix = if ix < sz+        then do+          let b = f (indexUnliftedArray arr ix)+          writeUnliftedArray marr ix b+          go (ix + 1)+        else return ()+  go 0+  where+  !sz = sizeofUnliftedArray arr++-- | Convert the unlifted array to a list.+{-# INLINE unliftedArrayToList #-}+unliftedArrayToList :: PrimUnlifted a => UnliftedArray a -> [a]+unliftedArrayToList xs = build (\c n -> foldrUnliftedArray c n xs)++unliftedArrayFromList :: PrimUnlifted a => [a] -> UnliftedArray a+unliftedArrayFromList xs = unliftedArrayFromListN (L.length xs) xs++unliftedArrayFromListN :: forall a. PrimUnlifted a => Int -> [a] -> UnliftedArray a+unliftedArrayFromListN len vs = unsafeCreateUnliftedArray len run where+  run :: forall s. MutableUnliftedArray s a -> ST s ()+  run arr = do+    let go :: [a] -> Int -> ST s ()+        go [] !ix = if ix == len+          -- The size check is mandatory since failure to initialize all elements+          -- introduces the possibility of a segfault happening when someone attempts+          -- to read the unitialized element. See the docs for unsafeNewUnliftedArray.+          then return ()+          else die "unliftedArrayFromListN" "list length less than specified size"+        go (a : as) !ix = if ix < len+          then do+            writeUnliftedArray arr ix a+            go as (ix + 1)+          else die "unliftedArrayFromListN" "list length greater than specified size"+    go vs 0+++#if MIN_VERSION_base(4,7,0)+-- | @since 0.6.4.0+instance PrimUnlifted a => E.IsList (UnliftedArray a) where+  type Item (UnliftedArray a) = a+  fromList = unliftedArrayFromList+  fromListN = unliftedArrayFromListN+  toList = unliftedArrayToList+#endif+
changelog.md view
@@ -1,3 +1,64 @@+## Changes in version 0.6.4.0++ * Introduce `Data.Primitive.PrimArray`, which offers types and function+   for dealing with a `ByteArray` tagged with a phantom type variable for+   tracking the element type.++ * Implement `isByteArrayPinned` and `isMutableByteArrayPinned`.++ * Add `Eq1`, `Ord1`, `Show1`, and `Read1` instances for `Array` and+   `SmallArray`.++ * Improve the test suite. This includes having property tests for+   typeclasses from `base` such as `Eq`, `Ord`, `Functor`, `Applicative`,+   `Monad`, `IsList`, `Monoid`, `Foldable`, and `Traversable`.++ * Fix the broken `IsList` instance for `ByteArray`. The old definition+   would allocate a byte array of the correct size and then leave the+   memory unitialized instead of writing the list elements to it.++ * Fix the broken `Functor` instance for `Array`. The old definition+   would allocate an array of the correct size with thunks for erroring+   installed at every index. It failed to replace these thunks with+   the result of the function applied to the elements of the argument array.++ * Fix the broken `Applicative` instances of `Array` and `SmallArray`.+   The old implementation of `<*>` for `Array` failed to initialize+   some elements but correctly initialized others in the resulting+   `Array`. It is unclear what the old behavior of `<*>` was for+   `SmallArray`, but it was incorrect.++ * Fix the broken `Monad` instances for `Array` and `SmallArray`.++ * Fix the implementation of `foldl1` in the `Foldable` instances for+   `Array` and `SmallArray`. In both cases, the old implementation+   simply returned the first element of the array and made no use of+   the other elements in the array.++ * Fix the implementation of `mconcat` in the `Monoid` instance for+   `SmallArray`.+ + * Implement `Data.Primitive.Ptr`, implementations of `Ptr` functions+   that require a `Prim` constraint instead of a `Storable` constraint.+++ * Add `PrimUnlifted` instances for `TVar` and `MVar`.++ * Use `compareByteArrays#` for the `Eq` and `Ord` instances of+   `ByteArray` when building with GHC 8.4 and newer.++ * Add `Prim` instances for lots of types in `Foreign.C.Types` and+   `System.Posix.Types`.++ * Reexport `Data.Primitive.SmallArray` and `Data.Primitive.UnliftedArray`+   from `Data.Primitive`.++ * Add fold functions and map function to `Data.Primitive.UnliftedArray`.+   Add typeclass instances for `IsList`, `Ord`, and `Show`.++ * Add `defaultSetByteArray#` and `defaultSetOffAddr#` to+   `Data.Primitive.Types`.+ ## Changes in version 0.6.3.0   * Add `PrimMonad` instances for `ContT`, `AccumT`, and `SelectT` from
primitive.cabal view
@@ -1,5 +1,5 @@ Name:           primitive-Version:        0.6.3.0+Version:        0.6.4.0 License:        BSD3 License-File:   LICENSE @@ -15,6 +15,9 @@ Description:    This package provides various primitive memory-related operations.  Extra-Source-Files: changelog.md+                    test/*.hs+                    test/LICENSE+                    test/primitive-tests.cabal  Tested-With:   GHC == 7.4.2,@@ -23,7 +26,7 @@   GHC == 7.10.3,   GHC == 8.0.2,   GHC == 8.2.2,-  GHC == 8.4.1+  GHC == 8.4.2  Library   Default-Language: Haskell2010@@ -38,10 +41,13 @@         Data.Primitive.Types         Data.Primitive.Array         Data.Primitive.ByteArray+        Data.Primitive.PrimArray         Data.Primitive.SmallArray         Data.Primitive.UnliftedArray         Data.Primitive.Addr+        Data.Primitive.Ptr         Data.Primitive.MutVar+        Data.Primitive.MVar    Other-Modules:         Data.Primitive.Internal.Compat@@ -51,27 +57,16 @@                , ghc-prim >= 0.2 && < 0.6                , transformers >= 0.2 && < 0.6 -  Ghc-Options: -O2 -Wall+  Ghc-Options: -O2    Include-Dirs: cbits   Install-Includes: primitive-memops.h   includes: primitive-memops.h   c-sources: cbits/primitive-memops.c-  cc-options: -O3 -fomit-frame-pointer -Wall   if !os(solaris)       cc-options: -ftree-vectorize   if arch(i386) || arch(x86_64)       cc-options: -msse2--test-suite test-  Default-Language: Haskell2010-  hs-source-dirs: test-  main-is: main.hs-  type: exitcode-stdio-1.0-  build-depends: base-               , ghc-prim-               , primitive-  ghc-options: -O2  source-repository head   type:     git
+ test/LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2008-2009, Roman Leshchinskiy+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++- Redistributions of source code must retain the above copyright notice,+this list of conditions and the following disclaimer.+ +- Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation+and/or other materials provided with the distribution.+ +- Neither name of the University nor the names of its contributors may be+used to endorse or promote products derived from this software without+specific prior written permission. ++THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF+GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE+UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH+DAMAGE.+
test/main.hs view
@@ -1,26 +1,228 @@-{-# LANGUAGE MagicHash, UnboxedTuples #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE ScopedTypeVariables #-} +import Control.Applicative import Control.Monad+import Control.Monad.Fix (fix) import Control.Monad.Primitive import Control.Monad.ST+import Data.Monoid import Data.Primitive import Data.Primitive.Array import Data.Primitive.ByteArray import Data.Primitive.Types+import Data.Primitive.SmallArray+import Data.Primitive.PrimArray import Data.Word+import Data.Proxy (Proxy(..)) import GHC.Int import GHC.IO import GHC.Prim+import Data.Function (on)+#if MIN_VERSION_base(4,9,0)+import Data.Semigroup (stimes)+#endif --- Since we only have two test cases right now, I'm going to avoid the--- issue of choosing a test framework for the moment. This also keeps the--- package as a whole light on dependencies.+import Test.Tasty (defaultMain,testGroup,TestTree)+import Test.QuickCheck (Arbitrary,Arbitrary1,Gen,(===),CoArbitrary,Function)+import qualified Test.Tasty.QuickCheck as TQC+import qualified Test.QuickCheck as QC+import qualified Test.QuickCheck.Classes as QCC+import qualified Test.QuickCheck.Classes.IsList as QCCL+import qualified Data.List as L  main :: IO () main = do-    testArray-    testByteArray+  testArray+  testByteArray+  defaultMain $ testGroup "properties"+    [ testGroup "Array"+      [ lawsToTest (QCC.eqLaws (Proxy :: Proxy (Array Int)))+      , lawsToTest (QCC.ordLaws (Proxy :: Proxy (Array Int)))+      , lawsToTest (QCC.monoidLaws (Proxy :: Proxy (Array Int)))+      , lawsToTest (QCC.showReadLaws (Proxy :: Proxy (Array Int)))+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+      , lawsToTest (QCC.functorLaws (Proxy1 :: Proxy1 Array))+      , lawsToTest (QCC.applicativeLaws (Proxy1 :: Proxy1 Array))+      , lawsToTest (QCC.monadLaws (Proxy1 :: Proxy1 Array))+      , lawsToTest (QCC.foldableLaws (Proxy1 :: Proxy1 Array))+      , lawsToTest (QCC.traversableLaws (Proxy1 :: Proxy1 Array))+#endif+#if MIN_VERSION_base(4,7,0)+      , lawsToTest (QCC.isListLaws (Proxy :: Proxy (Array Int)))+      , TQC.testProperty "mapArray'" (QCCL.mapProp int16 int32 mapArray')+#endif+      ]+    , testGroup "SmallArray"+      [ lawsToTest (QCC.eqLaws (Proxy :: Proxy (SmallArray Int)))+      , lawsToTest (QCC.ordLaws (Proxy :: Proxy (SmallArray Int)))+      , lawsToTest (QCC.monoidLaws (Proxy :: Proxy (SmallArray Int)))+      , lawsToTest (QCC.showReadLaws (Proxy :: Proxy (Array Int)))+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)+      , lawsToTest (QCC.functorLaws (Proxy1 :: Proxy1 SmallArray))+      , lawsToTest (QCC.applicativeLaws (Proxy1 :: Proxy1 SmallArray))+      , lawsToTest (QCC.monadLaws (Proxy1 :: Proxy1 SmallArray))+      , lawsToTest (QCC.foldableLaws (Proxy1 :: Proxy1 SmallArray))+      , lawsToTest (QCC.traversableLaws (Proxy1 :: Proxy1 SmallArray))+#endif+#if MIN_VERSION_base(4,7,0)+      , lawsToTest (QCC.isListLaws (Proxy :: Proxy (SmallArray Int)))+      , TQC.testProperty "mapSmallArray'" (QCCL.mapProp int16 int32 mapSmallArray')+#endif+      ]+    , testGroup "ByteArray"+      [ testGroup "Ordering"+        [ TQC.testProperty "equality" byteArrayEqProp+        , TQC.testProperty "compare" byteArrayCompareProp+        ]+      , testGroup "Resize"+        [ TQC.testProperty "shrink" byteArrayShrinkProp+        , TQC.testProperty "grow" byteArrayGrowProp+        ]+      , lawsToTest (QCC.eqLaws (Proxy :: Proxy ByteArray))+      , lawsToTest (QCC.ordLaws (Proxy :: Proxy ByteArray))+      , lawsToTest (QCC.showReadLaws (Proxy :: Proxy (Array Int)))+#if MIN_VERSION_base(4,7,0)+      , lawsToTest (QCC.isListLaws (Proxy :: Proxy ByteArray))+#endif+      ]+    , testGroup "PrimArray"+      [ lawsToTest (QCC.eqLaws (Proxy :: Proxy (PrimArray Word16)))+      , lawsToTest (QCC.ordLaws (Proxy :: Proxy (PrimArray Word16)))+      , lawsToTest (QCC.monoidLaws (Proxy :: Proxy (PrimArray Word16)))+#if MIN_VERSION_base(4,7,0)+      , lawsToTest (QCC.isListLaws (Proxy :: Proxy (PrimArray Word16)))+      , TQC.testProperty "foldrPrimArray" (QCCL.foldrProp int16 foldrPrimArray)+      , TQC.testProperty "foldrPrimArray'" (QCCL.foldrProp int16 foldrPrimArray')+      , TQC.testProperty "foldlPrimArray" (QCCL.foldlProp int16 foldlPrimArray)+      , TQC.testProperty "foldlPrimArray'" (QCCL.foldlProp int16 foldlPrimArray')+      , TQC.testProperty "foldlPrimArrayM'" (QCCL.foldlMProp int16 foldlPrimArrayM')+      , TQC.testProperty "mapPrimArray" (QCCL.mapProp int16 int32 mapPrimArray)+      , TQC.testProperty "traversePrimArray" (QCCL.traverseProp int16 int32 traversePrimArray)+      , TQC.testProperty "traversePrimArrayP" (QCCL.traverseProp int16 int32 traversePrimArrayP)+      , TQC.testProperty "imapPrimArray" (QCCL.imapProp int16 int32 imapPrimArray)+      , TQC.testProperty "itraversePrimArray" (QCCL.imapMProp int16 int32 itraversePrimArray)+      , TQC.testProperty "itraversePrimArrayP" (QCCL.imapMProp int16 int32 itraversePrimArrayP)+      , TQC.testProperty "generatePrimArray" (QCCL.generateProp int16 generatePrimArray)+      , TQC.testProperty "generatePrimArrayA" (QCCL.generateMProp int16 generatePrimArrayA)+      , TQC.testProperty "generatePrimArrayP" (QCCL.generateMProp int16 generatePrimArrayP)+      , TQC.testProperty "replicatePrimArray" (QCCL.replicateProp int16 replicatePrimArray)+      , TQC.testProperty "replicatePrimArrayA" (QCCL.replicateMProp int16 replicatePrimArrayA)+      , TQC.testProperty "replicatePrimArrayP" (QCCL.replicateMProp int16 replicatePrimArrayP)+      , TQC.testProperty "filterPrimArray" (QCCL.filterProp int16 filterPrimArray)+      , TQC.testProperty "filterPrimArrayA" (QCCL.filterMProp int16 filterPrimArrayA)+      , TQC.testProperty "filterPrimArrayP" (QCCL.filterMProp int16 filterPrimArrayP)+      , TQC.testProperty "mapMaybePrimArray" (QCCL.mapMaybeProp int16 int32 mapMaybePrimArray)+      , TQC.testProperty "mapMaybePrimArrayA" (QCCL.mapMaybeMProp int16 int32 mapMaybePrimArrayA)+      , TQC.testProperty "mapMaybePrimArrayP" (QCCL.mapMaybeMProp int16 int32 mapMaybePrimArrayP)+#endif+      ]+    , testGroup "UnliftedArray"+      [ lawsToTest (QCC.eqLaws (Proxy :: Proxy (UnliftedArray (PrimArray Int16))))+      , lawsToTest (QCC.ordLaws (Proxy :: Proxy (UnliftedArray (PrimArray Int16))))+      , lawsToTest (QCC.monoidLaws (Proxy :: Proxy (UnliftedArray (PrimArray Int16))))+#if MIN_VERSION_base(4,7,0)+      , lawsToTest (QCC.isListLaws (Proxy :: Proxy (UnliftedArray (PrimArray Int16))))+      , TQC.testProperty "mapUnliftedArray" (QCCL.mapProp arrInt16 arrInt32 mapUnliftedArray)+      , TQC.testProperty "foldrUnliftedArray" (QCCL.foldrProp arrInt16 foldrUnliftedArray)+      , TQC.testProperty "foldrUnliftedArray'" (QCCL.foldrProp arrInt16 foldrUnliftedArray')+      , TQC.testProperty "foldlUnliftedArray" (QCCL.foldlProp arrInt16 foldlUnliftedArray)+      , TQC.testProperty "foldlUnliftedArray'" (QCCL.foldlProp arrInt16 foldlUnliftedArray')+#endif+      ]+    , testGroup "DefaultSetMethod"+      [ lawsToTest (QCC.primLaws (Proxy :: Proxy DefaultSetMethod))+      ]+    -- , testGroup "PrimStorable"+    --   [ lawsToTest (QCC.storableLaws (Proxy :: Proxy Derived))+    --   ]+    ] +int16 :: Proxy Int16+int16 = Proxy++int32 :: Proxy Int32+int32 = Proxy++arrInt16 :: Proxy (PrimArray Int16)+arrInt16 = Proxy++arrInt32 :: Proxy (PrimArray Int16)+arrInt32 = Proxy++-- Tests that using resizeByteArray to shrink a byte array produces+-- the same results as calling Data.List.take on the list that the+-- byte array corresponds to.+byteArrayShrinkProp :: QC.Property+byteArrayShrinkProp = QC.property $ \(QC.NonNegative (n :: Int)) (QC.NonNegative (m :: Int)) ->+  let large = max n m+      small = min n m+      xs = intsLessThan large+      ys = byteArrayFromList xs+      largeBytes = large * sizeOf (undefined :: Int)+      smallBytes = small * sizeOf (undefined :: Int)+      expected = byteArrayFromList (L.take small xs)+      actual = runST $ do+        mzs0 <- newByteArray largeBytes+        copyByteArray mzs0 0 ys 0 largeBytes+        mzs1 <- resizeMutableByteArray mzs0 smallBytes+        unsafeFreezeByteArray mzs1+   in expected === actual++-- Tests that using resizeByteArray with copyByteArray (to fill in the+-- new empty space) to grow a byte array produces the same results as+-- calling Data.List.++ on the lists corresponding to the original+-- byte array and the appended byte array.+byteArrayGrowProp :: QC.Property+byteArrayGrowProp = QC.property $ \(QC.NonNegative (n :: Int)) (QC.NonNegative (m :: Int)) ->+  let large = max n m+      small = min n m+      xs1 = intsLessThan small+      xs2 = intsLessThan (large - small)+      ys1 = byteArrayFromList xs1+      ys2 = byteArrayFromList xs2+      largeBytes = large * sizeOf (undefined :: Int)+      smallBytes = small * sizeOf (undefined :: Int)+      expected = byteArrayFromList (xs1 ++ xs2)+      actual = runST $ do+        mzs0 <- newByteArray smallBytes+        copyByteArray mzs0 0 ys1 0 smallBytes+        mzs1 <- resizeMutableByteArray mzs0 largeBytes+        copyByteArray mzs1 smallBytes ys2 0 ((large - small) * sizeOf (undefined :: Int))+        unsafeFreezeByteArray mzs1+   in expected === actual++-- Provide the non-negative integers up to the bound. For example:+--+-- >>> intsLessThan 5+-- [0,1,2,3,4]+intsLessThan :: Int -> [Int]+intsLessThan i = if i < 1+  then []+  else (i - 1) : intsLessThan (i - 1)+  +byteArrayCompareProp :: QC.Property+byteArrayCompareProp = QC.property $ \(xs :: [Word8]) (ys :: [Word8]) ->+  compareLengthFirst xs ys === compare (byteArrayFromList xs) (byteArrayFromList ys)++byteArrayEqProp :: QC.Property+byteArrayEqProp = QC.property $ \(xs :: [Word8]) (ys :: [Word8]) ->+  (compareLengthFirst xs ys == EQ) === (byteArrayFromList xs == byteArrayFromList ys)++compareLengthFirst :: [Word8] -> [Word8] -> Ordering+compareLengthFirst xs ys = (compare `on` length) xs ys <> compare xs ys++-- on GHC 7.4, Proxy is not polykinded, so we need this instead.+data Proxy1 (f :: * -> *) = Proxy1++lawsToTest :: QCC.Laws -> TestTree+lawsToTest (QCC.Laws name pairs) = testGroup name (map (uncurry TQC.testProperty) pairs)+ testArray :: IO () testArray = do     arr <- newArray 1 'A'@@ -41,15 +243,100 @@     let arr1 = mkByteArray ([0xde, 0xad, 0xbe, 0xef] :: [Word8])         arr2 = mkByteArray ([0xde, 0xad, 0xbe, 0xef] :: [Word8])         arr3 = mkByteArray ([0xde, 0xad, 0xbe, 0xee] :: [Word8])+        arr4 = mkByteArray ([0xde, 0xad, 0xbe, 0xdd] :: [Word8])+        arr5 = mkByteArray ([0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xdd] :: [Word8])     when (show arr1 /= "[0xde, 0xad, 0xbe, 0xef]") $         fail $ "ByteArray Show incorrect: "++show arr1     unless (arr1 > arr3) $         fail $ "ByteArray Ord incorrect"     unless (arr1 == arr2) $         fail $ "ByteArray Eq incorrect"+    unless (mappend arr1 arr4 == arr5) $+        fail $ "ByteArray Monoid mappend incorrect"+    unless (mappend arr1 (mappend arr3 arr4) == mappend (mappend arr1 arr3) arr4) $+        fail $ "ByteArray Monoid mappend not associative"+    unless (mconcat [arr1,arr2,arr3,arr4,arr5] == (arr1 <> arr2 <> arr3 <> arr4 <> arr5)) $+        fail $ "ByteArray Monoid mconcat incorrect"+#if MIN_VERSION_base(4,9,0)+    unless (stimes (3 :: Int) arr4 == (arr4 <> arr4 <> arr4)) $+        fail $ "ByteArray Semigroup stimes incorrect"+#endif  mkByteArray :: Prim a => [a] -> ByteArray mkByteArray xs = runST $ do     marr <- newByteArray (length xs * sizeOf (head xs))     sequence $ zipWith (writeByteArray marr) [0..] xs     unsafeFreezeByteArray marr++instance Arbitrary1 Array where+  liftArbitrary elemGen = fmap fromList (QC.liftArbitrary elemGen)++instance Arbitrary a => Arbitrary (Array a) where+  arbitrary = fmap fromList QC.arbitrary++instance Arbitrary1 SmallArray where+  liftArbitrary elemGen = fmap smallArrayFromList (QC.liftArbitrary elemGen)++instance Arbitrary a => Arbitrary (SmallArray a) where+  arbitrary = fmap smallArrayFromList QC.arbitrary++instance Arbitrary ByteArray where+  arbitrary = do+    xs <- QC.arbitrary :: Gen [Word8]+    return $ runST $ do+      a <- newByteArray (L.length xs)+      iforM_ xs $ \ix x -> do+        writeByteArray a ix x+      unsafeFreezeByteArray a++instance (Arbitrary a, Prim a) => Arbitrary (PrimArray a) where+  arbitrary = do+    xs <- QC.arbitrary :: Gen [a]+    return $ runST $ do+      a <- newPrimArray (L.length xs)+      iforM_ xs $ \ix x -> do+        writePrimArray a ix x+      unsafeFreezePrimArray a++instance (Arbitrary a, PrimUnlifted a) => Arbitrary (UnliftedArray a) where+  arbitrary = do+    xs <- QC.vector =<< QC.choose (0,3)+    return (unliftedArrayFromList xs)++instance (Prim a, CoArbitrary a) => CoArbitrary (PrimArray a) where+  coarbitrary x = QC.coarbitrary (primArrayToList x)++instance (Prim a, Function a) => Function (PrimArray a) where+  function = QC.functionMap primArrayToList primArrayFromList++iforM_ :: Monad m => [a] -> (Int -> a -> m b) -> m ()+iforM_ xs0 f = go 0 xs0 where+  go !_ [] = return ()+  go !ix (x : xs) = f ix x >> go (ix + 1) xs++newtype DefaultSetMethod = DefaultSetMethod Int16+  deriving (Eq,Show,Arbitrary)++instance Prim DefaultSetMethod where+  sizeOf# _ = sizeOf# (undefined :: Int16)+  alignment# _ = alignment# (undefined :: Int16)+  indexByteArray# arr ix = DefaultSetMethod (indexByteArray# arr ix)+  readByteArray# arr ix s0 = case readByteArray# arr ix s0 of+    (# s1, n #) -> (# s1, DefaultSetMethod n #)+  writeByteArray# arr ix (DefaultSetMethod n) s0 = writeByteArray# arr ix n s0+  setByteArray# = defaultSetByteArray#+  indexOffAddr# addr off = DefaultSetMethod (indexOffAddr# addr off)+  readOffAddr# addr off s0 = case readOffAddr# addr off s0 of+    (# s1, n #) -> (# s1, DefaultSetMethod n #)+  writeOffAddr# addr off (DefaultSetMethod n) s0 = writeOffAddr# addr off n s0+  setOffAddr# = defaultSetOffAddr#++-- TODO: Uncomment this out when GHC 8.6 is release. Also, uncomment+-- the corresponding PrimStorable test group above.+--+-- newtype Derived = Derived Int16+--   deriving newtype (Prim)+--   deriving Storable via (PrimStorable Derived)+++
+ test/primitive-tests.cabal view
@@ -0,0 +1,45 @@+Name:           primitive-tests+Version:        0.1+License:        BSD3+License-File:   LICENSE++Author:         Roman Leshchinskiy <rl@cse.unsw.edu.au>+Maintainer:     libraries@haskell.org+Copyright:      (c) Roman Leshchinskiy 2009-2012+Homepage:       https://github.com/haskell/primitive+Bug-Reports:    https://github.com/haskell/primitive/issues+Category:       Data+Synopsis:       primitive tests+Cabal-Version:  >= 1.10+Build-Type:     Simple+Description:    @primitive@ tests++Tested-With:+  GHC == 7.4.2,+  GHC == 7.6.3,+  GHC == 7.8.4,+  GHC == 7.10.3,+  GHC == 8.0.2,+  GHC == 8.2.2,+  GHC == 8.4.2++test-suite test+  Default-Language: Haskell2010+  hs-source-dirs: .+  main-is: main.hs+  type: exitcode-stdio-1.0+  build-depends: base >= 4.5 && < 4.12+               , ghc-prim+               , primitive+               , QuickCheck+               , tasty+               , tasty-quickcheck+               , tagged+               , transformers >= 0.3+               , quickcheck-classes >= 0.4.11.1+  ghc-options: -O2++source-repository head+  type:     git+  location: https://github.com/haskell/primitive+  subdir:   test