primitive-0.9.0.0: Data/Primitive/ByteArray.hs
{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples, UnliftedFFITypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE RankNTypes #-}
-- |
-- 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 byte arrays. Most functions in this module include
-- an element type in their type signature and interpret the unit for offsets
-- and lengths as that element. A few functions (e.g. 'copyByteArray',
-- 'freezeByteArray') do not include an element type. Such functions
-- interpret offsets and lengths as units of 8-bit words.
module Data.Primitive.ByteArray (
-- * Types
ByteArray(..), MutableByteArray(..), ByteArray#, MutableByteArray#,
-- * Allocation
newByteArray, newPinnedByteArray, newAlignedPinnedByteArray,
resizeMutableByteArray,
shrinkMutableByteArray,
-- * Element access
readByteArray, writeByteArray, indexByteArray,
-- * Char Element Access
-- $charElementAccess
readCharArray, writeCharArray, indexCharArray,
-- * Constructing
emptyByteArray,
byteArrayFromList, byteArrayFromListN,
-- * Folding
foldrByteArray,
-- * Comparing
compareByteArrays,
-- * Freezing and thawing
freezeByteArray, thawByteArray, runByteArray,
unsafeFreezeByteArray, unsafeThawByteArray,
-- * Block operations
copyByteArray, copyMutableByteArray,
copyByteArrayToPtr, copyMutableByteArrayToPtr,
copyByteArrayToAddr, copyMutableByteArrayToAddr,
copyPtrToMutableByteArray,
moveByteArray,
setByteArray, fillByteArray,
cloneByteArray, cloneMutableByteArray,
-- * Information
sizeofByteArray,
sizeofMutableByteArray, getSizeofMutableByteArray, sameMutableByteArray,
#if __GLASGOW_HASKELL__ >= 802
isByteArrayPinned, isMutableByteArrayPinned,
#endif
byteArrayContents,
withByteArrayContents,
mutableByteArrayContents,
withMutableByteArrayContents
) where
import Control.Monad.Primitive
import Control.Monad.ST
import Data.Primitive.Types
import Data.Proxy
#if MIN_VERSION_base(4,10,0)
import qualified GHC.ST as GHCST
#endif
import Foreign.C.Types
import Data.Word ( Word8 )
#if __GLASGOW_HASKELL__ >= 802
import qualified GHC.Exts as Exts
#endif
import GHC.Exts hiding (setByteArray#)
#if __GLASGOW_HASKELL__ < 804
import System.IO.Unsafe (unsafeDupablePerformIO)
#endif
import Data.Array.Byte (ByteArray(..), MutableByteArray(..))
import Data.Primitive.Internal.Operations (mutableByteArrayContentsShim)
-- | Create a new mutable byte array of the specified size in bytes.
-- The underlying memory is left uninitialized.
--
-- /Note:/ this function does not check if the input is non-negative.
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. The underlying memory is left uninitialized.
--
-- /Note:/ this function does not check if the input is non-negative.
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.
-- The underlying memory is left uninitialized.
--
-- /Note:/ this function does not check if the input is non-negative.
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. Byte arrays allocated by 'newPinnedByteArray' and
-- 'newAlignedPinnedByteArray' are guaranteed to be pinned. Byte arrays
-- allocated by 'newByteArray' may or may not be pinned (use
-- 'isByteArrayPinned' to figure out).
--
-- Prefer 'withByteArrayContents', which ensures that the array is not
-- garbage collected while the pointer is being used.
byteArrayContents :: ByteArray -> Ptr Word8
{-# INLINE byteArrayContents #-}
byteArrayContents (ByteArray arr#) = Ptr (byteArrayContents# arr#)
-- | A composition of 'byteArrayContents' and 'keepAliveUnlifted'.
-- The callback function must not return the pointer. The argument byte
-- array must be /pinned/. See 'byteArrayContents' for an explanation
-- of which byte arrays are pinned.
--
-- Note: This could be implemented with 'keepAlive' instead of
-- 'keepAliveUnlifted', but 'keepAlive' here would cause GHC to materialize
-- the wrapper data constructor on the heap.
withByteArrayContents :: PrimBase m => ByteArray -> (Ptr Word8 -> m a) -> m a
{-# INLINE withByteArrayContents #-}
withByteArrayContents (ByteArray arr#) f =
keepAliveUnlifted arr# (f (Ptr (byteArrayContents# arr#)))
-- | Yield a pointer to the array's data. This operation is only safe on
-- /pinned/ byte arrays. See 'byteArrayContents' for an explanation
-- of which byte arrays are pinned.
--
-- Prefer 'withByteArrayContents', which ensures that the array is not
-- garbage collected while the pointer is being used.
mutableByteArrayContents :: MutableByteArray s -> Ptr Word8
{-# INLINE mutableByteArrayContents #-}
mutableByteArrayContents (MutableByteArray arr#) = Ptr (mutableByteArrayContentsShim arr#)
-- | A composition of 'mutableByteArrayContents' and 'keepAliveUnlifted'.
-- The callback function must not return the pointer. The argument byte
-- array must be /pinned/. See 'byteArrayContents' for an explanation
-- of which byte arrays are pinned.
withMutableByteArrayContents :: PrimBase m => MutableByteArray (PrimState m) -> (Ptr Word8 -> m a) -> m a
{-# INLINE withMutableByteArrayContents #-}
withMutableByteArrayContents (MutableByteArray arr#) f =
keepAliveUnlifted arr# (f (Ptr (mutableByteArrayContentsShim 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 #-}
resizeMutableByteArray (MutableByteArray arr#) (I# n#)
= primitive (\s# -> case resizeMutableByteArray# arr# n# s# of
(# s'#, arr'# #) -> (# s'#, MutableByteArray arr'# #))
-- | 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
-- | Create an immutable copy of a slice of a byte array. The offset and
-- length are given in bytes.
--
-- This operation makes a copy of the specified section, so it is safe to
-- continue using the mutable array afterward.
--
-- /Note:/ The provided array should contain the full subrange
-- specified by the two Ints, but this is not checked.
freezeByteArray
:: PrimMonad m
=> MutableByteArray (PrimState m) -- ^ source
-> Int -- ^ offset in bytes
-> Int -- ^ length in bytes
-> m ByteArray
{-# INLINE freezeByteArray #-}
freezeByteArray !src !off !len = do
dst <- newByteArray len
copyMutableByteArray dst 0 src off len
unsafeFreezeByteArray dst
-- | Create a mutable byte array from a slice of an immutable byte array.
-- The offset and length are given in bytes.
--
-- This operation makes a copy of the specified slice, so it is safe to
-- use the immutable array afterward.
--
-- /Note:/ The provided array should contain the full subrange
-- specified by the two Ints, but this is not checked.
--
-- @since 0.7.2.0
thawByteArray
:: PrimMonad m
=> ByteArray -- ^ source
-> Int -- ^ offset in bytes
-> Int -- ^ length in bytes
-> m (MutableByteArray (PrimState m))
{-# INLINE thawByteArray #-}
thawByteArray !src !off !len = do
dst <- newByteArray len
copyByteArray dst 0 src off len
return dst
-- | 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 is deprecated and will be removed. Its behavior
-- is undefined if 'resizeMutableByteArray' is ever called on the mutable
-- byte array given as the argument. Prefer 'getSizeofMutableByteArray',
-- which ensures correct sequencing in the presence of resizing.
sizeofMutableByteArray :: MutableByteArray s -> Int
{-# INLINE sizeofMutableByteArray #-}
{-# DEPRECATED sizeofMutableByteArray "use getSizeofMutableByteArray instead" #-}
sizeofMutableByteArray (MutableByteArray arr#) = I# (sizeofMutableByteArray# arr#)
-- | Shrink a mutable byte array. The new size is given in bytes.
-- It must be smaller than the old size. The array will be resized in place.
--
-- @since 0.7.1.0
shrinkMutableByteArray :: PrimMonad m
=> MutableByteArray (PrimState m)
-> Int -- ^ new size
-> m ()
{-# INLINE shrinkMutableByteArray #-}
shrinkMutableByteArray (MutableByteArray arr#) (I# n#)
= primitive_ (shrinkMutableByteArray# arr# n#)
#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.
--
-- Caution: 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.
--
-- Caution: 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.
--
-- /Note:/ this function does not do bounds checking.
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.
--
-- /Note:/ this function does not do bounds checking.
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.
--
-- /Note:/ this function does not do bounds checking.
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
{-# INLINE foldrByteArray #-}
foldrByteArray f z arr = go 0
where
go i
| i < maxI = f (indexByteArray arr i) (go (i + 1))
| otherwise = z
maxI = sizeofByteArray arr `quot` sizeOfType @a
-- | Create a 'ByteArray' from a list.
--
-- @byteArrayFromList xs = `byteArrayFromListN` (length xs) xs@
byteArrayFromList :: Prim a => [a] -> ByteArray
byteArrayFromList xs = byteArrayFromListN (length xs) xs
-- | Create a 'ByteArray' from a list of a known length. If the length
-- of the list does not match the given length, this throws an exception.
byteArrayFromListN :: forall a. Prim a => Int -> [a] -> ByteArray
byteArrayFromListN n ys = runST $ do
marr <- newByteArray (n * sizeOfType @a)
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.
--
-- /Note:/ this function does not do bounds or overlap checking.
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.
--
-- /Note:/ this function does not do bounds or overlap checking.
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))
-- | Copy a slice of a byte array to an unmanaged pointer address. These must not
-- overlap. The offset and length are given in elements, not in bytes.
--
-- /Note:/ this function does not do bounds or overlap checking.
--
-- @since 0.7.1.0
copyByteArrayToPtr
:: forall m a. (PrimMonad m, Prim a)
=> Ptr a -- ^ destination
-> ByteArray -- ^ source array
-> Int -- ^ offset into source array, interpreted as elements of type @a@
-> Int -- ^ number of elements to copy
-> m ()
{-# INLINE copyByteArrayToPtr #-}
copyByteArrayToPtr (Ptr dst#) (ByteArray src#) soff sz
= primitive_ (copyByteArrayToAddr# src# (unI# soff *# siz#) dst# (unI# sz *# siz#))
where
siz# = sizeOfType# (Proxy :: Proxy a)
-- | Copy from an unmanaged pointer address to a byte array. These must not
-- overlap. The offset and length are given in elements, not in bytes.
--
-- /Note:/ this function does not do bounds or overlap checking.
copyPtrToMutableByteArray :: forall m a. (PrimMonad m, Prim a)
=> MutableByteArray (PrimState m) -- ^ destination array
-> Int -- ^ destination offset given in elements of type @a@
-> Ptr a -- ^ source pointer
-> Int -- ^ number of elements
-> m ()
{-# INLINE copyPtrToMutableByteArray #-}
copyPtrToMutableByteArray (MutableByteArray ba#) (I# doff#) (Ptr addr#) (I# n#) =
primitive_ (copyAddrToByteArray# addr# ba# (doff# *# siz#) (n# *# siz#))
where
siz# = sizeOfType# (Proxy :: Proxy a)
-- | Copy a slice of a mutable byte array to an unmanaged pointer address.
-- These must not overlap. The offset and length are given in elements, not
-- in bytes.
--
-- /Note:/ this function does not do bounds or overlap checking.
--
-- @since 0.7.1.0
copyMutableByteArrayToPtr
:: forall m a. (PrimMonad m, Prim a)
=> Ptr a -- ^ destination
-> MutableByteArray (PrimState m) -- ^ source array
-> Int -- ^ offset into source array, interpreted as elements of type @a@
-> Int -- ^ number of elements to copy
-> m ()
{-# INLINE copyMutableByteArrayToPtr #-}
copyMutableByteArrayToPtr (Ptr dst#) (MutableByteArray src#) soff sz
= primitive_ (copyMutableByteArrayToAddr# src# (unI# soff *# siz#) dst# (unI# sz *# siz#))
where
siz# = sizeOfType# (Proxy :: Proxy a)
------
--- These latter two should be DEPRECATED
-----
-- | Copy a slice of a byte array to an unmanaged address. These must not
-- overlap.
--
-- Note: This function is just 'copyByteArrayToPtr' where @a@ is 'Word8'.
--
-- @since 0.6.4.0
copyByteArrayToAddr
:: PrimMonad m
=> Ptr Word8 -- ^ destination
-> ByteArray -- ^ source array
-> Int -- ^ offset into source array
-> Int -- ^ number of bytes to copy
-> m ()
{-# INLINE copyByteArrayToAddr #-}
copyByteArrayToAddr (Ptr 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.
--
-- Note: This function is just 'copyMutableByteArrayToPtr' where @a@ is 'Word8'.
--
-- @since 0.6.4.0
copyMutableByteArrayToAddr
:: PrimMonad m
=> Ptr Word8 -- ^ destination
-> MutableByteArray (PrimState m) -- ^ source array
-> Int -- ^ offset into source array
-> Int -- ^ number of bytes to copy
-> m ()
{-# INLINE copyMutableByteArrayToAddr #-}
copyMutableByteArrayToAddr (Ptr dst#) (MutableByteArray src#) soff sz
= primitive_ (copyMutableByteArrayToAddr# src# (unI# soff) dst# (unI# sz))
-- | 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.
--
-- /Note:/ this function does not do bounds checking.
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.
--
-- /Note:/ this function does not do bounds checking.
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 -> CPtrdiff
-> MutableByteArray# s -> CPtrdiff
-> CSize -> IO ()
-- | Lexicographic comparison of equal-length slices into two byte arrays.
-- This wraps the @compareByteArrays#@ primop, which wraps @memcmp@.
compareByteArrays
:: ByteArray -- ^ array A
-> Int -- ^ offset A, given in bytes
-> ByteArray -- ^ array B
-> Int -- ^ offset B, given in bytes
-> Int -- ^ length of the slice, given in bytes
-> Ordering
{-# INLINE compareByteArrays #-}
#if __GLASGOW_HASKELL__ >= 804
compareByteArrays (ByteArray ba1#) (I# off1#) (ByteArray ba2#) (I# off2#) (I# n#)
= compare (I# (compareByteArrays# ba1# off1# ba2# off2# n#)) 0
#else
-- Emulate GHC 8.4's 'GHC.Prim.compareByteArrays#'
compareByteArrays (ByteArray ba1#) (I# off1#) (ByteArray ba2#) (I# off2#) (I# n#)
= compare (fromCInt (unsafeDupablePerformIO (memcmp_ba_offs ba1# off1# ba2# off2# n))) 0
where
n = fromIntegral (I# n#) :: CSize
fromCInt = fromIntegral :: CInt -> Int
foreign import ccall unsafe "primitive-memops.h hsprimitive_memcmp_offset"
memcmp_ba_offs :: ByteArray# -> Int# -> ByteArray# -> Int# -> CSize -> IO CInt
#endif
-- | The empty 'ByteArray'.
emptyByteArray :: ByteArray
{-# NOINLINE emptyByteArray #-}
emptyByteArray = runST (newByteArray 0 >>= unsafeFreezeByteArray)
die :: String -> String -> a
die fun problem = error $ "Data.Primitive.ByteArray." ++ fun ++ ": " ++ problem
-- | 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.
cloneByteArray
:: ByteArray -- ^ source array
-> Int -- ^ offset into destination array
-> Int -- ^ number of bytes to copy
-> ByteArray
{-# INLINE cloneByteArray #-}
cloneByteArray src off n = runByteArray $ do
dst <- newByteArray n
copyByteArray dst 0 src off n
return dst
-- | Return a newly allocated mutable array with the specified subrange of
-- the provided mutable array. The provided mutable array should contain the
-- full subrange specified by the two Ints, but this is not checked.
cloneMutableByteArray :: PrimMonad m
=> MutableByteArray (PrimState m) -- ^ source array
-> Int -- ^ offset into destination array
-> Int -- ^ number of bytes to copy
-> m (MutableByteArray (PrimState m))
{-# INLINE cloneMutableByteArray #-}
cloneMutableByteArray src off n = do
dst <- newByteArray n
copyMutableByteArray dst 0 src off n
return dst
-- | Execute the monadic action and freeze the resulting array.
--
-- > runByteArray m = runST $ m >>= unsafeFreezeByteArray
runByteArray
:: (forall s. ST s (MutableByteArray s))
-> ByteArray
#if MIN_VERSION_base(4,10,0) /* In new GHCs, runRW# is available. */
runByteArray m = ByteArray (runByteArray# m)
runByteArray#
:: (forall s. ST s (MutableByteArray s))
-> ByteArray#
runByteArray# m = case runRW# $ \s ->
case unST m s of { (# s', MutableByteArray mary# #) ->
unsafeFreezeByteArray# mary# s'} of (# _, ary# #) -> ary#
unST :: ST s a -> State# s -> (# State# s, a #)
unST (GHCST.ST f) = f
#else /* In older GHCs, runRW# is not available. */
runByteArray m = runST $ m >>= unsafeFreezeByteArray
#endif
{- $charElementAccess
GHC provides two sets of element accessors for 'Char'. One set faithfully
represents 'Char' as 32-bit words using UTF-32. The other set represents
'Char' as 8-bit words using Latin-1 (ISO-8859-1), and the write operation
has undefined behavior for codepoints outside of the ASCII and Latin-1
blocks. The 'Prim' instance for 'Char' uses the UTF-32 set of operators.
-}
-- | Read an 8-bit element from the byte array, interpreting it as a
-- Latin-1-encoded character. The offset is given in bytes.
--
-- /Note:/ this function does not do bounds checking.
readCharArray :: PrimMonad m => MutableByteArray (PrimState m) -> Int -> m Char
{-# INLINE readCharArray #-}
readCharArray (MutableByteArray arr#) (I# i#) = primitive
(\s0 -> case readCharArray# arr# i# s0 of
(# s1, c #) -> (# s1, C# c #)
)
-- | Write a character to the byte array, encoding it with Latin-1 as
-- a single byte. Behavior is undefined for codepoints outside of the
-- ASCII and Latin-1 blocks. The offset is given in bytes.
--
-- /Note:/ this function does not do bounds checking.
writeCharArray
:: PrimMonad m => MutableByteArray (PrimState m) -> Int -> Char -> m ()
{-# INLINE writeCharArray #-}
writeCharArray (MutableByteArray arr#) (I# i#) (C# c)
= primitive_ (writeCharArray# arr# i# c)
-- | Read an 8-bit element from the byte array, interpreting it as a
-- Latin-1-encoded character. The offset is given in bytes.
--
-- /Note:/ this function does not do bounds checking.
indexCharArray :: ByteArray -> Int -> Char
{-# INLINE indexCharArray #-}
indexCharArray (ByteArray arr#) (I# i#) = C# (indexCharArray# arr# i#)