primitive-checked-0.7.2.0: src/Data/Primitive/PrimArray.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Data.Primitive.PrimArray
( -- * Types
PrimArray(..)
, MutablePrimArray(..)
-- * Allocation
, newPrimArray
, newPinnedPrimArray
, newAlignedPinnedPrimArray
, resizeMutablePrimArray
, shrinkMutablePrimArray
-- * Element Access
, readPrimArray
, writePrimArray
, indexPrimArray
-- * Freezing and Thawing
, freezePrimArray
, thawPrimArray
, unsafeFreezePrimArray
, A.unsafeThawPrimArray
-- * Block Operations
, copyPrimArray
, copyMutablePrimArray
, copyPrimArrayToPtr
, copyMutablePrimArrayToPtr
, clonePrimArray
, cloneMutablePrimArray
, setPrimArray
-- * Information
, A.sameMutablePrimArray
, A.getSizeofMutablePrimArray
, A.sizeofMutablePrimArray
, A.sizeofPrimArray
, A.primArrayContents
, A.mutablePrimArrayContents
, A.isPrimArrayPinned
, A.isMutablePrimArrayPinned
-- * List Conversion
, A.primArrayToList
, A.primArrayFromList
, A.primArrayFromListN
-- * Folding
, A.foldrPrimArray
, A.foldrPrimArray'
, A.foldlPrimArray
, A.foldlPrimArray'
, A.foldlPrimArrayM'
-- * Effectful Folding
, A.traversePrimArray_
, A.itraversePrimArray_
-- * Map/Create
, A.mapPrimArray
, A.imapPrimArray
, A.generatePrimArray
, A.replicatePrimArray
, A.filterPrimArray
, A.mapMaybePrimArray
-- * Effectful Map/Create
-- ** Lazy Applicative
, A.traversePrimArray
, A.itraversePrimArray
, A.generatePrimArrayA
, A.replicatePrimArrayA
, A.filterPrimArrayA
, A.mapMaybePrimArrayA
-- ** Strict Primitive Monadic
, A.traversePrimArrayP
, A.itraversePrimArrayP
, A.generatePrimArrayP
, A.replicatePrimArrayP
, A.filterPrimArrayP
, A.mapMaybePrimArrayP
) where
import Control.Monad.Primitive (PrimMonad, PrimState)
import Control.Exception (throw, ArrayException(..))
import Data.Primitive.Types (Prim, Ptr, sizeOf)
import Data.Word (Word8)
import "primitive" Data.Primitive.PrimArray (PrimArray, MutablePrimArray)
import qualified "primitive" Data.Primitive.PrimArray as A
import GHC.Stack
import qualified Data.List as L
check :: HasCallStack => String -> Bool -> a -> a
check _ True x = x
check errMsg False _ = throw (IndexOutOfBounds $ "Data.Primitive.PrimArray." ++ errMsg ++ "\n" ++ prettyCallStack callStack)
newPrimArray :: forall m a. (HasCallStack, PrimMonad m, Prim a) => Int -> m (MutablePrimArray (PrimState m) a)
newPrimArray n =
check "newPrimArray: negative size" (n >= 0)
$ check ("newPrimArray: requested " ++ show n ++ " elements of size " ++ show elemSz) (n * elemSz < 1024*1024*1024)
$ A.newPrimArray n
where
elemSz = sizeOf (undefined :: a)
newPinnedPrimArray :: forall m a. (HasCallStack, PrimMonad m, Prim a) => Int -> m (MutablePrimArray (PrimState m) a)
newPinnedPrimArray n =
check "newPinnedPrimArray: negative size" (n >= 0)
$ check ("newPinnedPrimArray: requested " ++ show n ++ " elements of size " ++ show elemSz) (n * elemSz < 1024*1024*1024)
$ A.newPinnedPrimArray n
where
elemSz = sizeOf (undefined :: a)
newAlignedPinnedPrimArray :: forall m a. (HasCallStack, PrimMonad m, Prim a) => Int -> m (MutablePrimArray (PrimState m) a)
newAlignedPinnedPrimArray n =
check "newAlignedPinnedPrimArray: negative size" (n >= 0)
$ check ("newAlignedPinnedPrimArray: requested " ++ show n ++ " elements of size " ++ show elemSz) (n * elemSz < 1024*1024*1024)
$ A.newAlignedPinnedPrimArray n
where
elemSz = sizeOf (undefined :: a)
-- | After a call to resizeMutablePrimArray, the original reference to
-- the mutable array should not be used again. This cannot truly be enforced
-- except by linear types. To attempt to enforce this, we always make a
-- copy of the mutable primitive array and intentionally corrupt the original
-- of the original one. The strategy used here to corrupt the array is
-- simply to write 1 to every bit.
resizeMutablePrimArray :: forall m a. (HasCallStack, PrimMonad m, Prim a)
=> MutablePrimArray (PrimState m) a
-> Int -- ^ new size
-> m (MutablePrimArray (PrimState m) a)
resizeMutablePrimArray marr@(A.MutablePrimArray x) n = check "resizeMutablePrimArray: negative size" (n >= 0) $ do
let sz = A.sizeofMutablePrimArray marr
marr' <- A.cloneMutablePrimArray marr 0 sz
A.setPrimArray (A.MutablePrimArray x) 0 (sz * sizeOf (undefined :: a)) (0xFF :: Word8)
return marr'
freezePrimArray
:: (HasCallStack, PrimMonad m, Prim a)
=> MutablePrimArray (PrimState m) a -- ^ source
-> Int -- ^ offset
-> Int -- ^ length
-> m (PrimArray a)
freezePrimArray marr s l = check "freezePrimArray: index range of out bounds"
(s >= 0 && l >= 0 && s + l <= A.sizeofMutablePrimArray marr)
(A.freezePrimArray marr s l)
thawPrimArray
:: (HasCallStack, PrimMonad m, Prim a)
=> PrimArray a -- ^ source
-> Int -- ^ offset
-> Int -- ^ length
-> m (MutablePrimArray (PrimState m) a)
thawPrimArray arr s l = check "thawPrimArray: index range of out bounds"
(s >= 0 && l >= 0 && s + l <= A.sizeofPrimArray arr)
(A.thawPrimArray arr s l)
-- | This corrupts the contents of the argument array.
unsafeFreezePrimArray :: forall m a. (HasCallStack, PrimMonad m, Prim a)
=> MutablePrimArray (PrimState m) a
-> m (PrimArray a)
unsafeFreezePrimArray marr@(A.MutablePrimArray x) = do
let sz = A.sizeofMutablePrimArray marr
arr <- A.freezePrimArray marr 0 sz
A.setPrimArray (A.MutablePrimArray x) 0 (sz * sizeOf (undefined :: a)) (0xFF :: Word8)
return arr
shrinkMutablePrimArray :: forall m a. (HasCallStack, PrimMonad m, Prim a)
=> MutablePrimArray (PrimState m) a
-> Int -- ^ new size
-> m ()
shrinkMutablePrimArray marr n = do
old <- A.getSizeofMutablePrimArray marr
check "shrinkMutablePrimArray: illegal new size" (n >= 0 && n <= old) (A.shrinkMutablePrimArray marr n)
readPrimArray :: (HasCallStack, Prim a, PrimMonad m) => MutablePrimArray (PrimState m) a -> Int -> m a
readPrimArray marr i = do
siz <- A.getSizeofMutablePrimArray marr
let explain = L.concat
[ "[size: "
, show siz
, ", index: "
, show i
, "]"
]
check ("readPrimArray: index out of bounds " ++ explain) (i >= 0 && i < siz) (A.readPrimArray marr i)
writePrimArray :: (HasCallStack, Prim a, PrimMonad m)
=> MutablePrimArray (PrimState m) a -- ^ array
-> Int -- ^ index
-> a -- ^ element
-> m ()
writePrimArray marr i x = do
siz <- A.getSizeofMutablePrimArray marr
let explain = L.concat
[ "[size: "
, show siz
, ", index: "
, show i
, "]"
]
check ("writePrimArray: index out of bounds " ++ explain) (i >= 0 && i < siz) (A.writePrimArray marr i x)
indexPrimArray :: forall a. Prim a => PrimArray a -> Int -> a
indexPrimArray arr i =
let sz = A.sizeofPrimArray arr
explain = L.concat
[ "[size: "
, show sz
, ", index: "
, show i
, "]"
]
in check ("indexPrimArray: index out of bounds " ++ explain)
(i >= 0 && i < sz)
(A.indexPrimArray arr i)
setPrimArray :: forall m a. (HasCallStack, 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 ()
setPrimArray dst doff sz x = do
arrSz <- A.getSizeofMutablePrimArray dst
let explain = L.concat
[ "[size: "
, show arrSz
, ", offset: "
, show doff
, ", length: "
, show sz
, "]"
]
check ("setPrimArray: index range of out bounds " ++ explain)
(doff >= 0 && doff + sz <= arrSz)
(A.setPrimArray dst doff sz x)
copyPrimArray :: forall m a. (HasCallStack, 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 ()
copyPrimArray marr s1 arr s2 l = do
dstSz <- A.getSizeofMutablePrimArray marr
let srcSz = A.sizeofPrimArray arr
let explain = L.concat
[ "[dst_sz: "
, show dstSz
, ", dst_off: "
, show s1
, ", src_sz: "
, show srcSz
, ", src_off: "
, show s2
, ", len: "
, show l
, "]"
]
check ("copyPrimArray: index range of out bounds " ++ explain)
(s1 >= 0 && s2 >= 0 && l >= 0 && s1 + l <= dstSz && s2 + l <= srcSz)
(A.copyPrimArray marr s1 arr s2 l)
copyMutablePrimArray :: forall m a. (HasCallStack, 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 ()
copyMutablePrimArray marr1 s1 marr2 s2 l = do
dstSz <- A.getSizeofMutablePrimArray marr1
srcSz <- A.getSizeofMutablePrimArray marr2
let explain = L.concat
[ "[dst_sz: "
, show dstSz
, ", dst_off: "
, show s1
, ", src_sz: "
, show srcSz
, ", src_off: "
, show s2
, ", len: "
, show l
, "]"
]
check ("copyMutablePrimArray: index range of out bounds " ++ explain)
(s1 >= 0 && s2 >= 0 && l >= 0 && s1 + l <= dstSz && s2 + l <= srcSz)
(A.copyMutablePrimArray marr1 s1 marr2 s2 l)
copyPrimArrayToPtr :: forall m a. (HasCallStack, PrimMonad m, Prim a)
=> Ptr a -- ^ destination pointer
-> PrimArray a -- ^ source array
-> Int -- ^ offset into source array
-> Int -- ^ number of elements to copy
-> m ()
copyPrimArrayToPtr ptr arr s l = do
let srcSz = A.sizeofPrimArray arr
let explain = L.concat
[ "[src_sz: "
, show srcSz
, ", src_off: "
, show s
, ", len: "
, show l
, "]"
]
check ("copyPrimArrayToPtr: index range of out bounds " ++ explain)
(s >= 0 && l >= 0 && s + l <= srcSz)
(A.copyPrimArrayToPtr ptr arr s l)
copyMutablePrimArrayToPtr :: forall m a. (HasCallStack, PrimMonad m, Prim a)
=> Ptr a -- ^ destination pointer
-> MutablePrimArray (PrimState m) a -- ^ source array
-> Int -- ^ offset into source array
-> Int -- ^ number of elements to copy
-> m ()
copyMutablePrimArrayToPtr ptr marr s l = do
srcSz <- A.getSizeofMutablePrimArray marr
let explain = L.concat
[ "[src_sz: "
, show srcSz
, ", src_off: "
, show s
, ", len: "
, show l
, "]"
]
check ("copyMutablePrimArrayToPtr: index range of out bounds " ++ explain)
(s >= 0 && l >= 0 && s + l <= srcSz)
(A.copyMutablePrimArrayToPtr ptr marr s l)
clonePrimArray :: (HasCallStack, Prim a)
=> PrimArray a -- ^ source array
-> Int -- ^ offset into source array
-> Int -- ^ number of elements to copy
-> PrimArray a
clonePrimArray arr s l = check "clonePrimArray: index range of out bounds"
(s >= 0 && l >= 0 && s + l <= A.sizeofPrimArray arr)
(A.clonePrimArray arr s l)
cloneMutablePrimArray :: (HasCallStack, PrimMonad m, Prim a)
=> MutablePrimArray (PrimState m) a -- ^ source array
-> Int -- ^ offset into source array
-> Int -- ^ number of elements to copy
-> m (MutablePrimArray (PrimState m) a)
cloneMutablePrimArray marr s l = check "cloneMutablePrimArray: index range of out bounds"
(s >= 0 && l >= 0 && s + l <= A.sizeofMutablePrimArray marr)
(A.cloneMutablePrimArray marr s l)