feat(third_party/bazel): Check in rules_haskell from Tweag
This commit is contained in:
parent
2eb1dc26e4
commit
f723b8b878
479 changed files with 51484 additions and 0 deletions
85
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive.hs
vendored
Normal file
85
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive.hs
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
{-# LANGUAGE MagicHash #-}
|
||||
{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}
|
||||
-- |
|
||||
-- Module : Data.Primitive
|
||||
-- Copyright : (c) Roman Leshchinskiy 2009-2012
|
||||
-- License : BSD-style
|
||||
--
|
||||
-- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au>
|
||||
-- Portability : non-portable
|
||||
--
|
||||
-- Reexports all primitive operations
|
||||
--
|
||||
module Data.Primitive (
|
||||
-- * 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)
|
||||
-}
|
||||
133
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Addr.hs
vendored
Normal file
133
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Addr.hs
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
{-# LANGUAGE MagicHash, UnboxedTuples, CPP #-}
|
||||
|
||||
-- |
|
||||
-- Module : Data.Primitive.Addr
|
||||
-- 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
|
||||
--
|
||||
|
||||
module Data.Primitive.Addr (
|
||||
-- * Types
|
||||
Addr(..),
|
||||
|
||||
-- * Address arithmetic
|
||||
nullAddr, plusAddr, minusAddr, remAddr,
|
||||
|
||||
-- * Element access
|
||||
indexOffAddr, readOffAddr, writeOffAddr,
|
||||
|
||||
-- * Block operations
|
||||
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
|
||||
|
||||
import GHC.Ptr
|
||||
import Foreign.Marshal.Utils
|
||||
|
||||
|
||||
-- | The null address
|
||||
nullAddr :: Addr
|
||||
nullAddr = Addr nullAddr#
|
||||
|
||||
infixl 6 `plusAddr`, `minusAddr`
|
||||
infixl 7 `remAddr`
|
||||
|
||||
-- | Offset an address by the given number of bytes
|
||||
plusAddr :: Addr -> Int -> Addr
|
||||
plusAddr (Addr a#) (I# i#) = Addr (plusAddr# a# i#)
|
||||
|
||||
-- | Distance in bytes between two addresses. The result is only valid if the
|
||||
-- difference fits in an 'Int'.
|
||||
minusAddr :: Addr -> Addr -> Int
|
||||
minusAddr (Addr a#) (Addr b#) = I# (minusAddr# a# b#)
|
||||
|
||||
-- | The remainder of the address and the integer.
|
||||
remAddr :: Addr -> Int -> Int
|
||||
remAddr (Addr a#) (I# i#) = I# (remAddr# a# i#)
|
||||
|
||||
-- | Read a value from a memory position given by an address 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.
|
||||
indexOffAddr :: Prim a => Addr -> Int -> a
|
||||
{-# INLINE indexOffAddr #-}
|
||||
indexOffAddr (Addr 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.
|
||||
readOffAddr :: (Prim a, PrimMonad m) => Addr -> Int -> m a
|
||||
{-# INLINE readOffAddr #-}
|
||||
readOffAddr (Addr 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.
|
||||
writeOffAddr :: (Prim a, PrimMonad m) => Addr -> Int -> a -> m ()
|
||||
{-# INLINE writeOffAddr #-}
|
||||
writeOffAddr (Addr addr#) (I# i#) x = primitive_ (writeOffAddr# addr# i# x)
|
||||
|
||||
-- | Copy the given number of bytes from the second 'Addr' to the first. The
|
||||
-- areas may not overlap.
|
||||
copyAddr :: PrimMonad m => Addr -- ^ destination address
|
||||
-> Addr -- ^ source address
|
||||
-> Int -- ^ number of bytes
|
||||
-> m ()
|
||||
{-# INLINE copyAddr #-}
|
||||
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
|
||||
-> Addr -- ^ source address
|
||||
-> Int -- ^ number of bytes
|
||||
-> m ()
|
||||
{-# INLINE moveAddr #-}
|
||||
moveAddr (Addr dst#) (Addr src#) n
|
||||
= unsafePrimToPrim $ moveBytes (Ptr dst#) (Ptr src#) n
|
||||
|
||||
-- | Fill a memory block of with the given value. The length is in
|
||||
-- elements of type @a@ rather than in bytes.
|
||||
setAddr :: (Prim a, PrimMonad m) => Addr -> Int -> a -> m ()
|
||||
{-# 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#)
|
||||
822
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Array.hs
vendored
Normal file
822
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Array.hs
vendored
Normal file
|
|
@ -0,0 +1,822 @@
|
|||
{-# LANGUAGE CPP, MagicHash, UnboxedTuples, DeriveDataTypeable, BangPatterns #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
|
||||
-- |
|
||||
-- Module : Data.Primitive.Array
|
||||
-- Copyright : (c) Roman Leshchinskiy 2009-2012
|
||||
-- License : BSD-style
|
||||
--
|
||||
-- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au>
|
||||
-- Portability : non-portable
|
||||
--
|
||||
-- Primitive arrays of boxed values.
|
||||
--
|
||||
|
||||
module Data.Primitive.Array (
|
||||
Array(..), MutableArray(..),
|
||||
|
||||
newArray, readArray, writeArray, indexArray, indexArrayM, indexArray##,
|
||||
freezeArray, thawArray, runArray,
|
||||
unsafeFreezeArray, unsafeThawArray, sameMutableArray,
|
||||
copyArray, copyMutableArray,
|
||||
cloneArray, cloneMutableArray,
|
||||
sizeofArray, sizeofMutableArray,
|
||||
fromListN, fromList,
|
||||
mapArray',
|
||||
traverseArrayP
|
||||
) where
|
||||
|
||||
import Control.Monad.Primitive
|
||||
|
||||
import GHC.Base ( Int(..) )
|
||||
import GHC.Prim
|
||||
import qualified GHC.Exts as Exts
|
||||
#if (MIN_VERSION_base(4,7,0))
|
||||
import GHC.Exts (fromListN, fromList)
|
||||
#endif
|
||||
|
||||
import Data.Typeable ( Typeable )
|
||||
import Data.Data
|
||||
(Data(..), DataType, mkDataType, Constr, mkConstr, Fixity(..), constrIndex)
|
||||
import Data.Primitive.Internal.Compat ( isTrue#, mkNoRepType )
|
||||
|
||||
import Control.Monad.ST(ST,runST)
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Monad (MonadPlus(..), when)
|
||||
import Control.Monad.Fix
|
||||
#if MIN_VERSION_base(4,4,0)
|
||||
import Control.Monad.Zip
|
||||
#endif
|
||||
import Data.Foldable (Foldable(..), toList)
|
||||
#if !(MIN_VERSION_base(4,8,0))
|
||||
import Data.Traversable (Traversable(..))
|
||||
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 }
|
||||
deriving ( Typeable )
|
||||
|
||||
-- | Mutable boxed arrays associated with a primitive state token.
|
||||
data MutableArray s a = MutableArray
|
||||
{ marray# :: MutableArray# s a }
|
||||
deriving ( Typeable )
|
||||
|
||||
sizeofArray :: Array a -> Int
|
||||
sizeofArray a = I# (sizeofArray# (array# a))
|
||||
{-# INLINE sizeofArray #-}
|
||||
|
||||
sizeofMutableArray :: MutableArray s a -> Int
|
||||
sizeofMutableArray a = I# (sizeofMutableArray# (marray# a))
|
||||
{-# INLINE sizeofMutableArray #-}
|
||||
|
||||
-- | Create a new mutable array of the specified size and initialise all
|
||||
-- elements with the given value.
|
||||
newArray :: PrimMonad m => Int -> a -> m (MutableArray (PrimState m) a)
|
||||
{-# INLINE newArray #-}
|
||||
newArray (I# n#) x = primitive
|
||||
(\s# -> case newArray# n# x s# of
|
||||
(# s'#, arr# #) ->
|
||||
let ma = MutableArray arr#
|
||||
in (# s'# , ma #))
|
||||
|
||||
-- | Read a value from the array at the given index.
|
||||
readArray :: PrimMonad m => MutableArray (PrimState m) a -> Int -> m a
|
||||
{-# INLINE readArray #-}
|
||||
readArray arr (I# i#) = primitive (readArray# (marray# arr) i#)
|
||||
|
||||
-- | Write a value to the array at the given index.
|
||||
writeArray :: PrimMonad m => MutableArray (PrimState m) a -> Int -> a -> m ()
|
||||
{-# INLINE writeArray #-}
|
||||
writeArray arr (I# i#) x = primitive_ (writeArray# (marray# arr) i# x)
|
||||
|
||||
-- | Read a value from the immutable array at the given index.
|
||||
indexArray :: Array a -> Int -> a
|
||||
{-# 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
|
||||
-- copy an array. We could do something like this:
|
||||
--
|
||||
-- > copy marr arr ... = do ...
|
||||
-- > writeArray marr i (indexArray arr i) ...
|
||||
-- > ...
|
||||
--
|
||||
-- But since primitive arrays are lazy, the calls to 'indexArray' will not be
|
||||
-- evaluated. Rather, @marr@ will be filled with thunks each of which would
|
||||
-- retain a reference to @arr@. This is definitely not what we want!
|
||||
--
|
||||
-- With 'indexArrayM', we can instead write
|
||||
--
|
||||
-- > copy marr arr ... = do ...
|
||||
-- > x <- indexArrayM arr i
|
||||
-- > writeArray marr i x
|
||||
-- > ...
|
||||
--
|
||||
-- Now, indexing is executed immediately although the returned element is
|
||||
-- still not evaluated.
|
||||
--
|
||||
indexArrayM :: Monad m => Array a -> Int -> m a
|
||||
{-# INLINE indexArrayM #-}
|
||||
indexArrayM arr (I# i#)
|
||||
= case indexArray# (array# arr) i# of (# x #) -> return x
|
||||
|
||||
-- | Create an immutable copy of a slice of an array.
|
||||
--
|
||||
-- This operation makes a copy of the specified section, so it is safe to
|
||||
-- continue using the mutable array afterward.
|
||||
freezeArray
|
||||
:: PrimMonad m
|
||||
=> MutableArray (PrimState m) a -- ^ source
|
||||
-> Int -- ^ offset
|
||||
-> Int -- ^ length
|
||||
-> m (Array a)
|
||||
{-# INLINE freezeArray #-}
|
||||
freezeArray (MutableArray ma#) (I# off#) (I# len#) =
|
||||
primitive $ \s -> case freezeArray# ma# off# len# s of
|
||||
(# s', a# #) -> (# s', Array a# #)
|
||||
|
||||
-- | Convert a mutable array to an immutable one without copying. The
|
||||
-- array should not be modified after the conversion.
|
||||
unsafeFreezeArray :: PrimMonad m => MutableArray (PrimState m) a -> m (Array a)
|
||||
{-# INLINE unsafeFreezeArray #-}
|
||||
unsafeFreezeArray arr
|
||||
= primitive (\s# -> case unsafeFreezeArray# (marray# arr) s# of
|
||||
(# s'#, arr'# #) ->
|
||||
let a = Array arr'#
|
||||
in (# s'#, a #))
|
||||
|
||||
-- | Create a mutable array from a slice of an immutable array.
|
||||
--
|
||||
-- This operation makes a copy of the specified slice, so it is safe to use the
|
||||
-- immutable array afterward.
|
||||
thawArray
|
||||
:: PrimMonad m
|
||||
=> Array a -- ^ source
|
||||
-> Int -- ^ offset
|
||||
-> Int -- ^ length
|
||||
-> m (MutableArray (PrimState m) a)
|
||||
{-# INLINE thawArray #-}
|
||||
thawArray (Array a#) (I# off#) (I# len#) =
|
||||
primitive $ \s -> case thawArray# a# off# len# s of
|
||||
(# s', ma# #) -> (# s', MutableArray ma# #)
|
||||
|
||||
-- | Convert an immutable array to an mutable one without copying. The
|
||||
-- immutable array should not be used after the conversion.
|
||||
unsafeThawArray :: PrimMonad m => Array a -> m (MutableArray (PrimState m) a)
|
||||
{-# INLINE unsafeThawArray #-}
|
||||
unsafeThawArray a
|
||||
= primitive (\s# -> case unsafeThawArray# (array# a) s# of
|
||||
(# s'#, arr'# #) ->
|
||||
let ma = MutableArray arr'#
|
||||
in (# s'#, ma #))
|
||||
|
||||
-- | Check whether the two arrays refer to the same memory block.
|
||||
sameMutableArray :: MutableArray s a -> MutableArray s a -> Bool
|
||||
{-# INLINE sameMutableArray #-}
|
||||
sameMutableArray arr brr
|
||||
= isTrue# (sameMutableArray# (marray# arr) (marray# brr))
|
||||
|
||||
-- | Copy a slice of an immutable array to a mutable array.
|
||||
copyArray :: PrimMonad m
|
||||
=> MutableArray (PrimState m) a -- ^ destination array
|
||||
-> Int -- ^ offset into destination array
|
||||
-> Array a -- ^ source array
|
||||
-> Int -- ^ offset into source array
|
||||
-> Int -- ^ number of elements to copy
|
||||
-> m ()
|
||||
{-# INLINE copyArray #-}
|
||||
#if __GLASGOW_HASKELL__ > 706
|
||||
-- NOTE: copyArray# and copyMutableArray# are slightly broken in GHC 7.6.* and earlier
|
||||
copyArray (MutableArray dst#) (I# doff#) (Array src#) (I# soff#) (I# len#)
|
||||
= primitive_ (copyArray# src# soff# dst# doff# len#)
|
||||
#else
|
||||
copyArray !dst !doff !src !soff !len = go 0
|
||||
where
|
||||
go i | i < len = do
|
||||
x <- indexArrayM src (soff+i)
|
||||
writeArray dst (doff+i) x
|
||||
go (i+1)
|
||||
| otherwise = return ()
|
||||
#endif
|
||||
|
||||
-- | Copy a slice of a mutable array to another array. The two arrays may
|
||||
-- not be the same.
|
||||
copyMutableArray :: PrimMonad m
|
||||
=> MutableArray (PrimState m) a -- ^ destination array
|
||||
-> Int -- ^ offset into destination array
|
||||
-> MutableArray (PrimState m) a -- ^ source array
|
||||
-> Int -- ^ offset into source array
|
||||
-> Int -- ^ number of elements to copy
|
||||
-> m ()
|
||||
{-# INLINE copyMutableArray #-}
|
||||
#if __GLASGOW_HASKELL__ >= 706
|
||||
-- NOTE: copyArray# and copyMutableArray# are slightly broken in GHC 7.6.* and earlier
|
||||
copyMutableArray (MutableArray dst#) (I# doff#)
|
||||
(MutableArray src#) (I# soff#) (I# len#)
|
||||
= primitive_ (copyMutableArray# src# soff# dst# doff# len#)
|
||||
#else
|
||||
copyMutableArray !dst !doff !src !soff !len = go 0
|
||||
where
|
||||
go i | i < len = do
|
||||
x <- readArray src (soff+i)
|
||||
writeArray dst (doff+i) x
|
||||
go (i+1)
|
||||
| otherwise = return ()
|
||||
#endif
|
||||
|
||||
-- | Return a newly allocated Array with the specified subrange of the
|
||||
-- provided Array. The provided Array should contain the full subrange
|
||||
-- specified by the two Ints, but this is not checked.
|
||||
cloneArray :: Array a -- ^ source array
|
||||
-> Int -- ^ offset into destination array
|
||||
-> Int -- ^ number of elements to copy
|
||||
-> Array a
|
||||
{-# INLINE cloneArray #-}
|
||||
cloneArray (Array arr#) (I# off#) (I# len#)
|
||||
= case cloneArray# arr# off# len# of arr'# -> Array arr'#
|
||||
|
||||
-- | Return a newly allocated MutableArray. with the specified subrange of
|
||||
-- the provided MutableArray. The provided MutableArray should contain the
|
||||
-- full subrange specified by the two Ints, but this is not checked.
|
||||
cloneMutableArray :: PrimMonad m
|
||||
=> MutableArray (PrimState m) a -- ^ source array
|
||||
-> Int -- ^ offset into destination array
|
||||
-> Int -- ^ number of elements to copy
|
||||
-> m (MutableArray (PrimState m) a)
|
||||
{-# INLINE cloneMutableArray #-}
|
||||
cloneMutableArray (MutableArray arr#) (I# off#) (I# len#) = primitive
|
||||
(\s# -> case cloneMutableArray# arr# off# len# s# of
|
||||
(# s'#, arr'# #) -> (# s'#, MutableArray arr'# #))
|
||||
|
||||
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 = 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 = 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 = 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
|
||||
-- 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 !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 = \ !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 = \ !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 !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 !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)
|
||||
null a = sizeofArray a == 0
|
||||
{-# INLINE null #-}
|
||||
length = sizeofArray
|
||||
{-# INLINE length #-}
|
||||
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 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 #-}
|
||||
product = foldl' (*) 1
|
||||
{-# 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 = 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 = arrayFromListN
|
||||
fromList = arrayFromList
|
||||
toList = toList
|
||||
#else
|
||||
fromListN :: Int -> [a] -> Array a
|
||||
fromListN = arrayFromListN
|
||||
|
||||
fromList :: [a] -> Array a
|
||||
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
|
||||
= 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 = createArray (sizeofArray a) e (\ !_ -> pure ())
|
||||
#endif
|
||||
|
||||
instance Applicative Array where
|
||||
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
|
||||
| otherwise = return ()
|
||||
in go 0
|
||||
where sza = sizeofArray a ; szb = sizeofArray b
|
||||
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
|
||||
= 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
|
||||
|
||||
instance Alternative Array where
|
||||
empty = emptyArray
|
||||
a1 <|> a2 = createArray (sza1 + sza2) (die "<|>" "impossible") $ \ma ->
|
||||
copyArray ma 0 a1 0 sza1 >> copyArray ma sza1 a2 0 sza2
|
||||
where sza1 = sizeofArray a1 ; sza2 = sizeofArray a2
|
||||
some a | sizeofArray a == 0 = emptyArray
|
||||
| otherwise = die "some" "infinite arrays are not well defined"
|
||||
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
|
||||
(>>) = (*>)
|
||||
|
||||
ary >>= f = collect 0 EmptyStack (la-1)
|
||||
where
|
||||
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)
|
||||
|
||||
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
|
||||
mzero = empty
|
||||
mplus = (<|>)
|
||||
|
||||
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
|
||||
= 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 #-}
|
||||
|
||||
#if MIN_VERSION_base(4,4,0)
|
||||
instance MonadZip Array where
|
||||
mzip aa ab = zipW "mzip" (,) aa ab
|
||||
mzipWith f aa ab = zipW "mzipWith" f aa ab
|
||||
munzip aab = runST $ do
|
||||
let sz = sizeofArray aab
|
||||
ma <- newArray sz (die "munzip" "impossible")
|
||||
mb <- newArray sz (die "munzip" "impossible")
|
||||
let go i | i < sz = do
|
||||
(a, b) <- indexArrayM aab i
|
||||
writeArray ma i a
|
||||
writeArray mb i b
|
||||
go (i+1)
|
||||
go _ = return ()
|
||||
go 0
|
||||
(,) <$> unsafeFreezeArray ma <*> unsafeFreezeArray mb
|
||||
#endif
|
||||
|
||||
instance MonadFix Array where
|
||||
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
|
||||
#endif
|
||||
|
||||
instance Monoid (Array a) where
|
||||
mempty = empty
|
||||
#if !(MIN_VERSION_base(4,11,0))
|
||||
mappend = (<|>)
|
||||
#endif
|
||||
mconcat l = createArray sz (die "mconcat" "impossible") $ \ma ->
|
||||
let go !_ [ ] = return ()
|
||||
go off (a:as) =
|
||||
copyArray ma off a 0 (sizeofArray a) >> go (off + sizeofArray a) as
|
||||
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 = 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 = 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]
|
||||
|
||||
fromListConstr :: Constr
|
||||
fromListConstr = mkConstr arrayDataType "fromList" [] Prefix
|
||||
|
||||
instance Data a => Data (Array a) where
|
||||
toConstr _ = fromListConstr
|
||||
dataTypeOf _ = arrayDataType
|
||||
gunfold k z c = case constrIndex c of
|
||||
1 -> k (z fromList)
|
||||
_ -> error "gunfold"
|
||||
gfoldl f z m = z fromList `f` toList m
|
||||
|
||||
instance (Typeable s, Typeable a) => Data (MutableArray s a) where
|
||||
toConstr _ = error "toConstr"
|
||||
gunfold _ _ = error "gunfold"
|
||||
dataTypeOf _ = mkNoRepType "Data.Primitive.Array.MutableArray"
|
||||
549
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/ByteArray.hs
vendored
Normal file
549
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/ByteArray.hs
vendored
Normal file
|
|
@ -0,0 +1,549 @@
|
|||
{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples, UnliftedFFITypes, DeriveDataTypeable #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
|
||||
-- |
|
||||
-- Module : Data.Primitive.ByteArray
|
||||
-- Copyright : (c) Roman Leshchinskiy 2009-2012
|
||||
-- License : BSD-style
|
||||
--
|
||||
-- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au>
|
||||
-- Portability : non-portable
|
||||
--
|
||||
-- Primitive operations on ByteArrays
|
||||
--
|
||||
|
||||
module Data.Primitive.ByteArray (
|
||||
-- * Types
|
||||
ByteArray(..), MutableByteArray(..), ByteArray#, MutableByteArray#,
|
||||
|
||||
-- * Allocation
|
||||
newByteArray, newPinnedByteArray, newAlignedPinnedByteArray,
|
||||
resizeMutableByteArray,
|
||||
|
||||
-- * Element access
|
||||
readByteArray, writeByteArray, indexByteArray,
|
||||
|
||||
-- * Constructing
|
||||
byteArrayFromList, byteArrayFromListN,
|
||||
|
||||
-- * Folding
|
||||
foldrByteArray,
|
||||
|
||||
-- * Freezing and thawing
|
||||
unsafeFreezeByteArray, unsafeThawByteArray,
|
||||
|
||||
-- * Block operations
|
||||
copyByteArray, copyMutableByteArray,
|
||||
#if __GLASGOW_HASKELL__ >= 708
|
||||
copyByteArrayToAddr, copyMutableByteArrayToAddr,
|
||||
#endif
|
||||
moveByteArray,
|
||||
setByteArray, fillByteArray,
|
||||
|
||||
-- * Information
|
||||
sizeofByteArray,
|
||||
sizeofMutableByteArray, getSizeofMutableByteArray, sameMutableByteArray,
|
||||
#if __GLASGOW_HASKELL__ >= 802
|
||||
isByteArrayPinned, isMutableByteArrayPinned,
|
||||
#endif
|
||||
byteArrayContents, mutableByteArrayContents
|
||||
|
||||
) where
|
||||
|
||||
import Control.Monad.Primitive
|
||||
import Control.Monad.ST
|
||||
import Data.Primitive.Types
|
||||
|
||||
import Foreign.C.Types
|
||||
import Data.Word ( Word8 )
|
||||
import GHC.Base ( Int(..) )
|
||||
#if __GLASGOW_HASKELL__ >= 708
|
||||
import qualified GHC.Exts as Exts ( IsList(..) )
|
||||
#endif
|
||||
import GHC.Prim
|
||||
#if __GLASGOW_HASKELL__ >= 706
|
||||
hiding (setByteArray#)
|
||||
#endif
|
||||
|
||||
import Data.Typeable ( Typeable )
|
||||
import Data.Data ( Data(..) )
|
||||
import Data.Primitive.Internal.Compat ( isTrue#, mkNoRepType )
|
||||
import Numeric
|
||||
|
||||
#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 )
|
||||
|
||||
-- | Mutable byte arrays associated with a primitive state token
|
||||
data MutableByteArray s = MutableByteArray (MutableByteArray# s)
|
||||
deriving( Typeable )
|
||||
|
||||
-- | Create a new mutable byte array of the specified size in bytes.
|
||||
newByteArray :: PrimMonad m => Int -> m (MutableByteArray (PrimState m))
|
||||
{-# INLINE newByteArray #-}
|
||||
newByteArray (I# n#)
|
||||
= primitive (\s# -> case newByteArray# n# s# of
|
||||
(# s'#, arr# #) -> (# s'#, MutableByteArray arr# #))
|
||||
|
||||
-- | Create a /pinned/ byte array of the specified size in bytes. The garbage
|
||||
-- collector is guaranteed not to move it.
|
||||
newPinnedByteArray :: PrimMonad m => Int -> m (MutableByteArray (PrimState m))
|
||||
{-# INLINE newPinnedByteArray #-}
|
||||
newPinnedByteArray (I# n#)
|
||||
= primitive (\s# -> case newPinnedByteArray# n# s# of
|
||||
(# s'#, arr# #) -> (# s'#, MutableByteArray arr# #))
|
||||
|
||||
-- | Create a /pinned/ byte array of the specified size in bytes and with the
|
||||
-- given alignment. The garbage collector is guaranteed not to move it.
|
||||
newAlignedPinnedByteArray
|
||||
:: 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
|
||||
(# s'#, arr# #) -> (# s'#, MutableByteArray arr# #))
|
||||
|
||||
-- | Yield a pointer to the array's data. This operation is only safe on
|
||||
-- /pinned/ byte arrays allocated by 'newPinnedByteArray' or
|
||||
-- 'newAlignedPinnedByteArray'.
|
||||
byteArrayContents :: ByteArray -> Addr
|
||||
{-# INLINE byteArrayContents #-}
|
||||
byteArrayContents (ByteArray arr#) = Addr (byteArrayContents# arr#)
|
||||
|
||||
-- | Yield a pointer to the array's data. This operation is only safe on
|
||||
-- /pinned/ byte arrays allocated by 'newPinnedByteArray' or
|
||||
-- 'newAlignedPinnedByteArray'.
|
||||
mutableByteArrayContents :: MutableByteArray s -> Addr
|
||||
{-# INLINE mutableByteArrayContents #-}
|
||||
mutableByteArrayContents (MutableByteArray arr#)
|
||||
= Addr (byteArrayContents# (unsafeCoerce# arr#))
|
||||
|
||||
-- | Check if the two arrays refer to the same memory block.
|
||||
sameMutableByteArray :: MutableByteArray s -> MutableByteArray s -> Bool
|
||||
{-# INLINE sameMutableByteArray #-}
|
||||
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
|
||||
:: PrimMonad m => MutableByteArray (PrimState m) -> m ByteArray
|
||||
{-# INLINE unsafeFreezeByteArray #-}
|
||||
unsafeFreezeByteArray (MutableByteArray arr#)
|
||||
= primitive (\s# -> case unsafeFreezeByteArray# arr# s# of
|
||||
(# s'#, arr'# #) -> (# s'#, ByteArray arr'# #))
|
||||
|
||||
-- | Convert an immutable byte array to a mutable one without copying. The
|
||||
-- original array should not be used after the conversion.
|
||||
unsafeThawByteArray
|
||||
:: PrimMonad m => ByteArray -> m (MutableByteArray (PrimState m))
|
||||
{-# INLINE unsafeThawByteArray #-}
|
||||
unsafeThawByteArray (ByteArray arr#)
|
||||
= primitive (\s# -> (# s#, MutableByteArray (unsafeCoerce# arr#) #))
|
||||
|
||||
-- | Size of the byte array in bytes.
|
||||
sizeofByteArray :: ByteArray -> Int
|
||||
{-# INLINE sizeofByteArray #-}
|
||||
sizeofByteArray (ByteArray arr#) = I# (sizeofByteArray# arr#)
|
||||
|
||||
-- | 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
|
||||
{-# INLINE indexByteArray #-}
|
||||
indexByteArray (ByteArray arr#) (I# i#) = indexByteArray# arr# i#
|
||||
|
||||
-- | Read a primitive value from the byte array. The offset is given in
|
||||
-- elements of type @a@ rather than in bytes.
|
||||
readByteArray
|
||||
:: (Prim a, PrimMonad m) => MutableByteArray (PrimState m) -> Int -> m a
|
||||
{-# INLINE readByteArray #-}
|
||||
readByteArray (MutableByteArray arr#) (I# i#)
|
||||
= primitive (readByteArray# arr# i#)
|
||||
|
||||
-- | Write a primitive value to the byte array. The offset is given in
|
||||
-- elements of type @a@ rather than in bytes.
|
||||
writeByteArray
|
||||
:: (Prim a, PrimMonad m) => MutableByteArray (PrimState m) -> Int -> a -> m ()
|
||||
{-# INLINE writeByteArray #-}
|
||||
writeByteArray (MutableByteArray arr#) (I# i#) x
|
||||
= primitive_ (writeByteArray# arr# i# x)
|
||||
|
||||
-- | Right-fold over the elements of a 'ByteArray'.
|
||||
foldrByteArray :: forall a b. (Prim a) => (a -> b -> b) -> b -> ByteArray -> b
|
||||
foldrByteArray f z arr = go 0
|
||||
where
|
||||
go i
|
||||
| sizeofByteArray arr > i * sz = f (indexByteArray arr i) (go (i+1))
|
||||
| otherwise = z
|
||||
sz = sizeOf (undefined :: a)
|
||||
|
||||
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
|
||||
|
||||
unI# :: Int -> Int#
|
||||
unI# (I# n#) = n#
|
||||
|
||||
-- | Copy a slice of an immutable byte array to a mutable byte array.
|
||||
copyByteArray
|
||||
:: PrimMonad m => MutableByteArray (PrimState m)
|
||||
-- ^ destination array
|
||||
-> Int -- ^ offset into destination array
|
||||
-> ByteArray -- ^ source array
|
||||
-> Int -- ^ offset into source array
|
||||
-> Int -- ^ number of bytes to copy
|
||||
-> m ()
|
||||
{-# INLINE copyByteArray #-}
|
||||
copyByteArray (MutableByteArray dst#) doff (ByteArray src#) soff sz
|
||||
= primitive_ (copyByteArray# src# (unI# soff) dst# (unI# doff) (unI# sz))
|
||||
|
||||
-- | Copy a slice of a mutable byte array into another array. The two slices
|
||||
-- may not overlap.
|
||||
copyMutableByteArray
|
||||
:: PrimMonad m => MutableByteArray (PrimState m)
|
||||
-- ^ destination array
|
||||
-> Int -- ^ offset into destination array
|
||||
-> MutableByteArray (PrimState m)
|
||||
-- ^ source array
|
||||
-> Int -- ^ offset into source array
|
||||
-> Int -- ^ number of bytes to copy
|
||||
-> m ()
|
||||
{-# INLINE copyMutableByteArray #-}
|
||||
copyMutableByteArray (MutableByteArray dst#) doff
|
||||
(MutableByteArray src#) soff sz
|
||||
= primitive_ (copyMutableByteArray# src# (unI# soff) dst# (unI# doff) (unI# 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
|
||||
-- overlapping array.
|
||||
moveByteArray
|
||||
:: PrimMonad m => MutableByteArray (PrimState m)
|
||||
-- ^ destination array
|
||||
-> Int -- ^ offset into destination array
|
||||
-> MutableByteArray (PrimState m)
|
||||
-- ^ source array
|
||||
-> Int -- ^ offset into source array
|
||||
-> Int -- ^ number of bytes to copy
|
||||
-> m ()
|
||||
{-# INLINE moveByteArray #-}
|
||||
moveByteArray (MutableByteArray dst#) doff
|
||||
(MutableByteArray src#) soff sz
|
||||
= unsafePrimToPrim
|
||||
$ memmove_mba dst# (fromIntegral doff) src# (fromIntegral soff)
|
||||
(fromIntegral sz)
|
||||
|
||||
-- | Fill a slice of a mutable byte array with a value. The offset and length
|
||||
-- are given in elements of type @a@ rather than in bytes.
|
||||
setByteArray
|
||||
:: (Prim a, PrimMonad m) => MutableByteArray (PrimState m) -- ^ array to fill
|
||||
-> Int -- ^ offset into array
|
||||
-> Int -- ^ number of values to fill
|
||||
-> a -- ^ value to fill with
|
||||
-> m ()
|
||||
{-# INLINE setByteArray #-}
|
||||
setByteArray (MutableByteArray dst#) (I# doff#) (I# sz#) x
|
||||
= primitive_ (setByteArray# dst# doff# sz# x)
|
||||
|
||||
-- | Fill a slice of a mutable byte array with a byte.
|
||||
fillByteArray
|
||||
:: PrimMonad m => MutableByteArray (PrimState m)
|
||||
-- ^ array to fill
|
||||
-> Int -- ^ offset into array
|
||||
-> Int -- ^ number of bytes to fill
|
||||
-> Word8 -- ^ byte to fill with
|
||||
-> m ()
|
||||
{-# INLINE fillByteArray #-}
|
||||
fillByteArray = setByteArray
|
||||
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memmove"
|
||||
memmove_mba :: MutableByteArray# s -> CInt
|
||||
-> MutableByteArray# s -> CInt
|
||||
-> CSize -> IO ()
|
||||
|
||||
instance Data ByteArray where
|
||||
toConstr _ = error "toConstr"
|
||||
gunfold _ _ = error "gunfold"
|
||||
dataTypeOf _ = mkNoRepType "Data.Primitive.ByteArray.ByteArray"
|
||||
|
||||
instance Typeable s => Data (MutableByteArray s) where
|
||||
toConstr _ = error "toConstr"
|
||||
gunfold _ _ = error "gunfold"
|
||||
dataTypeOf _ = mkNoRepType "Data.Primitive.ByteArray.MutableByteArray"
|
||||
|
||||
-- | @since 0.6.3.0
|
||||
instance Show ByteArray where
|
||||
showsPrec _ ba =
|
||||
showString "[" . go 0
|
||||
where
|
||||
go i
|
||||
| i < sizeofByteArray ba = comma . showString "0x" . showHex (indexByteArray ba i :: Word8) . go (i+1)
|
||||
| otherwise = showChar ']'
|
||||
where
|
||||
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
|
||||
#if __GLASGOW_HASKELL__ >= 708
|
||||
r -> isTrue# r
|
||||
#else
|
||||
1# -> True
|
||||
0# -> False
|
||||
#endif
|
||||
|
||||
-- | @since 0.6.3.0
|
||||
instance Eq ByteArray where
|
||||
ba1@(ByteArray ba1#) == ba2@(ByteArray ba2#)
|
||||
| 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 = 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 = byteArrayFromListN (length xs) xs
|
||||
fromListN = byteArrayFromListN
|
||||
#endif
|
||||
|
||||
die :: String -> String -> a
|
||||
die fun problem = error $ "Data.Primitive.ByteArray." ++ fun ++ ": " ++ problem
|
||||
|
||||
38
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Internal/Compat.hs
vendored
Normal file
38
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Internal/Compat.hs
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{-# LANGUAGE CPP, MagicHash #-}
|
||||
|
||||
-- |
|
||||
-- Module : Data.Primitive.Internal.Compat
|
||||
-- Copyright : (c) Roman Leshchinskiy 2011-2012
|
||||
-- License : BSD-style
|
||||
--
|
||||
-- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au>
|
||||
-- Portability : non-portable
|
||||
--
|
||||
-- Compatibility functions
|
||||
--
|
||||
|
||||
module Data.Primitive.Internal.Compat (
|
||||
isTrue#
|
||||
, mkNoRepType
|
||||
) where
|
||||
|
||||
#if MIN_VERSION_base(4,2,0)
|
||||
import Data.Data (mkNoRepType)
|
||||
#else
|
||||
import Data.Data (mkNorepType)
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION_base(4,7,0)
|
||||
import GHC.Exts (isTrue#)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !MIN_VERSION_base(4,2,0)
|
||||
mkNoRepType = mkNorepType
|
||||
#endif
|
||||
|
||||
#if !MIN_VERSION_base(4,7,0)
|
||||
isTrue# :: Bool -> Bool
|
||||
isTrue# b = b
|
||||
#endif
|
||||
90
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Internal/Operations.hs
vendored
Normal file
90
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Internal/Operations.hs
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
{-# LANGUAGE MagicHash, UnliftedFFITypes #-}
|
||||
|
||||
-- |
|
||||
-- Module : Data.Primitive.Internal.Operations
|
||||
-- Copyright : (c) Roman Leshchinskiy 2011-2012
|
||||
-- License : BSD-style
|
||||
--
|
||||
-- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au>
|
||||
-- Portability : non-portable
|
||||
--
|
||||
-- Internal operations
|
||||
--
|
||||
|
||||
|
||||
module Data.Primitive.Internal.Operations (
|
||||
setWord8Array#, setWord16Array#, setWord32Array#,
|
||||
setWord64Array#, setWordArray#,
|
||||
setInt8Array#, setInt16Array#, setInt32Array#,
|
||||
setInt64Array#, setIntArray#,
|
||||
setAddrArray#, setFloatArray#, setDoubleArray#, setWideCharArray#,
|
||||
|
||||
setWord8OffAddr#, setWord16OffAddr#, setWord32OffAddr#,
|
||||
setWord64OffAddr#, setWordOffAddr#,
|
||||
setInt8OffAddr#, setInt16OffAddr#, setInt32OffAddr#,
|
||||
setInt64OffAddr#, setIntOffAddr#,
|
||||
setAddrOffAddr#, setFloatOffAddr#, setDoubleOffAddr#, setWideCharOffAddr#
|
||||
) where
|
||||
|
||||
import Data.Primitive.MachDeps (Word64_#, Int64_#)
|
||||
import Foreign.C.Types
|
||||
import GHC.Prim
|
||||
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8"
|
||||
setWord8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16"
|
||||
setWord16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32"
|
||||
setWord32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64"
|
||||
setWord64Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word64_# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word"
|
||||
setWordArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8"
|
||||
setInt8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16"
|
||||
setInt16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32"
|
||||
setInt32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64"
|
||||
setInt64Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int64_# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word"
|
||||
setIntArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Ptr"
|
||||
setAddrArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Addr# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Float"
|
||||
setFloatArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Float# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Double"
|
||||
setDoubleArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Double# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Char"
|
||||
setWideCharArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Char# -> IO ()
|
||||
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8"
|
||||
setWord8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16"
|
||||
setWord16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32"
|
||||
setWord32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64"
|
||||
setWord64OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word64_# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word"
|
||||
setWordOffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8"
|
||||
setInt8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16"
|
||||
setInt16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32"
|
||||
setInt32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64"
|
||||
setInt64OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int64_# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word"
|
||||
setIntOffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Ptr"
|
||||
setAddrOffAddr# :: Addr# -> CPtrdiff -> CSize -> Addr# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Float"
|
||||
setFloatOffAddr# :: Addr# -> CPtrdiff -> CSize -> Float# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Double"
|
||||
setDoubleOffAddr# :: Addr# -> CPtrdiff -> CSize -> Double# -> IO ()
|
||||
foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Char"
|
||||
setWideCharOffAddr# :: Addr# -> CPtrdiff -> CSize -> Char# -> IO ()
|
||||
|
||||
155
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/MVar.hs
vendored
Normal file
155
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/MVar.hs
vendored
Normal file
|
|
@ -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#) #)
|
||||
123
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/MachDeps.hs
vendored
Normal file
123
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/MachDeps.hs
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
{-# LANGUAGE CPP, MagicHash #-}
|
||||
-- |
|
||||
-- Module : Data.Primitive.MachDeps
|
||||
-- Copyright : (c) Roman Leshchinskiy 2009-2012
|
||||
-- License : BSD-style
|
||||
--
|
||||
-- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au>
|
||||
-- Portability : non-portable
|
||||
--
|
||||
-- Machine-dependent constants
|
||||
--
|
||||
|
||||
module Data.Primitive.MachDeps where
|
||||
|
||||
#include "MachDeps.h"
|
||||
|
||||
import GHC.Prim
|
||||
|
||||
sIZEOF_CHAR,
|
||||
aLIGNMENT_CHAR,
|
||||
|
||||
sIZEOF_INT,
|
||||
aLIGNMENT_INT,
|
||||
|
||||
sIZEOF_WORD,
|
||||
aLIGNMENT_WORD,
|
||||
|
||||
sIZEOF_DOUBLE,
|
||||
aLIGNMENT_DOUBLE,
|
||||
|
||||
sIZEOF_FLOAT,
|
||||
aLIGNMENT_FLOAT,
|
||||
|
||||
sIZEOF_PTR,
|
||||
aLIGNMENT_PTR,
|
||||
|
||||
sIZEOF_FUNPTR,
|
||||
aLIGNMENT_FUNPTR,
|
||||
|
||||
sIZEOF_STABLEPTR,
|
||||
aLIGNMENT_STABLEPTR,
|
||||
|
||||
sIZEOF_INT8,
|
||||
aLIGNMENT_INT8,
|
||||
|
||||
sIZEOF_WORD8,
|
||||
aLIGNMENT_WORD8,
|
||||
|
||||
sIZEOF_INT16,
|
||||
aLIGNMENT_INT16,
|
||||
|
||||
sIZEOF_WORD16,
|
||||
aLIGNMENT_WORD16,
|
||||
|
||||
sIZEOF_INT32,
|
||||
aLIGNMENT_INT32,
|
||||
|
||||
sIZEOF_WORD32,
|
||||
aLIGNMENT_WORD32,
|
||||
|
||||
sIZEOF_INT64,
|
||||
aLIGNMENT_INT64,
|
||||
|
||||
sIZEOF_WORD64,
|
||||
aLIGNMENT_WORD64 :: Int
|
||||
|
||||
|
||||
sIZEOF_CHAR = SIZEOF_HSCHAR
|
||||
aLIGNMENT_CHAR = ALIGNMENT_HSCHAR
|
||||
|
||||
sIZEOF_INT = SIZEOF_HSINT
|
||||
aLIGNMENT_INT = ALIGNMENT_HSINT
|
||||
|
||||
sIZEOF_WORD = SIZEOF_HSWORD
|
||||
aLIGNMENT_WORD = ALIGNMENT_HSWORD
|
||||
|
||||
sIZEOF_DOUBLE = SIZEOF_HSDOUBLE
|
||||
aLIGNMENT_DOUBLE = ALIGNMENT_HSDOUBLE
|
||||
|
||||
sIZEOF_FLOAT = SIZEOF_HSFLOAT
|
||||
aLIGNMENT_FLOAT = ALIGNMENT_HSFLOAT
|
||||
|
||||
sIZEOF_PTR = SIZEOF_HSPTR
|
||||
aLIGNMENT_PTR = ALIGNMENT_HSPTR
|
||||
|
||||
sIZEOF_FUNPTR = SIZEOF_HSFUNPTR
|
||||
aLIGNMENT_FUNPTR = ALIGNMENT_HSFUNPTR
|
||||
|
||||
sIZEOF_STABLEPTR = SIZEOF_HSSTABLEPTR
|
||||
aLIGNMENT_STABLEPTR = ALIGNMENT_HSSTABLEPTR
|
||||
|
||||
sIZEOF_INT8 = SIZEOF_INT8
|
||||
aLIGNMENT_INT8 = ALIGNMENT_INT8
|
||||
|
||||
sIZEOF_WORD8 = SIZEOF_WORD8
|
||||
aLIGNMENT_WORD8 = ALIGNMENT_WORD8
|
||||
|
||||
sIZEOF_INT16 = SIZEOF_INT16
|
||||
aLIGNMENT_INT16 = ALIGNMENT_INT16
|
||||
|
||||
sIZEOF_WORD16 = SIZEOF_WORD16
|
||||
aLIGNMENT_WORD16 = ALIGNMENT_WORD16
|
||||
|
||||
sIZEOF_INT32 = SIZEOF_INT32
|
||||
aLIGNMENT_INT32 = ALIGNMENT_INT32
|
||||
|
||||
sIZEOF_WORD32 = SIZEOF_WORD32
|
||||
aLIGNMENT_WORD32 = ALIGNMENT_WORD32
|
||||
|
||||
sIZEOF_INT64 = SIZEOF_INT64
|
||||
aLIGNMENT_INT64 = ALIGNMENT_INT64
|
||||
|
||||
sIZEOF_WORD64 = SIZEOF_WORD64
|
||||
aLIGNMENT_WORD64 = ALIGNMENT_WORD64
|
||||
|
||||
#if WORD_SIZE_IN_BITS == 32
|
||||
type Word64_# = Word64#
|
||||
type Int64_# = Int64#
|
||||
#else
|
||||
type Word64_# = Word#
|
||||
type Int64_# = Int#
|
||||
#endif
|
||||
|
||||
86
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/MutVar.hs
vendored
Normal file
86
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/MutVar.hs
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
{-# LANGUAGE MagicHash, UnboxedTuples, DeriveDataTypeable #-}
|
||||
|
||||
-- |
|
||||
-- Module : Data.Primitive.MutVar
|
||||
-- Copyright : (c) Justin Bonnar 2011, Roman Leshchinskiy 2011-2012
|
||||
-- License : BSD-style
|
||||
--
|
||||
-- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au>
|
||||
-- Portability : non-portable
|
||||
--
|
||||
-- Primitive boxed mutable variables
|
||||
--
|
||||
|
||||
module Data.Primitive.MutVar (
|
||||
MutVar(..),
|
||||
|
||||
newMutVar,
|
||||
readMutVar,
|
||||
writeMutVar,
|
||||
|
||||
atomicModifyMutVar,
|
||||
atomicModifyMutVar',
|
||||
modifyMutVar,
|
||||
modifyMutVar'
|
||||
) where
|
||||
|
||||
import Control.Monad.Primitive ( PrimMonad(..), primitive_ )
|
||||
import GHC.Prim ( MutVar#, sameMutVar#, newMutVar#,
|
||||
readMutVar#, writeMutVar#, atomicModifyMutVar# )
|
||||
import Data.Primitive.Internal.Compat ( isTrue# )
|
||||
import Data.Typeable ( Typeable )
|
||||
|
||||
-- | A 'MutVar' behaves like a single-element mutable array associated
|
||||
-- with a primitive state token.
|
||||
data MutVar s a = MutVar (MutVar# s a)
|
||||
deriving ( Typeable )
|
||||
|
||||
instance Eq (MutVar s a) where
|
||||
MutVar mva# == MutVar mvb# = isTrue# (sameMutVar# mva# mvb#)
|
||||
|
||||
-- | Create a new 'MutVar' with the specified initial value
|
||||
newMutVar :: PrimMonad m => a -> m (MutVar (PrimState m) a)
|
||||
{-# INLINE newMutVar #-}
|
||||
newMutVar initialValue = primitive $ \s# ->
|
||||
case newMutVar# initialValue s# of
|
||||
(# s'#, mv# #) -> (# s'#, MutVar mv# #)
|
||||
|
||||
-- | Read the value of a 'MutVar'
|
||||
readMutVar :: PrimMonad m => MutVar (PrimState m) a -> m a
|
||||
{-# INLINE readMutVar #-}
|
||||
readMutVar (MutVar mv#) = primitive (readMutVar# mv#)
|
||||
|
||||
-- | Write a new value into a 'MutVar'
|
||||
writeMutVar :: PrimMonad m => MutVar (PrimState m) a -> a -> m ()
|
||||
{-# INLINE writeMutVar #-}
|
||||
writeMutVar (MutVar mv#) newValue = primitive_ (writeMutVar# mv# newValue)
|
||||
|
||||
-- | Atomically mutate the contents of a 'MutVar'
|
||||
atomicModifyMutVar :: PrimMonad m => MutVar (PrimState m) a -> (a -> (a,b)) -> m b
|
||||
{-# INLINE atomicModifyMutVar #-}
|
||||
atomicModifyMutVar (MutVar mv#) f = primitive $ atomicModifyMutVar# mv# f
|
||||
|
||||
-- | Strict version of 'atomicModifyMutVar'. This forces both the value stored
|
||||
-- in the 'MutVar' as well as the value returned.
|
||||
atomicModifyMutVar' :: PrimMonad m => MutVar (PrimState m) a -> (a -> (a, b)) -> m b
|
||||
{-# INLINE atomicModifyMutVar' #-}
|
||||
atomicModifyMutVar' mv f = do
|
||||
b <- atomicModifyMutVar mv force
|
||||
b `seq` return b
|
||||
where
|
||||
force x = let (a, b) = f x in (a, a `seq` b)
|
||||
|
||||
-- | Mutate the contents of a 'MutVar'
|
||||
modifyMutVar :: PrimMonad m => MutVar (PrimState m) a -> (a -> a) -> m ()
|
||||
{-# INLINE modifyMutVar #-}
|
||||
modifyMutVar (MutVar mv#) g = primitive_ $ \s# ->
|
||||
case readMutVar# mv# s# of
|
||||
(# s'#, a #) -> writeMutVar# mv# (g a) s'#
|
||||
|
||||
-- | Strict version of 'modifyMutVar'
|
||||
modifyMutVar' :: PrimMonad m => MutVar (PrimState m) a -> (a -> a) -> m ()
|
||||
{-# INLINE modifyMutVar' #-}
|
||||
modifyMutVar' (MutVar mv#) g = primitive_ $ \s# ->
|
||||
case readMutVar# mv# s# of
|
||||
(# s'#, a #) -> let a' = g a in a' `seq` writeMutVar# mv# a' s'#
|
||||
|
||||
969
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/PrimArray.hs
vendored
Normal file
969
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/PrimArray.hs
vendored
Normal file
|
|
@ -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.
|
||||
-}
|
||||
|
||||
|
||||
125
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Ptr.hs
vendored
Normal file
125
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Ptr.hs
vendored
Normal file
|
|
@ -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
|
||||
967
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/SmallArray.hs
vendored
Normal file
967
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/SmallArray.hs
vendored
Normal file
|
|
@ -0,0 +1,967 @@
|
|||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE MagicHash #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE UnboxedTuples #-}
|
||||
{-# LANGUAGE DeriveTraversable #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
{-# LANGUAGE BangPatterns #-}
|
||||
|
||||
-- |
|
||||
-- Module : Data.Primitive.SmallArray
|
||||
-- Copyright: (c) 2015 Dan Doel
|
||||
-- License: BSD3
|
||||
--
|
||||
-- Maintainer: libraries@haskell.org
|
||||
-- Portability: non-portable
|
||||
--
|
||||
-- Small arrays are boxed (im)mutable arrays.
|
||||
--
|
||||
-- The underlying structure of the 'Array' type contains a card table, allowing
|
||||
-- segments of the array to be marked as having been mutated. This allows the
|
||||
-- garbage collector to only re-traverse segments of the array that have been
|
||||
-- marked during certain phases, rather than having to traverse the entire
|
||||
-- array.
|
||||
--
|
||||
-- 'SmallArray' lacks this table. This means that it takes up less memory and
|
||||
-- has slightly faster writes. It is also more efficient during garbage
|
||||
-- collection so long as the card table would have a single entry covering the
|
||||
-- entire array. These advantages make them suitable for use as arrays that are
|
||||
-- known to be small.
|
||||
--
|
||||
-- The card size is 128, so for uses much larger than that, 'Array' would likely
|
||||
-- be superior.
|
||||
--
|
||||
-- The underlying type, 'SmallArray#', was introduced in GHC 7.10, so prior to
|
||||
-- that version, this module simply implements small arrays as 'Array'.
|
||||
|
||||
module Data.Primitive.SmallArray
|
||||
( SmallArray(..)
|
||||
, SmallMutableArray(..)
|
||||
, newSmallArray
|
||||
, readSmallArray
|
||||
, writeSmallArray
|
||||
, copySmallArray
|
||||
, copySmallMutableArray
|
||||
, indexSmallArray
|
||||
, indexSmallArrayM
|
||||
, indexSmallArray##
|
||||
, cloneSmallArray
|
||||
, cloneSmallMutableArray
|
||||
, freezeSmallArray
|
||||
, unsafeFreezeSmallArray
|
||||
, thawSmallArray
|
||||
, runSmallArray
|
||||
, unsafeThawSmallArray
|
||||
, sizeofSmallArray
|
||||
, sizeofSmallMutableArray
|
||||
, smallArrayFromList
|
||||
, smallArrayFromListN
|
||||
, mapSmallArray'
|
||||
, traverseSmallArrayP
|
||||
) where
|
||||
|
||||
|
||||
#if (__GLASGOW_HASKELL__ >= 710)
|
||||
#define HAVE_SMALL_ARRAY 1
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION_base(4,7,0)
|
||||
import GHC.Exts hiding (toList)
|
||||
import qualified GHC.Exts
|
||||
#endif
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Monad
|
||||
import Control.Monad.Fix
|
||||
import Control.Monad.Primitive
|
||||
import Control.Monad.ST
|
||||
import Control.Monad.Zip
|
||||
import Data.Data
|
||||
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.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
|
||||
#else
|
||||
newtype SmallArray a = SmallArray (Array a) deriving
|
||||
( Eq
|
||||
, Ord
|
||||
, Show
|
||||
, Read
|
||||
, Foldable
|
||||
, Traversable
|
||||
, Functor
|
||||
, Applicative
|
||||
, Alternative
|
||||
, Monad
|
||||
, MonadPlus
|
||||
, MonadZip
|
||||
, 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)
|
||||
instance IsList (SmallArray a) where
|
||||
type Item (SmallArray a) = a
|
||||
fromListN n l = SmallArray (fromListN n l)
|
||||
fromList l = SmallArray (fromList l)
|
||||
toList a = Foldable.toList a
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAVE_SMALL_ARRAY
|
||||
data SmallMutableArray s a = SmallMutableArray (SmallMutableArray# s a)
|
||||
deriving Typeable
|
||||
#else
|
||||
newtype SmallMutableArray s a = SmallMutableArray (MutableArray s a)
|
||||
deriving (Eq, Typeable)
|
||||
#endif
|
||||
|
||||
-- | Create a new small mutable array.
|
||||
newSmallArray
|
||||
:: PrimMonad m
|
||||
=> Int -- ^ size
|
||||
-> a -- ^ initial contents
|
||||
-> m (SmallMutableArray (PrimState m) a)
|
||||
#if HAVE_SMALL_ARRAY
|
||||
newSmallArray (I# i#) x = primitive $ \s ->
|
||||
case newSmallArray# i# x s of
|
||||
(# s', sma# #) -> (# s', SmallMutableArray sma# #)
|
||||
#else
|
||||
newSmallArray n e = SmallMutableArray `liftM` newArray n e
|
||||
#endif
|
||||
{-# INLINE newSmallArray #-}
|
||||
|
||||
-- | Read the element at a given index in a mutable array.
|
||||
readSmallArray
|
||||
:: PrimMonad m
|
||||
=> SmallMutableArray (PrimState m) a -- ^ array
|
||||
-> Int -- ^ index
|
||||
-> m a
|
||||
#if HAVE_SMALL_ARRAY
|
||||
readSmallArray (SmallMutableArray sma#) (I# i#) =
|
||||
primitive $ readSmallArray# sma# i#
|
||||
#else
|
||||
readSmallArray (SmallMutableArray a) = readArray a
|
||||
#endif
|
||||
{-# INLINE readSmallArray #-}
|
||||
|
||||
-- | Write an element at the given idex in a mutable array.
|
||||
writeSmallArray
|
||||
:: PrimMonad m
|
||||
=> SmallMutableArray (PrimState m) a -- ^ array
|
||||
-> Int -- ^ index
|
||||
-> a -- ^ new element
|
||||
-> m ()
|
||||
#if HAVE_SMALL_ARRAY
|
||||
writeSmallArray (SmallMutableArray sma#) (I# i#) x =
|
||||
primitive_ $ writeSmallArray# sma# i# x
|
||||
#else
|
||||
writeSmallArray (SmallMutableArray a) = writeArray a
|
||||
#endif
|
||||
{-# INLINE writeSmallArray #-}
|
||||
|
||||
-- | Look up an element in an immutable array.
|
||||
--
|
||||
-- The purpose of returning a result using a monad is to allow the caller to
|
||||
-- avoid retaining references to the array. Evaluating the return value will
|
||||
-- cause the array lookup to be performed, even though it may not require the
|
||||
-- element of the array to be evaluated (which could throw an exception). For
|
||||
-- instance:
|
||||
--
|
||||
-- > data Box a = Box a
|
||||
-- > ...
|
||||
-- >
|
||||
-- > f sa = case indexSmallArrayM sa 0 of
|
||||
-- > Box x -> ...
|
||||
--
|
||||
-- 'x' is not a closure that references 'sa' as it would be if we instead
|
||||
-- wrote:
|
||||
--
|
||||
-- > let x = indexSmallArray sa 0
|
||||
--
|
||||
-- And does not prevent 'sa' from being garbage collected.
|
||||
--
|
||||
-- Note that 'Identity' is not adequate for this use, as it is a newtype, and
|
||||
-- cannot be evaluated without evaluating the element.
|
||||
indexSmallArrayM
|
||||
:: Monad m
|
||||
=> SmallArray a -- ^ array
|
||||
-> Int -- ^ index
|
||||
-> m a
|
||||
#if HAVE_SMALL_ARRAY
|
||||
indexSmallArrayM (SmallArray sa#) (I# i#) =
|
||||
case indexSmallArray# sa# i# of
|
||||
(# x #) -> pure x
|
||||
#else
|
||||
indexSmallArrayM (SmallArray a) = indexArrayM a
|
||||
#endif
|
||||
{-# INLINE indexSmallArrayM #-}
|
||||
|
||||
-- | Look up an element in an immutable array.
|
||||
indexSmallArray
|
||||
:: SmallArray a -- ^ array
|
||||
-> Int -- ^ index
|
||||
-> a
|
||||
#if HAVE_SMALL_ARRAY
|
||||
indexSmallArray sa i = runIdentity $ indexSmallArrayM sa i
|
||||
#else
|
||||
indexSmallArray (SmallArray a) = indexArray a
|
||||
#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
|
||||
-> Int -- ^ offset
|
||||
-> Int -- ^ length
|
||||
-> SmallArray a
|
||||
#if HAVE_SMALL_ARRAY
|
||||
cloneSmallArray (SmallArray sa#) (I# i#) (I# j#) =
|
||||
SmallArray (cloneSmallArray# sa# i# j#)
|
||||
#else
|
||||
cloneSmallArray (SmallArray a) i j = SmallArray $ cloneArray a i j
|
||||
#endif
|
||||
{-# INLINE cloneSmallArray #-}
|
||||
|
||||
-- | Create a copy of a slice of a mutable array.
|
||||
cloneSmallMutableArray
|
||||
:: PrimMonad m
|
||||
=> SmallMutableArray (PrimState m) a -- ^ source
|
||||
-> Int -- ^ offset
|
||||
-> Int -- ^ length
|
||||
-> m (SmallMutableArray (PrimState m) a)
|
||||
#if HAVE_SMALL_ARRAY
|
||||
cloneSmallMutableArray (SmallMutableArray sma#) (I# o#) (I# l#) =
|
||||
primitive $ \s -> case cloneSmallMutableArray# sma# o# l# s of
|
||||
(# s', smb# #) -> (# s', SmallMutableArray smb# #)
|
||||
#else
|
||||
cloneSmallMutableArray (SmallMutableArray ma) i j =
|
||||
SmallMutableArray `liftM` cloneMutableArray ma i j
|
||||
#endif
|
||||
{-# INLINE cloneSmallMutableArray #-}
|
||||
|
||||
-- | Create an immutable array corresponding to a slice of a mutable array.
|
||||
--
|
||||
-- This operation copies the portion of the array to be frozen.
|
||||
freezeSmallArray
|
||||
:: PrimMonad m
|
||||
=> SmallMutableArray (PrimState m) a -- ^ source
|
||||
-> Int -- ^ offset
|
||||
-> Int -- ^ length
|
||||
-> m (SmallArray a)
|
||||
#if HAVE_SMALL_ARRAY
|
||||
freezeSmallArray (SmallMutableArray sma#) (I# i#) (I# j#) =
|
||||
primitive $ \s -> case freezeSmallArray# sma# i# j# s of
|
||||
(# s', sa# #) -> (# s', SmallArray sa# #)
|
||||
#else
|
||||
freezeSmallArray (SmallMutableArray ma) i j =
|
||||
SmallArray `liftM` freezeArray ma i j
|
||||
#endif
|
||||
{-# INLINE freezeSmallArray #-}
|
||||
|
||||
-- | Render a mutable array immutable.
|
||||
--
|
||||
-- This operation performs no copying, so care must be taken not to modify the
|
||||
-- input array after freezing.
|
||||
unsafeFreezeSmallArray
|
||||
:: PrimMonad m => SmallMutableArray (PrimState m) a -> m (SmallArray a)
|
||||
#if HAVE_SMALL_ARRAY
|
||||
unsafeFreezeSmallArray (SmallMutableArray sma#) =
|
||||
primitive $ \s -> case unsafeFreezeSmallArray# sma# s of
|
||||
(# s', sa# #) -> (# s', SmallArray sa# #)
|
||||
#else
|
||||
unsafeFreezeSmallArray (SmallMutableArray ma) =
|
||||
SmallArray `liftM` unsafeFreezeArray ma
|
||||
#endif
|
||||
{-# INLINE unsafeFreezeSmallArray #-}
|
||||
|
||||
-- | Create a mutable array corresponding to a slice of an immutable array.
|
||||
--
|
||||
-- This operation copies the portion of the array to be thawed.
|
||||
thawSmallArray
|
||||
:: PrimMonad m
|
||||
=> SmallArray a -- ^ source
|
||||
-> Int -- ^ offset
|
||||
-> Int -- ^ length
|
||||
-> m (SmallMutableArray (PrimState m) a)
|
||||
#if HAVE_SMALL_ARRAY
|
||||
thawSmallArray (SmallArray sa#) (I# o#) (I# l#) =
|
||||
primitive $ \s -> case thawSmallArray# sa# o# l# s of
|
||||
(# s', sma# #) -> (# s', SmallMutableArray sma# #)
|
||||
#else
|
||||
thawSmallArray (SmallArray a) off len =
|
||||
SmallMutableArray `liftM` thawArray a off len
|
||||
#endif
|
||||
{-# INLINE thawSmallArray #-}
|
||||
|
||||
-- | Render an immutable array mutable.
|
||||
--
|
||||
-- This operation performs no copying, so care must be taken with its use.
|
||||
unsafeThawSmallArray
|
||||
:: PrimMonad m => SmallArray a -> m (SmallMutableArray (PrimState m) a)
|
||||
#if HAVE_SMALL_ARRAY
|
||||
unsafeThawSmallArray (SmallArray sa#) =
|
||||
primitive $ \s -> case unsafeThawSmallArray# sa# s of
|
||||
(# s', sma# #) -> (# s', SmallMutableArray sma# #)
|
||||
#else
|
||||
unsafeThawSmallArray (SmallArray a) = SmallMutableArray `liftM` unsafeThawArray a
|
||||
#endif
|
||||
{-# INLINE unsafeThawSmallArray #-}
|
||||
|
||||
-- | Copy a slice of an immutable array into a mutable array.
|
||||
copySmallArray
|
||||
:: PrimMonad m
|
||||
=> SmallMutableArray (PrimState m) a -- ^ destination
|
||||
-> Int -- ^ destination offset
|
||||
-> SmallArray a -- ^ source
|
||||
-> Int -- ^ source offset
|
||||
-> Int -- ^ length
|
||||
-> m ()
|
||||
#if HAVE_SMALL_ARRAY
|
||||
copySmallArray
|
||||
(SmallMutableArray dst#) (I# do#) (SmallArray src#) (I# so#) (I# l#) =
|
||||
primitive_ $ copySmallArray# src# so# dst# do# l#
|
||||
#else
|
||||
copySmallArray (SmallMutableArray dst) i (SmallArray src) = copyArray dst i src
|
||||
#endif
|
||||
{-# INLINE copySmallArray #-}
|
||||
|
||||
-- | Copy a slice of one mutable array into another.
|
||||
copySmallMutableArray
|
||||
:: PrimMonad m
|
||||
=> SmallMutableArray (PrimState m) a -- ^ destination
|
||||
-> Int -- ^ destination offset
|
||||
-> SmallMutableArray (PrimState m) a -- ^ source
|
||||
-> Int -- ^ source offset
|
||||
-> Int -- ^ length
|
||||
-> m ()
|
||||
#if HAVE_SMALL_ARRAY
|
||||
copySmallMutableArray
|
||||
(SmallMutableArray dst#) (I# do#)
|
||||
(SmallMutableArray src#) (I# so#)
|
||||
(I# l#) =
|
||||
primitive_ $ copySmallMutableArray# src# so# dst# do# l#
|
||||
#else
|
||||
copySmallMutableArray (SmallMutableArray dst) i (SmallMutableArray src) =
|
||||
copyMutableArray dst i src
|
||||
#endif
|
||||
{-# INLINE copySmallMutableArray #-}
|
||||
|
||||
sizeofSmallArray :: SmallArray a -> Int
|
||||
#if HAVE_SMALL_ARRAY
|
||||
sizeofSmallArray (SmallArray sa#) = I# (sizeofSmallArray# sa#)
|
||||
#else
|
||||
sizeofSmallArray (SmallArray a) = sizeofArray a
|
||||
#endif
|
||||
{-# INLINE sizeofSmallArray #-}
|
||||
|
||||
sizeofSmallMutableArray :: SmallMutableArray s a -> Int
|
||||
#if HAVE_SMALL_ARRAY
|
||||
sizeofSmallMutableArray (SmallMutableArray sa#) =
|
||||
I# (sizeofSmallMutableArray# sa#)
|
||||
#else
|
||||
sizeofSmallMutableArray (SmallMutableArray ma) = sizeofMutableArray ma
|
||||
#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
|
||||
|
||||
emptySmallArray :: SmallArray a
|
||||
emptySmallArray =
|
||||
runST $ newSmallArray 0 (die "emptySmallArray" "impossible")
|
||||
>>= unsafeFreezeSmallArray
|
||||
{-# NOINLINE emptySmallArray #-}
|
||||
|
||||
|
||||
infixl 1 ?
|
||||
(?) :: (a -> b -> c) -> (b -> a -> c)
|
||||
(?) = flip
|
||||
{-# INLINE (?) #-}
|
||||
|
||||
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 = 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 sa1 sa2 = smallArrayLiftCompare compare sa1 sa2
|
||||
|
||||
instance Foldable SmallArray where
|
||||
-- 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 #-}
|
||||
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 #-}
|
||||
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 = \ !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 #-}
|
||||
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 = 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) $ do
|
||||
x <- indexSmallArrayM sa i
|
||||
writeSmallArray smb i (f x) *> go (i+1)
|
||||
{-# INLINE fmap #-}
|
||||
|
||||
x <$ sa = createSmallArray (length sa) x noOp
|
||||
|
||||
instance Applicative SmallArray where
|
||||
pure x = createSmallArray 1 x noOp
|
||||
|
||||
sa *> sb = createSmallArray (la*lb) (die "*>" "impossible") $ \smb ->
|
||||
fix ? 0 $ \go i ->
|
||||
when (i < la) $
|
||||
copySmallArray smb 0 sb 0 lb *> go (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
|
||||
|
||||
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
|
||||
|
||||
sl <|> sr =
|
||||
createSmallArray (length sl + length sr) (die "<|>" "impossible") $ \sma ->
|
||||
copySmallArray sma 0 sl 0 (length sl)
|
||||
*> copySmallArray sma (length sl) sr 0 (length sr)
|
||||
|
||||
many sa | null sa = pure []
|
||||
| otherwise = die "many" "infinite arrays are not well defined"
|
||||
|
||||
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 EmptyStack (la-1)
|
||||
where
|
||||
la = length sa
|
||||
collect sz stk i
|
||||
| i < 0 = createSmallArray sz (die ">>=" "impossible") $ fill 0 stk
|
||||
| (# 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 _ EmptyStack _ = return ()
|
||||
fill off (PushArray sb sbs) smb =
|
||||
copySmallArray smb off sb 0 (length sb)
|
||||
*> fill (off + length sb) sbs smb
|
||||
|
||||
fail _ = emptySmallArray
|
||||
|
||||
instance MonadPlus SmallArray where
|
||||
mzero = empty
|
||||
mplus = (<|>)
|
||||
|
||||
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) $ do
|
||||
x <- indexSmallArrayM sa i
|
||||
y <- indexSmallArrayM sb i
|
||||
writeSmallArray mc i (f x y)
|
||||
go (i+1)
|
||||
{-# INLINE zipW #-}
|
||||
|
||||
instance MonadZip SmallArray where
|
||||
mzip = zipW "mzip" (,)
|
||||
mzipWith = zipW "mzipWith"
|
||||
{-# INLINE mzipWith #-}
|
||||
munzip sab = runST $ do
|
||||
let sz = length sab
|
||||
sma <- newSmallArray sz $ die "munzip" "impossible"
|
||||
smb <- newSmallArray sz $ die "munzip" "impossible"
|
||||
fix ? 0 $ \go i ->
|
||||
when (i < sz) $ case indexSmallArray sab i of
|
||||
(x, y) -> do writeSmallArray sma i x
|
||||
writeSmallArray smb i y
|
||||
go $ i+1
|
||||
(,) <$> unsafeFreezeSmallArray sma
|
||||
<*> unsafeFreezeSmallArray smb
|
||||
|
||||
instance MonadFix SmallArray where
|
||||
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
|
||||
#endif
|
||||
|
||||
instance Monoid (SmallArray a) where
|
||||
mempty = empty
|
||||
#if !(MIN_VERSION_base(4,11,0))
|
||||
mappend = (<|>)
|
||||
#endif
|
||||
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 = 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 = 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
|
||||
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]
|
||||
|
||||
fromListConstr :: Constr
|
||||
fromListConstr = mkConstr smallArrayDataType "fromList" [] Prefix
|
||||
|
||||
instance Data a => Data (SmallArray a) where
|
||||
toConstr _ = fromListConstr
|
||||
dataTypeOf _ = smallArrayDataType
|
||||
gunfold k z c = case constrIndex c of
|
||||
1 -> k (z fromList)
|
||||
_ -> die "gunfold" "SmallArray"
|
||||
gfoldl f z m = z fromList `f` toList m
|
||||
|
||||
instance (Typeable s, Typeable a) => Data (SmallMutableArray s a) where
|
||||
toConstr _ = die "toConstr" "SmallMutableArray"
|
||||
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
|
||||
395
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Types.hs
vendored
Normal file
395
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/Types.hs
vendored
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
{-# 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
|
||||
-- License : BSD-style
|
||||
--
|
||||
-- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au>
|
||||
-- Portability : non-portable
|
||||
--
|
||||
-- Basic types and classes for primitive array operations
|
||||
--
|
||||
|
||||
module Data.Primitive.Types (
|
||||
Prim(..),
|
||||
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(..),
|
||||
)
|
||||
import GHC.Float (
|
||||
Float(..), Double(..)
|
||||
)
|
||||
import GHC.Word (
|
||||
Word(..), Word8(..), Word16(..), Word32(..), Word64(..)
|
||||
)
|
||||
import GHC.Int (
|
||||
Int8(..), Int16(..), Int32(..), Int64(..)
|
||||
)
|
||||
|
||||
import GHC.Ptr (
|
||||
Ptr(..), FunPtr(..)
|
||||
)
|
||||
|
||||
import GHC.Prim
|
||||
#if __GLASGOW_HASKELL__ >= 706
|
||||
hiding (setByteArray#)
|
||||
#endif
|
||||
|
||||
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#)
|
||||
|
||||
instance Ord Addr where
|
||||
Addr a# > Addr b# = isTrue# (gtAddr# a# b#)
|
||||
Addr a# >= Addr b# = isTrue# (geAddr# a# b#)
|
||||
Addr a# < Addr b# = isTrue# (ltAddr# a# b#)
|
||||
Addr a# <= Addr b# = isTrue# (leAddr# a# b#)
|
||||
|
||||
instance Data Addr where
|
||||
toConstr _ = error "toConstr"
|
||||
gunfold _ _ = error "gunfold"
|
||||
dataTypeOf _ = mkNoRepType "Data.Primitive.Types.Addr"
|
||||
|
||||
|
||||
-- | Class of types supporting primitive array operations
|
||||
class Prim a where
|
||||
|
||||
-- | Size of values of type @a@. The argument is not used.
|
||||
sizeOf# :: a -> Int#
|
||||
|
||||
-- | Alignment of values of type @a@. The argument is not used.
|
||||
alignment# :: a -> Int#
|
||||
|
||||
-- | Read a value from the array. The offset is in elements of type
|
||||
-- @a@ rather than in bytes.
|
||||
indexByteArray# :: ByteArray# -> Int# -> a
|
||||
|
||||
-- | Read a value from the mutable array. The offset is in elements of type
|
||||
-- @a@ rather than in bytes.
|
||||
readByteArray# :: MutableByteArray# s -> Int# -> State# s -> (# State# s, a #)
|
||||
|
||||
-- | Write a value to the mutable array. The offset is in elements of type
|
||||
-- @a@ rather than in bytes.
|
||||
writeByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> State# s
|
||||
|
||||
-- | Fill a slice of the mutable array with a value. The offset and length
|
||||
-- of the chunk are in elements of type @a@ rather than in bytes.
|
||||
setByteArray# :: MutableByteArray# s -> Int# -> Int# -> a -> State# s -> State# s
|
||||
|
||||
-- | Read a value from a memory position given by an address 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.
|
||||
indexOffAddr# :: Addr# -> Int# -> a
|
||||
|
||||
-- | 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.
|
||||
readOffAddr# :: Addr# -> Int# -> State# s -> (# State# s, a #)
|
||||
|
||||
-- | 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.
|
||||
writeOffAddr# :: Addr# -> Int# -> a -> State# s -> State# s
|
||||
|
||||
-- | Fill a memory block given by an address, an offset and a length.
|
||||
-- The offset and length are in elements of type @a@ rather than in bytes.
|
||||
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 \
|
||||
; alignment# _ = unI# align \
|
||||
; indexByteArray# arr# i# = ctr (idx_arr arr# i#) \
|
||||
; readByteArray# arr# i# s# = case rd_arr arr# i# s# of \
|
||||
{ (# s1#, x# #) -> (# s1#, ctr x# #) } \
|
||||
; writeByteArray# arr# i# (ctr x#) s# = wr_arr arr# i# x# s# \
|
||||
; setByteArray# arr# i# n# (ctr x#) s# \
|
||||
= let { i = fromIntegral (I# i#) \
|
||||
; n = fromIntegral (I# n#) \
|
||||
} in \
|
||||
case unsafeCoerce# (internal (set_arr arr# i n x#)) s# of \
|
||||
{ (# s1#, _ #) -> s1# } \
|
||||
\
|
||||
; indexOffAddr# addr# i# = ctr (idx_addr addr# i#) \
|
||||
; readOffAddr# addr# i# s# = case rd_addr addr# i# s# of \
|
||||
{ (# s1#, x# #) -> (# s1#, ctr x# #) } \
|
||||
; writeOffAddr# addr# i# (ctr x#) s# = wr_addr addr# i# x# s# \
|
||||
; setOffAddr# addr# i# n# (ctr x#) s# \
|
||||
= let { i = fromIntegral (I# i#) \
|
||||
; n = fromIntegral (I# n#) \
|
||||
} in \
|
||||
case unsafeCoerce# (internal (set_addr addr# i n x#)) s# of \
|
||||
{ (# s1#, _ #) -> s1# } \
|
||||
; {-# INLINE sizeOf# #-} \
|
||||
; {-# INLINE alignment# #-} \
|
||||
; {-# INLINE indexByteArray# #-} \
|
||||
; {-# INLINE readByteArray# #-} \
|
||||
; {-# INLINE writeByteArray# #-} \
|
||||
; {-# INLINE setByteArray# #-} \
|
||||
; {-# INLINE indexOffAddr# #-} \
|
||||
; {-# INLINE readOffAddr# #-} \
|
||||
; {-# INLINE writeOffAddr# #-} \
|
||||
; {-# INLINE setOffAddr# #-} \
|
||||
}
|
||||
|
||||
unI# :: Int -> Int#
|
||||
unI# (I# n#) = n#
|
||||
|
||||
derivePrim(Word, W#, sIZEOF_WORD, aLIGNMENT_WORD,
|
||||
indexWordArray#, readWordArray#, writeWordArray#, setWordArray#,
|
||||
indexWordOffAddr#, readWordOffAddr#, writeWordOffAddr#, setWordOffAddr#)
|
||||
derivePrim(Word8, W8#, sIZEOF_WORD8, aLIGNMENT_WORD8,
|
||||
indexWord8Array#, readWord8Array#, writeWord8Array#, setWord8Array#,
|
||||
indexWord8OffAddr#, readWord8OffAddr#, writeWord8OffAddr#, setWord8OffAddr#)
|
||||
derivePrim(Word16, W16#, sIZEOF_WORD16, aLIGNMENT_WORD16,
|
||||
indexWord16Array#, readWord16Array#, writeWord16Array#, setWord16Array#,
|
||||
indexWord16OffAddr#, readWord16OffAddr#, writeWord16OffAddr#, setWord16OffAddr#)
|
||||
derivePrim(Word32, W32#, sIZEOF_WORD32, aLIGNMENT_WORD32,
|
||||
indexWord32Array#, readWord32Array#, writeWord32Array#, setWord32Array#,
|
||||
indexWord32OffAddr#, readWord32OffAddr#, writeWord32OffAddr#, setWord32OffAddr#)
|
||||
derivePrim(Word64, W64#, sIZEOF_WORD64, aLIGNMENT_WORD64,
|
||||
indexWord64Array#, readWord64Array#, writeWord64Array#, setWord64Array#,
|
||||
indexWord64OffAddr#, readWord64OffAddr#, writeWord64OffAddr#, setWord64OffAddr#)
|
||||
derivePrim(Int, I#, sIZEOF_INT, aLIGNMENT_INT,
|
||||
indexIntArray#, readIntArray#, writeIntArray#, setIntArray#,
|
||||
indexIntOffAddr#, readIntOffAddr#, writeIntOffAddr#, setIntOffAddr#)
|
||||
derivePrim(Int8, I8#, sIZEOF_INT8, aLIGNMENT_INT8,
|
||||
indexInt8Array#, readInt8Array#, writeInt8Array#, setInt8Array#,
|
||||
indexInt8OffAddr#, readInt8OffAddr#, writeInt8OffAddr#, setInt8OffAddr#)
|
||||
derivePrim(Int16, I16#, sIZEOF_INT16, aLIGNMENT_INT16,
|
||||
indexInt16Array#, readInt16Array#, writeInt16Array#, setInt16Array#,
|
||||
indexInt16OffAddr#, readInt16OffAddr#, writeInt16OffAddr#, setInt16OffAddr#)
|
||||
derivePrim(Int32, I32#, sIZEOF_INT32, aLIGNMENT_INT32,
|
||||
indexInt32Array#, readInt32Array#, writeInt32Array#, setInt32Array#,
|
||||
indexInt32OffAddr#, readInt32OffAddr#, writeInt32OffAddr#, setInt32OffAddr#)
|
||||
derivePrim(Int64, I64#, sIZEOF_INT64, aLIGNMENT_INT64,
|
||||
indexInt64Array#, readInt64Array#, writeInt64Array#, setInt64Array#,
|
||||
indexInt64OffAddr#, readInt64OffAddr#, writeInt64OffAddr#, setInt64OffAddr#)
|
||||
derivePrim(Float, F#, sIZEOF_FLOAT, aLIGNMENT_FLOAT,
|
||||
indexFloatArray#, readFloatArray#, writeFloatArray#, setFloatArray#,
|
||||
indexFloatOffAddr#, readFloatOffAddr#, writeFloatOffAddr#, setFloatOffAddr#)
|
||||
derivePrim(Double, D#, sIZEOF_DOUBLE, aLIGNMENT_DOUBLE,
|
||||
indexDoubleArray#, readDoubleArray#, writeDoubleArray#, setDoubleArray#,
|
||||
indexDoubleOffAddr#, readDoubleOffAddr#, writeDoubleOffAddr#, setDoubleOffAddr#)
|
||||
derivePrim(Char, C#, sIZEOF_CHAR, aLIGNMENT_CHAR,
|
||||
indexWideCharArray#, readWideCharArray#, writeWideCharArray#, setWideCharArray#,
|
||||
indexWideCharOffAddr#, readWideCharOffAddr#, writeWideCharOffAddr#, setWideCharOffAddr#)
|
||||
derivePrim(Addr, Addr, sIZEOF_PTR, aLIGNMENT_PTR,
|
||||
indexAddrArray#, readAddrArray#, writeAddrArray#, setAddrArray#,
|
||||
indexAddrOffAddr#, readAddrOffAddr#, writeAddrOffAddr#, setAddrOffAddr#)
|
||||
derivePrim(Ptr a, Ptr, sIZEOF_PTR, aLIGNMENT_PTR,
|
||||
indexAddrArray#, readAddrArray#, writeAddrArray#, setAddrArray#,
|
||||
indexAddrOffAddr#, readAddrOffAddr#, writeAddrOffAddr#, setAddrOffAddr#)
|
||||
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
|
||||
638
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/UnliftedArray.hs
vendored
Normal file
638
third_party/bazel/rules_haskell/examples/primitive/Data/Primitive/UnliftedArray.hs
vendored
Normal file
|
|
@ -0,0 +1,638 @@
|
|||
{-# Language BangPatterns #-}
|
||||
{-# Language CPP #-}
|
||||
{-# Language DeriveDataTypeable #-}
|
||||
{-# Language MagicHash #-}
|
||||
{-# Language RankNTypes #-}
|
||||
{-# Language ScopedTypeVariables #-}
|
||||
{-# Language TypeFamilies #-}
|
||||
{-# Language UnboxedTuples #-}
|
||||
|
||||
-- |
|
||||
-- Module : Data.Primitive.UnliftedArray
|
||||
-- Copyright : (c) Dan Doel 2016
|
||||
-- License : BSD-style
|
||||
--
|
||||
-- Maintainer : Libraries <libraries@haskell.org>
|
||||
-- Portability : non-portable
|
||||
--
|
||||
-- GHC contains three general classes of value types:
|
||||
--
|
||||
-- 1. Unboxed types: values are machine values made up of fixed numbers of bytes
|
||||
-- 2. Unlifted types: values are pointers, but strictly evaluated
|
||||
-- 3. Lifted types: values are pointers, lazily evaluated
|
||||
--
|
||||
-- The first category can be stored in a 'ByteArray', and this allows types in
|
||||
-- category 3 that are simple wrappers around category 1 types to be stored
|
||||
-- more efficiently using a 'ByteArray'. This module provides the same facility
|
||||
-- for category 2 types.
|
||||
--
|
||||
-- GHC has two primitive types, 'ArrayArray#' and 'MutableArrayArray#'. These
|
||||
-- are arrays of pointers, but of category 2 values, so they are known to not
|
||||
-- be bottom. This allows types that are wrappers around such types to be stored
|
||||
-- in an array without an extra level of indirection.
|
||||
--
|
||||
-- The way that the 'ArrayArray#' API works is that one can read and write
|
||||
-- 'ArrayArray#' values to the positions. This works because all category 2
|
||||
-- types share a uniform representation, unlike unboxed values which are
|
||||
-- represented by varying (by type) numbers of bytes. However, using the
|
||||
-- this makes the internal API very unsafe to use, as one has to coerce values
|
||||
-- to and from 'ArrayArray#'.
|
||||
--
|
||||
-- The API presented by this module is more type safe. 'UnliftedArray' and
|
||||
-- 'MutableUnliftedArray' are parameterized by the type of arrays they contain, and
|
||||
-- the coercions necessary are abstracted into a class, 'PrimUnlifted', of things
|
||||
-- that are eligible to be stored.
|
||||
|
||||
module Data.Primitive.UnliftedArray
|
||||
( -- * Types
|
||||
UnliftedArray(..)
|
||||
, MutableUnliftedArray(..)
|
||||
, PrimUnlifted(..)
|
||||
-- * Operations
|
||||
, unsafeNewUnliftedArray
|
||||
, newUnliftedArray
|
||||
, setUnliftedArray
|
||||
, sizeofUnliftedArray
|
||||
, sizeofMutableUnliftedArray
|
||||
, readUnliftedArray
|
||||
, writeUnliftedArray
|
||||
, indexUnliftedArray
|
||||
, indexUnliftedArrayM
|
||||
, 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(..),build)
|
||||
|
||||
import Control.Monad.Primitive
|
||||
|
||||
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.
|
||||
data UnliftedArray e = UnliftedArray ArrayArray#
|
||||
deriving (Typeable)
|
||||
|
||||
-- | Mutable 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.
|
||||
data MutableUnliftedArray s e = MutableUnliftedArray (MutableArrayArray# s)
|
||||
deriving (Typeable)
|
||||
|
||||
-- | Classifies the types that are able to be stored in 'UnliftedArray' and
|
||||
-- 'MutableUnliftedArray'. These should be types that are just liftings of the
|
||||
-- unlifted pointer types, so that their internal contents can be safely coerced
|
||||
-- into an 'ArrayArray#'.
|
||||
class PrimUnlifted a where
|
||||
toArrayArray# :: a -> ArrayArray#
|
||||
fromArrayArray# :: ArrayArray# -> a
|
||||
|
||||
instance PrimUnlifted (UnliftedArray e) where
|
||||
toArrayArray# (UnliftedArray aa#) = aa#
|
||||
fromArrayArray# aa# = UnliftedArray aa#
|
||||
|
||||
instance PrimUnlifted (MutableUnliftedArray s e) where
|
||||
toArrayArray# (MutableUnliftedArray maa#) = unsafeCoerce# maa#
|
||||
fromArrayArray# aa# = MutableUnliftedArray (unsafeCoerce# aa#)
|
||||
|
||||
instance PrimUnlifted (Array a) where
|
||||
toArrayArray# (A.Array a#) = unsafeCoerce# a#
|
||||
fromArrayArray# aa# = A.Array (unsafeCoerce# aa#)
|
||||
|
||||
instance PrimUnlifted (A.MutableArray s a) where
|
||||
toArrayArray# (A.MutableArray ma#) = unsafeCoerce# ma#
|
||||
fromArrayArray# aa# = A.MutableArray (unsafeCoerce# aa#)
|
||||
|
||||
instance PrimUnlifted ByteArray where
|
||||
toArrayArray# (BA.ByteArray ba#) = unsafeCoerce# ba#
|
||||
fromArrayArray# aa# = BA.ByteArray (unsafeCoerce# aa#)
|
||||
|
||||
instance PrimUnlifted (BA.MutableByteArray s) where
|
||||
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#)
|
||||
|
||||
instance PrimUnlifted (SA.SmallMutableArray s a) where
|
||||
toArrayArray# (SA.SmallMutableArray sma#) = unsafeCoerce# sma#
|
||||
fromArrayArray# aa# = SA.SmallMutableArray (unsafeCoerce# aa#)
|
||||
|
||||
instance PrimUnlifted (MV.MutVar s a) where
|
||||
toArrayArray# (MV.MutVar mv#) = unsafeCoerce# mv#
|
||||
fromArrayArray# aa# = MV.MutVar (unsafeCoerce# aa#)
|
||||
|
||||
-- | @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
|
||||
-> m (MutableUnliftedArray (PrimState m) a)
|
||||
unsafeNewUnliftedArray (I# i#) = primitive $ \s -> case newArrayArray# i# s of
|
||||
(# s', maa# #) -> (# s', MutableUnliftedArray maa# #)
|
||||
{-# inline unsafeNewUnliftedArray #-}
|
||||
|
||||
-- | Sets all the positions in an unlifted array to the designated value.
|
||||
setUnliftedArray
|
||||
:: (PrimMonad m, PrimUnlifted a)
|
||||
=> MutableUnliftedArray (PrimState m) a -- ^ destination
|
||||
-> a -- ^ value to fill with
|
||||
-> m ()
|
||||
setUnliftedArray mua v = loop $ sizeofMutableUnliftedArray mua - 1
|
||||
where
|
||||
loop i | i < 0 = return ()
|
||||
| otherwise = writeUnliftedArray mua i v >> loop (i-1)
|
||||
{-# inline setUnliftedArray #-}
|
||||
|
||||
-- | Creates a new 'MutableUnliftedArray' with the specified value as initial
|
||||
-- contents. This is slower than 'unsafeNewUnliftedArray', but safer.
|
||||
newUnliftedArray
|
||||
:: (PrimMonad m, PrimUnlifted a)
|
||||
=> Int -- ^ size
|
||||
-> a -- ^ initial value
|
||||
-> m (MutableUnliftedArray (PrimState m) a)
|
||||
newUnliftedArray len v =
|
||||
unsafeNewUnliftedArray len >>= \mua -> setUnliftedArray mua v >> return mua
|
||||
{-# inline newUnliftedArray #-}
|
||||
|
||||
-- | Yields the length of an 'UnliftedArray'.
|
||||
sizeofUnliftedArray :: UnliftedArray e -> Int
|
||||
sizeofUnliftedArray (UnliftedArray aa#) = I# (sizeofArrayArray# aa#)
|
||||
{-# inline sizeofUnliftedArray #-}
|
||||
|
||||
-- | Yields the length of a 'MutableUnliftedArray'.
|
||||
sizeofMutableUnliftedArray :: MutableUnliftedArray s e -> Int
|
||||
sizeofMutableUnliftedArray (MutableUnliftedArray maa#)
|
||||
= I# (sizeofMutableArrayArray# maa#)
|
||||
{-# inline sizeofMutableUnliftedArray #-}
|
||||
|
||||
-- Internal indexing function.
|
||||
--
|
||||
-- Note: ArrayArray# is strictly evaluated, so this should have similar
|
||||
-- consequences to indexArray#, where matching on the unboxed single causes the
|
||||
-- array access to happen.
|
||||
indexUnliftedArrayU
|
||||
:: PrimUnlifted a
|
||||
=> UnliftedArray a
|
||||
-> Int
|
||||
-> (# a #)
|
||||
indexUnliftedArrayU (UnliftedArray src#) (I# i#)
|
||||
= case indexArrayArrayArray# src# i# of
|
||||
aa# -> (# fromArrayArray# aa# #)
|
||||
{-# inline indexUnliftedArrayU #-}
|
||||
|
||||
-- | Gets the value at the specified position of an 'UnliftedArray'.
|
||||
indexUnliftedArray
|
||||
:: PrimUnlifted a
|
||||
=> UnliftedArray a -- ^ source
|
||||
-> Int -- ^ index
|
||||
-> a
|
||||
indexUnliftedArray ua i
|
||||
= case indexUnliftedArrayU ua i of (# v #) -> v
|
||||
{-# inline indexUnliftedArray #-}
|
||||
|
||||
-- | Gets the value at the specified position of an 'UnliftedArray'.
|
||||
-- The purpose of the 'Monad' is to allow for being eager in the
|
||||
-- 'UnliftedArray' value without having to introduce a data dependency
|
||||
-- directly on the result value.
|
||||
--
|
||||
-- It should be noted that this is not as much of a problem as with a normal
|
||||
-- 'Array', because elements of an 'UnliftedArray' are guaranteed to not
|
||||
-- be exceptional. This function is provided in case it is more desirable
|
||||
-- than being strict in the result value.
|
||||
indexUnliftedArrayM
|
||||
:: (PrimUnlifted a, Monad m)
|
||||
=> UnliftedArray a -- ^ source
|
||||
-> Int -- ^ index
|
||||
-> m a
|
||||
indexUnliftedArrayM ua i
|
||||
= case indexUnliftedArrayU ua i of
|
||||
(# v #) -> return v
|
||||
{-# inline indexUnliftedArrayM #-}
|
||||
|
||||
-- | Gets the value at the specified position of a 'MutableUnliftedArray'.
|
||||
readUnliftedArray
|
||||
:: (PrimMonad m, PrimUnlifted a)
|
||||
=> MutableUnliftedArray (PrimState m) a -- ^ source
|
||||
-> Int -- ^ index
|
||||
-> m a
|
||||
readUnliftedArray (MutableUnliftedArray maa#) (I# i#)
|
||||
= primitive $ \s -> case readArrayArrayArray# maa# i# s of
|
||||
(# s', aa# #) -> (# s', fromArrayArray# aa# #)
|
||||
{-# inline readUnliftedArray #-}
|
||||
|
||||
-- | Sets the value at the specified position of a 'MutableUnliftedArray'.
|
||||
writeUnliftedArray
|
||||
:: (PrimMonad m, PrimUnlifted a)
|
||||
=> MutableUnliftedArray (PrimState m) a -- ^ destination
|
||||
-> Int -- ^ index
|
||||
-> a -- ^ value
|
||||
-> m ()
|
||||
writeUnliftedArray (MutableUnliftedArray maa#) (I# i#) a
|
||||
= primitive_ (writeArrayArrayArray# maa# i# (toArrayArray# a))
|
||||
{-# inline writeUnliftedArray #-}
|
||||
|
||||
-- | Freezes a 'MutableUnliftedArray', yielding an 'UnliftedArray'. This simply
|
||||
-- marks the array as frozen in place, so it should only be used when no further
|
||||
-- modifications to the mutable array will be performed.
|
||||
unsafeFreezeUnliftedArray
|
||||
:: (PrimMonad m)
|
||||
=> MutableUnliftedArray (PrimState m) a
|
||||
-> m (UnliftedArray a)
|
||||
unsafeFreezeUnliftedArray (MutableUnliftedArray maa#)
|
||||
= primitive $ \s -> case unsafeFreezeArrayArray# maa# s of
|
||||
(# s', aa# #) -> (# s', UnliftedArray aa# #)
|
||||
{-# inline unsafeFreezeUnliftedArray #-}
|
||||
|
||||
-- | Determines whether two 'MutableUnliftedArray' values are the same. This is
|
||||
-- object/pointer identity, not based on the contents.
|
||||
sameMutableUnliftedArray
|
||||
:: MutableUnliftedArray s a
|
||||
-> MutableUnliftedArray s a
|
||||
-> Bool
|
||||
sameMutableUnliftedArray (MutableUnliftedArray maa1#) (MutableUnliftedArray maa2#)
|
||||
= isTrue# (sameMutableArrayArray# maa1# maa2#)
|
||||
{-# inline sameMutableUnliftedArray #-}
|
||||
|
||||
-- | Copies the contents of an immutable array into a mutable array.
|
||||
copyUnliftedArray
|
||||
:: (PrimMonad m)
|
||||
=> MutableUnliftedArray (PrimState m) a -- ^ destination
|
||||
-> Int -- ^ offset into destination
|
||||
-> UnliftedArray a -- ^ source
|
||||
-> Int -- ^ offset into source
|
||||
-> Int -- ^ number of elements to copy
|
||||
-> m ()
|
||||
copyUnliftedArray
|
||||
(MutableUnliftedArray dst) (I# doff)
|
||||
(UnliftedArray src) (I# soff) (I# ln) =
|
||||
primitive_ $ copyArrayArray# src soff dst doff ln
|
||||
{-# inline copyUnliftedArray #-}
|
||||
|
||||
-- | Copies the contents of one mutable array into another.
|
||||
copyMutableUnliftedArray
|
||||
:: (PrimMonad m)
|
||||
=> MutableUnliftedArray (PrimState m) a -- ^ destination
|
||||
-> Int -- ^ offset into destination
|
||||
-> MutableUnliftedArray (PrimState m) a -- ^ source
|
||||
-> Int -- ^ offset into source
|
||||
-> Int -- ^ number of elements to copy
|
||||
-> m ()
|
||||
copyMutableUnliftedArray
|
||||
(MutableUnliftedArray dst) (I# doff)
|
||||
(MutableUnliftedArray src) (I# soff) (I# ln) =
|
||||
primitive_ $ copyMutableArrayArray# src soff dst doff ln
|
||||
{-# inline copyMutableUnliftedArray #-}
|
||||
|
||||
-- | Freezes a portion of a 'MutableUnliftedArray', yielding an 'UnliftedArray'.
|
||||
-- This operation is safe, in that it copies the frozen portion, and the
|
||||
-- existing mutable array may still be used afterward.
|
||||
freezeUnliftedArray
|
||||
:: (PrimMonad m)
|
||||
=> MutableUnliftedArray (PrimState m) a -- ^ source
|
||||
-> Int -- ^ offset
|
||||
-> Int -- ^ length
|
||||
-> m (UnliftedArray a)
|
||||
freezeUnliftedArray src off len = do
|
||||
dst <- unsafeNewUnliftedArray len
|
||||
copyMutableUnliftedArray dst 0 src off len
|
||||
unsafeFreezeUnliftedArray dst
|
||||
{-# inline freezeUnliftedArray #-}
|
||||
|
||||
-- | Thaws a portion of an 'UnliftedArray', yielding a 'MutableUnliftedArray'.
|
||||
-- This copies the thawed portion, so mutations will not affect the original
|
||||
-- array.
|
||||
thawUnliftedArray
|
||||
:: (PrimMonad m)
|
||||
=> UnliftedArray a -- ^ source
|
||||
-> Int -- ^ offset
|
||||
-> Int -- ^ length
|
||||
-> m (MutableUnliftedArray (PrimState m) a)
|
||||
thawUnliftedArray src off len = do
|
||||
dst <- unsafeNewUnliftedArray len
|
||||
copyUnliftedArray dst 0 src off len
|
||||
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
|
||||
-> Int -- ^ offset
|
||||
-> Int -- ^ length
|
||||
-> UnliftedArray a
|
||||
cloneUnliftedArray src off len =
|
||||
runUnliftedArray (thawUnliftedArray src off len)
|
||||
{-# inline cloneUnliftedArray #-}
|
||||
|
||||
-- | Creates a new 'MutableUnliftedArray' containing a copy of a portion of
|
||||
-- another mutable array.
|
||||
cloneMutableUnliftedArray
|
||||
:: (PrimMonad m)
|
||||
=> MutableUnliftedArray (PrimState m) a -- ^ source
|
||||
-> Int -- ^ offset
|
||||
-> Int -- ^ length
|
||||
-> m (MutableUnliftedArray (PrimState m) a)
|
||||
cloneMutableUnliftedArray src off len = do
|
||||
dst <- unsafeNewUnliftedArray len
|
||||
copyMutableUnliftedArray dst 0 src off len
|
||||
return dst
|
||||
{-# inline cloneMutableUnliftedArray #-}
|
||||
|
||||
instance Eq (MutableUnliftedArray s a) where
|
||||
(==) = sameMutableUnliftedArray
|
||||
|
||||
instance (Eq a, PrimUnlifted a) => Eq (UnliftedArray a) where
|
||||
aa1 == aa2 = sizeofUnliftedArray aa1 == sizeofUnliftedArray aa2
|
||||
&& loop (sizeofUnliftedArray aa1 - 1)
|
||||
where
|
||||
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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue