module Data.Repa.Array.Internals.Target ( Target (..), IOBuffer, TargetI , fromList, fromListInto) where import Data.Repa.Array.Index as A import Data.Repa.Array.Internals.Bulk as A import System.IO.Unsafe import Control.Monad import Control.Monad.Primitive import Prelude as P -- Target --------------------------------------------------------------------- -- | Class of manifest array representations that can be constructed -- in a random-access manner. -- --- -- TODO: generalise to work with higher ranked indices. class Layout l => Target l a where -- | Mutable buffer for some array representation. data Buffer s l a -- | Allocate a new mutable buffer for the given layout. -- -- UNSAFE: The integer must be positive, but this is not checked. unsafeNewBuffer :: PrimMonad m => l -> m (Buffer (PrimState m) l a) -- | Read an element from the mutable buffer. -- -- UNSAFE: The index bounds are not checked. unsafeReadBuffer :: PrimMonad m => Buffer (PrimState m) l a -> Int -> m a -- | Write an element into the mutable buffer. -- -- UNSAFE: The index bounds are not checked. unsafeWriteBuffer :: PrimMonad m => Buffer (PrimState m) l a -> Int -> a -> m () -- | O(n). Copy the contents of a buffer that is larger by the given -- number of elements. -- -- UNSAFE: The integer must be positive, but this is not checked. unsafeGrowBuffer :: PrimMonad m => Buffer (PrimState m) l a -> Int -> m (Buffer (PrimState m) l a) -- | O(1). Yield a slice of the buffer without copying. -- -- UNSAFE: The given starting position and length must be within the bounds -- of the of the source buffer, but this is not checked. unsafeSliceBuffer :: PrimMonad m => Int -> Int -> Buffer (PrimState m) l a -> m (Buffer (PrimState m) l a) -- | O(1). Freeze a mutable buffer into an immutable Repa array. -- -- UNSAFE: If the buffer is mutated further then the result of reading from -- the returned array will be non-deterministic. unsafeFreezeBuffer :: PrimMonad m => Buffer (PrimState m) l a -> m (Array l a) -- | O(1). Thaw an Array into a mutable buffer. -- -- UNSAFE: The Array is no longer safe to use. unsafeThawBuffer :: PrimMonad m => Array l a -> m (Buffer (PrimState m) l a) -- | Ensure the array is still live at this point. -- Sometimes needed when the mutable buffer is a ForeignPtr with a finalizer. touchBuffer :: PrimMonad m => Buffer (PrimState m) l a -> m () -- | O(1). Get the layout from a Buffer. bufferLayout :: Buffer s l a -> l type IOBuffer = Buffer RealWorld -- | Constraint synonym that requires an integer index space. type TargetI l a = (Target l a, Index l ~ Int) ------------------------------------------------------------------------------- -- | O(length src). Construct a linear array from a list of elements. fromList :: TargetI l a => Name l -> [a] -> Array l a fromList nDst xx = let len = P.length xx lDst = create nDst len Just arr = fromListInto lDst xx in arr {-# NOINLINE fromList #-} -- | O(length src). Construct an array from a list of elements, -- and give it the provided layout. -- -- The `length` of the provided shape must match the length of the list, -- else `Nothing`. -- fromListInto :: Target l a => l -> [a] -> Maybe (Array l a) fromListInto lDst xx = unsafePerformIO $ do let !len = P.length xx if len /= size (extent lDst) then return Nothing else do buf <- unsafeNewBuffer lDst zipWithM_ (unsafeWriteBuffer buf) [0..] xx arr <- unsafeFreezeBuffer buf return $ Just arr {-# NOINLINE fromListInto #-}